1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2018 MediaTek Inc.
4 * Author: Chunhui Dai <chunhui.dai@mediatek.com>
7 #include "phy-mtk-hdmi.h"
8 #include "phy-mtk-io.h"
10 #define HDMI_CON0 0x00
11 #define RG_HDMITX_DRV_IBIAS_MASK GENMASK(5, 0)
12 #define RG_HDMITX_EN_SER_MASK GENMASK(15, 12)
13 #define RG_HDMITX_EN_SLDO_MASK GENMASK(19, 16)
14 #define RG_HDMITX_EN_PRED_MASK GENMASK(23, 20)
15 #define RG_HDMITX_EN_IMP_MASK GENMASK(27, 24)
16 #define RG_HDMITX_EN_DRV_MASK GENMASK(31, 28)
18 #define HDMI_CON1 0x04
19 #define RG_HDMITX_PRED_IBIAS_MASK GENMASK(21, 18)
20 #define RG_HDMITX_PRED_IMP BIT(22)
21 #define RG_HDMITX_DRV_IMP_MASK GENMASK(31, 26)
23 #define HDMI_CON2 0x08
24 #define RG_HDMITX_EN_TX_CKLDO BIT(0)
25 #define RG_HDMITX_EN_TX_POSDIV BIT(1)
26 #define RG_HDMITX_TX_POSDIV_MASK GENMASK(4, 3)
27 #define RG_HDMITX_EN_MBIAS BIT(6)
28 #define RG_HDMITX_MBIAS_LPF_EN BIT(7)
30 #define HDMI_CON4 0x10
31 #define RG_HDMITX_RESERVE_MASK GENMASK(31, 0)
33 #define HDMI_CON6 0x18
34 #define RG_HTPLL_BR_MASK GENMASK(1, 0)
35 #define RG_HTPLL_BC_MASK GENMASK(3, 2)
36 #define RG_HTPLL_BP_MASK GENMASK(7, 4)
37 #define RG_HTPLL_IR_MASK GENMASK(11, 8)
38 #define RG_HTPLL_IC_MASK GENMASK(15, 12)
39 #define RG_HTPLL_POSDIV_MASK GENMASK(17, 16)
40 #define RG_HTPLL_PREDIV_MASK GENMASK(19, 18)
41 #define RG_HTPLL_FBKSEL_MASK GENMASK(21, 20)
42 #define RG_HTPLL_RLH_EN BIT(22)
43 #define RG_HTPLL_FBKDIV_MASK GENMASK(30, 24)
44 #define RG_HTPLL_EN BIT(31)
46 #define HDMI_CON7 0x1c
47 #define RG_HTPLL_AUTOK_EN BIT(23)
48 #define RG_HTPLL_DIVEN_MASK GENMASK(30, 28)
50 static int mtk_hdmi_pll_prepare(struct clk_hw
*hw
)
52 struct mtk_hdmi_phy
*hdmi_phy
= to_mtk_hdmi_phy(hw
);
53 void __iomem
*base
= hdmi_phy
->regs
;
55 mtk_phy_set_bits(base
+ HDMI_CON7
, RG_HTPLL_AUTOK_EN
);
56 mtk_phy_clear_bits(base
+ HDMI_CON6
, RG_HTPLL_RLH_EN
);
57 mtk_phy_set_bits(base
+ HDMI_CON6
, RG_HTPLL_POSDIV_MASK
);
58 mtk_phy_set_bits(base
+ HDMI_CON2
, RG_HDMITX_EN_MBIAS
);
59 usleep_range(80, 100);
60 mtk_phy_set_bits(base
+ HDMI_CON6
, RG_HTPLL_EN
);
61 mtk_phy_set_bits(base
+ HDMI_CON2
, RG_HDMITX_EN_TX_CKLDO
);
62 mtk_phy_set_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_SLDO_MASK
);
63 usleep_range(80, 100);
64 mtk_phy_set_bits(base
+ HDMI_CON2
, RG_HDMITX_MBIAS_LPF_EN
);
65 mtk_phy_set_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_SER_MASK
);
66 mtk_phy_set_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_PRED_MASK
);
67 mtk_phy_set_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_DRV_MASK
);
68 usleep_range(80, 100);
72 static void mtk_hdmi_pll_unprepare(struct clk_hw
*hw
)
74 struct mtk_hdmi_phy
*hdmi_phy
= to_mtk_hdmi_phy(hw
);
75 void __iomem
*base
= hdmi_phy
->regs
;
77 mtk_phy_clear_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_DRV_MASK
);
78 mtk_phy_clear_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_PRED_MASK
);
79 mtk_phy_clear_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_SER_MASK
);
80 mtk_phy_clear_bits(base
+ HDMI_CON2
, RG_HDMITX_MBIAS_LPF_EN
);
81 usleep_range(80, 100);
82 mtk_phy_clear_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_SLDO_MASK
);
83 mtk_phy_clear_bits(base
+ HDMI_CON2
, RG_HDMITX_EN_TX_CKLDO
);
84 mtk_phy_clear_bits(base
+ HDMI_CON6
, RG_HTPLL_EN
);
85 usleep_range(80, 100);
86 mtk_phy_clear_bits(base
+ HDMI_CON2
, RG_HDMITX_EN_MBIAS
);
87 mtk_phy_clear_bits(base
+ HDMI_CON6
, RG_HTPLL_POSDIV_MASK
);
88 mtk_phy_clear_bits(base
+ HDMI_CON6
, RG_HTPLL_RLH_EN
);
89 mtk_phy_clear_bits(base
+ HDMI_CON7
, RG_HTPLL_AUTOK_EN
);
90 usleep_range(80, 100);
93 static long mtk_hdmi_pll_round_rate(struct clk_hw
*hw
, unsigned long rate
,
94 unsigned long *parent_rate
)
99 static int mtk_hdmi_pll_set_rate(struct clk_hw
*hw
, unsigned long rate
,
100 unsigned long parent_rate
)
102 struct mtk_hdmi_phy
*hdmi_phy
= to_mtk_hdmi_phy(hw
);
103 void __iomem
*base
= hdmi_phy
->regs
;
106 if (rate
<= 64000000)
108 else if (rate
<= 128000000)
113 mtk_phy_set_bits(base
+ HDMI_CON6
, RG_HTPLL_PREDIV_MASK
);
114 mtk_phy_set_bits(base
+ HDMI_CON6
, RG_HTPLL_POSDIV_MASK
);
115 mtk_phy_set_bits(base
+ HDMI_CON2
, RG_HDMITX_EN_TX_POSDIV
);
116 mtk_phy_update_field(base
+ HDMI_CON6
, RG_HTPLL_IC_MASK
, 0x1);
117 mtk_phy_update_field(base
+ HDMI_CON6
, RG_HTPLL_IR_MASK
, 0x1);
118 mtk_phy_update_field(base
+ HDMI_CON2
, RG_HDMITX_TX_POSDIV_MASK
, pos_div
);
119 mtk_phy_update_field(base
+ HDMI_CON6
, RG_HTPLL_FBKSEL_MASK
, 1);
120 mtk_phy_update_field(base
+ HDMI_CON6
, RG_HTPLL_FBKDIV_MASK
, 19);
121 mtk_phy_update_field(base
+ HDMI_CON7
, RG_HTPLL_DIVEN_MASK
, 0x2);
122 mtk_phy_update_field(base
+ HDMI_CON6
, RG_HTPLL_BP_MASK
, 0xc);
123 mtk_phy_update_field(base
+ HDMI_CON6
, RG_HTPLL_BC_MASK
, 0x2);
124 mtk_phy_update_field(base
+ HDMI_CON6
, RG_HTPLL_BR_MASK
, 0x1);
126 mtk_phy_clear_bits(base
+ HDMI_CON1
, RG_HDMITX_PRED_IMP
);
127 mtk_phy_update_field(base
+ HDMI_CON1
, RG_HDMITX_PRED_IBIAS_MASK
, 0x3);
128 mtk_phy_clear_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_IMP_MASK
);
129 mtk_phy_update_field(base
+ HDMI_CON1
, RG_HDMITX_DRV_IMP_MASK
, 0x28);
130 mtk_phy_update_field(base
+ HDMI_CON4
, RG_HDMITX_RESERVE_MASK
, 0x28);
131 mtk_phy_update_field(base
+ HDMI_CON0
, RG_HDMITX_DRV_IBIAS_MASK
, 0xa);
135 static unsigned long mtk_hdmi_pll_recalc_rate(struct clk_hw
*hw
,
136 unsigned long parent_rate
)
138 struct mtk_hdmi_phy
*hdmi_phy
= to_mtk_hdmi_phy(hw
);
139 unsigned long out_rate
, val
;
142 tmp
= readl(hdmi_phy
->regs
+ HDMI_CON6
);
143 val
= FIELD_GET(RG_HTPLL_PREDIV_MASK
, tmp
);
146 out_rate
= parent_rate
;
149 out_rate
= parent_rate
/ 2;
152 out_rate
= parent_rate
/ 4;
156 val
= FIELD_GET(RG_HTPLL_FBKDIV_MASK
, tmp
);
157 out_rate
*= (val
+ 1) * 2;
159 tmp
= readl(hdmi_phy
->regs
+ HDMI_CON2
);
160 val
= FIELD_GET(RG_HDMITX_TX_POSDIV_MASK
, tmp
);
163 if (tmp
& RG_HDMITX_EN_TX_POSDIV
)
169 static const struct clk_ops mtk_hdmi_phy_pll_ops
= {
170 .prepare
= mtk_hdmi_pll_prepare
,
171 .unprepare
= mtk_hdmi_pll_unprepare
,
172 .set_rate
= mtk_hdmi_pll_set_rate
,
173 .round_rate
= mtk_hdmi_pll_round_rate
,
174 .recalc_rate
= mtk_hdmi_pll_recalc_rate
,
177 static void mtk_hdmi_phy_enable_tmds(struct mtk_hdmi_phy
*hdmi_phy
)
179 void __iomem
*base
= hdmi_phy
->regs
;
181 mtk_phy_set_bits(base
+ HDMI_CON7
, RG_HTPLL_AUTOK_EN
);
182 mtk_phy_clear_bits(base
+ HDMI_CON6
, RG_HTPLL_RLH_EN
);
183 mtk_phy_set_bits(base
+ HDMI_CON6
, RG_HTPLL_POSDIV_MASK
);
184 mtk_phy_set_bits(base
+ HDMI_CON2
, RG_HDMITX_EN_MBIAS
);
185 usleep_range(80, 100);
186 mtk_phy_set_bits(base
+ HDMI_CON6
, RG_HTPLL_EN
);
187 mtk_phy_set_bits(base
+ HDMI_CON2
, RG_HDMITX_EN_TX_CKLDO
);
188 mtk_phy_set_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_SLDO_MASK
);
189 usleep_range(80, 100);
190 mtk_phy_set_bits(base
+ HDMI_CON2
, RG_HDMITX_MBIAS_LPF_EN
);
191 mtk_phy_set_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_SER_MASK
);
192 mtk_phy_set_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_PRED_MASK
);
193 mtk_phy_set_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_DRV_MASK
);
194 usleep_range(80, 100);
197 static void mtk_hdmi_phy_disable_tmds(struct mtk_hdmi_phy
*hdmi_phy
)
199 void __iomem
*base
= hdmi_phy
->regs
;
201 mtk_phy_clear_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_DRV_MASK
);
202 mtk_phy_clear_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_PRED_MASK
);
203 mtk_phy_clear_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_SER_MASK
);
204 mtk_phy_clear_bits(base
+ HDMI_CON2
, RG_HDMITX_MBIAS_LPF_EN
);
205 usleep_range(80, 100);
206 mtk_phy_clear_bits(base
+ HDMI_CON0
, RG_HDMITX_EN_SLDO_MASK
);
207 mtk_phy_clear_bits(base
+ HDMI_CON2
, RG_HDMITX_EN_TX_CKLDO
);
208 mtk_phy_clear_bits(base
+ HDMI_CON6
, RG_HTPLL_EN
);
209 usleep_range(80, 100);
210 mtk_phy_clear_bits(base
+ HDMI_CON2
, RG_HDMITX_EN_MBIAS
);
211 mtk_phy_clear_bits(base
+ HDMI_CON6
, RG_HTPLL_POSDIV_MASK
);
212 mtk_phy_clear_bits(base
+ HDMI_CON6
, RG_HTPLL_RLH_EN
);
213 mtk_phy_clear_bits(base
+ HDMI_CON7
, RG_HTPLL_AUTOK_EN
);
214 usleep_range(80, 100);
217 struct mtk_hdmi_phy_conf mtk_hdmi_phy_2701_conf
= {
218 .flags
= CLK_SET_RATE_GATE
,
219 .pll_default_off
= true,
220 .hdmi_phy_clk_ops
= &mtk_hdmi_phy_pll_ops
,
221 .hdmi_phy_enable_tmds
= mtk_hdmi_phy_enable_tmds
,
222 .hdmi_phy_disable_tmds
= mtk_hdmi_phy_disable_tmds
,
225 MODULE_AUTHOR("Chunhui Dai <chunhui.dai@mediatek.com>");
226 MODULE_DESCRIPTION("MediaTek HDMI PHY Driver");
227 MODULE_LICENSE("GPL v2");