]>
Commit | Line | Data |
---|---|---|
6fa83833 CM |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Author(s): Chris Morgan <macromorgan@hotmail.com> | |
4 | * | |
5 | * This MIPI DSI controller driver is heavily based on the Linux Kernel | |
6 | * driver from drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c and the | |
7 | * U-Boot driver from drivers/video/stm32/stm32_dsi.c. | |
8 | */ | |
9 | ||
10 | #define LOG_CATEGORY UCLASS_VIDEO_BRIDGE | |
11 | ||
12 | #include <clk.h> | |
13 | #include <dm.h> | |
14 | #include <div64.h> | |
15 | #include <dsi_host.h> | |
16 | #include <generic-phy.h> | |
17 | #include <mipi_dsi.h> | |
18 | #include <panel.h> | |
19 | #include <phy-mipi-dphy.h> | |
20 | #include <reset.h> | |
bd6375c5 | 21 | #include <syscon.h> |
6fa83833 CM |
22 | #include <video_bridge.h> |
23 | #include <dm/device_compat.h> | |
24 | #include <dm/lists.h> | |
25 | #include <linux/iopoll.h> | |
26 | ||
d678a59d | 27 | #include <common.h> |
6fa83833 CM |
28 | #include <log.h> |
29 | #include <video.h> | |
6fa83833 CM |
30 | #include <dm/device-internal.h> |
31 | #include <linux/bitops.h> | |
13248d66 | 32 | #include <linux/time.h> |
6fa83833 | 33 | |
bd6375c5 OJ |
34 | #include <asm/arch-rockchip/clock.h> |
35 | #include <asm/arch-rockchip/hardware.h> | |
36 | ||
6fa83833 CM |
37 | /* |
38 | * DSI wrapper registers & bit definitions | |
39 | * Note: registers are named as in the Reference Manual | |
40 | */ | |
41 | #define DSI_WCR 0x0404 /* Wrapper Control Reg */ | |
42 | #define WCR_DSIEN BIT(3) /* DSI ENable */ | |
43 | ||
44 | #define DSI_PHY_TST_CTRL0 0xb4 | |
45 | #define PHY_TESTCLK BIT(1) | |
46 | #define PHY_UNTESTCLK 0 | |
47 | #define PHY_TESTCLR BIT(0) | |
48 | #define PHY_UNTESTCLR 0 | |
49 | ||
50 | #define DSI_PHY_TST_CTRL1 0xb8 | |
51 | #define PHY_TESTEN BIT(16) | |
52 | #define PHY_UNTESTEN 0 | |
53 | #define PHY_TESTDOUT(n) (((n) & 0xff) << 8) | |
54 | #define PHY_TESTDIN(n) (((n) & 0xff) << 0) | |
55 | ||
56 | #define BYPASS_VCO_RANGE BIT(7) | |
57 | #define VCO_RANGE_CON_SEL(val) (((val) & 0x7) << 3) | |
58 | #define VCO_IN_CAP_CON_DEFAULT (0x0 << 1) | |
59 | #define VCO_IN_CAP_CON_LOW (0x1 << 1) | |
60 | #define VCO_IN_CAP_CON_HIGH (0x2 << 1) | |
61 | #define REF_BIAS_CUR_SEL BIT(0) | |
62 | ||
63 | #define CP_CURRENT_3UA 0x1 | |
64 | #define CP_CURRENT_4_5UA 0x2 | |
65 | #define CP_CURRENT_7_5UA 0x6 | |
66 | #define CP_CURRENT_6UA 0x9 | |
67 | #define CP_CURRENT_12UA 0xb | |
68 | #define CP_CURRENT_SEL(val) ((val) & 0xf) | |
69 | #define CP_PROGRAM_EN BIT(7) | |
70 | ||
71 | #define LPF_RESISTORS_15_5KOHM 0x1 | |
72 | #define LPF_RESISTORS_13KOHM 0x2 | |
73 | #define LPF_RESISTORS_11_5KOHM 0x4 | |
74 | #define LPF_RESISTORS_10_5KOHM 0x8 | |
75 | #define LPF_RESISTORS_8KOHM 0x10 | |
76 | #define LPF_PROGRAM_EN BIT(6) | |
77 | #define LPF_RESISTORS_SEL(val) ((val) & 0x3f) | |
78 | ||
79 | #define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1) | |
80 | ||
81 | #define INPUT_DIVIDER(val) (((val) - 1) & 0x7f) | |
82 | #define LOW_PROGRAM_EN 0 | |
83 | #define HIGH_PROGRAM_EN BIT(7) | |
84 | #define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f) | |
85 | #define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0xf) | |
86 | #define PLL_LOOP_DIV_EN BIT(5) | |
87 | #define PLL_INPUT_DIV_EN BIT(4) | |
88 | ||
89 | #define POWER_CONTROL BIT(6) | |
90 | #define INTERNAL_REG_CURRENT BIT(3) | |
91 | #define BIAS_BLOCK_ON BIT(2) | |
92 | #define BANDGAP_ON BIT(0) | |
93 | ||
94 | #define TER_RESISTOR_HIGH BIT(7) | |
95 | #define TER_RESISTOR_LOW 0 | |
96 | #define LEVEL_SHIFTERS_ON BIT(6) | |
97 | #define TER_CAL_DONE BIT(5) | |
98 | #define SETRD_MAX (0x7 << 2) | |
99 | #define POWER_MANAGE BIT(1) | |
100 | #define TER_RESISTORS_ON BIT(0) | |
101 | ||
102 | #define BIASEXTR_SEL(val) ((val) & 0x7) | |
103 | #define BANDGAP_SEL(val) ((val) & 0x7) | |
104 | #define TLP_PROGRAM_EN BIT(7) | |
105 | #define THS_PRE_PROGRAM_EN BIT(7) | |
106 | #define THS_ZERO_PROGRAM_EN BIT(6) | |
107 | ||
108 | #define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10 | |
109 | #define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11 | |
110 | #define PLL_LPF_AND_CP_CONTROL 0x12 | |
111 | #define PLL_INPUT_DIVIDER_RATIO 0x17 | |
112 | #define PLL_LOOP_DIVIDER_RATIO 0x18 | |
113 | #define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19 | |
114 | #define BANDGAP_AND_BIAS_CONTROL 0x20 | |
115 | #define TERMINATION_RESISTER_CONTROL 0x21 | |
116 | #define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22 | |
117 | #define HS_RX_CONTROL_OF_LANE_CLK 0x34 | |
118 | #define HS_RX_CONTROL_OF_LANE_0 0x44 | |
119 | #define HS_RX_CONTROL_OF_LANE_1 0x54 | |
120 | #define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60 | |
121 | #define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61 | |
122 | #define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62 | |
123 | #define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL 0x63 | |
124 | #define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL 0x64 | |
125 | #define HS_TX_CLOCK_LANE_POST_TIME_CONTROL 0x65 | |
126 | #define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL 0x70 | |
127 | #define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL 0x71 | |
128 | #define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72 | |
129 | #define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73 | |
130 | #define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74 | |
131 | #define HS_RX_DATA_LANE_THS_SETTLE_CONTROL 0x75 | |
132 | #define HS_RX_CONTROL_OF_LANE_2 0x84 | |
133 | #define HS_RX_CONTROL_OF_LANE_3 0x94 | |
134 | ||
0825522e OJ |
135 | #define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0) |
136 | #define DW_MIPI_NEEDS_GRF_CLK BIT(1) | |
137 | ||
138 | #define RK3399_GRF_SOC_CON20 0x6250 | |
139 | #define RK3399_DSI0_LCDC_SEL BIT(0) | |
140 | #define RK3399_DSI1_LCDC_SEL BIT(4) | |
141 | ||
142 | #define RK3399_GRF_SOC_CON22 0x6258 | |
143 | #define RK3399_DSI0_TURNREQUEST (0xf << 12) | |
144 | #define RK3399_DSI0_TURNDISABLE (0xf << 8) | |
145 | #define RK3399_DSI0_FORCETXSTOPMODE (0xf << 4) | |
146 | #define RK3399_DSI0_FORCERXMODE (0xf << 0) | |
147 | ||
148 | #define RK3399_GRF_SOC_CON23 0x625c | |
149 | #define RK3399_DSI1_TURNDISABLE (0xf << 12) | |
150 | #define RK3399_DSI1_FORCETXSTOPMODE (0xf << 8) | |
151 | #define RK3399_DSI1_FORCERXMODE (0xf << 4) | |
152 | #define RK3399_DSI1_ENABLE (0xf << 0) | |
153 | ||
154 | #define RK3399_GRF_SOC_CON24 0x6260 | |
155 | #define RK3399_TXRX_MASTERSLAVEZ BIT(7) | |
156 | #define RK3399_TXRX_ENABLECLK BIT(6) | |
157 | #define RK3399_TXRX_BASEDIR BIT(5) | |
158 | #define RK3399_TXRX_SRC_SEL_ISP0 BIT(4) | |
159 | #define RK3399_TXRX_TURNREQUEST GENMASK(3, 0) | |
160 | ||
6fa83833 CM |
161 | #define RK3568_GRF_VO_CON2 0x0368 |
162 | #define RK3568_DSI0_SKEWCALHS (0x1f << 11) | |
163 | #define RK3568_DSI0_FORCETXSTOPMODE (0xf << 4) | |
164 | #define RK3568_DSI0_TURNDISABLE BIT(2) | |
165 | #define RK3568_DSI0_FORCERXMODE BIT(0) | |
166 | ||
167 | /* | |
168 | * Note these registers do not appear in the datasheet, they are | |
169 | * however present in the BSP driver which is where these values | |
170 | * come from. Name GRF_VO_CON3 is assumed. | |
171 | */ | |
172 | #define RK3568_GRF_VO_CON3 0x36c | |
173 | #define RK3568_DSI1_SKEWCALHS (0x1f << 11) | |
174 | #define RK3568_DSI1_FORCETXSTOPMODE (0xf << 4) | |
175 | #define RK3568_DSI1_TURNDISABLE BIT(2) | |
176 | #define RK3568_DSI1_FORCERXMODE BIT(0) | |
177 | ||
178 | #define HIWORD_UPDATE(val, mask) (val | (mask) << 16) | |
179 | ||
180 | /* Timeout for regulator on/off, pll lock/unlock & fifo empty */ | |
181 | #define TIMEOUT_US 200000 | |
182 | ||
183 | enum { | |
184 | BANDGAP_97_07, | |
185 | BANDGAP_98_05, | |
186 | BANDGAP_99_02, | |
187 | BANDGAP_100_00, | |
188 | BANDGAP_93_17, | |
189 | BANDGAP_94_15, | |
190 | BANDGAP_95_12, | |
191 | BANDGAP_96_10, | |
192 | }; | |
193 | ||
194 | enum { | |
195 | BIASEXTR_87_1, | |
196 | BIASEXTR_91_5, | |
197 | BIASEXTR_95_9, | |
198 | BIASEXTR_100, | |
199 | BIASEXTR_105_94, | |
200 | BIASEXTR_111_88, | |
201 | BIASEXTR_118_8, | |
202 | BIASEXTR_127_7, | |
203 | }; | |
204 | ||
205 | struct rockchip_dw_dsi_chip_data { | |
206 | u32 reg; | |
207 | ||
208 | u32 lcdsel_grf_reg; | |
209 | u32 lcdsel_big; | |
210 | u32 lcdsel_lit; | |
211 | ||
212 | u32 enable_grf_reg; | |
213 | u32 enable; | |
214 | ||
215 | u32 lanecfg1_grf_reg; | |
216 | u32 lanecfg1; | |
217 | u32 lanecfg2_grf_reg; | |
218 | u32 lanecfg2; | |
219 | ||
220 | unsigned int flags; | |
221 | unsigned int max_data_lanes; | |
222 | }; | |
223 | ||
224 | struct dw_rockchip_dsi_priv { | |
225 | struct mipi_dsi_device device; | |
226 | void __iomem *base; | |
227 | struct udevice *panel; | |
bd6375c5 | 228 | void __iomem *grf; |
6fa83833 CM |
229 | |
230 | /* Optional external dphy */ | |
231 | struct phy phy; | |
232 | struct phy_configure_opts_mipi_dphy phy_opts; | |
233 | ||
234 | struct clk *pclk; | |
235 | struct clk *ref; | |
0825522e OJ |
236 | struct clk *grf_clk; |
237 | struct clk *phy_cfg_clk; | |
6fa83833 CM |
238 | struct reset_ctl *rst; |
239 | unsigned int lane_mbps; /* per lane */ | |
240 | u16 input_div; | |
241 | u16 feedback_div; | |
242 | const struct rockchip_dw_dsi_chip_data *cdata; | |
243 | struct udevice *dsi_host; | |
244 | }; | |
245 | ||
246 | static inline void dsi_write(struct dw_rockchip_dsi_priv *dsi, u32 reg, u32 val) | |
247 | { | |
248 | writel(val, dsi->base + reg); | |
249 | } | |
250 | ||
251 | static inline u32 dsi_read(struct dw_rockchip_dsi_priv *dsi, u32 reg) | |
252 | { | |
253 | return readl(dsi->base + reg); | |
254 | } | |
255 | ||
256 | static inline void dsi_set(struct dw_rockchip_dsi_priv *dsi, u32 reg, u32 mask) | |
257 | { | |
258 | dsi_write(dsi, reg, dsi_read(dsi, reg) | mask); | |
259 | } | |
260 | ||
261 | static inline void dsi_clear(struct dw_rockchip_dsi_priv *dsi, u32 reg, u32 mask) | |
262 | { | |
263 | dsi_write(dsi, reg, dsi_read(dsi, reg) & ~mask); | |
264 | } | |
265 | ||
266 | static inline void dsi_update_bits(struct dw_rockchip_dsi_priv *dsi, u32 reg, | |
267 | u32 mask, u32 val) | |
268 | { | |
269 | dsi_write(dsi, reg, (dsi_read(dsi, reg) & ~mask) | val); | |
270 | } | |
271 | ||
272 | static void dw_mipi_dsi_phy_write(struct dw_rockchip_dsi_priv *dsi, | |
273 | u8 test_code, | |
274 | u8 test_data) | |
275 | { | |
276 | /* | |
277 | * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content | |
278 | * is latched internally as the current test code. Test data is | |
279 | * programmed internally by rising edge on TESTCLK. | |
280 | */ | |
281 | dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR); | |
282 | ||
283 | dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) | | |
284 | PHY_TESTDIN(test_code)); | |
285 | ||
286 | dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR); | |
287 | ||
288 | dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) | | |
289 | PHY_TESTDIN(test_data)); | |
290 | ||
291 | dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR); | |
292 | } | |
293 | ||
294 | struct dphy_pll_parameter_map { | |
295 | unsigned int max_mbps; | |
296 | u8 hsfreqrange; | |
297 | u8 icpctrl; | |
298 | u8 lpfctrl; | |
299 | }; | |
300 | ||
301 | /* The table is based on 27MHz DPHY pll reference clock. */ | |
302 | static const struct dphy_pll_parameter_map dppa_map[] = { | |
303 | { 89, 0x00, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM }, | |
304 | { 99, 0x10, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM }, | |
305 | { 109, 0x20, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM }, | |
306 | { 129, 0x01, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM }, | |
307 | { 139, 0x11, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM }, | |
308 | { 149, 0x21, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM }, | |
309 | { 169, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM }, | |
310 | { 179, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM }, | |
311 | { 199, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM }, | |
312 | { 219, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM }, | |
313 | { 239, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM }, | |
314 | { 249, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM }, | |
315 | { 269, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM }, | |
316 | { 299, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM }, | |
317 | { 329, 0x05, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM }, | |
318 | { 359, 0x15, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM }, | |
319 | { 399, 0x25, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM }, | |
320 | { 449, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM }, | |
321 | { 499, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM }, | |
322 | { 549, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM }, | |
323 | { 599, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM }, | |
324 | { 649, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM }, | |
325 | { 699, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM }, | |
326 | { 749, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM }, | |
327 | { 799, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM }, | |
328 | { 849, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM }, | |
329 | { 899, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM }, | |
330 | { 949, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM }, | |
331 | { 999, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM }, | |
332 | {1049, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM }, | |
333 | {1099, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM }, | |
334 | {1149, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }, | |
335 | {1199, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }, | |
336 | {1249, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }, | |
337 | {1299, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }, | |
338 | {1349, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }, | |
339 | {1399, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }, | |
340 | {1449, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }, | |
341 | {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM } | |
342 | }; | |
343 | ||
344 | static int max_mbps_to_parameter(unsigned int max_mbps) | |
345 | { | |
346 | int i; | |
347 | ||
348 | for (i = 0; i < ARRAY_SIZE(dppa_map); i++) | |
349 | if (dppa_map[i].max_mbps >= max_mbps) | |
350 | return i; | |
351 | ||
352 | return -EINVAL; | |
353 | } | |
354 | ||
355 | /* | |
356 | * ns2bc - Nanoseconds to byte clock cycles | |
357 | */ | |
358 | static inline unsigned int ns2bc(struct dw_rockchip_dsi_priv *dsi, int ns) | |
359 | { | |
360 | return DIV_ROUND_UP(ns * dsi->lane_mbps / 8, 1000); | |
361 | } | |
362 | ||
363 | /* | |
364 | * ns2ui - Nanoseconds to UI time periods | |
365 | */ | |
366 | static inline unsigned int ns2ui(struct dw_rockchip_dsi_priv *dsi, int ns) | |
367 | { | |
368 | return DIV_ROUND_UP(ns * dsi->lane_mbps, 1000); | |
369 | } | |
370 | ||
371 | static int dsi_phy_init(void *priv_data) | |
372 | { | |
373 | struct mipi_dsi_device *device = priv_data; | |
374 | struct udevice *dev = device->dev; | |
375 | struct dw_rockchip_dsi_priv *dsi = dev_get_priv(dev); | |
376 | int ret, i, vco; | |
377 | ||
3b4e6e94 | 378 | if (generic_phy_valid(&dsi->phy)) { |
6fa83833 CM |
379 | ret = generic_phy_configure(&dsi->phy, &dsi->phy_opts); |
380 | if (ret) { | |
381 | dev_err(dsi->dsi_host, | |
382 | "Configure external dphy fail %d\n", | |
383 | ret); | |
384 | return ret; | |
385 | } | |
386 | ||
387 | ret = generic_phy_power_on(&dsi->phy); | |
388 | if (ret) { | |
389 | dev_err(dsi->dsi_host, | |
390 | "Generic phy power on fail %d\n", ret); | |
391 | return ret; | |
392 | } | |
393 | ||
394 | return 0; | |
395 | } | |
396 | ||
397 | /* | |
398 | * Get vco from frequency(lane_mbps) | |
399 | * vco frequency table | |
400 | * 000 - between 80 and 200 MHz | |
401 | * 001 - between 200 and 300 MHz | |
402 | * 010 - between 300 and 500 MHz | |
403 | * 011 - between 500 and 700 MHz | |
404 | * 100 - between 700 and 900 MHz | |
405 | * 101 - between 900 and 1100 MHz | |
406 | * 110 - between 1100 and 1300 MHz | |
407 | * 111 - between 1300 and 1500 MHz | |
408 | */ | |
409 | vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200; | |
410 | ||
411 | i = max_mbps_to_parameter(dsi->lane_mbps); | |
412 | if (i < 0) { | |
413 | dev_err(dsi->dsi_host, | |
414 | "failed to get parameter for %dmbps clock\n", | |
415 | dsi->lane_mbps); | |
416 | return i; | |
417 | } | |
418 | ||
419 | dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL, | |
420 | BYPASS_VCO_RANGE | | |
421 | VCO_RANGE_CON_SEL(vco) | | |
422 | VCO_IN_CAP_CON_LOW | | |
423 | REF_BIAS_CUR_SEL); | |
424 | ||
425 | dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS, | |
426 | CP_CURRENT_SEL(dppa_map[i].icpctrl)); | |
427 | dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL, | |
428 | CP_PROGRAM_EN | LPF_PROGRAM_EN | | |
429 | LPF_RESISTORS_SEL(dppa_map[i].lpfctrl)); | |
430 | ||
431 | dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0, | |
432 | HSFREQRANGE_SEL(dppa_map[i].hsfreqrange)); | |
433 | ||
434 | dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO, | |
435 | INPUT_DIVIDER(dsi->input_div)); | |
436 | dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO, | |
437 | LOOP_DIV_LOW_SEL(dsi->feedback_div) | | |
438 | LOW_PROGRAM_EN); | |
439 | /* | |
440 | * We need set PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL immediately | |
441 | * to make the configured LSB effective according to IP simulation | |
442 | * and lab test results. | |
443 | * Only in this way can we get correct mipi phy pll frequency. | |
444 | */ | |
445 | dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL, | |
446 | PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN); | |
447 | dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO, | |
448 | LOOP_DIV_HIGH_SEL(dsi->feedback_div) | | |
449 | HIGH_PROGRAM_EN); | |
450 | dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL, | |
451 | PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN); | |
452 | ||
453 | dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY, | |
454 | LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7)); | |
455 | dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY, | |
456 | HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10)); | |
457 | ||
458 | dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL, | |
459 | POWER_CONTROL | INTERNAL_REG_CURRENT | | |
460 | BIAS_BLOCK_ON | BANDGAP_ON); | |
461 | ||
462 | dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL, | |
463 | TER_RESISTOR_LOW | TER_CAL_DONE | | |
464 | SETRD_MAX | TER_RESISTORS_ON); | |
465 | dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL, | |
466 | TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON | | |
467 | SETRD_MAX | POWER_MANAGE | | |
468 | TER_RESISTORS_ON); | |
469 | ||
470 | dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL, | |
471 | TLP_PROGRAM_EN | ns2bc(dsi, 500)); | |
472 | dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL, | |
473 | THS_PRE_PROGRAM_EN | ns2ui(dsi, 40)); | |
474 | dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL, | |
475 | THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300)); | |
476 | dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL, | |
477 | THS_PRE_PROGRAM_EN | ns2ui(dsi, 100)); | |
478 | dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL, | |
479 | BIT(5) | ns2bc(dsi, 100)); | |
480 | dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL, | |
481 | BIT(5) | (ns2bc(dsi, 60) + 7)); | |
482 | ||
483 | dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL, | |
484 | TLP_PROGRAM_EN | ns2bc(dsi, 500)); | |
485 | dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL, | |
486 | THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 20)); | |
487 | dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL, | |
488 | THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2)); | |
489 | dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL, | |
490 | THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8)); | |
491 | dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL, | |
492 | BIT(5) | ns2bc(dsi, 100)); | |
493 | ||
4158d7f9 | 494 | return 0; |
6fa83833 CM |
495 | } |
496 | ||
497 | static void dsi_phy_post_set_mode(void *priv_data, unsigned long mode_flags) | |
498 | { | |
499 | struct mipi_dsi_device *device = priv_data; | |
500 | struct udevice *dev = device->dev; | |
501 | struct dw_rockchip_dsi_priv *dsi = dev_get_priv(dev); | |
502 | ||
503 | dev_dbg(dev, "Set mode %p enable %ld\n", dsi, | |
504 | mode_flags & MIPI_DSI_MODE_VIDEO); | |
505 | ||
506 | if (!dsi) | |
507 | return; | |
508 | ||
509 | /* | |
510 | * DSI wrapper must be enabled in video mode & disabled in command mode. | |
511 | * If wrapper is enabled in command mode, the display controller | |
512 | * register access will hang. Note that this was carried over from the | |
513 | * stm32 dsi driver and is unknown if necessary for Rockchip. | |
514 | */ | |
515 | ||
516 | if (mode_flags & MIPI_DSI_MODE_VIDEO) | |
517 | dsi_set(dsi, DSI_WCR, WCR_DSIEN); | |
518 | else | |
519 | dsi_clear(dsi, DSI_WCR, WCR_DSIEN); | |
520 | } | |
521 | ||
522 | static int | |
523 | dw_mipi_dsi_get_lane_mbps(void *priv_data, struct display_timing *timings, | |
524 | u32 lanes, u32 format, unsigned int *lane_mbps) | |
525 | { | |
526 | struct mipi_dsi_device *device = priv_data; | |
527 | struct udevice *dev = device->dev; | |
528 | struct dw_rockchip_dsi_priv *dsi = dev_get_priv(dev); | |
529 | int bpp; | |
530 | unsigned long mpclk, tmp; | |
531 | unsigned int target_mbps = 1000; | |
532 | unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps; | |
533 | unsigned long best_freq = 0; | |
534 | unsigned long fvco_min, fvco_max, fin, fout; | |
535 | unsigned int min_prediv, max_prediv; | |
536 | unsigned int _prediv, best_prediv; | |
537 | unsigned long _fbdiv, best_fbdiv; | |
538 | unsigned long min_delta = ULONG_MAX; | |
6fa83833 CM |
539 | |
540 | bpp = mipi_dsi_pixel_format_to_bpp(format); | |
541 | if (bpp < 0) { | |
542 | dev_err(dsi->dsi_host, | |
543 | "failed to get bpp for pixel format %d\n", | |
544 | format); | |
545 | return bpp; | |
546 | } | |
547 | ||
548 | mpclk = DIV_ROUND_UP(timings->pixelclock.typ, 1000); | |
549 | if (mpclk) { | |
550 | /* take 1 / 0.8, since mbps must big than bandwidth of RGB */ | |
551 | tmp = (mpclk * (bpp / lanes) * 10 / 8) / 1000; | |
552 | if (tmp < max_mbps) | |
553 | target_mbps = tmp; | |
554 | else | |
555 | dev_err(dsi->dsi_host, | |
556 | "DPHY clock frequency is out of range\n"); | |
557 | } | |
558 | ||
559 | /* for external phy only the mipi_dphy_config is necessary */ | |
3b4e6e94 | 560 | if (generic_phy_valid(&dsi->phy)) { |
6fa83833 CM |
561 | phy_mipi_dphy_get_default_config(timings->pixelclock.typ * 10 / 8, |
562 | bpp, lanes, | |
563 | &dsi->phy_opts); | |
564 | dsi->lane_mbps = target_mbps; | |
565 | *lane_mbps = dsi->lane_mbps; | |
566 | ||
567 | return 0; | |
568 | } | |
569 | ||
dc3f2403 | 570 | fin = clk_get_rate(dsi->ref); |
6fa83833 CM |
571 | fout = target_mbps * USEC_PER_SEC; |
572 | ||
573 | /* constraint: 5Mhz <= Fref / N <= 40MHz */ | |
574 | min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC); | |
575 | max_prediv = fin / (5 * USEC_PER_SEC); | |
576 | ||
577 | /* constraint: 80MHz <= Fvco <= 1500Mhz */ | |
578 | fvco_min = 80 * USEC_PER_SEC; | |
579 | fvco_max = 1500 * USEC_PER_SEC; | |
580 | ||
581 | for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) { | |
582 | u64 tmp; | |
583 | u32 delta; | |
584 | /* Fvco = Fref * M / N */ | |
585 | tmp = (u64)fout * _prediv; | |
586 | do_div(tmp, fin); | |
587 | _fbdiv = tmp; | |
588 | /* | |
589 | * Due to the use of a "by 2 pre-scaler," the range of the | |
590 | * feedback multiplication value M is limited to even division | |
591 | * numbers, and m must be greater than 6, not bigger than 512. | |
592 | */ | |
593 | if (_fbdiv < 6 || _fbdiv > 512) | |
594 | continue; | |
595 | ||
596 | _fbdiv += _fbdiv % 2; | |
597 | ||
598 | tmp = (u64)_fbdiv * fin; | |
599 | do_div(tmp, _prediv); | |
600 | if (tmp < fvco_min || tmp > fvco_max) | |
601 | continue; | |
602 | ||
603 | delta = abs(fout - tmp); | |
604 | if (delta < min_delta) { | |
605 | best_prediv = _prediv; | |
606 | best_fbdiv = _fbdiv; | |
607 | min_delta = delta; | |
608 | best_freq = tmp; | |
609 | } | |
610 | } | |
611 | ||
612 | if (best_freq) { | |
613 | dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC); | |
614 | *lane_mbps = dsi->lane_mbps; | |
615 | dsi->input_div = best_prediv; | |
616 | dsi->feedback_div = best_fbdiv; | |
617 | } else { | |
618 | dev_err(dsi->dsi_host, "Can not find best_freq for DPHY\n"); | |
619 | return -EINVAL; | |
620 | } | |
621 | ||
622 | return 0; | |
623 | } | |
624 | ||
625 | struct hstt { | |
626 | unsigned int maxfreq; | |
627 | struct mipi_dsi_phy_timing timing; | |
628 | }; | |
629 | ||
630 | #define HSTT(_maxfreq, _c_lp2hs, _c_hs2lp, _d_lp2hs, _d_hs2lp) \ | |
631 | { \ | |
632 | .maxfreq = _maxfreq, \ | |
633 | .timing = { \ | |
634 | .clk_lp2hs = _c_lp2hs, \ | |
635 | .clk_hs2lp = _c_hs2lp, \ | |
636 | .data_lp2hs = _d_lp2hs, \ | |
637 | .data_hs2lp = _d_hs2lp, \ | |
638 | } \ | |
639 | } | |
640 | ||
641 | /* | |
642 | * Table A-3 High-Speed Transition Times | |
643 | * (Note spacing is deliberate for readability). | |
644 | */ | |
645 | static struct hstt hstt_table[] = { | |
646 | HSTT( 90, 32, 20, 26, 13), | |
647 | HSTT( 100, 35, 23, 28, 14), | |
648 | HSTT( 110, 32, 22, 26, 13), | |
649 | HSTT( 130, 31, 20, 27, 13), | |
650 | HSTT( 140, 33, 22, 26, 14), | |
651 | HSTT( 150, 33, 21, 26, 14), | |
652 | HSTT( 170, 32, 20, 27, 13), | |
653 | HSTT( 180, 36, 23, 30, 15), | |
654 | HSTT( 200, 40, 22, 33, 15), | |
655 | HSTT( 220, 40, 22, 33, 15), | |
656 | HSTT( 240, 44, 24, 36, 16), | |
657 | HSTT( 250, 48, 24, 38, 17), | |
658 | HSTT( 270, 48, 24, 38, 17), | |
659 | HSTT( 300, 50, 27, 41, 18), | |
660 | HSTT( 330, 56, 28, 45, 18), | |
661 | HSTT( 360, 59, 28, 48, 19), | |
662 | HSTT( 400, 61, 30, 50, 20), | |
663 | HSTT( 450, 67, 31, 55, 21), | |
664 | HSTT( 500, 73, 31, 59, 22), | |
665 | HSTT( 550, 79, 36, 63, 24), | |
666 | HSTT( 600, 83, 37, 68, 25), | |
667 | HSTT( 650, 90, 38, 73, 27), | |
668 | HSTT( 700, 95, 40, 77, 28), | |
669 | HSTT( 750, 102, 40, 84, 28), | |
670 | HSTT( 800, 106, 42, 87, 30), | |
671 | HSTT( 850, 113, 44, 93, 31), | |
672 | HSTT( 900, 118, 47, 98, 32), | |
673 | HSTT( 950, 124, 47, 102, 34), | |
674 | HSTT(1000, 130, 49, 107, 35), | |
675 | HSTT(1050, 135, 51, 111, 37), | |
676 | HSTT(1100, 139, 51, 114, 38), | |
677 | HSTT(1150, 146, 54, 120, 40), | |
678 | HSTT(1200, 153, 57, 125, 41), | |
679 | HSTT(1250, 158, 58, 130, 42), | |
680 | HSTT(1300, 163, 58, 135, 44), | |
681 | HSTT(1350, 168, 60, 140, 45), | |
682 | HSTT(1400, 172, 64, 144, 47), | |
683 | HSTT(1450, 176, 65, 148, 48), | |
684 | HSTT(1500, 181, 66, 153, 50) | |
685 | }; | |
686 | ||
687 | static int dw_mipi_dsi_rockchip_get_timing(void *priv_data, | |
688 | unsigned int lane_mbps, | |
689 | struct mipi_dsi_phy_timing *timing) | |
690 | { | |
691 | int i; | |
692 | ||
693 | for (i = 0; i < ARRAY_SIZE(hstt_table); i++) | |
694 | if (lane_mbps < hstt_table[i].maxfreq) | |
695 | break; | |
696 | ||
697 | if (i == ARRAY_SIZE(hstt_table)) | |
698 | i--; | |
699 | ||
700 | *timing = hstt_table[i].timing; | |
701 | ||
702 | return 0; | |
703 | } | |
704 | ||
705 | static const struct mipi_dsi_phy_ops dsi_rockchip_phy_ops = { | |
706 | .init = dsi_phy_init, | |
707 | .get_lane_mbps = dw_mipi_dsi_get_lane_mbps, | |
708 | .get_timing = dw_mipi_dsi_rockchip_get_timing, | |
709 | .post_set_mode = dsi_phy_post_set_mode, | |
710 | }; | |
711 | ||
712 | static int dw_mipi_dsi_rockchip_attach(struct udevice *dev) | |
713 | { | |
714 | struct dw_rockchip_dsi_priv *priv = dev_get_priv(dev); | |
715 | struct mipi_dsi_device *device = &priv->device; | |
716 | struct mipi_dsi_panel_plat *mplat; | |
717 | struct display_timing timings; | |
718 | int ret; | |
719 | ||
720 | ret = uclass_first_device_err(UCLASS_PANEL, &priv->panel); | |
721 | if (ret) { | |
722 | dev_err(dev, "panel device error %d\n", ret); | |
723 | return ret; | |
724 | } | |
725 | ||
726 | mplat = dev_get_plat(priv->panel); | |
727 | mplat->device = &priv->device; | |
728 | device->lanes = mplat->lanes; | |
729 | device->format = mplat->format; | |
730 | device->mode_flags = mplat->mode_flags; | |
731 | ||
732 | ret = panel_get_display_timing(priv->panel, &timings); | |
733 | if (ret) { | |
734 | ret = ofnode_decode_display_timing(dev_ofnode(priv->panel), | |
735 | 0, &timings); | |
736 | if (ret) { | |
737 | dev_err(dev, "decode display timing error %d\n", ret); | |
738 | return ret; | |
739 | } | |
740 | } | |
741 | ||
742 | ret = uclass_get_device(UCLASS_DSI_HOST, 0, &priv->dsi_host); | |
743 | if (ret) { | |
744 | dev_err(dev, "No video dsi host detected %d\n", ret); | |
745 | return ret; | |
746 | } | |
747 | ||
748 | ret = dsi_host_init(priv->dsi_host, device, &timings, 4, | |
749 | &dsi_rockchip_phy_ops); | |
750 | if (ret) { | |
751 | dev_err(dev, "failed to initialize mipi dsi host\n"); | |
752 | return ret; | |
753 | } | |
754 | ||
755 | return 0; | |
756 | } | |
757 | ||
758 | static int dw_mipi_dsi_rockchip_set_bl(struct udevice *dev, int percent) | |
759 | { | |
760 | struct dw_rockchip_dsi_priv *priv = dev_get_priv(dev); | |
761 | int ret; | |
762 | ||
763 | /* | |
764 | * Allow backlight to be optional, since this driver may be | |
765 | * used to simply detect a panel rather than bring one up. | |
766 | */ | |
767 | ret = panel_enable_backlight(priv->panel); | |
768 | if ((ret) && (ret != -ENOSYS)) { | |
769 | dev_err(dev, "panel %s enable backlight error %d\n", | |
770 | priv->panel->name, ret); | |
771 | return ret; | |
772 | } | |
773 | ||
774 | ret = dsi_host_enable(priv->dsi_host); | |
775 | if (ret) { | |
776 | dev_err(dev, "failed to enable mipi dsi host\n"); | |
777 | return ret; | |
778 | } | |
779 | ||
780 | return 0; | |
781 | } | |
782 | ||
783 | static void dw_mipi_dsi_rockchip_config(struct dw_rockchip_dsi_priv *dsi) | |
784 | { | |
785 | if (dsi->cdata->lanecfg1_grf_reg) | |
bd6375c5 | 786 | rk_setreg(dsi->grf + dsi->cdata->lanecfg1_grf_reg, dsi->cdata->lanecfg1); |
6fa83833 CM |
787 | |
788 | if (dsi->cdata->lanecfg2_grf_reg) | |
bd6375c5 | 789 | rk_setreg(dsi->grf + dsi->cdata->lanecfg2_grf_reg, dsi->cdata->lanecfg2); |
6fa83833 CM |
790 | |
791 | if (dsi->cdata->enable_grf_reg) | |
bd6375c5 | 792 | rk_setreg(dsi->grf + dsi->cdata->enable_grf_reg, dsi->cdata->enable); |
6fa83833 CM |
793 | } |
794 | ||
795 | static int dw_mipi_dsi_rockchip_bind(struct udevice *dev) | |
796 | { | |
797 | int ret; | |
798 | ||
799 | ret = device_bind_driver_to_node(dev, "dw_mipi_dsi", "dsihost", | |
800 | dev_ofnode(dev), NULL); | |
801 | if (ret) { | |
802 | dev_err(dev, "failed to bind driver to node\n"); | |
803 | return ret; | |
804 | } | |
805 | ||
806 | return dm_scan_fdt_dev(dev); | |
807 | } | |
808 | ||
809 | static int dw_mipi_dsi_rockchip_probe(struct udevice *dev) | |
810 | { | |
811 | struct dw_rockchip_dsi_priv *priv = dev_get_priv(dev); | |
812 | struct mipi_dsi_device *device = &priv->device; | |
813 | int ret, i; | |
814 | const struct rockchip_dw_dsi_chip_data *cdata = | |
815 | (const struct rockchip_dw_dsi_chip_data *)dev_get_driver_data(dev); | |
816 | ||
817 | device->dev = dev; | |
818 | ||
819 | priv->base = (void *)dev_read_addr(dev); | |
820 | if ((fdt_addr_t)priv->base == FDT_ADDR_T_NONE) { | |
821 | dev_err(dev, "dsi dt register address error\n"); | |
822 | return -EINVAL; | |
823 | } | |
824 | ||
bd6375c5 OJ |
825 | priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF); |
826 | ||
6fa83833 CM |
827 | i = 0; |
828 | while (cdata[i].reg) { | |
829 | if (cdata[i].reg == (fdt_addr_t)priv->base) { | |
830 | priv->cdata = &cdata[i]; | |
831 | break; | |
832 | } | |
833 | ||
834 | i++; | |
835 | } | |
836 | ||
837 | if (!priv->cdata) { | |
838 | dev_err(dev, "no dsi-config for %s node\n", dev->name); | |
839 | return -EINVAL; | |
840 | } | |
841 | ||
842 | /* | |
843 | * Get an optional external dphy. The external dphy stays as | |
844 | * NULL if it's not initialized. | |
845 | */ | |
846 | ret = generic_phy_get_by_name(dev, "dphy", &priv->phy); | |
7c5f278a | 847 | if (ret && ret != -ENODATA) { |
6fa83833 | 848 | dev_err(dev, "failed to get mipi dphy: %d\n", ret); |
7c5f278a | 849 | return ret; |
6fa83833 CM |
850 | } |
851 | ||
852 | priv->pclk = devm_clk_get(dev, "pclk"); | |
853 | if (IS_ERR(priv->pclk)) { | |
14dd77fd | 854 | ret = PTR_ERR(priv->pclk); |
6fa83833 CM |
855 | dev_err(dev, "peripheral clock get error %d\n", ret); |
856 | return ret; | |
857 | } | |
858 | ||
859 | /* Get a ref clock only if not using an external phy. */ | |
3b4e6e94 | 860 | if (generic_phy_valid(&priv->phy)) { |
6fa83833 CM |
861 | dev_dbg(dev, "setting priv->ref to NULL\n"); |
862 | priv->ref = NULL; | |
863 | ||
864 | } else { | |
865 | priv->ref = devm_clk_get(dev, "ref"); | |
14dd77fd OJ |
866 | if (IS_ERR(priv->ref)) { |
867 | ret = PTR_ERR(priv->ref); | |
6fa83833 CM |
868 | dev_err(dev, "pll reference clock get error %d\n", ret); |
869 | return ret; | |
870 | } | |
871 | } | |
872 | ||
0825522e OJ |
873 | if (cdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) { |
874 | priv->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); | |
875 | if (IS_ERR(priv->phy_cfg_clk)) { | |
876 | ret = PTR_ERR(priv->phy_cfg_clk); | |
877 | dev_err(dev, "phy_cfg_clk clock get error %d\n", ret); | |
878 | return ret; | |
879 | } | |
880 | ||
881 | clk_enable(priv->phy_cfg_clk); | |
882 | } | |
883 | ||
884 | if (cdata->flags & DW_MIPI_NEEDS_GRF_CLK) { | |
885 | priv->grf_clk = devm_clk_get(dev, "grf"); | |
886 | if (IS_ERR(priv->grf_clk)) { | |
887 | ret = PTR_ERR(priv->grf_clk); | |
888 | dev_err(dev, "grf_clk clock get error %d\n", ret); | |
889 | return ret; | |
890 | } | |
891 | ||
892 | clk_enable(priv->grf_clk); | |
893 | } | |
894 | ||
6fa83833 CM |
895 | priv->rst = devm_reset_control_get_by_index(device->dev, 0); |
896 | if (IS_ERR(priv->rst)) { | |
14dd77fd OJ |
897 | ret = PTR_ERR(priv->rst); |
898 | dev_err(dev, "missing dsi hardware reset %d\n", ret); | |
6fa83833 CM |
899 | return ret; |
900 | } | |
901 | ||
902 | /* Reset */ | |
903 | reset_deassert(priv->rst); | |
904 | ||
905 | dw_mipi_dsi_rockchip_config(priv); | |
906 | ||
907 | return 0; | |
908 | } | |
909 | ||
910 | struct video_bridge_ops dw_mipi_dsi_rockchip_ops = { | |
911 | .attach = dw_mipi_dsi_rockchip_attach, | |
912 | .set_backlight = dw_mipi_dsi_rockchip_set_bl, | |
913 | }; | |
914 | ||
0825522e OJ |
915 | static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = { |
916 | { | |
917 | .reg = 0xff960000, | |
918 | .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, | |
919 | .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI0_LCDC_SEL), | |
920 | .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI0_LCDC_SEL, | |
921 | RK3399_DSI0_LCDC_SEL), | |
922 | ||
923 | .lanecfg1_grf_reg = RK3399_GRF_SOC_CON22, | |
924 | .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI0_TURNREQUEST | | |
925 | RK3399_DSI0_TURNDISABLE | | |
926 | RK3399_DSI0_FORCETXSTOPMODE | | |
927 | RK3399_DSI0_FORCERXMODE), | |
928 | ||
929 | .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK, | |
930 | .max_data_lanes = 4, | |
931 | }, | |
932 | { | |
933 | .reg = 0xff968000, | |
934 | .lcdsel_grf_reg = RK3399_GRF_SOC_CON20, | |
935 | .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI1_LCDC_SEL), | |
936 | .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI1_LCDC_SEL, | |
937 | RK3399_DSI1_LCDC_SEL), | |
938 | ||
939 | .lanecfg1_grf_reg = RK3399_GRF_SOC_CON23, | |
940 | .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI1_TURNDISABLE | | |
941 | RK3399_DSI1_FORCETXSTOPMODE | | |
942 | RK3399_DSI1_FORCERXMODE | | |
943 | RK3399_DSI1_ENABLE), | |
944 | ||
945 | .lanecfg2_grf_reg = RK3399_GRF_SOC_CON24, | |
946 | .lanecfg2 = HIWORD_UPDATE(RK3399_TXRX_MASTERSLAVEZ | | |
947 | RK3399_TXRX_ENABLECLK, | |
948 | RK3399_TXRX_MASTERSLAVEZ | | |
949 | RK3399_TXRX_ENABLECLK | | |
950 | RK3399_TXRX_BASEDIR), | |
951 | ||
952 | .enable_grf_reg = RK3399_GRF_SOC_CON23, | |
953 | .enable = HIWORD_UPDATE(RK3399_DSI1_ENABLE, RK3399_DSI1_ENABLE), | |
954 | ||
955 | .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK, | |
956 | .max_data_lanes = 4, | |
957 | }, | |
958 | { /* sentinel */ } | |
959 | }; | |
960 | ||
6fa83833 CM |
961 | static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = { |
962 | { | |
963 | .reg = 0xfe060000, | |
964 | .lanecfg1_grf_reg = RK3568_GRF_VO_CON2, | |
965 | .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI0_SKEWCALHS | | |
966 | RK3568_DSI0_FORCETXSTOPMODE | | |
967 | RK3568_DSI0_TURNDISABLE | | |
968 | RK3568_DSI0_FORCERXMODE), | |
969 | .max_data_lanes = 4, | |
970 | }, | |
971 | { | |
972 | .reg = 0xfe070000, | |
973 | .lanecfg1_grf_reg = RK3568_GRF_VO_CON3, | |
974 | .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI1_SKEWCALHS | | |
975 | RK3568_DSI1_FORCETXSTOPMODE | | |
976 | RK3568_DSI1_TURNDISABLE | | |
977 | RK3568_DSI1_FORCERXMODE), | |
978 | .max_data_lanes = 4, | |
979 | }, | |
980 | { /* sentinel */ } | |
981 | }; | |
982 | ||
983 | static const struct udevice_id dw_mipi_dsi_rockchip_dt_ids[] = { | |
0825522e OJ |
984 | { .compatible = "rockchip,rk3399-mipi-dsi", |
985 | .data = (long)&rk3399_chip_data, | |
986 | }, | |
6fa83833 CM |
987 | { .compatible = "rockchip,rk3568-mipi-dsi", |
988 | .data = (long)&rk3568_chip_data, | |
989 | }, | |
990 | { /* sentinel */ } | |
991 | }; | |
992 | ||
993 | U_BOOT_DRIVER(dw_mipi_dsi_rockchip) = { | |
994 | .name = "dw-mipi-dsi-rockchip", | |
995 | .id = UCLASS_VIDEO_BRIDGE, | |
996 | .of_match = dw_mipi_dsi_rockchip_dt_ids, | |
997 | .bind = dw_mipi_dsi_rockchip_bind, | |
998 | .probe = dw_mipi_dsi_rockchip_probe, | |
999 | .ops = &dw_mipi_dsi_rockchip_ops, | |
1000 | .priv_auto = sizeof(struct dw_rockchip_dsi_priv), | |
1001 | }; |