]>
Commit | Line | Data |
---|---|---|
aa227118 JT |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Rockchip Innosilicon HDMI PHY | |
4 | * | |
5 | * Copyright (c) 2023 Edgeble AI Technologies Pvt. Ltd. | |
6 | * Copyright (c) 2017 Rockchip Electronics Co. Ltd. | |
7 | */ | |
8 | ||
9 | #include <clk-uclass.h> | |
10 | #include <dm.h> | |
11 | #include <div64.h> | |
12 | #include <dm/device_compat.h> | |
13 | #include <dm/device-internal.h> | |
14 | #include <dm/lists.h> | |
15 | #include <generic-phy.h> | |
16 | #include <asm/io.h> | |
17 | #include <linux/delay.h> | |
18 | #include <linux/iopoll.h> | |
19 | ||
20 | #define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) | |
21 | ||
22 | /* REG: 0x01 */ | |
23 | #define RK3328_BYPASS_RXSENSE_EN BIT(2) | |
24 | #define RK3328_BYPASS_POWERON_EN BIT(1) | |
25 | #define RK3328_BYPASS_PLLPD_EN BIT(0) | |
26 | /* REG: 0x02 */ | |
27 | #define RK3328_INT_POL_HIGH BIT(7) | |
28 | #define RK3328_BYPASS_PDATA_EN BIT(4) | |
29 | #define RK3328_PDATA_EN BIT(0) | |
30 | /* REG:0x05 */ | |
31 | #define RK3328_INT_TMDS_CLK(x) UPDATE(x, 7, 4) | |
32 | #define RK3328_INT_TMDS_D2(x) UPDATE(x, 3, 0) | |
33 | /* REG:0x07 */ | |
34 | #define RK3328_INT_TMDS_D1(x) UPDATE(x, 7, 4) | |
35 | #define RK3328_INT_TMDS_D0(x) UPDATE(x, 3, 0) | |
36 | /* for all RK3328_INT_TMDS_*, ESD_DET as defined in 0xc8-0xcb */ | |
37 | #define RK3328_INT_AGND_LOW_PULSE_LOCKED BIT(3) | |
38 | #define RK3328_INT_RXSENSE_LOW_PULSE_LOCKED BIT(2) | |
39 | #define RK3328_INT_VSS_AGND_ESD_DET BIT(1) | |
40 | #define RK3328_INT_AGND_VSS_ESD_DET BIT(0) | |
41 | /* REG: 0xa0 */ | |
42 | #define RK3328_PCLK_VCO_DIV_5_MASK BIT(1) | |
43 | #define RK3328_PCLK_VCO_DIV_5(x) UPDATE(x, 1, 1) | |
44 | #define RK3328_PRE_PLL_POWER_DOWN BIT(0) | |
45 | /* REG: 0xa1 */ | |
46 | #define RK3328_PRE_PLL_PRE_DIV_MASK GENMASK(5, 0) | |
47 | #define RK3328_PRE_PLL_PRE_DIV(x) UPDATE(x, 5, 0) | |
48 | /* REG: 0xa2 */ | |
49 | /* unset means center spread */ | |
50 | #define RK3328_SPREAD_SPECTRUM_MOD_DOWN BIT(7) | |
51 | #define RK3328_SPREAD_SPECTRUM_MOD_DISABLE BIT(6) | |
52 | #define RK3328_PRE_PLL_FRAC_DIV_DISABLE UPDATE(3, 5, 4) | |
53 | #define RK3328_PRE_PLL_FB_DIV_11_8_MASK GENMASK(3, 0) | |
54 | #define RK3328_PRE_PLL_FB_DIV_11_8(x) UPDATE((x) >> 8, 3, 0) | |
55 | /* REG: 0xa3 */ | |
56 | #define RK3328_PRE_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) | |
57 | /* REG: 0xa4*/ | |
58 | #define RK3328_PRE_PLL_TMDSCLK_DIV_C_MASK GENMASK(1, 0) | |
59 | #define RK3328_PRE_PLL_TMDSCLK_DIV_C(x) UPDATE(x, 1, 0) | |
60 | #define RK3328_PRE_PLL_TMDSCLK_DIV_B_MASK GENMASK(3, 2) | |
61 | #define RK3328_PRE_PLL_TMDSCLK_DIV_B(x) UPDATE(x, 3, 2) | |
62 | #define RK3328_PRE_PLL_TMDSCLK_DIV_A_MASK GENMASK(5, 4) | |
63 | #define RK3328_PRE_PLL_TMDSCLK_DIV_A(x) UPDATE(x, 5, 4) | |
64 | /* REG: 0xa5 */ | |
65 | #define RK3328_PRE_PLL_PCLK_DIV_B_SHIFT 5 | |
66 | #define RK3328_PRE_PLL_PCLK_DIV_B_MASK GENMASK(6, 5) | |
67 | #define RK3328_PRE_PLL_PCLK_DIV_B(x) UPDATE(x, 6, 5) | |
68 | #define RK3328_PRE_PLL_PCLK_DIV_A_MASK GENMASK(4, 0) | |
69 | #define RK3328_PRE_PLL_PCLK_DIV_A(x) UPDATE(x, 4, 0) | |
70 | /* REG: 0xa6 */ | |
71 | #define RK3328_PRE_PLL_PCLK_DIV_C_SHIFT 5 | |
72 | #define RK3328_PRE_PLL_PCLK_DIV_C_MASK GENMASK(6, 5) | |
73 | #define RK3328_PRE_PLL_PCLK_DIV_C(x) UPDATE(x, 6, 5) | |
74 | #define RK3328_PRE_PLL_PCLK_DIV_D_MASK GENMASK(4, 0) | |
75 | #define RK3328_PRE_PLL_PCLK_DIV_D(x) UPDATE(x, 4, 0) | |
76 | /* REG: 0xa9 */ | |
77 | #define RK3328_PRE_PLL_LOCK_STATUS BIT(0) | |
78 | /* REG: 0xaa */ | |
79 | #define RK3328_POST_PLL_POST_DIV_ENABLE GENMASK(3, 2) | |
80 | #define RK3328_POST_PLL_REFCLK_SEL_TMDS BIT(1) | |
81 | #define RK3328_POST_PLL_POWER_DOWN BIT(0) | |
82 | /* REG:0xab */ | |
83 | #define RK3328_POST_PLL_FB_DIV_8(x) UPDATE((x) >> 8, 7, 7) | |
84 | #define RK3328_POST_PLL_PRE_DIV(x) UPDATE(x, 4, 0) | |
85 | /* REG: 0xac */ | |
86 | #define RK3328_POST_PLL_FB_DIV_7_0(x) UPDATE(x, 7, 0) | |
87 | /* REG: 0xad */ | |
88 | #define RK3328_POST_PLL_POST_DIV_MASK GENMASK(1, 0) | |
89 | #define RK3328_POST_PLL_POST_DIV_2 0x0 | |
90 | #define RK3328_POST_PLL_POST_DIV_4 0x1 | |
91 | #define RK3328_POST_PLL_POST_DIV_8 0x3 | |
92 | /* REG: 0xaf */ | |
93 | #define RK3328_POST_PLL_LOCK_STATUS BIT(0) | |
94 | /* REG: 0xb0 */ | |
95 | #define RK3328_BANDGAP_ENABLE BIT(2) | |
96 | /* REG: 0xb2 */ | |
97 | #define RK3328_TMDS_CLK_DRIVER_EN BIT(3) | |
98 | #define RK3328_TMDS_D2_DRIVER_EN BIT(2) | |
99 | #define RK3328_TMDS_D1_DRIVER_EN BIT(1) | |
100 | #define RK3328_TMDS_D0_DRIVER_EN BIT(0) | |
101 | #define RK3328_TMDS_DRIVER_ENABLE (RK3328_TMDS_CLK_DRIVER_EN | \ | |
102 | RK3328_TMDS_D2_DRIVER_EN | \ | |
103 | RK3328_TMDS_D1_DRIVER_EN | \ | |
104 | RK3328_TMDS_D0_DRIVER_EN) | |
105 | /* REG:0xc5 */ | |
106 | #define RK3328_BYPASS_TERM_RESISTOR_CALIB BIT(7) | |
107 | #define RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(x) UPDATE((x) >> 8, 6, 0) | |
108 | /* REG:0xc6 */ | |
109 | #define RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(x) UPDATE(x, 7, 0) | |
110 | /* REG:0xc7 */ | |
111 | #define RK3328_TERM_RESISTOR_50 UPDATE(0, 2, 1) | |
112 | #define RK3328_TERM_RESISTOR_62_5 UPDATE(1, 2, 1) | |
113 | #define RK3328_TERM_RESISTOR_75 UPDATE(2, 2, 1) | |
114 | #define RK3328_TERM_RESISTOR_100 UPDATE(3, 2, 1) | |
115 | /* REG 0xc8 - 0xcb */ | |
116 | #define RK3328_ESD_DETECT_MASK GENMASK(7, 6) | |
117 | #define RK3328_ESD_DETECT_340MV (0x0 << 6) | |
118 | #define RK3328_ESD_DETECT_280MV (0x1 << 6) | |
119 | #define RK3328_ESD_DETECT_260MV (0x2 << 6) | |
120 | #define RK3328_ESD_DETECT_240MV (0x3 << 6) | |
121 | /* resistors can be used in parallel */ | |
122 | #define RK3328_TMDS_TERM_RESIST_MASK GENMASK(5, 0) | |
123 | #define RK3328_TMDS_TERM_RESIST_75 BIT(5) | |
124 | #define RK3328_TMDS_TERM_RESIST_150 BIT(4) | |
125 | #define RK3328_TMDS_TERM_RESIST_300 BIT(3) | |
126 | #define RK3328_TMDS_TERM_RESIST_600 BIT(2) | |
127 | #define RK3328_TMDS_TERM_RESIST_1000 BIT(1) | |
128 | #define RK3328_TMDS_TERM_RESIST_2000 BIT(0) | |
129 | /* REG: 0xd1 */ | |
130 | #define RK3328_PRE_PLL_FRAC_DIV_23_16(x) UPDATE((x) >> 16, 7, 0) | |
131 | /* REG: 0xd2 */ | |
132 | #define RK3328_PRE_PLL_FRAC_DIV_15_8(x) UPDATE((x) >> 8, 7, 0) | |
133 | /* REG: 0xd3 */ | |
134 | #define RK3328_PRE_PLL_FRAC_DIV_7_0(x) UPDATE(x, 7, 0) | |
135 | ||
136 | struct phy_config { | |
137 | unsigned long tmdsclock; | |
138 | u8 regs[14]; | |
139 | }; | |
140 | ||
141 | struct pre_pll_config { | |
142 | unsigned long pixclock; | |
143 | unsigned long tmdsclock; | |
144 | u8 prediv; | |
145 | u16 fbdiv; | |
146 | u8 tmds_div_a; | |
147 | u8 tmds_div_b; | |
148 | u8 tmds_div_c; | |
149 | u8 pclk_div_a; | |
150 | u8 pclk_div_b; | |
151 | u8 pclk_div_c; | |
152 | u8 pclk_div_d; | |
153 | u8 vco_div_5_en; | |
154 | u32 fracdiv; | |
155 | }; | |
156 | ||
157 | struct post_pll_config { | |
158 | unsigned long tmdsclock; | |
159 | u8 prediv; | |
160 | u16 fbdiv; | |
161 | u8 postdiv; | |
162 | u8 version; | |
163 | }; | |
164 | ||
165 | struct inno_hdmi_phy_plat_ops { | |
166 | void (*init)(struct phy *phy); | |
167 | int (*power_on)(struct phy *phy, const struct post_pll_config *cfg, | |
168 | const struct phy_config *phy_cfg); | |
169 | void (*power_off)(struct phy *phy); | |
170 | void (*clk_enable)(struct phy *phy); | |
171 | void (*clk_disable)(struct phy *phy); | |
172 | unsigned long (*clk_recalc_rate)(struct phy *phy, | |
173 | unsigned long parent_rate); | |
174 | long (*clk_round_rate)(struct phy *phy, unsigned long rate); | |
175 | int (*clk_set_rate)(struct phy *phy, unsigned long rate, | |
176 | unsigned long parent_rate); | |
177 | }; | |
178 | ||
179 | enum inno_hdmi_phy_type { | |
180 | INNO_HDMI_PHY_RK3328, | |
181 | }; | |
182 | ||
183 | struct inno_hdmi_phy_data { | |
184 | enum inno_hdmi_phy_type phy_type; | |
185 | const struct inno_hdmi_phy_plat_ops *plat_ops; | |
186 | const struct phy_config *phy_cfg_table; | |
187 | }; | |
188 | ||
189 | struct inno_hdmi_phy { | |
190 | struct udevice *dev; | |
191 | ofnode node; | |
192 | void *regs; | |
193 | ||
194 | struct clk refoclk; | |
195 | struct clk sysclk; | |
196 | unsigned long tmdsclock; | |
197 | unsigned long pixclock; | |
198 | u32 bus_width; | |
199 | struct phy_config *phy_cfg; | |
200 | const struct inno_hdmi_phy_data *data; | |
201 | }; | |
202 | ||
203 | static const struct pre_pll_config pre_pll_cfg_table[] = { | |
204 | { 25175000, 25175000, 3, 125, 3, 1, 1, 1, 3, 3, 4, 0, 0xe00000}, | |
205 | { 25175000, 31468750, 1, 41, 0, 3, 3, 1, 3, 3, 4, 0, 0xf5554f}, | |
206 | { 27000000, 27000000, 1, 36, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
207 | { 27000000, 33750000, 1, 45, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, | |
208 | { 31500000, 31500000, 1, 42, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
209 | { 31500000, 39375000, 1, 105, 1, 3, 3, 10, 0, 3, 4, 0, 0x0}, | |
210 | { 33750000, 33750000, 1, 45, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
211 | { 33750000, 42187500, 1, 169, 2, 3, 3, 15, 0, 3, 4, 0, 0x0}, | |
212 | { 35500000, 35500000, 1, 71, 2, 2, 2, 6, 0, 3, 4, 0, 0x0}, | |
213 | { 35500000, 44375000, 1, 74, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, | |
214 | { 36000000, 36000000, 1, 36, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
215 | { 36000000, 45000000, 1, 45, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, | |
216 | { 40000000, 40000000, 1, 40, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
217 | { 40000000, 50000000, 1, 50, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, | |
218 | { 49500000, 49500000, 1, 66, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
219 | { 49500000, 61875000, 1, 165, 1, 3, 3, 10, 0, 3, 4, 0, 0x0}, | |
220 | { 50000000, 50000000, 1, 50, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
221 | { 50000000, 62500000, 1, 125, 2, 2, 2, 15, 0, 2, 2, 0, 0x0}, | |
222 | { 54000000, 54000000, 1, 36, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
223 | { 54000000, 67500000, 1, 45, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
224 | { 56250000, 56250000, 1, 75, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
225 | { 56250000, 70312500, 1, 117, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, | |
226 | { 59341000, 59341000, 1, 118, 2, 2, 2, 6, 0, 3, 4, 0, 0xae978d}, | |
227 | { 59341000, 74176250, 2, 148, 2, 1, 1, 15, 0, 1, 1, 0, 0x5a3d70}, | |
228 | { 59400000, 59400000, 1, 99, 3, 1, 1, 1, 3, 3, 4, 0, 0x0}, | |
229 | { 59400000, 74250000, 1, 99, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, | |
230 | { 65000000, 65000000, 1, 65, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
231 | { 65000000, 81250000, 3, 325, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, | |
232 | { 68250000, 68250000, 1, 91, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
233 | { 68250000, 85312500, 1, 142, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, | |
234 | { 71000000, 71000000, 1, 71, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
235 | { 71000000, 88750000, 3, 355, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, | |
236 | { 72000000, 72000000, 1, 36, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, | |
237 | { 72000000, 90000000, 1, 60, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
238 | { 73250000, 73250000, 3, 293, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
239 | { 73250000, 91562500, 1, 61, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
240 | { 74176000, 74176000, 1, 37, 2, 0, 0, 1, 1, 2, 2, 0, 0x16872b}, | |
241 | { 74176000, 92720000, 2, 185, 2, 1, 1, 15, 0, 1, 1, 0, 0x70a3d7}, | |
242 | { 74250000, 74250000, 1, 99, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
243 | { 74250000, 92812500, 4, 495, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, | |
244 | { 75000000, 75000000, 1, 50, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
245 | { 75000000, 93750000, 1, 125, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, | |
246 | { 78750000, 78750000, 1, 105, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
247 | { 78750000, 98437500, 1, 164, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, | |
248 | { 79500000, 79500000, 1, 53, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
249 | { 79500000, 99375000, 1, 199, 2, 2, 2, 15, 0, 2, 2, 0, 0x0}, | |
250 | { 83500000, 83500000, 2, 167, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
251 | { 83500000, 104375000, 1, 104, 2, 1, 1, 15, 0, 1, 1, 0, 0x600000}, | |
252 | { 85500000, 85500000, 1, 57, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
253 | { 85500000, 106875000, 1, 178, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, | |
254 | { 85750000, 85750000, 3, 343, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
255 | { 85750000, 107187500, 1, 143, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, | |
256 | { 88750000, 88750000, 3, 355, 0, 3, 3, 1, 2, 3, 4, 0, 0x0}, | |
257 | { 88750000, 110937500, 1, 110, 2, 1, 1, 15, 0, 1, 1, 0, 0xf00000}, | |
258 | { 94500000, 94500000, 1, 63, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
259 | { 94500000, 118125000, 1, 197, 3, 1, 1, 25, 0, 1, 1, 0, 0x0}, | |
260 | {101000000, 101000000, 1, 101, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
261 | {101000000, 126250000, 1, 42, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
262 | {102250000, 102250000, 4, 409, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
263 | {102250000, 127812500, 1, 128, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, | |
264 | {106500000, 106500000, 1, 71, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
265 | {106500000, 133125000, 1, 133, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, | |
266 | {108000000, 108000000, 1, 36, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
267 | {108000000, 135000000, 1, 45, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
268 | {115500000, 115500000, 1, 77, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
269 | {115500000, 144375000, 1, 48, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
270 | {117500000, 117500000, 2, 235, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
271 | {117500000, 146875000, 1, 49, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
272 | {119000000, 119000000, 1, 119, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
273 | {119000000, 148750000, 3, 148, 0, 1, 1, 1, 3, 1, 1, 0, 0xc00000}, | |
274 | {121750000, 121750000, 4, 487, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
275 | {121750000, 152187500, 1, 203, 0, 3, 3, 1, 3, 3, 4, 0, 0x0}, | |
276 | {122500000, 122500000, 2, 245, 2, 1, 1, 1, 1, 3, 4, 0, 0x0}, | |
277 | {122500000, 153125000, 1, 51, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
278 | {135000000, 135000000, 1, 45, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
279 | {135000000, 168750000, 1, 169, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, | |
280 | {136750000, 136750000, 1, 68, 2, 0, 0, 1, 1, 2, 2, 0, 0x600000}, | |
281 | {136750000, 170937500, 1, 113, 0, 2, 2, 1, 3, 2, 2, 0, 0xf5554f}, | |
282 | {140250000, 140250000, 2, 187, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
283 | {140250000, 175312500, 1, 117, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
284 | {146250000, 146250000, 2, 195, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
285 | {146250000, 182812500, 1, 61, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
286 | {148250000, 148250000, 3, 222, 2, 0, 0, 1, 1, 2, 2, 0, 0x600000}, | |
287 | {148250000, 185312500, 1, 123, 0, 2, 2, 1, 3, 2, 2, 0, 0x8aaab0}, | |
288 | {148352000, 148352000, 2, 148, 2, 0, 0, 1, 1, 2, 2, 0, 0x5a1cac}, | |
289 | {148352000, 185440000, 3, 185, 0, 1, 1, 1, 3, 1, 1, 0, 0x70a3d7}, | |
290 | {148500000, 148500000, 1, 99, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
291 | {148500000, 185625000, 4, 495, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
292 | {154000000, 154000000, 1, 77, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, | |
293 | {154000000, 192500000, 1, 64, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
294 | {156000000, 156000000, 1, 52, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
295 | {156000000, 195000000, 1, 65, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
296 | {156750000, 156750000, 2, 209, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
297 | {156750000, 195937500, 1, 196, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, | |
298 | {157000000, 157000000, 2, 157, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, | |
299 | {157000000, 196250000, 1, 131, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
300 | {157500000, 157500000, 1, 105, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
301 | {157500000, 196875000, 1, 197, 2, 1, 1, 15, 0, 1, 1, 0, 0x0}, | |
302 | {162000000, 162000000, 1, 54, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
303 | {162000000, 202500000, 2, 135, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
304 | {175500000, 175500000, 1, 117, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
305 | {175500000, 219375000, 1, 73, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
306 | {179500000, 179500000, 3, 359, 0, 2, 2, 1, 0, 3, 4, 0, 0x0}, | |
307 | {179500000, 224375000, 1, 75, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
308 | {182750000, 182750000, 1, 91, 2, 0, 0, 1, 1, 2, 2, 0, 0x600000}, | |
309 | {182750000, 228437500, 1, 152, 0, 2, 2, 1, 3, 2, 2, 0, 0x4aaab0}, | |
310 | {182750000, 228437500, 1, 152, 0, 2, 2, 1, 3, 2, 2, 0, 0x4aaab0}, | |
311 | {187000000, 187000000, 2, 187, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, | |
312 | {187000000, 233750000, 1, 39, 0, 0, 0, 1, 3, 0, 0, 1, 0x0}, | |
313 | {187250000, 187250000, 3, 280, 2, 0, 0, 1, 1, 2, 2, 0, 0xe00000}, | |
314 | {187250000, 234062500, 1, 156, 0, 2, 2, 1, 3, 2, 2, 0, 0xaaab0}, | |
315 | {189000000, 189000000, 1, 63, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
316 | {189000000, 236250000, 1, 79, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
317 | {193250000, 193250000, 3, 289, 2, 0, 0, 1, 1, 2, 2, 0, 0xe00000}, | |
318 | {193250000, 241562500, 1, 161, 0, 2, 2, 1, 3, 2, 2, 0, 0xaaab0}, | |
319 | {202500000, 202500000, 2, 135, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
320 | {202500000, 253125000, 1, 169, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
321 | {204750000, 204750000, 4, 273, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
322 | {204750000, 255937500, 1, 171, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
323 | {208000000, 208000000, 1, 104, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, | |
324 | {208000000, 260000000, 1, 173, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
325 | {214750000, 214750000, 1, 107, 2, 0, 0, 1, 1, 2, 2, 0, 0x600000}, | |
326 | {214750000, 268437500, 1, 178, 0, 2, 2, 1, 3, 2, 2, 0, 0xf5554f}, | |
327 | {218250000, 218250000, 4, 291, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
328 | {218250000, 272812500, 1, 91, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
329 | {229500000, 229500000, 2, 153, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
330 | {229500000, 286875000, 1, 191, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
331 | {234000000, 234000000, 1, 39, 0, 0, 0, 1, 0, 1, 1, 0, 0x0}, | |
332 | {234000000, 292500000, 1, 195, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
333 | {241500000, 241500000, 2, 161, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
334 | {241500000, 301875000, 1, 201, 0, 2, 2, 1, 3, 2, 2, 0, 0x0}, | |
335 | {245250000, 245250000, 4, 327, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
336 | {245250000, 306562500, 1, 51, 0, 0, 0, 1, 3, 0, 0, 1, 0x0}, | |
337 | {245500000, 245500000, 4, 491, 2, 0, 0, 1, 1, 2, 2, 0, 0x0}, | |
338 | {245500000, 306875000, 1, 51, 0, 0, 0, 1, 3, 0, 0, 1, 0x0}, | |
339 | {261000000, 261000000, 1, 87, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
340 | {261000000, 326250000, 1, 109, 0, 1, 1, 1, 3, 1, 1, 0, 0x0}, | |
341 | {268250000, 268250000, 9, 402, 0, 0, 0, 1, 0, 1, 1, 0, 0x600000}, | |
342 | {268250000, 335312500, 1, 111, 0, 1, 1, 1, 3, 1, 1, 0, 0xc5554f}, | |
343 | {268500000, 268500000, 2, 179, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
344 | {268500000, 335625000, 1, 56, 0, 0, 0, 1, 3, 0, 0, 1, 0x0}, | |
345 | {281250000, 281250000, 4, 375, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
346 | {281250000, 351562500, 1, 117, 0, 3, 1, 1, 3, 1, 1, 0, 0x0}, | |
347 | {288000000, 288000000, 1, 48, 0, 0, 0, 1, 0, 1, 1, 0, 0x0}, | |
348 | {288000000, 360000000, 1, 60, 0, 2, 0, 1, 3, 0, 0, 1, 0x0}, | |
349 | {296703000, 296703000, 1, 49, 0, 0, 0, 1, 0, 1, 1, 0, 0x7353f7}, | |
350 | {296703000, 370878750, 1, 123, 0, 3, 1, 1, 3, 1, 1, 0, 0xa051eb}, | |
351 | {297000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
352 | {297000000, 371250000, 4, 495, 0, 3, 1, 1, 3, 1, 1, 0, 0x0}, | |
353 | {312250000, 312250000, 9, 468, 0, 0, 0, 1, 0, 1, 1, 0, 0x600000}, | |
354 | {312250000, 390312500, 1, 130, 0, 3, 1, 1, 3, 1, 1, 0, 0x1aaab0}, | |
355 | {317000000, 317000000, 3, 317, 0, 1, 1, 1, 0, 2, 2, 0, 0x0}, | |
356 | {317000000, 396250000, 1, 66, 0, 2, 0, 1, 3, 0, 0, 1, 0x0}, | |
357 | {319750000, 319750000, 3, 159, 0, 0, 0, 1, 0, 1, 1, 0, 0xe00000}, | |
358 | {319750000, 399687500, 3, 199, 0, 2, 0, 1, 3, 0, 0, 1, 0xd80000}, | |
359 | {333250000, 333250000, 9, 499, 0, 0, 0, 1, 0, 1, 1, 0, 0xe00000}, | |
360 | {333250000, 416562500, 1, 138, 0, 3, 1, 1, 3, 1, 1, 0, 0xdaaab0}, | |
361 | {348500000, 348500000, 9, 522, 0, 2, 0, 1, 0, 1, 1, 0, 0xc00000}, | |
362 | {348500000, 435625000, 1, 145, 0, 3, 1, 1, 3, 1, 1, 0, 0x35554f}, | |
363 | {356500000, 356500000, 9, 534, 0, 2, 0, 1, 0, 1, 1, 0, 0xc00000}, | |
364 | {356500000, 445625000, 1, 148, 0, 3, 1, 1, 3, 1, 1, 0, 0x8aaab0}, | |
365 | {380500000, 380500000, 9, 570, 0, 2, 0, 1, 0, 1, 1, 0, 0xc00000}, | |
366 | {380500000, 475625000, 1, 158, 0, 3, 1, 1, 3, 1, 1, 0, 0x8aaab0}, | |
367 | {443250000, 443250000, 1, 73, 0, 2, 0, 1, 0, 1, 1, 0, 0xe00000}, | |
368 | {443250000, 554062500, 1, 92, 0, 2, 0, 1, 3, 0, 0, 1, 0x580000}, | |
369 | {505250000, 505250000, 9, 757, 0, 2, 0, 1, 0, 1, 1, 0, 0xe00000}, | |
370 | {552750000, 552750000, 3, 276, 0, 2, 0, 1, 0, 1, 1, 0, 0x600000}, | |
371 | {593407000, 296703500, 3, 296, 0, 1, 1, 1, 0, 1, 1, 0, 0xb41893}, | |
372 | {593407000, 370879375, 4, 494, 0, 3, 1, 1, 3, 0, 0, 1, 0x817e4a}, | |
373 | {593407000, 593407000, 3, 296, 0, 2, 0, 1, 0, 1, 1, 0, 0xb41893}, | |
374 | {594000000, 297000000, 1, 99, 0, 1, 1, 1, 0, 1, 1, 0, 0x0}, | |
375 | {594000000, 371250000, 4, 495, 0, 3, 1, 1, 3, 0, 0, 1, 0x0}, | |
376 | {594000000, 594000000, 1, 99, 0, 2, 0, 1, 0, 1, 1, 0, 0x0}, | |
377 | { /* sentinel */ } | |
378 | }; | |
379 | ||
380 | static const struct post_pll_config post_pll_cfg_table[] = { | |
381 | {33750000, 1, 40, 8, 1}, | |
382 | {33750000, 1, 80, 8, 2}, | |
383 | {74250000, 1, 40, 8, 1}, | |
384 | {74250000, 18, 80, 8, 2}, | |
385 | {148500000, 2, 40, 4, 3}, | |
386 | {297000000, 4, 40, 2, 3}, | |
387 | {594000000, 8, 40, 1, 3}, | |
388 | { /* sentinel */ } | |
389 | }; | |
390 | ||
391 | /* phy tuning values for an undocumented set of registers */ | |
392 | static const struct phy_config rk3328_phy_cfg[] = { | |
393 | { 165000000, { | |
394 | 0x07, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x08, 0x08, 0x08, | |
395 | 0x00, 0xac, 0xcc, 0xcc, 0xcc, | |
396 | }, | |
397 | }, { | |
398 | 340000000, { | |
399 | 0x0b, 0x0d, 0x0d, 0x0d, 0x07, 0x15, 0x08, 0x08, 0x08, | |
400 | 0x3f, 0xac, 0xcc, 0xcd, 0xdd, | |
401 | }, | |
402 | }, { | |
403 | 594000000, { | |
404 | 0x10, 0x1a, 0x1a, 0x1a, 0x07, 0x15, 0x08, 0x08, 0x08, | |
405 | 0x00, 0xac, 0xcc, 0xcc, 0xcc, | |
406 | }, | |
407 | }, { /* sentinel */ }, | |
408 | }; | |
409 | ||
410 | static inline void inno_write(struct inno_hdmi_phy *inno, u32 reg, u8 val) | |
411 | { | |
412 | writel(val, inno->regs + (reg * 4)); | |
413 | } | |
414 | ||
415 | static inline u8 inno_read(struct inno_hdmi_phy *inno, u32 reg) | |
416 | { | |
417 | u32 val; | |
418 | ||
419 | val = readl(inno->regs + (reg * 4)); | |
420 | ||
421 | return val; | |
422 | } | |
423 | ||
424 | static inline void inno_update_bits(struct inno_hdmi_phy *inno, u8 reg, | |
425 | u8 mask, u8 val) | |
426 | { | |
427 | u32 tmp, orig; | |
428 | ||
429 | orig = inno_read(inno, reg); | |
430 | tmp = orig & ~mask; | |
431 | tmp |= val & mask; | |
432 | inno_write(inno, reg, tmp); | |
433 | } | |
434 | ||
35214b99 JT |
435 | #define inno_poll(inno, reg, val, cond, sleep_us, timeout_us) \ |
436 | readl_poll_sleep_timeout((inno)->regs + ((reg) * 4), val, cond, sleep_us, timeout_us) | |
aa227118 JT |
437 | |
438 | static unsigned long inno_hdmi_phy_get_tmdsclk(struct inno_hdmi_phy *inno, | |
439 | unsigned long rate) | |
440 | { | |
441 | int bus_width = inno->bus_width; | |
442 | ||
443 | switch (bus_width) { | |
444 | case 4: | |
445 | case 5: | |
446 | case 6: | |
447 | case 10: | |
448 | case 12: | |
449 | case 16: | |
450 | return (u64)rate * bus_width / 8; | |
451 | default: | |
452 | return rate; | |
453 | } | |
454 | } | |
455 | ||
456 | static | |
457 | unsigned long inno_hdmi_phy_rk3328_clk_recalc_rate(struct phy *phy, | |
458 | unsigned long parent_rate) | |
459 | { | |
460 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
461 | unsigned long frac; | |
462 | u8 nd, no_a, no_b, no_d; | |
463 | u64 vco; | |
464 | u16 nf; | |
465 | ||
466 | nd = inno_read(inno, 0xa1) & RK3328_PRE_PLL_PRE_DIV_MASK; | |
467 | nf = ((inno_read(inno, 0xa2) & RK3328_PRE_PLL_FB_DIV_11_8_MASK) << 8); | |
468 | nf |= inno_read(inno, 0xa3); | |
469 | vco = parent_rate * nf; | |
470 | ||
471 | if (!(inno_read(inno, 0xa2) & RK3328_PRE_PLL_FRAC_DIV_DISABLE)) { | |
472 | frac = inno_read(inno, 0xd3) | | |
473 | (inno_read(inno, 0xd2) << 8) | | |
474 | (inno_read(inno, 0xd1) << 16); | |
475 | vco += DIV_ROUND_CLOSEST(parent_rate * frac, (1 << 24)); | |
476 | } | |
477 | ||
478 | if (inno_read(inno, 0xa0) & RK3328_PCLK_VCO_DIV_5_MASK) { | |
479 | do_div(vco, nd * 5); | |
480 | } else { | |
481 | no_a = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_A_MASK; | |
482 | no_b = inno_read(inno, 0xa5) & RK3328_PRE_PLL_PCLK_DIV_B_MASK; | |
483 | no_b >>= RK3328_PRE_PLL_PCLK_DIV_B_SHIFT; | |
484 | no_b += 2; | |
485 | no_d = inno_read(inno, 0xa6) & RK3328_PRE_PLL_PCLK_DIV_D_MASK; | |
486 | ||
487 | do_div(vco, (nd * (no_a == 1 ? no_b : no_a) * no_d * 2)); | |
488 | } | |
489 | ||
490 | inno->pixclock = DIV_ROUND_CLOSEST((unsigned long)vco, 1000) * 1000; | |
491 | ||
492 | dev_info(phy->dev, "rate %lu vco %llu\n", inno->pixclock, vco); | |
493 | ||
494 | return inno->pixclock; | |
495 | } | |
496 | ||
497 | static long inno_hdmi_phy_rk3328_clk_round_rate(struct phy *phy, | |
498 | unsigned long rate) | |
499 | { | |
500 | const struct pre_pll_config *cfg = pre_pll_cfg_table; | |
501 | ||
502 | rate = (rate / 1000) * 1000; | |
503 | ||
504 | for (; cfg->pixclock != 0; cfg++) | |
505 | if (cfg->pixclock == rate) | |
506 | break; | |
507 | ||
508 | if (cfg->pixclock == 0) | |
509 | return -EINVAL; | |
510 | ||
511 | return cfg->pixclock; | |
512 | } | |
513 | ||
514 | static const | |
515 | struct pre_pll_config *inno_hdmi_phy_get_pre_pll_cfg(struct inno_hdmi_phy *inno, | |
516 | unsigned long rate) | |
517 | { | |
518 | const struct pre_pll_config *cfg = pre_pll_cfg_table; | |
519 | unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); | |
520 | ||
521 | for (; cfg->pixclock != 0; cfg++) | |
522 | if (cfg->pixclock == rate && cfg->tmdsclock == tmdsclock) | |
523 | break; | |
524 | ||
525 | if (cfg->pixclock == 0) | |
526 | return ERR_PTR(-EINVAL); | |
527 | ||
528 | return cfg; | |
529 | } | |
530 | ||
531 | static int | |
532 | inno_hdmi_phy_rk3328_clk_set_rate(struct phy *phy, | |
533 | unsigned long rate, | |
534 | unsigned long parent_rate) | |
535 | { | |
536 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
537 | unsigned long tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, rate); | |
538 | const struct pre_pll_config *cfg; | |
539 | u32 val; | |
540 | int ret; | |
541 | ||
542 | dev_info(phy->dev, "rate %lu tmdsclk %lu\n", rate, tmdsclock); | |
543 | ||
544 | if (inno->pixclock == rate && inno->tmdsclock == tmdsclock) | |
545 | return 0; | |
546 | ||
547 | cfg = inno_hdmi_phy_get_pre_pll_cfg(inno, rate); | |
548 | if (IS_ERR(cfg)) | |
549 | return PTR_ERR(cfg); | |
550 | ||
551 | inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, | |
552 | RK3328_PRE_PLL_POWER_DOWN); | |
553 | ||
554 | /* Configure pre-pll */ | |
555 | inno_update_bits(inno, 0xa0, RK3328_PCLK_VCO_DIV_5_MASK, | |
556 | RK3328_PCLK_VCO_DIV_5(cfg->vco_div_5_en)); | |
557 | inno_write(inno, 0xa1, RK3328_PRE_PLL_PRE_DIV(cfg->prediv)); | |
558 | ||
559 | val = RK3328_SPREAD_SPECTRUM_MOD_DISABLE; | |
560 | if (!cfg->fracdiv) | |
561 | val |= RK3328_PRE_PLL_FRAC_DIV_DISABLE; | |
562 | inno_write(inno, 0xa2, RK3328_PRE_PLL_FB_DIV_11_8(cfg->fbdiv) | val); | |
563 | inno_write(inno, 0xa3, RK3328_PRE_PLL_FB_DIV_7_0(cfg->fbdiv)); | |
564 | inno_write(inno, 0xa5, RK3328_PRE_PLL_PCLK_DIV_A(cfg->pclk_div_a) | | |
565 | RK3328_PRE_PLL_PCLK_DIV_B(cfg->pclk_div_b)); | |
566 | inno_write(inno, 0xa6, RK3328_PRE_PLL_PCLK_DIV_C(cfg->pclk_div_c) | | |
567 | RK3328_PRE_PLL_PCLK_DIV_D(cfg->pclk_div_d)); | |
568 | inno_write(inno, 0xa4, RK3328_PRE_PLL_TMDSCLK_DIV_C(cfg->tmds_div_c) | | |
569 | RK3328_PRE_PLL_TMDSCLK_DIV_A(cfg->tmds_div_a) | | |
570 | RK3328_PRE_PLL_TMDSCLK_DIV_B(cfg->tmds_div_b)); | |
571 | inno_write(inno, 0xd3, RK3328_PRE_PLL_FRAC_DIV_7_0(cfg->fracdiv)); | |
572 | inno_write(inno, 0xd2, RK3328_PRE_PLL_FRAC_DIV_15_8(cfg->fracdiv)); | |
573 | inno_write(inno, 0xd1, RK3328_PRE_PLL_FRAC_DIV_23_16(cfg->fracdiv)); | |
574 | ||
575 | inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0); | |
576 | ||
577 | /* Wait for Pre-PLL lock */ | |
35214b99 | 578 | ret = inno_poll(inno, 0xa9, val, val & RK3328_PRE_PLL_LOCK_STATUS, |
aa227118 JT |
579 | 1000, 10000); |
580 | if (ret) { | |
581 | dev_err(phy->dev, "Pre-PLL locking failed\n"); | |
582 | return ret; | |
583 | } | |
584 | ||
585 | inno->pixclock = rate; | |
586 | inno->tmdsclock = tmdsclock; | |
587 | ||
588 | return 0; | |
589 | } | |
590 | ||
591 | static void inno_hdmi_phy_rk3328_clk_enable(struct phy *phy) | |
592 | { | |
593 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
594 | ||
595 | inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, 0); | |
596 | } | |
597 | ||
598 | static void inno_hdmi_phy_rk3328_clk_disable(struct phy *phy) | |
599 | { | |
600 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
601 | ||
602 | inno_update_bits(inno, 0xa0, RK3328_PRE_PLL_POWER_DOWN, | |
603 | RK3328_PRE_PLL_POWER_DOWN); | |
604 | } | |
605 | ||
606 | static int | |
607 | inno_hdmi_phy_rk3328_power_on(struct phy *phy, | |
608 | const struct post_pll_config *cfg, | |
609 | const struct phy_config *phy_cfg) | |
610 | { | |
611 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
612 | int ret; | |
613 | u32 v; | |
614 | ||
615 | inno_update_bits(inno, 0x02, RK3328_PDATA_EN, 0); | |
616 | inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, | |
617 | RK3328_POST_PLL_POWER_DOWN); | |
618 | ||
619 | inno_write(inno, 0xac, RK3328_POST_PLL_FB_DIV_7_0(cfg->fbdiv)); | |
620 | if (cfg->postdiv == 1) { | |
621 | inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | | |
622 | RK3328_POST_PLL_PRE_DIV(cfg->prediv)); | |
623 | inno_write(inno, 0xaa, RK3328_POST_PLL_REFCLK_SEL_TMDS | | |
624 | RK3328_POST_PLL_POWER_DOWN); | |
625 | } else { | |
626 | v = (cfg->postdiv / 2) - 1; | |
627 | v &= RK3328_POST_PLL_POST_DIV_MASK; | |
628 | inno_write(inno, 0xad, v); | |
629 | inno_write(inno, 0xab, RK3328_POST_PLL_FB_DIV_8(cfg->fbdiv) | | |
630 | RK3328_POST_PLL_PRE_DIV(cfg->prediv)); | |
631 | inno_write(inno, 0xaa, RK3328_POST_PLL_POST_DIV_ENABLE | | |
632 | RK3328_POST_PLL_REFCLK_SEL_TMDS | | |
633 | RK3328_POST_PLL_POWER_DOWN); | |
634 | } | |
635 | ||
636 | for (v = 0; v < 14; v++) | |
637 | inno_write(inno, 0xb5 + v, phy_cfg->regs[v]); | |
638 | ||
639 | /* set ESD detection threshold for TMDS CLK, D2, D1 and D0 */ | |
640 | for (v = 0; v < 4; v++) | |
641 | inno_update_bits(inno, 0xc8 + v, RK3328_ESD_DETECT_MASK, | |
642 | RK3328_ESD_DETECT_340MV); | |
643 | ||
644 | if (phy_cfg->tmdsclock > 340000000) { | |
645 | /* Set termination resistor to 100ohm */ | |
646 | v = clk_get_rate(&inno->sysclk) / 100000; | |
647 | inno_write(inno, 0xc5, RK3328_TERM_RESISTOR_CALIB_SPEED_14_8(v) | |
648 | | RK3328_BYPASS_TERM_RESISTOR_CALIB); | |
649 | inno_write(inno, 0xc6, RK3328_TERM_RESISTOR_CALIB_SPEED_7_0(v)); | |
650 | inno_write(inno, 0xc7, RK3328_TERM_RESISTOR_100); | |
651 | inno_update_bits(inno, 0xc5, | |
652 | RK3328_BYPASS_TERM_RESISTOR_CALIB, 0); | |
653 | } else { | |
654 | inno_write(inno, 0xc5, RK3328_BYPASS_TERM_RESISTOR_CALIB); | |
655 | ||
656 | /* clk termination resistor is 50ohm (parallel resistors) */ | |
657 | if (phy_cfg->tmdsclock > 165000000) | |
658 | inno_update_bits(inno, 0xc8, | |
659 | RK3328_TMDS_TERM_RESIST_MASK, | |
660 | RK3328_TMDS_TERM_RESIST_75 | | |
661 | RK3328_TMDS_TERM_RESIST_150); | |
662 | ||
663 | /* data termination resistor for D2, D1 and D0 is 150ohm */ | |
664 | for (v = 0; v < 3; v++) | |
665 | inno_update_bits(inno, 0xc9 + v, | |
666 | RK3328_TMDS_TERM_RESIST_MASK, | |
667 | RK3328_TMDS_TERM_RESIST_150); | |
668 | } | |
669 | ||
670 | inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, 0); | |
671 | inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE, | |
672 | RK3328_BANDGAP_ENABLE); | |
673 | inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE, | |
674 | RK3328_TMDS_DRIVER_ENABLE); | |
675 | ||
676 | /* Wait for post PLL lock */ | |
35214b99 | 677 | ret = inno_poll(inno, 0xaf, v, v & RK3328_POST_PLL_LOCK_STATUS, |
aa227118 JT |
678 | 1000, 10000); |
679 | if (ret) { | |
680 | dev_err(phy->dev, "Post-PLL locking failed\n"); | |
681 | return ret; | |
682 | } | |
683 | ||
684 | if (phy_cfg->tmdsclock > 340000000) | |
685 | mdelay(100); | |
686 | ||
687 | inno_update_bits(inno, 0x02, RK3328_PDATA_EN, RK3328_PDATA_EN); | |
688 | ||
689 | /* Enable PHY IRQ */ | |
690 | inno_write(inno, 0x05, RK3328_INT_TMDS_CLK(RK3328_INT_VSS_AGND_ESD_DET) | |
691 | | RK3328_INT_TMDS_D2(RK3328_INT_VSS_AGND_ESD_DET)); | |
692 | inno_write(inno, 0x07, RK3328_INT_TMDS_D1(RK3328_INT_VSS_AGND_ESD_DET) | |
693 | | RK3328_INT_TMDS_D0(RK3328_INT_VSS_AGND_ESD_DET)); | |
694 | ||
695 | return 0; | |
696 | } | |
697 | ||
698 | static void inno_hdmi_phy_rk3328_power_off(struct phy *phy) | |
699 | { | |
700 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
701 | ||
702 | inno_update_bits(inno, 0xb2, RK3328_TMDS_DRIVER_ENABLE, 0); | |
703 | inno_update_bits(inno, 0xb0, RK3328_BANDGAP_ENABLE, 0); | |
704 | inno_update_bits(inno, 0xaa, RK3328_POST_PLL_POWER_DOWN, | |
705 | RK3328_POST_PLL_POWER_DOWN); | |
706 | ||
707 | /* Disable PHY IRQ */ | |
708 | inno_write(inno, 0x05, 0); | |
709 | inno_write(inno, 0x07, 0); | |
710 | } | |
711 | ||
712 | static void inno_hdmi_phy_rk3328_init(struct phy *phy) | |
713 | { | |
714 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
715 | const struct inno_hdmi_phy_plat_ops *plat_ops = inno->data->plat_ops; | |
716 | ||
717 | /* | |
718 | * Use phy internal register control | |
719 | * rxsense/poweron/pllpd/pdataen signal. | |
720 | */ | |
721 | inno_write(inno, 0x01, RK3328_BYPASS_RXSENSE_EN | | |
722 | RK3328_BYPASS_POWERON_EN | | |
723 | RK3328_BYPASS_PLLPD_EN); | |
724 | inno_write(inno, 0x02, RK3328_INT_POL_HIGH | RK3328_BYPASS_PDATA_EN | | |
725 | RK3328_PDATA_EN); | |
726 | ||
727 | /* Disable phy irq */ | |
728 | inno_write(inno, 0x05, 0); | |
729 | inno_write(inno, 0x07, 0); | |
730 | ||
731 | if (plat_ops->clk_recalc_rate) | |
732 | plat_ops->clk_recalc_rate(phy, clk_get_rate(&inno->refoclk)); | |
733 | ||
734 | if (plat_ops->clk_round_rate) | |
735 | plat_ops->clk_round_rate(phy, inno->pixclock); | |
736 | } | |
737 | ||
738 | static const struct inno_hdmi_phy_plat_ops rk3328_hdmi_phy_plat_ops = { | |
739 | .init = inno_hdmi_phy_rk3328_init, | |
740 | .power_on = inno_hdmi_phy_rk3328_power_on, | |
741 | .power_off = inno_hdmi_phy_rk3328_power_off, | |
742 | .clk_enable = inno_hdmi_phy_rk3328_clk_enable, | |
743 | .clk_disable = inno_hdmi_phy_rk3328_clk_disable, | |
744 | .clk_recalc_rate = inno_hdmi_phy_rk3328_clk_recalc_rate, | |
745 | .clk_round_rate = inno_hdmi_phy_rk3328_clk_round_rate, | |
746 | .clk_set_rate = inno_hdmi_phy_rk3328_clk_set_rate, | |
747 | }; | |
748 | ||
749 | static int inno_hdmi_phy_power_on(struct phy *phy) | |
750 | { | |
751 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
752 | const struct post_pll_config *cfg = post_pll_cfg_table; | |
753 | const struct phy_config *phy_cfg = inno->data->phy_cfg_table; | |
754 | u32 tmdsclock = inno_hdmi_phy_get_tmdsclk(inno, inno->pixclock); | |
755 | const struct inno_hdmi_phy_plat_ops *plat_ops = inno->data->plat_ops; | |
756 | int ret; | |
757 | ||
758 | if (!tmdsclock) { | |
759 | dev_err(phy->dev, "TMDS clock is zero!\n"); | |
760 | return -EINVAL; | |
761 | } | |
762 | ||
763 | if (!plat_ops->power_on) | |
764 | return -EINVAL; | |
765 | ||
766 | dev_info(phy->dev, "TMDS clock = %d\n", tmdsclock); | |
767 | ||
768 | for (; cfg->tmdsclock != ~0UL; cfg++) | |
769 | if (tmdsclock <= cfg->tmdsclock) | |
770 | break; | |
771 | ||
772 | for (; phy_cfg->tmdsclock != ~0UL; phy_cfg++) | |
773 | if (tmdsclock <= phy_cfg->tmdsclock) | |
774 | break; | |
775 | ||
776 | if (cfg->tmdsclock == 0 || phy_cfg->tmdsclock == 0) | |
777 | return -EINVAL; | |
778 | ||
779 | if (plat_ops->clk_set_rate) { | |
780 | ret = plat_ops->clk_set_rate(phy, inno->pixclock, 24000000); | |
781 | if (ret) | |
782 | return ret; | |
783 | } | |
784 | ||
785 | if (plat_ops->clk_enable) | |
786 | plat_ops->clk_enable(phy); | |
787 | ||
788 | if (plat_ops->power_on) { | |
789 | ret = plat_ops->power_on(phy, cfg, phy_cfg); | |
790 | if (ret) { | |
791 | if (plat_ops->clk_disable) | |
792 | plat_ops->clk_disable(phy); | |
793 | return ret; | |
794 | } | |
795 | } | |
796 | ||
797 | return 0; | |
798 | } | |
799 | ||
800 | static int inno_hdmi_phy_power_off(struct phy *phy) | |
801 | { | |
802 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
803 | const struct inno_hdmi_phy_plat_ops *plat_ops = inno->data->plat_ops; | |
804 | ||
805 | if (!plat_ops->power_off) | |
806 | return -EINVAL; | |
807 | ||
808 | plat_ops->power_off(phy); | |
809 | ||
810 | if (plat_ops->clk_disable) | |
811 | plat_ops->clk_disable(phy); | |
812 | ||
813 | inno->tmdsclock = 0; | |
814 | ||
815 | return 0; | |
816 | } | |
817 | ||
818 | static int inno_hdmi_phy_init(struct phy *phy) | |
819 | { | |
820 | struct inno_hdmi_phy *inno = dev_get_priv(phy->dev); | |
821 | ||
822 | if (inno->data->plat_ops->init) | |
823 | inno->data->plat_ops->init(phy); | |
824 | ||
825 | return 0; | |
826 | } | |
827 | ||
828 | static struct phy_ops inno_hdmi_phy_ops = { | |
829 | .init = inno_hdmi_phy_init, | |
830 | .power_on = inno_hdmi_phy_power_on, | |
831 | .power_off = inno_hdmi_phy_power_off, | |
832 | }; | |
833 | ||
834 | static int inno_hdmi_phy_probe(struct udevice *dev) | |
835 | { | |
836 | struct inno_hdmi_phy *inno = dev_get_priv(dev); | |
837 | int ret; | |
838 | ||
839 | inno->regs = dev_read_addr_ptr(dev); | |
840 | if (!inno->regs) | |
841 | return -ENOMEM; | |
842 | ||
843 | inno->data = (const struct inno_hdmi_phy_data *)dev_get_driver_data(dev); | |
844 | if (!inno->data) | |
845 | return -EINVAL; | |
846 | ||
847 | inno->bus_width = 8; | |
848 | ||
849 | ret = clk_get_by_name(dev, "refoclk", &inno->refoclk); | |
850 | if (ret) { | |
851 | dev_err(dev, "failed to get the refoclk (ret=%d)\n", ret); | |
852 | return ret; | |
853 | } | |
854 | ||
855 | ret = clk_get_by_name(dev, "sysclk", &inno->sysclk); | |
856 | if (ret) { | |
857 | dev_err(dev, "failed to get the sysclk (ret=%d)\n", ret); | |
858 | return ret; | |
859 | } | |
860 | ||
861 | return 0; | |
862 | } | |
863 | ||
864 | static const struct inno_hdmi_phy_data rk3328_inno_hdmi_phy_drv_data = { | |
865 | .phy_type = INNO_HDMI_PHY_RK3328, | |
866 | .plat_ops = &rk3328_hdmi_phy_plat_ops, | |
867 | .phy_cfg_table = rk3328_phy_cfg, | |
868 | }; | |
869 | ||
870 | static const struct udevice_id inno_hdmi_phy_ids[] = { | |
871 | { | |
872 | .compatible = "rockchip,rk3328-hdmi-phy", | |
873 | .data = (ulong)&rk3328_inno_hdmi_phy_drv_data, | |
874 | }, | |
875 | { /* sentile */ } | |
876 | }; | |
877 | ||
878 | U_BOOT_DRIVER(inno_hdmi_phy) = { | |
879 | .name = "inno_hdmi_phy", | |
880 | .id = UCLASS_PHY, | |
881 | .of_match = inno_hdmi_phy_ids, | |
882 | .ops = &inno_hdmi_phy_ops, | |
883 | .probe = inno_hdmi_phy_probe, | |
884 | .priv_auto = sizeof(struct inno_hdmi_phy), | |
885 | }; |