diff options
| author | chunhui dai <chunhui.dai@mediatek.com> | 2018-10-02 23:41:47 -0400 |
|---|---|---|
| committer | CK Hu <ck.hu@mediatek.com> | 2018-10-02 23:56:32 -0400 |
| commit | be28b6507c46050f5b7244d9d98a19c03b9cf074 (patch) | |
| tree | 4fdd9687ee93c513674bdb5728b7fee0396442ea /drivers | |
| parent | d08b5ab972449b0ab494600fa985979e91e090ca (diff) | |
drm/mediatek: separate hdmi phy to different file
Different IC has different phy setting of HDMI.
This patch separates the phy hardware relate part for mt8173.
Signed-off-by: chunhui dai <chunhui.dai@mediatek.com>
Signed-off-by: CK Hu <ck.hu@mediatek.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpu/drm/mediatek/Makefile | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/mediatek/mtk_hdmi.c | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/mediatek/mtk_hdmi.h | 2 | ||||
| -rw-r--r-- | drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | 232 | ||||
| -rw-r--r-- | drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | 58 | ||||
| -rw-r--r-- | drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | 226 |
6 files changed, 302 insertions, 223 deletions
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile index ce83c396a742..61cf0d2ab28a 100644 --- a/drivers/gpu/drm/mediatek/Makefile +++ b/drivers/gpu/drm/mediatek/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | |||
| 2 | mediatek-drm-y := mtk_disp_color.o \ | 3 | mediatek-drm-y := mtk_disp_color.o \ |
| 3 | mtk_disp_ovl.o \ | 4 | mtk_disp_ovl.o \ |
| 4 | mtk_disp_rdma.o \ | 5 | mtk_disp_rdma.o \ |
| @@ -18,6 +19,7 @@ obj-$(CONFIG_DRM_MEDIATEK) += mediatek-drm.o | |||
| 18 | mediatek-drm-hdmi-objs := mtk_cec.o \ | 19 | mediatek-drm-hdmi-objs := mtk_cec.o \ |
| 19 | mtk_hdmi.o \ | 20 | mtk_hdmi.o \ |
| 20 | mtk_hdmi_ddc.o \ | 21 | mtk_hdmi_ddc.o \ |
| 21 | mtk_mt8173_hdmi_phy.o | 22 | mtk_mt8173_hdmi_phy.o \ |
| 23 | mtk_hdmi_phy.o | ||
| 22 | 24 | ||
| 23 | obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o | 25 | obj-$(CONFIG_DRM_MEDIATEK_HDMI) += mediatek-drm-hdmi.o \ No newline at end of file |
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c index 2d45d1dd9554..2ca9f6a64dab 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c | |||
| @@ -233,6 +233,7 @@ static void mtk_hdmi_hw_vid_black(struct mtk_hdmi *hdmi, bool black) | |||
| 233 | static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable) | 233 | static void mtk_hdmi_hw_make_reg_writable(struct mtk_hdmi *hdmi, bool enable) |
| 234 | { | 234 | { |
| 235 | struct arm_smccc_res res; | 235 | struct arm_smccc_res res; |
| 236 | struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(hdmi->phy); | ||
| 236 | 237 | ||
| 237 | /* | 238 | /* |
| 238 | * MT8173 HDMI hardware has an output control bit to enable/disable HDMI | 239 | * MT8173 HDMI hardware has an output control bit to enable/disable HDMI |
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.h b/drivers/gpu/drm/mediatek/mtk_hdmi.h index 6371b3de1ff6..3e9fb8d19802 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi.h +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.h | |||
| @@ -13,11 +13,11 @@ | |||
| 13 | */ | 13 | */ |
| 14 | #ifndef _MTK_HDMI_CTRL_H | 14 | #ifndef _MTK_HDMI_CTRL_H |
| 15 | #define _MTK_HDMI_CTRL_H | 15 | #define _MTK_HDMI_CTRL_H |
| 16 | #include "mtk_hdmi_phy.h" | ||
| 16 | 17 | ||
| 17 | struct platform_driver; | 18 | struct platform_driver; |
| 18 | 19 | ||
| 19 | extern struct platform_driver mtk_cec_driver; | 20 | extern struct platform_driver mtk_cec_driver; |
| 20 | extern struct platform_driver mtk_hdmi_ddc_driver; | 21 | extern struct platform_driver mtk_hdmi_ddc_driver; |
| 21 | extern struct platform_driver mtk_hdmi_phy_driver; | ||
| 22 | 22 | ||
| 23 | #endif /* _MTK_HDMI_CTRL_H */ | 23 | #endif /* _MTK_HDMI_CTRL_H */ |
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c new file mode 100644 index 000000000000..514f3e9a8767 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.c | |||
| @@ -0,0 +1,232 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2018 MediaTek Inc. | ||
| 4 | * Author: Jie Qiu <jie.qiu@mediatek.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include "mtk_hdmi_phy.h" | ||
| 8 | |||
| 9 | static int mtk_hdmi_phy_power_on(struct phy *phy); | ||
| 10 | static int mtk_hdmi_phy_power_off(struct phy *phy); | ||
| 11 | |||
| 12 | static const struct phy_ops mtk_hdmi_phy_dev_ops = { | ||
| 13 | .power_on = mtk_hdmi_phy_power_on, | ||
| 14 | .power_off = mtk_hdmi_phy_power_off, | ||
| 15 | .owner = THIS_MODULE, | ||
| 16 | }; | ||
| 17 | |||
| 18 | long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, | ||
| 19 | unsigned long *parent_rate) | ||
| 20 | { | ||
| 21 | struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); | ||
| 22 | |||
| 23 | hdmi_phy->pll_rate = rate; | ||
| 24 | if (rate <= 74250000) | ||
| 25 | *parent_rate = rate; | ||
| 26 | else | ||
| 27 | *parent_rate = rate / 2; | ||
| 28 | |||
| 29 | return rate; | ||
| 30 | } | ||
| 31 | |||
| 32 | unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, | ||
| 33 | unsigned long parent_rate) | ||
| 34 | { | ||
| 35 | struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); | ||
| 36 | |||
| 37 | return hdmi_phy->pll_rate; | ||
| 38 | } | ||
| 39 | |||
| 40 | void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, | ||
| 41 | u32 bits) | ||
| 42 | { | ||
| 43 | void __iomem *reg = hdmi_phy->regs + offset; | ||
| 44 | u32 tmp; | ||
| 45 | |||
| 46 | tmp = readl(reg); | ||
| 47 | tmp &= ~bits; | ||
| 48 | writel(tmp, reg); | ||
| 49 | } | ||
| 50 | |||
| 51 | void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, | ||
| 52 | u32 bits) | ||
| 53 | { | ||
| 54 | void __iomem *reg = hdmi_phy->regs + offset; | ||
| 55 | u32 tmp; | ||
| 56 | |||
| 57 | tmp = readl(reg); | ||
| 58 | tmp |= bits; | ||
| 59 | writel(tmp, reg); | ||
| 60 | } | ||
| 61 | |||
| 62 | void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, | ||
| 63 | u32 val, u32 mask) | ||
| 64 | { | ||
| 65 | void __iomem *reg = hdmi_phy->regs + offset; | ||
| 66 | u32 tmp; | ||
| 67 | |||
| 68 | tmp = readl(reg); | ||
| 69 | tmp = (tmp & ~mask) | (val & mask); | ||
| 70 | writel(tmp, reg); | ||
| 71 | } | ||
| 72 | |||
| 73 | inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw) | ||
| 74 | { | ||
| 75 | return container_of(hw, struct mtk_hdmi_phy, pll_hw); | ||
| 76 | } | ||
| 77 | |||
| 78 | static int mtk_hdmi_phy_power_on(struct phy *phy) | ||
| 79 | { | ||
| 80 | struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); | ||
| 81 | int ret; | ||
| 82 | |||
| 83 | ret = clk_prepare_enable(hdmi_phy->pll); | ||
| 84 | if (ret < 0) | ||
| 85 | return ret; | ||
| 86 | |||
| 87 | hdmi_phy->conf->hdmi_phy_enable_tmds(hdmi_phy); | ||
| 88 | return 0; | ||
| 89 | } | ||
| 90 | |||
| 91 | static int mtk_hdmi_phy_power_off(struct phy *phy) | ||
| 92 | { | ||
| 93 | struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); | ||
| 94 | |||
| 95 | hdmi_phy->conf->hdmi_phy_disable_tmds(hdmi_phy); | ||
| 96 | clk_disable_unprepare(hdmi_phy->pll); | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static const struct phy_ops * | ||
| 102 | mtk_hdmi_phy_dev_get_ops(const struct mtk_hdmi_phy *hdmi_phy) | ||
| 103 | { | ||
| 104 | if (hdmi_phy && hdmi_phy->conf && | ||
| 105 | hdmi_phy->conf->hdmi_phy_enable_tmds && | ||
| 106 | hdmi_phy->conf->hdmi_phy_disable_tmds) | ||
| 107 | return &mtk_hdmi_phy_dev_ops; | ||
| 108 | |||
| 109 | dev_err(hdmi_phy->dev, "Failed to get dev ops of phy\n"); | ||
| 110 | return NULL; | ||
| 111 | } | ||
| 112 | |||
| 113 | static void mtk_hdmi_phy_clk_get_ops(struct mtk_hdmi_phy *hdmi_phy, | ||
| 114 | const struct clk_ops **ops) | ||
| 115 | { | ||
| 116 | if (hdmi_phy && hdmi_phy->conf && hdmi_phy->conf->hdmi_phy_clk_ops) | ||
| 117 | *ops = hdmi_phy->conf->hdmi_phy_clk_ops; | ||
| 118 | else | ||
| 119 | dev_err(hdmi_phy->dev, "Failed to get clk ops of phy\n"); | ||
| 120 | } | ||
| 121 | |||
| 122 | static int mtk_hdmi_phy_probe(struct platform_device *pdev) | ||
| 123 | { | ||
| 124 | struct device *dev = &pdev->dev; | ||
| 125 | struct mtk_hdmi_phy *hdmi_phy; | ||
| 126 | struct resource *mem; | ||
| 127 | struct clk *ref_clk; | ||
| 128 | const char *ref_clk_name; | ||
| 129 | struct clk_init_data clk_init = { | ||
| 130 | .num_parents = 1, | ||
| 131 | .parent_names = (const char * const *)&ref_clk_name, | ||
| 132 | .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, | ||
| 133 | }; | ||
| 134 | |||
| 135 | struct phy *phy; | ||
| 136 | struct phy_provider *phy_provider; | ||
| 137 | int ret; | ||
| 138 | |||
| 139 | hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL); | ||
| 140 | if (!hdmi_phy) | ||
| 141 | return -ENOMEM; | ||
| 142 | |||
| 143 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 144 | hdmi_phy->regs = devm_ioremap_resource(dev, mem); | ||
| 145 | if (IS_ERR(hdmi_phy->regs)) { | ||
| 146 | ret = PTR_ERR(hdmi_phy->regs); | ||
| 147 | dev_err(dev, "Failed to get memory resource: %d\n", ret); | ||
| 148 | return ret; | ||
| 149 | } | ||
| 150 | |||
| 151 | ref_clk = devm_clk_get(dev, "pll_ref"); | ||
| 152 | if (IS_ERR(ref_clk)) { | ||
| 153 | ret = PTR_ERR(ref_clk); | ||
| 154 | dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n", | ||
| 155 | ret); | ||
| 156 | return ret; | ||
| 157 | } | ||
| 158 | ref_clk_name = __clk_get_name(ref_clk); | ||
| 159 | |||
| 160 | ret = of_property_read_string(dev->of_node, "clock-output-names", | ||
| 161 | &clk_init.name); | ||
| 162 | if (ret < 0) { | ||
| 163 | dev_err(dev, "Failed to read clock-output-names: %d\n", ret); | ||
| 164 | return ret; | ||
| 165 | } | ||
| 166 | |||
| 167 | hdmi_phy->dev = dev; | ||
| 168 | hdmi_phy->conf = | ||
| 169 | (struct mtk_hdmi_phy_conf *)of_device_get_match_data(dev); | ||
| 170 | mtk_hdmi_phy_clk_get_ops(hdmi_phy, &clk_init.ops); | ||
| 171 | hdmi_phy->pll_hw.init = &clk_init; | ||
| 172 | hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw); | ||
| 173 | if (IS_ERR(hdmi_phy->pll)) { | ||
| 174 | ret = PTR_ERR(hdmi_phy->pll); | ||
| 175 | dev_err(dev, "Failed to register PLL: %d\n", ret); | ||
| 176 | return ret; | ||
| 177 | } | ||
| 178 | |||
| 179 | ret = of_property_read_u32(dev->of_node, "mediatek,ibias", | ||
| 180 | &hdmi_phy->ibias); | ||
| 181 | if (ret < 0) { | ||
| 182 | dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret); | ||
| 183 | return ret; | ||
| 184 | } | ||
| 185 | |||
| 186 | ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up", | ||
| 187 | &hdmi_phy->ibias_up); | ||
| 188 | if (ret < 0) { | ||
| 189 | dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret); | ||
| 190 | return ret; | ||
| 191 | } | ||
| 192 | |||
| 193 | dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n"); | ||
| 194 | hdmi_phy->drv_imp_clk = 0x30; | ||
| 195 | hdmi_phy->drv_imp_d2 = 0x30; | ||
| 196 | hdmi_phy->drv_imp_d1 = 0x30; | ||
| 197 | hdmi_phy->drv_imp_d0 = 0x30; | ||
| 198 | |||
| 199 | phy = devm_phy_create(dev, NULL, mtk_hdmi_phy_dev_get_ops(hdmi_phy)); | ||
| 200 | if (IS_ERR(phy)) { | ||
| 201 | dev_err(dev, "Failed to create HDMI PHY\n"); | ||
| 202 | return PTR_ERR(phy); | ||
| 203 | } | ||
| 204 | phy_set_drvdata(phy, hdmi_phy); | ||
| 205 | |||
| 206 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
| 207 | if (IS_ERR(phy_provider)) { | ||
| 208 | dev_err(dev, "Failed to register HDMI PHY\n"); | ||
| 209 | return PTR_ERR(phy_provider); | ||
| 210 | } | ||
| 211 | |||
| 212 | return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, | ||
| 213 | hdmi_phy->pll); | ||
| 214 | } | ||
| 215 | |||
| 216 | static const struct of_device_id mtk_hdmi_phy_match[] = { | ||
| 217 | { .compatible = "mediatek,mt8173-hdmi-phy", | ||
| 218 | .data = &mtk_hdmi_phy_8173_conf, | ||
| 219 | }, | ||
| 220 | {}, | ||
| 221 | }; | ||
| 222 | |||
| 223 | struct platform_driver mtk_hdmi_phy_driver = { | ||
| 224 | .probe = mtk_hdmi_phy_probe, | ||
| 225 | .driver = { | ||
| 226 | .name = "mediatek-hdmi-phy", | ||
| 227 | .of_match_table = mtk_hdmi_phy_match, | ||
| 228 | }, | ||
| 229 | }; | ||
| 230 | |||
| 231 | MODULE_DESCRIPTION("MediaTek HDMI PHY Driver"); | ||
| 232 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h new file mode 100644 index 000000000000..09b8f525e6b8 --- /dev/null +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_phy.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2018 MediaTek Inc. | ||
| 4 | * Author: Chunhui Dai <chunhui.dai@mediatek.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef _MTK_HDMI_PHY_H | ||
| 8 | #define _MTK_HDMI_PHY_H | ||
| 9 | #include <linux/clk.h> | ||
| 10 | #include <linux/clk-provider.h> | ||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/io.h> | ||
| 13 | #include <linux/mfd/syscon.h> | ||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/of_device.h> | ||
| 16 | #include <linux/phy/phy.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/types.h> | ||
| 19 | |||
| 20 | struct mtk_hdmi_phy; | ||
| 21 | |||
| 22 | struct mtk_hdmi_phy_conf { | ||
| 23 | const struct clk_ops *hdmi_phy_clk_ops; | ||
| 24 | void (*hdmi_phy_enable_tmds)(struct mtk_hdmi_phy *hdmi_phy); | ||
| 25 | void (*hdmi_phy_disable_tmds)(struct mtk_hdmi_phy *hdmi_phy); | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct mtk_hdmi_phy { | ||
| 29 | void __iomem *regs; | ||
| 30 | struct device *dev; | ||
| 31 | struct mtk_hdmi_phy_conf *conf; | ||
| 32 | struct clk *pll; | ||
| 33 | struct clk_hw pll_hw; | ||
| 34 | unsigned long pll_rate; | ||
| 35 | unsigned char drv_imp_clk; | ||
| 36 | unsigned char drv_imp_d2; | ||
| 37 | unsigned char drv_imp_d1; | ||
| 38 | unsigned char drv_imp_d0; | ||
| 39 | unsigned int ibias; | ||
| 40 | unsigned int ibias_up; | ||
| 41 | }; | ||
| 42 | |||
| 43 | void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, | ||
| 44 | u32 bits); | ||
| 45 | void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, | ||
| 46 | u32 bits); | ||
| 47 | void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, | ||
| 48 | u32 val, u32 mask); | ||
| 49 | struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw); | ||
| 50 | long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, | ||
| 51 | unsigned long *parent_rate); | ||
| 52 | unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, | ||
| 53 | unsigned long parent_rate); | ||
| 54 | |||
| 55 | extern struct platform_driver mtk_hdmi_phy_driver; | ||
| 56 | extern struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf; | ||
| 57 | |||
| 58 | #endif /* _MTK_HDMI_PHY_H */ | ||
diff --git a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c index 51cb9cfb6646..ed5916b27658 100644 --- a/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c +++ b/drivers/gpu/drm/mediatek/mtk_mt8173_hdmi_phy.c | |||
| @@ -12,15 +12,7 @@ | |||
| 12 | * GNU General Public License for more details. | 12 | * GNU General Public License for more details. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/clk.h> | 15 | #include "mtk_hdmi_phy.h" |
| 16 | #include <linux/clk-provider.h> | ||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/mfd/syscon.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/phy/phy.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/types.h> | ||
| 24 | 16 | ||
| 25 | #define HDMI_CON0 0x00 | 17 | #define HDMI_CON0 0x00 |
| 26 | #define RG_HDMITX_PLL_EN BIT(31) | 18 | #define RG_HDMITX_PLL_EN BIT(31) |
| @@ -123,20 +115,6 @@ | |||
| 123 | #define RGS_HDMITX_5T1_EDG (0xf << 4) | 115 | #define RGS_HDMITX_5T1_EDG (0xf << 4) |
| 124 | #define RGS_HDMITX_PLUG_TST BIT(0) | 116 | #define RGS_HDMITX_PLUG_TST BIT(0) |
| 125 | 117 | ||
| 126 | struct mtk_hdmi_phy { | ||
| 127 | void __iomem *regs; | ||
| 128 | struct device *dev; | ||
| 129 | struct clk *pll; | ||
| 130 | struct clk_hw pll_hw; | ||
| 131 | unsigned long pll_rate; | ||
| 132 | u8 drv_imp_clk; | ||
| 133 | u8 drv_imp_d2; | ||
| 134 | u8 drv_imp_d1; | ||
| 135 | u8 drv_imp_d0; | ||
| 136 | u32 ibias; | ||
| 137 | u32 ibias_up; | ||
| 138 | }; | ||
| 139 | |||
| 140 | static const u8 PREDIV[3][4] = { | 118 | static const u8 PREDIV[3][4] = { |
| 141 | {0x0, 0x0, 0x0, 0x0}, /* 27Mhz */ | 119 | {0x0, 0x0, 0x0, 0x0}, /* 27Mhz */ |
| 142 | {0x1, 0x1, 0x1, 0x1}, /* 74Mhz */ | 120 | {0x1, 0x1, 0x1, 0x1}, /* 74Mhz */ |
| @@ -185,44 +163,6 @@ static const u8 HTPLLBR[3][4] = { | |||
| 185 | {0x1, 0x2, 0x2, 0x1} /* 148Mhz */ | 163 | {0x1, 0x2, 0x2, 0x1} /* 148Mhz */ |
| 186 | }; | 164 | }; |
| 187 | 165 | ||
| 188 | static void mtk_hdmi_phy_clear_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, | ||
| 189 | u32 bits) | ||
| 190 | { | ||
| 191 | void __iomem *reg = hdmi_phy->regs + offset; | ||
| 192 | u32 tmp; | ||
| 193 | |||
| 194 | tmp = readl(reg); | ||
| 195 | tmp &= ~bits; | ||
| 196 | writel(tmp, reg); | ||
| 197 | } | ||
| 198 | |||
| 199 | static void mtk_hdmi_phy_set_bits(struct mtk_hdmi_phy *hdmi_phy, u32 offset, | ||
| 200 | u32 bits) | ||
| 201 | { | ||
| 202 | void __iomem *reg = hdmi_phy->regs + offset; | ||
| 203 | u32 tmp; | ||
| 204 | |||
| 205 | tmp = readl(reg); | ||
| 206 | tmp |= bits; | ||
| 207 | writel(tmp, reg); | ||
| 208 | } | ||
| 209 | |||
| 210 | static void mtk_hdmi_phy_mask(struct mtk_hdmi_phy *hdmi_phy, u32 offset, | ||
| 211 | u32 val, u32 mask) | ||
| 212 | { | ||
| 213 | void __iomem *reg = hdmi_phy->regs + offset; | ||
| 214 | u32 tmp; | ||
| 215 | |||
| 216 | tmp = readl(reg); | ||
| 217 | tmp = (tmp & ~mask) | (val & mask); | ||
| 218 | writel(tmp, reg); | ||
| 219 | } | ||
| 220 | |||
| 221 | static inline struct mtk_hdmi_phy *to_mtk_hdmi_phy(struct clk_hw *hw) | ||
| 222 | { | ||
| 223 | return container_of(hw, struct mtk_hdmi_phy, pll_hw); | ||
| 224 | } | ||
| 225 | |||
| 226 | static int mtk_hdmi_pll_prepare(struct clk_hw *hw) | 166 | static int mtk_hdmi_pll_prepare(struct clk_hw *hw) |
| 227 | { | 167 | { |
| 228 | struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); | 168 | struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); |
| @@ -345,29 +285,7 @@ static int mtk_hdmi_pll_set_rate(struct clk_hw *hw, unsigned long rate, | |||
| 345 | return 0; | 285 | return 0; |
| 346 | } | 286 | } |
| 347 | 287 | ||
| 348 | static long mtk_hdmi_pll_round_rate(struct clk_hw *hw, unsigned long rate, | 288 | static const struct clk_ops mtk_hdmi_phy_pll_ops = { |
| 349 | unsigned long *parent_rate) | ||
| 350 | { | ||
| 351 | struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); | ||
| 352 | |||
| 353 | hdmi_phy->pll_rate = rate; | ||
| 354 | if (rate <= 74250000) | ||
| 355 | *parent_rate = rate; | ||
| 356 | else | ||
| 357 | *parent_rate = rate / 2; | ||
| 358 | |||
| 359 | return rate; | ||
| 360 | } | ||
| 361 | |||
| 362 | static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw *hw, | ||
| 363 | unsigned long parent_rate) | ||
| 364 | { | ||
| 365 | struct mtk_hdmi_phy *hdmi_phy = to_mtk_hdmi_phy(hw); | ||
| 366 | |||
| 367 | return hdmi_phy->pll_rate; | ||
| 368 | } | ||
| 369 | |||
| 370 | static const struct clk_ops mtk_hdmi_pll_ops = { | ||
| 371 | .prepare = mtk_hdmi_pll_prepare, | 289 | .prepare = mtk_hdmi_pll_prepare, |
| 372 | .unprepare = mtk_hdmi_pll_unprepare, | 290 | .unprepare = mtk_hdmi_pll_unprepare, |
| 373 | .set_rate = mtk_hdmi_pll_set_rate, | 291 | .set_rate = mtk_hdmi_pll_set_rate, |
| @@ -390,142 +308,10 @@ static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy *hdmi_phy) | |||
| 390 | RG_HDMITX_SER_EN); | 308 | RG_HDMITX_SER_EN); |
| 391 | } | 309 | } |
| 392 | 310 | ||
| 393 | static int mtk_hdmi_phy_power_on(struct phy *phy) | 311 | struct mtk_hdmi_phy_conf mtk_hdmi_phy_8173_conf = { |
| 394 | { | 312 | .hdmi_phy_clk_ops = &mtk_hdmi_phy_pll_ops, |
| 395 | struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); | 313 | .hdmi_phy_enable_tmds = mtk_hdmi_phy_enable_tmds, |
| 396 | int ret; | 314 | .hdmi_phy_disable_tmds = mtk_hdmi_phy_disable_tmds, |
| 397 | |||
| 398 | ret = clk_prepare_enable(hdmi_phy->pll); | ||
| 399 | if (ret < 0) | ||
| 400 | return ret; | ||
| 401 | |||
| 402 | mtk_hdmi_phy_enable_tmds(hdmi_phy); | ||
| 403 | |||
| 404 | return 0; | ||
| 405 | } | ||
| 406 | |||
| 407 | static int mtk_hdmi_phy_power_off(struct phy *phy) | ||
| 408 | { | ||
| 409 | struct mtk_hdmi_phy *hdmi_phy = phy_get_drvdata(phy); | ||
| 410 | |||
| 411 | mtk_hdmi_phy_disable_tmds(hdmi_phy); | ||
| 412 | clk_disable_unprepare(hdmi_phy->pll); | ||
| 413 | |||
| 414 | return 0; | ||
| 415 | } | ||
| 416 | |||
| 417 | static const struct phy_ops mtk_hdmi_phy_ops = { | ||
| 418 | .power_on = mtk_hdmi_phy_power_on, | ||
| 419 | .power_off = mtk_hdmi_phy_power_off, | ||
| 420 | .owner = THIS_MODULE, | ||
| 421 | }; | ||
| 422 | |||
| 423 | static int mtk_hdmi_phy_probe(struct platform_device *pdev) | ||
| 424 | { | ||
| 425 | struct device *dev = &pdev->dev; | ||
| 426 | struct mtk_hdmi_phy *hdmi_phy; | ||
| 427 | struct resource *mem; | ||
| 428 | struct clk *ref_clk; | ||
| 429 | const char *ref_clk_name; | ||
| 430 | struct clk_init_data clk_init = { | ||
| 431 | .ops = &mtk_hdmi_pll_ops, | ||
| 432 | .num_parents = 1, | ||
| 433 | .parent_names = (const char * const *)&ref_clk_name, | ||
| 434 | .flags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE, | ||
| 435 | }; | ||
| 436 | struct phy *phy; | ||
| 437 | struct phy_provider *phy_provider; | ||
| 438 | int ret; | ||
| 439 | |||
| 440 | hdmi_phy = devm_kzalloc(dev, sizeof(*hdmi_phy), GFP_KERNEL); | ||
| 441 | if (!hdmi_phy) | ||
| 442 | return -ENOMEM; | ||
| 443 | |||
| 444 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 445 | hdmi_phy->regs = devm_ioremap_resource(dev, mem); | ||
| 446 | if (IS_ERR(hdmi_phy->regs)) { | ||
| 447 | ret = PTR_ERR(hdmi_phy->regs); | ||
| 448 | dev_err(dev, "Failed to get memory resource: %d\n", ret); | ||
| 449 | return ret; | ||
| 450 | } | ||
| 451 | |||
| 452 | ref_clk = devm_clk_get(dev, "pll_ref"); | ||
| 453 | if (IS_ERR(ref_clk)) { | ||
| 454 | ret = PTR_ERR(ref_clk); | ||
| 455 | dev_err(&pdev->dev, "Failed to get PLL reference clock: %d\n", | ||
| 456 | ret); | ||
| 457 | return ret; | ||
| 458 | } | ||
| 459 | ref_clk_name = __clk_get_name(ref_clk); | ||
| 460 | |||
| 461 | ret = of_property_read_string(dev->of_node, "clock-output-names", | ||
| 462 | &clk_init.name); | ||
| 463 | if (ret < 0) { | ||
| 464 | dev_err(dev, "Failed to read clock-output-names: %d\n", ret); | ||
| 465 | return ret; | ||
| 466 | } | ||
| 467 | |||
| 468 | hdmi_phy->pll_hw.init = &clk_init; | ||
| 469 | hdmi_phy->pll = devm_clk_register(dev, &hdmi_phy->pll_hw); | ||
| 470 | if (IS_ERR(hdmi_phy->pll)) { | ||
| 471 | ret = PTR_ERR(hdmi_phy->pll); | ||
| 472 | dev_err(dev, "Failed to register PLL: %d\n", ret); | ||
| 473 | return ret; | ||
| 474 | } | ||
| 475 | |||
| 476 | ret = of_property_read_u32(dev->of_node, "mediatek,ibias", | ||
| 477 | &hdmi_phy->ibias); | ||
| 478 | if (ret < 0) { | ||
| 479 | dev_err(&pdev->dev, "Failed to get ibias: %d\n", ret); | ||
| 480 | return ret; | ||
| 481 | } | ||
| 482 | |||
| 483 | ret = of_property_read_u32(dev->of_node, "mediatek,ibias_up", | ||
| 484 | &hdmi_phy->ibias_up); | ||
| 485 | if (ret < 0) { | ||
| 486 | dev_err(&pdev->dev, "Failed to get ibias up: %d\n", ret); | ||
| 487 | return ret; | ||
| 488 | } | ||
| 489 | |||
| 490 | dev_info(dev, "Using default TX DRV impedance: 4.2k/36\n"); | ||
| 491 | hdmi_phy->drv_imp_clk = 0x30; | ||
| 492 | hdmi_phy->drv_imp_d2 = 0x30; | ||
| 493 | hdmi_phy->drv_imp_d1 = 0x30; | ||
| 494 | hdmi_phy->drv_imp_d0 = 0x30; | ||
| 495 | |||
| 496 | phy = devm_phy_create(dev, NULL, &mtk_hdmi_phy_ops); | ||
| 497 | if (IS_ERR(phy)) { | ||
| 498 | dev_err(dev, "Failed to create HDMI PHY\n"); | ||
| 499 | return PTR_ERR(phy); | ||
| 500 | } | ||
| 501 | phy_set_drvdata(phy, hdmi_phy); | ||
| 502 | |||
| 503 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
| 504 | if (IS_ERR(phy_provider)) | ||
| 505 | return PTR_ERR(phy_provider); | ||
| 506 | |||
| 507 | hdmi_phy->dev = dev; | ||
| 508 | return of_clk_add_provider(dev->of_node, of_clk_src_simple_get, | ||
| 509 | hdmi_phy->pll); | ||
| 510 | } | ||
| 511 | |||
| 512 | static int mtk_hdmi_phy_remove(struct platform_device *pdev) | ||
| 513 | { | ||
| 514 | return 0; | ||
| 515 | } | ||
| 516 | |||
| 517 | static const struct of_device_id mtk_hdmi_phy_match[] = { | ||
| 518 | { .compatible = "mediatek,mt8173-hdmi-phy", }, | ||
| 519 | {}, | ||
| 520 | }; | ||
| 521 | |||
| 522 | struct platform_driver mtk_hdmi_phy_driver = { | ||
| 523 | .probe = mtk_hdmi_phy_probe, | ||
| 524 | .remove = mtk_hdmi_phy_remove, | ||
| 525 | .driver = { | ||
| 526 | .name = "mediatek-hdmi-phy", | ||
| 527 | .of_match_table = mtk_hdmi_phy_match, | ||
| 528 | }, | ||
| 529 | }; | 315 | }; |
| 530 | 316 | ||
| 531 | MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>"); | 317 | MODULE_AUTHOR("Jie Qiu <jie.qiu@mediatek.com>"); |
