]>
Commit | Line | Data |
---|---|---|
f819b0d4 XL |
1 | /* |
2 | * DesignWare MIPI DSI Host Controller v1.02 driver | |
3 | * | |
4 | * Copyright (c) 2016 Linaro Limited. | |
5 | * Copyright (c) 2014-2016 Hisilicon Limited. | |
6 | * | |
7 | * Author: | |
8 | * Xinliang Liu <z.liuxinliang@hisilicon.com> | |
9 | * Xinliang Liu <xinliang.liu@linaro.org> | |
10 | * Xinwei Kong <kong.kongxinwei@hisilicon.com> | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License version 2 as | |
14 | * published by the Free Software Foundation. | |
15 | * | |
16 | */ | |
17 | ||
18 | #include <linux/clk.h> | |
19 | #include <linux/component.h> | |
f819b0d4 XL |
20 | |
21 | #include <drm/drm_of.h> | |
22 | #include <drm/drm_crtc_helper.h> | |
23 | #include <drm/drm_mipi_dsi.h> | |
24 | #include <drm/drm_encoder_slave.h> | |
25 | #include <drm/drm_atomic_helper.h> | |
26 | ||
27 | #include "dw_dsi_reg.h" | |
28 | ||
29 | #define MAX_TX_ESC_CLK 10 | |
30 | #define ROUND(x, y) ((x) / (y) + \ | |
31 | ((x) % (y) * 10 / (y) >= 5 ? 1 : 0)) | |
32 | #define PHY_REF_CLK_RATE 19200000 | |
33 | #define PHY_REF_CLK_PERIOD_PS (1000000000 / (PHY_REF_CLK_RATE / 1000)) | |
34 | ||
35 | #define encoder_to_dsi(encoder) \ | |
36 | container_of(encoder, struct dw_dsi, encoder) | |
37 | #define host_to_dsi(host) \ | |
38 | container_of(host, struct dw_dsi, host) | |
39 | ||
40 | struct mipi_phy_params { | |
41 | u32 clk_t_lpx; | |
42 | u32 clk_t_hs_prepare; | |
43 | u32 clk_t_hs_zero; | |
44 | u32 clk_t_hs_trial; | |
45 | u32 clk_t_wakeup; | |
46 | u32 data_t_lpx; | |
47 | u32 data_t_hs_prepare; | |
48 | u32 data_t_hs_zero; | |
49 | u32 data_t_hs_trial; | |
50 | u32 data_t_ta_go; | |
51 | u32 data_t_ta_get; | |
52 | u32 data_t_wakeup; | |
53 | u32 hstx_ckg_sel; | |
54 | u32 pll_fbd_div5f; | |
55 | u32 pll_fbd_div1f; | |
56 | u32 pll_fbd_2p; | |
57 | u32 pll_enbwt; | |
58 | u32 pll_fbd_p; | |
59 | u32 pll_fbd_s; | |
60 | u32 pll_pre_div1p; | |
61 | u32 pll_pre_p; | |
62 | u32 pll_vco_750M; | |
63 | u32 pll_lpf_rs; | |
64 | u32 pll_lpf_cs; | |
65 | u32 clklp2hs_time; | |
66 | u32 clkhs2lp_time; | |
67 | u32 lp2hs_time; | |
68 | u32 hs2lp_time; | |
69 | u32 clk_to_data_delay; | |
70 | u32 data_to_clk_delay; | |
71 | u32 lane_byte_clk_kHz; | |
72 | u32 clk_division; | |
73 | }; | |
74 | ||
75 | struct dsi_hw_ctx { | |
76 | void __iomem *base; | |
77 | struct clk *pclk; | |
78 | }; | |
79 | ||
80 | struct dw_dsi { | |
81 | struct drm_encoder encoder; | |
40ed27b8 | 82 | struct drm_bridge *bridge; |
834480d2 | 83 | struct mipi_dsi_host host; |
f819b0d4 XL |
84 | struct drm_display_mode cur_mode; |
85 | struct dsi_hw_ctx *ctx; | |
86 | struct mipi_phy_params phy; | |
87 | ||
88 | u32 lanes; | |
89 | enum mipi_dsi_pixel_format format; | |
90 | unsigned long mode_flags; | |
91 | bool enable; | |
92 | }; | |
93 | ||
94 | struct dsi_data { | |
95 | struct dw_dsi dsi; | |
96 | struct dsi_hw_ctx ctx; | |
97 | }; | |
98 | ||
99 | struct dsi_phy_range { | |
100 | u32 min_range_kHz; | |
101 | u32 max_range_kHz; | |
102 | u32 pll_vco_750M; | |
103 | u32 hstx_ckg_sel; | |
104 | }; | |
105 | ||
106 | static const struct dsi_phy_range dphy_range_info[] = { | |
107 | { 46875, 62500, 1, 7 }, | |
108 | { 62500, 93750, 0, 7 }, | |
109 | { 93750, 125000, 1, 6 }, | |
110 | { 125000, 187500, 0, 6 }, | |
111 | { 187500, 250000, 1, 5 }, | |
112 | { 250000, 375000, 0, 5 }, | |
113 | { 375000, 500000, 1, 4 }, | |
114 | { 500000, 750000, 0, 4 }, | |
115 | { 750000, 1000000, 1, 0 }, | |
116 | { 1000000, 1500000, 0, 0 } | |
117 | }; | |
118 | ||
119 | static u32 dsi_calc_phy_rate(u32 req_kHz, struct mipi_phy_params *phy) | |
120 | { | |
121 | u32 ref_clk_ps = PHY_REF_CLK_PERIOD_PS; | |
122 | u32 tmp_kHz = req_kHz; | |
123 | u32 i = 0; | |
124 | u32 q_pll = 1; | |
125 | u32 m_pll = 0; | |
126 | u32 n_pll = 0; | |
127 | u32 r_pll = 1; | |
128 | u32 m_n = 0; | |
129 | u32 m_n_int = 0; | |
130 | u32 f_kHz = 0; | |
131 | u64 temp; | |
132 | ||
133 | /* | |
134 | * Find a rate >= req_kHz. | |
135 | */ | |
136 | do { | |
137 | f_kHz = tmp_kHz; | |
138 | ||
139 | for (i = 0; i < ARRAY_SIZE(dphy_range_info); i++) | |
140 | if (f_kHz >= dphy_range_info[i].min_range_kHz && | |
141 | f_kHz <= dphy_range_info[i].max_range_kHz) | |
142 | break; | |
143 | ||
144 | if (i == ARRAY_SIZE(dphy_range_info)) { | |
145 | DRM_ERROR("%dkHz out of range\n", f_kHz); | |
146 | return 0; | |
147 | } | |
148 | ||
149 | phy->pll_vco_750M = dphy_range_info[i].pll_vco_750M; | |
150 | phy->hstx_ckg_sel = dphy_range_info[i].hstx_ckg_sel; | |
151 | ||
152 | if (phy->hstx_ckg_sel <= 7 && | |
153 | phy->hstx_ckg_sel >= 4) | |
154 | q_pll = 0x10 >> (7 - phy->hstx_ckg_sel); | |
155 | ||
156 | temp = f_kHz * (u64)q_pll * (u64)ref_clk_ps; | |
157 | m_n_int = temp / (u64)1000000000; | |
158 | m_n = (temp % (u64)1000000000) / (u64)100000000; | |
159 | ||
160 | if (m_n_int % 2 == 0) { | |
161 | if (m_n * 6 >= 50) { | |
162 | n_pll = 2; | |
163 | m_pll = (m_n_int + 1) * n_pll; | |
164 | } else if (m_n * 6 >= 30) { | |
165 | n_pll = 3; | |
166 | m_pll = m_n_int * n_pll + 2; | |
167 | } else { | |
168 | n_pll = 1; | |
169 | m_pll = m_n_int * n_pll; | |
170 | } | |
171 | } else { | |
172 | if (m_n * 6 >= 50) { | |
173 | n_pll = 1; | |
174 | m_pll = (m_n_int + 1) * n_pll; | |
175 | } else if (m_n * 6 >= 30) { | |
176 | n_pll = 1; | |
177 | m_pll = (m_n_int + 1) * n_pll; | |
178 | } else if (m_n * 6 >= 10) { | |
179 | n_pll = 3; | |
180 | m_pll = m_n_int * n_pll + 1; | |
181 | } else { | |
182 | n_pll = 2; | |
183 | m_pll = m_n_int * n_pll; | |
184 | } | |
185 | } | |
186 | ||
187 | if (n_pll == 1) { | |
188 | phy->pll_fbd_p = 0; | |
189 | phy->pll_pre_div1p = 1; | |
190 | } else { | |
191 | phy->pll_fbd_p = n_pll; | |
192 | phy->pll_pre_div1p = 0; | |
193 | } | |
194 | ||
195 | if (phy->pll_fbd_2p <= 7 && phy->pll_fbd_2p >= 4) | |
196 | r_pll = 0x10 >> (7 - phy->pll_fbd_2p); | |
197 | ||
198 | if (m_pll == 2) { | |
199 | phy->pll_pre_p = 0; | |
200 | phy->pll_fbd_s = 0; | |
201 | phy->pll_fbd_div1f = 0; | |
202 | phy->pll_fbd_div5f = 1; | |
203 | } else if (m_pll >= 2 * 2 * r_pll && m_pll <= 2 * 4 * r_pll) { | |
204 | phy->pll_pre_p = m_pll / (2 * r_pll); | |
205 | phy->pll_fbd_s = 0; | |
206 | phy->pll_fbd_div1f = 1; | |
207 | phy->pll_fbd_div5f = 0; | |
208 | } else if (m_pll >= 2 * 5 * r_pll && m_pll <= 2 * 150 * r_pll) { | |
209 | if (((m_pll / (2 * r_pll)) % 2) == 0) { | |
210 | phy->pll_pre_p = | |
211 | (m_pll / (2 * r_pll)) / 2 - 1; | |
212 | phy->pll_fbd_s = | |
213 | (m_pll / (2 * r_pll)) % 2 + 2; | |
214 | } else { | |
215 | phy->pll_pre_p = | |
216 | (m_pll / (2 * r_pll)) / 2; | |
217 | phy->pll_fbd_s = | |
218 | (m_pll / (2 * r_pll)) % 2; | |
219 | } | |
220 | phy->pll_fbd_div1f = 0; | |
221 | phy->pll_fbd_div5f = 0; | |
222 | } else { | |
223 | phy->pll_pre_p = 0; | |
224 | phy->pll_fbd_s = 0; | |
225 | phy->pll_fbd_div1f = 0; | |
226 | phy->pll_fbd_div5f = 1; | |
227 | } | |
228 | ||
229 | f_kHz = (u64)1000000000 * (u64)m_pll / | |
230 | ((u64)ref_clk_ps * (u64)n_pll * (u64)q_pll); | |
231 | ||
232 | if (f_kHz >= req_kHz) | |
233 | break; | |
234 | ||
235 | tmp_kHz += 10; | |
236 | ||
237 | } while (true); | |
238 | ||
239 | return f_kHz; | |
240 | } | |
241 | ||
242 | static void dsi_get_phy_params(u32 phy_req_kHz, | |
243 | struct mipi_phy_params *phy) | |
244 | { | |
245 | u32 ref_clk_ps = PHY_REF_CLK_PERIOD_PS; | |
246 | u32 phy_rate_kHz; | |
247 | u32 ui; | |
248 | ||
249 | memset(phy, 0, sizeof(*phy)); | |
250 | ||
251 | phy_rate_kHz = dsi_calc_phy_rate(phy_req_kHz, phy); | |
252 | if (!phy_rate_kHz) | |
253 | return; | |
254 | ||
255 | ui = 1000000 / phy_rate_kHz; | |
256 | ||
257 | phy->clk_t_lpx = ROUND(50, 8 * ui); | |
258 | phy->clk_t_hs_prepare = ROUND(133, 16 * ui) - 1; | |
259 | ||
260 | phy->clk_t_hs_zero = ROUND(262, 8 * ui); | |
261 | phy->clk_t_hs_trial = 2 * (ROUND(60, 8 * ui) - 1); | |
262 | phy->clk_t_wakeup = ROUND(1000000, (ref_clk_ps / 1000) - 1); | |
263 | if (phy->clk_t_wakeup > 0xff) | |
264 | phy->clk_t_wakeup = 0xff; | |
265 | phy->data_t_wakeup = phy->clk_t_wakeup; | |
266 | phy->data_t_lpx = phy->clk_t_lpx; | |
267 | phy->data_t_hs_prepare = ROUND(125 + 10 * ui, 16 * ui) - 1; | |
268 | phy->data_t_hs_zero = ROUND(105 + 6 * ui, 8 * ui); | |
269 | phy->data_t_hs_trial = 2 * (ROUND(60 + 4 * ui, 8 * ui) - 1); | |
270 | phy->data_t_ta_go = 3; | |
271 | phy->data_t_ta_get = 4; | |
272 | ||
273 | phy->pll_enbwt = 1; | |
274 | phy->clklp2hs_time = ROUND(407, 8 * ui) + 12; | |
275 | phy->clkhs2lp_time = ROUND(105 + 12 * ui, 8 * ui); | |
276 | phy->lp2hs_time = ROUND(240 + 12 * ui, 8 * ui) + 1; | |
277 | phy->hs2lp_time = phy->clkhs2lp_time; | |
278 | phy->clk_to_data_delay = 1 + phy->clklp2hs_time; | |
279 | phy->data_to_clk_delay = ROUND(60 + 52 * ui, 8 * ui) + | |
280 | phy->clkhs2lp_time; | |
281 | ||
282 | phy->lane_byte_clk_kHz = phy_rate_kHz / 8; | |
283 | phy->clk_division = | |
284 | DIV_ROUND_UP(phy->lane_byte_clk_kHz, MAX_TX_ESC_CLK); | |
285 | } | |
286 | ||
287 | static u32 dsi_get_dpi_color_coding(enum mipi_dsi_pixel_format format) | |
288 | { | |
289 | u32 val; | |
290 | ||
291 | /* | |
292 | * TODO: only support RGB888 now, to support more | |
293 | */ | |
294 | switch (format) { | |
295 | case MIPI_DSI_FMT_RGB888: | |
296 | val = DSI_24BITS_1; | |
297 | break; | |
298 | default: | |
299 | val = DSI_24BITS_1; | |
300 | break; | |
301 | } | |
302 | ||
303 | return val; | |
304 | } | |
305 | ||
306 | /* | |
307 | * dsi phy reg write function | |
308 | */ | |
309 | static void dsi_phy_tst_set(void __iomem *base, u32 reg, u32 val) | |
310 | { | |
311 | u32 reg_write = 0x10000 + reg; | |
312 | ||
313 | /* | |
314 | * latch reg first | |
315 | */ | |
316 | writel(reg_write, base + PHY_TST_CTRL1); | |
317 | writel(0x02, base + PHY_TST_CTRL0); | |
318 | writel(0x00, base + PHY_TST_CTRL0); | |
319 | ||
320 | /* | |
321 | * then latch value | |
322 | */ | |
323 | writel(val, base + PHY_TST_CTRL1); | |
324 | writel(0x02, base + PHY_TST_CTRL0); | |
325 | writel(0x00, base + PHY_TST_CTRL0); | |
326 | } | |
327 | ||
328 | static void dsi_set_phy_timer(void __iomem *base, | |
329 | struct mipi_phy_params *phy, | |
330 | u32 lanes) | |
331 | { | |
332 | u32 val; | |
333 | ||
334 | /* | |
335 | * Set lane value and phy stop wait time. | |
336 | */ | |
337 | val = (lanes - 1) | (PHY_STOP_WAIT_TIME << 8); | |
338 | writel(val, base + PHY_IF_CFG); | |
339 | ||
340 | /* | |
341 | * Set phy clk division. | |
342 | */ | |
343 | val = readl(base + CLKMGR_CFG) | phy->clk_division; | |
344 | writel(val, base + CLKMGR_CFG); | |
345 | ||
346 | /* | |
347 | * Set lp and hs switching params. | |
348 | */ | |
349 | dw_update_bits(base + PHY_TMR_CFG, 24, MASK(8), phy->hs2lp_time); | |
350 | dw_update_bits(base + PHY_TMR_CFG, 16, MASK(8), phy->lp2hs_time); | |
351 | dw_update_bits(base + PHY_TMR_LPCLK_CFG, 16, MASK(10), | |
352 | phy->clkhs2lp_time); | |
353 | dw_update_bits(base + PHY_TMR_LPCLK_CFG, 0, MASK(10), | |
354 | phy->clklp2hs_time); | |
355 | dw_update_bits(base + CLK_DATA_TMR_CFG, 8, MASK(8), | |
356 | phy->data_to_clk_delay); | |
357 | dw_update_bits(base + CLK_DATA_TMR_CFG, 0, MASK(8), | |
358 | phy->clk_to_data_delay); | |
359 | } | |
360 | ||
361 | static void dsi_set_mipi_phy(void __iomem *base, | |
362 | struct mipi_phy_params *phy, | |
363 | u32 lanes) | |
364 | { | |
365 | u32 delay_count; | |
366 | u32 val; | |
367 | u32 i; | |
368 | ||
369 | /* phy timer setting */ | |
370 | dsi_set_phy_timer(base, phy, lanes); | |
371 | ||
372 | /* | |
373 | * Reset to clean up phy tst params. | |
374 | */ | |
375 | writel(0, base + PHY_RSTZ); | |
376 | writel(0, base + PHY_TST_CTRL0); | |
377 | writel(1, base + PHY_TST_CTRL0); | |
378 | writel(0, base + PHY_TST_CTRL0); | |
379 | ||
380 | /* | |
381 | * Clock lane timing control setting: TLPX, THS-PREPARE, | |
382 | * THS-ZERO, THS-TRAIL, TWAKEUP. | |
383 | */ | |
384 | dsi_phy_tst_set(base, CLK_TLPX, phy->clk_t_lpx); | |
385 | dsi_phy_tst_set(base, CLK_THS_PREPARE, phy->clk_t_hs_prepare); | |
386 | dsi_phy_tst_set(base, CLK_THS_ZERO, phy->clk_t_hs_zero); | |
387 | dsi_phy_tst_set(base, CLK_THS_TRAIL, phy->clk_t_hs_trial); | |
388 | dsi_phy_tst_set(base, CLK_TWAKEUP, phy->clk_t_wakeup); | |
389 | ||
390 | /* | |
391 | * Data lane timing control setting: TLPX, THS-PREPARE, | |
392 | * THS-ZERO, THS-TRAIL, TTA-GO, TTA-GET, TWAKEUP. | |
393 | */ | |
394 | for (i = 0; i < lanes; i++) { | |
395 | dsi_phy_tst_set(base, DATA_TLPX(i), phy->data_t_lpx); | |
396 | dsi_phy_tst_set(base, DATA_THS_PREPARE(i), | |
397 | phy->data_t_hs_prepare); | |
398 | dsi_phy_tst_set(base, DATA_THS_ZERO(i), phy->data_t_hs_zero); | |
399 | dsi_phy_tst_set(base, DATA_THS_TRAIL(i), phy->data_t_hs_trial); | |
400 | dsi_phy_tst_set(base, DATA_TTA_GO(i), phy->data_t_ta_go); | |
401 | dsi_phy_tst_set(base, DATA_TTA_GET(i), phy->data_t_ta_get); | |
402 | dsi_phy_tst_set(base, DATA_TWAKEUP(i), phy->data_t_wakeup); | |
403 | } | |
404 | ||
405 | /* | |
406 | * physical configuration: I, pll I, pll II, pll III, | |
407 | * pll IV, pll V. | |
408 | */ | |
409 | dsi_phy_tst_set(base, PHY_CFG_I, phy->hstx_ckg_sel); | |
410 | val = (phy->pll_fbd_div5f << 5) + (phy->pll_fbd_div1f << 4) + | |
411 | (phy->pll_fbd_2p << 1) + phy->pll_enbwt; | |
412 | dsi_phy_tst_set(base, PHY_CFG_PLL_I, val); | |
413 | dsi_phy_tst_set(base, PHY_CFG_PLL_II, phy->pll_fbd_p); | |
414 | dsi_phy_tst_set(base, PHY_CFG_PLL_III, phy->pll_fbd_s); | |
415 | val = (phy->pll_pre_div1p << 7) + phy->pll_pre_p; | |
416 | dsi_phy_tst_set(base, PHY_CFG_PLL_IV, val); | |
417 | val = (5 << 5) + (phy->pll_vco_750M << 4) + (phy->pll_lpf_rs << 2) + | |
418 | phy->pll_lpf_cs; | |
419 | dsi_phy_tst_set(base, PHY_CFG_PLL_V, val); | |
420 | ||
421 | writel(PHY_ENABLECLK, base + PHY_RSTZ); | |
422 | udelay(1); | |
423 | writel(PHY_ENABLECLK | PHY_UNSHUTDOWNZ, base + PHY_RSTZ); | |
424 | udelay(1); | |
425 | writel(PHY_ENABLECLK | PHY_UNRSTZ | PHY_UNSHUTDOWNZ, base + PHY_RSTZ); | |
426 | usleep_range(1000, 1500); | |
427 | ||
428 | /* | |
429 | * wait for phy's clock ready | |
430 | */ | |
431 | delay_count = 100; | |
165cccc8 | 432 | while (delay_count) { |
f819b0d4 XL |
433 | val = readl(base + PHY_STATUS); |
434 | if ((BIT(0) | BIT(2)) & val) | |
435 | break; | |
436 | ||
437 | udelay(1); | |
165cccc8 | 438 | delay_count--; |
f819b0d4 XL |
439 | } |
440 | ||
441 | if (!delay_count) | |
442 | DRM_INFO("phylock and phystopstateclklane is not ready.\n"); | |
443 | } | |
444 | ||
445 | static void dsi_set_mode_timing(void __iomem *base, | |
446 | u32 lane_byte_clk_kHz, | |
447 | struct drm_display_mode *mode, | |
448 | enum mipi_dsi_pixel_format format) | |
449 | { | |
450 | u32 hfp, hbp, hsw, vfp, vbp, vsw; | |
451 | u32 hline_time; | |
452 | u32 hsa_time; | |
453 | u32 hbp_time; | |
454 | u32 pixel_clk_kHz; | |
455 | int htot, vtot; | |
456 | u32 val; | |
457 | u64 tmp; | |
458 | ||
459 | val = dsi_get_dpi_color_coding(format); | |
460 | writel(val, base + DPI_COLOR_CODING); | |
461 | ||
462 | val = (mode->flags & DRM_MODE_FLAG_NHSYNC ? 1 : 0) << 2; | |
463 | val |= (mode->flags & DRM_MODE_FLAG_NVSYNC ? 1 : 0) << 1; | |
464 | writel(val, base + DPI_CFG_POL); | |
465 | ||
466 | /* | |
467 | * The DSI IP accepts vertical timing using lines as normal, | |
468 | * but horizontal timing is a mixture of pixel-clocks for the | |
469 | * active region and byte-lane clocks for the blanking-related | |
470 | * timings. hfp is specified as the total hline_time in byte- | |
471 | * lane clocks minus hsa, hbp and active. | |
472 | */ | |
473 | pixel_clk_kHz = mode->clock; | |
474 | htot = mode->htotal; | |
475 | vtot = mode->vtotal; | |
476 | hfp = mode->hsync_start - mode->hdisplay; | |
477 | hbp = mode->htotal - mode->hsync_end; | |
478 | hsw = mode->hsync_end - mode->hsync_start; | |
479 | vfp = mode->vsync_start - mode->vdisplay; | |
480 | vbp = mode->vtotal - mode->vsync_end; | |
481 | vsw = mode->vsync_end - mode->vsync_start; | |
482 | if (vsw > 15) { | |
483 | DRM_DEBUG_DRIVER("vsw exceeded 15\n"); | |
484 | vsw = 15; | |
485 | } | |
486 | ||
487 | hsa_time = (hsw * lane_byte_clk_kHz) / pixel_clk_kHz; | |
488 | hbp_time = (hbp * lane_byte_clk_kHz) / pixel_clk_kHz; | |
489 | tmp = (u64)htot * (u64)lane_byte_clk_kHz; | |
490 | hline_time = DIV_ROUND_UP(tmp, pixel_clk_kHz); | |
491 | ||
492 | /* all specified in byte-lane clocks */ | |
493 | writel(hsa_time, base + VID_HSA_TIME); | |
494 | writel(hbp_time, base + VID_HBP_TIME); | |
495 | writel(hline_time, base + VID_HLINE_TIME); | |
496 | ||
497 | writel(vsw, base + VID_VSA_LINES); | |
498 | writel(vbp, base + VID_VBP_LINES); | |
499 | writel(vfp, base + VID_VFP_LINES); | |
500 | writel(mode->vdisplay, base + VID_VACTIVE_LINES); | |
501 | writel(mode->hdisplay, base + VID_PKT_SIZE); | |
502 | ||
503 | DRM_DEBUG_DRIVER("htot=%d, hfp=%d, hbp=%d, hsw=%d\n", | |
504 | htot, hfp, hbp, hsw); | |
505 | DRM_DEBUG_DRIVER("vtol=%d, vfp=%d, vbp=%d, vsw=%d\n", | |
506 | vtot, vfp, vbp, vsw); | |
507 | DRM_DEBUG_DRIVER("hsa_time=%d, hbp_time=%d, hline_time=%d\n", | |
508 | hsa_time, hbp_time, hline_time); | |
509 | } | |
510 | ||
511 | static void dsi_set_video_mode(void __iomem *base, unsigned long flags) | |
512 | { | |
513 | u32 val; | |
514 | u32 mode_mask = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | | |
515 | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; | |
516 | u32 non_burst_sync_pulse = MIPI_DSI_MODE_VIDEO | | |
517 | MIPI_DSI_MODE_VIDEO_SYNC_PULSE; | |
518 | u32 non_burst_sync_event = MIPI_DSI_MODE_VIDEO; | |
519 | ||
520 | /* | |
521 | * choose video mode type | |
522 | */ | |
523 | if ((flags & mode_mask) == non_burst_sync_pulse) | |
524 | val = DSI_NON_BURST_SYNC_PULSES; | |
525 | else if ((flags & mode_mask) == non_burst_sync_event) | |
526 | val = DSI_NON_BURST_SYNC_EVENTS; | |
527 | else | |
528 | val = DSI_BURST_SYNC_PULSES_1; | |
529 | writel(val, base + VID_MODE_CFG); | |
530 | ||
531 | writel(PHY_TXREQUESTCLKHS, base + LPCLK_CTRL); | |
532 | writel(DSI_VIDEO_MODE, base + MODE_CFG); | |
533 | } | |
534 | ||
535 | static void dsi_mipi_init(struct dw_dsi *dsi) | |
536 | { | |
537 | struct dsi_hw_ctx *ctx = dsi->ctx; | |
538 | struct mipi_phy_params *phy = &dsi->phy; | |
539 | struct drm_display_mode *mode = &dsi->cur_mode; | |
540 | u32 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); | |
541 | void __iomem *base = ctx->base; | |
542 | u32 dphy_req_kHz; | |
543 | ||
544 | /* | |
545 | * count phy params | |
546 | */ | |
547 | dphy_req_kHz = mode->clock * bpp / dsi->lanes; | |
548 | dsi_get_phy_params(dphy_req_kHz, phy); | |
549 | ||
550 | /* reset Core */ | |
551 | writel(RESET, base + PWR_UP); | |
552 | ||
553 | /* set dsi phy params */ | |
554 | dsi_set_mipi_phy(base, phy, dsi->lanes); | |
555 | ||
556 | /* set dsi mode timing */ | |
557 | dsi_set_mode_timing(base, phy->lane_byte_clk_kHz, mode, dsi->format); | |
558 | ||
559 | /* set dsi video mode */ | |
560 | dsi_set_video_mode(base, dsi->mode_flags); | |
561 | ||
562 | /* dsi wake up */ | |
563 | writel(POWERUP, base + PWR_UP); | |
564 | ||
565 | DRM_DEBUG_DRIVER("lanes=%d, pixel_clk=%d kHz, bytes_freq=%d kHz\n", | |
566 | dsi->lanes, mode->clock, phy->lane_byte_clk_kHz); | |
567 | } | |
568 | ||
569 | static void dsi_encoder_disable(struct drm_encoder *encoder) | |
570 | { | |
571 | struct dw_dsi *dsi = encoder_to_dsi(encoder); | |
572 | struct dsi_hw_ctx *ctx = dsi->ctx; | |
573 | void __iomem *base = ctx->base; | |
574 | ||
575 | if (!dsi->enable) | |
576 | return; | |
577 | ||
578 | writel(0, base + PWR_UP); | |
579 | writel(0, base + LPCLK_CTRL); | |
580 | writel(0, base + PHY_RSTZ); | |
581 | clk_disable_unprepare(ctx->pclk); | |
582 | ||
583 | dsi->enable = false; | |
584 | } | |
585 | ||
586 | static void dsi_encoder_enable(struct drm_encoder *encoder) | |
587 | { | |
588 | struct dw_dsi *dsi = encoder_to_dsi(encoder); | |
589 | struct dsi_hw_ctx *ctx = dsi->ctx; | |
590 | int ret; | |
591 | ||
592 | if (dsi->enable) | |
593 | return; | |
594 | ||
595 | ret = clk_prepare_enable(ctx->pclk); | |
596 | if (ret) { | |
597 | DRM_ERROR("fail to enable pclk: %d\n", ret); | |
598 | return; | |
599 | } | |
600 | ||
601 | dsi_mipi_init(dsi); | |
602 | ||
603 | dsi->enable = true; | |
604 | } | |
605 | ||
606 | static void dsi_encoder_mode_set(struct drm_encoder *encoder, | |
607 | struct drm_display_mode *mode, | |
608 | struct drm_display_mode *adj_mode) | |
609 | { | |
610 | struct dw_dsi *dsi = encoder_to_dsi(encoder); | |
611 | ||
612 | drm_mode_copy(&dsi->cur_mode, adj_mode); | |
613 | } | |
614 | ||
615 | static int dsi_encoder_atomic_check(struct drm_encoder *encoder, | |
616 | struct drm_crtc_state *crtc_state, | |
617 | struct drm_connector_state *conn_state) | |
618 | { | |
619 | /* do nothing */ | |
620 | return 0; | |
621 | } | |
622 | ||
623 | static const struct drm_encoder_helper_funcs dw_encoder_helper_funcs = { | |
624 | .atomic_check = dsi_encoder_atomic_check, | |
625 | .mode_set = dsi_encoder_mode_set, | |
626 | .enable = dsi_encoder_enable, | |
627 | .disable = dsi_encoder_disable | |
628 | }; | |
629 | ||
630 | static const struct drm_encoder_funcs dw_encoder_funcs = { | |
631 | .destroy = drm_encoder_cleanup, | |
632 | }; | |
633 | ||
634 | static int dw_drm_encoder_init(struct device *dev, | |
635 | struct drm_device *drm_dev, | |
636 | struct drm_encoder *encoder) | |
637 | { | |
638 | int ret; | |
639 | u32 crtc_mask = drm_of_find_possible_crtcs(drm_dev, dev->of_node); | |
640 | ||
641 | if (!crtc_mask) { | |
642 | DRM_ERROR("failed to find crtc mask\n"); | |
643 | return -EINVAL; | |
644 | } | |
645 | ||
646 | encoder->possible_crtcs = crtc_mask; | |
647 | ret = drm_encoder_init(drm_dev, encoder, &dw_encoder_funcs, | |
648 | DRM_MODE_ENCODER_DSI, NULL); | |
649 | if (ret) { | |
650 | DRM_ERROR("failed to init dsi encoder\n"); | |
651 | return ret; | |
652 | } | |
653 | ||
654 | drm_encoder_helper_add(encoder, &dw_encoder_helper_funcs); | |
655 | ||
656 | return 0; | |
657 | } | |
658 | ||
834480d2 XL |
659 | static int dsi_host_attach(struct mipi_dsi_host *host, |
660 | struct mipi_dsi_device *mdsi) | |
661 | { | |
662 | struct dw_dsi *dsi = host_to_dsi(host); | |
663 | ||
664 | if (mdsi->lanes < 1 || mdsi->lanes > 4) { | |
665 | DRM_ERROR("dsi device params invalid\n"); | |
666 | return -EINVAL; | |
667 | } | |
668 | ||
669 | dsi->lanes = mdsi->lanes; | |
670 | dsi->format = mdsi->format; | |
671 | dsi->mode_flags = mdsi->mode_flags; | |
672 | ||
673 | return 0; | |
674 | } | |
675 | ||
676 | static int dsi_host_detach(struct mipi_dsi_host *host, | |
677 | struct mipi_dsi_device *mdsi) | |
678 | { | |
679 | /* do nothing */ | |
680 | return 0; | |
681 | } | |
682 | ||
683 | static const struct mipi_dsi_host_ops dsi_host_ops = { | |
684 | .attach = dsi_host_attach, | |
685 | .detach = dsi_host_detach, | |
686 | }; | |
687 | ||
688 | static int dsi_host_init(struct device *dev, struct dw_dsi *dsi) | |
689 | { | |
690 | struct mipi_dsi_host *host = &dsi->host; | |
691 | int ret; | |
692 | ||
693 | host->dev = dev; | |
694 | host->ops = &dsi_host_ops; | |
695 | ret = mipi_dsi_host_register(host); | |
696 | if (ret) { | |
697 | DRM_ERROR("failed to register dsi host\n"); | |
698 | return ret; | |
699 | } | |
700 | ||
701 | return 0; | |
702 | } | |
703 | ||
40ed27b8 XL |
704 | static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi) |
705 | { | |
706 | struct drm_encoder *encoder = &dsi->encoder; | |
707 | struct drm_bridge *bridge = dsi->bridge; | |
708 | int ret; | |
709 | ||
710 | /* associate the bridge to dsi encoder */ | |
3bb80f24 | 711 | ret = drm_bridge_attach(encoder, bridge, NULL); |
40ed27b8 XL |
712 | if (ret) { |
713 | DRM_ERROR("failed to attach external bridge\n"); | |
714 | return ret; | |
715 | } | |
716 | ||
717 | return 0; | |
718 | } | |
719 | ||
f819b0d4 XL |
720 | static int dsi_bind(struct device *dev, struct device *master, void *data) |
721 | { | |
722 | struct dsi_data *ddata = dev_get_drvdata(dev); | |
723 | struct dw_dsi *dsi = &ddata->dsi; | |
724 | struct drm_device *drm_dev = data; | |
725 | int ret; | |
726 | ||
727 | ret = dw_drm_encoder_init(dev, drm_dev, &dsi->encoder); | |
728 | if (ret) | |
729 | return ret; | |
730 | ||
834480d2 XL |
731 | ret = dsi_host_init(dev, dsi); |
732 | if (ret) | |
733 | return ret; | |
734 | ||
40ed27b8 XL |
735 | ret = dsi_bridge_init(drm_dev, dsi); |
736 | if (ret) | |
737 | return ret; | |
738 | ||
f819b0d4 XL |
739 | return 0; |
740 | } | |
741 | ||
742 | static void dsi_unbind(struct device *dev, struct device *master, void *data) | |
743 | { | |
744 | /* do nothing */ | |
745 | } | |
746 | ||
747 | static const struct component_ops dsi_ops = { | |
748 | .bind = dsi_bind, | |
749 | .unbind = dsi_unbind, | |
750 | }; | |
751 | ||
752 | static int dsi_parse_dt(struct platform_device *pdev, struct dw_dsi *dsi) | |
753 | { | |
754 | struct dsi_hw_ctx *ctx = dsi->ctx; | |
40ed27b8 | 755 | struct device_node *np = pdev->dev.of_node; |
f819b0d4 | 756 | struct resource *res; |
ebc94461 | 757 | int ret; |
f819b0d4 | 758 | |
40ed27b8 XL |
759 | /* |
760 | * Get the endpoint node. In our case, dsi has one output port1 | |
761 | * to which the external HDMI bridge is connected. | |
762 | */ | |
b2cc3c80 | 763 | ret = drm_of_find_panel_or_bridge(np, 1, 0, NULL, &dsi->bridge); |
ebc94461 RH |
764 | if (ret) |
765 | return ret; | |
40ed27b8 | 766 | |
f819b0d4 XL |
767 | ctx->pclk = devm_clk_get(&pdev->dev, "pclk"); |
768 | if (IS_ERR(ctx->pclk)) { | |
769 | DRM_ERROR("failed to get pclk clock\n"); | |
770 | return PTR_ERR(ctx->pclk); | |
771 | } | |
772 | ||
773 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
774 | ctx->base = devm_ioremap_resource(&pdev->dev, res); | |
775 | if (IS_ERR(ctx->base)) { | |
776 | DRM_ERROR("failed to remap dsi io region\n"); | |
777 | return PTR_ERR(ctx->base); | |
778 | } | |
779 | ||
780 | return 0; | |
781 | } | |
782 | ||
783 | static int dsi_probe(struct platform_device *pdev) | |
784 | { | |
785 | struct dsi_data *data; | |
786 | struct dw_dsi *dsi; | |
787 | struct dsi_hw_ctx *ctx; | |
788 | int ret; | |
789 | ||
790 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | |
791 | if (!data) { | |
792 | DRM_ERROR("failed to allocate dsi data.\n"); | |
793 | return -ENOMEM; | |
794 | } | |
795 | dsi = &data->dsi; | |
796 | ctx = &data->ctx; | |
797 | dsi->ctx = ctx; | |
798 | ||
799 | ret = dsi_parse_dt(pdev, dsi); | |
800 | if (ret) | |
801 | return ret; | |
802 | ||
803 | platform_set_drvdata(pdev, data); | |
804 | ||
805 | return component_add(&pdev->dev, &dsi_ops); | |
806 | } | |
807 | ||
808 | static int dsi_remove(struct platform_device *pdev) | |
809 | { | |
810 | component_del(&pdev->dev, &dsi_ops); | |
811 | ||
812 | return 0; | |
813 | } | |
814 | ||
815 | static const struct of_device_id dsi_of_match[] = { | |
816 | {.compatible = "hisilicon,hi6220-dsi"}, | |
817 | { } | |
818 | }; | |
819 | MODULE_DEVICE_TABLE(of, dsi_of_match); | |
820 | ||
821 | static struct platform_driver dsi_driver = { | |
822 | .probe = dsi_probe, | |
823 | .remove = dsi_remove, | |
824 | .driver = { | |
825 | .name = "dw-dsi", | |
826 | .of_match_table = dsi_of_match, | |
827 | }, | |
828 | }; | |
829 | ||
830 | module_platform_driver(dsi_driver); | |
831 | ||
832 | MODULE_AUTHOR("Xinliang Liu <xinliang.liu@linaro.org>"); | |
833 | MODULE_AUTHOR("Xinliang Liu <z.liuxinliang@hisilicon.com>"); | |
834 | MODULE_AUTHOR("Xinwei Kong <kong.kongxinwei@hisilicon.com>"); | |
835 | MODULE_DESCRIPTION("DesignWare MIPI DSI Host Controller v1.02 driver"); | |
836 | MODULE_LICENSE("GPL v2"); |