Commit | Line | Data |
---|---|---|
9e629c17 JQ |
1 | /* |
2 | * Copyright (c) 2014 MediaTek Inc. | |
3 | * Author: Jie Qiu <jie.qiu@mediatek.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | */ | |
14 | #include <drm/drmP.h> | |
15 | #include <drm/drm_crtc.h> | |
16 | #include <drm/drm_crtc_helper.h> | |
17 | #include <linux/kernel.h> | |
18 | #include <linux/component.h> | |
19 | #include <linux/platform_device.h> | |
20 | #include <linux/of.h> | |
21 | #include <linux/of_graph.h> | |
22 | #include <linux/interrupt.h> | |
23 | #include <linux/types.h> | |
24 | #include <linux/clk.h> | |
25 | ||
26 | #include "mtk_dpi_regs.h" | |
27 | #include "mtk_drm_ddp_comp.h" | |
28 | ||
29 | enum mtk_dpi_out_bit_num { | |
30 | MTK_DPI_OUT_BIT_NUM_8BITS, | |
31 | MTK_DPI_OUT_BIT_NUM_10BITS, | |
32 | MTK_DPI_OUT_BIT_NUM_12BITS, | |
33 | MTK_DPI_OUT_BIT_NUM_16BITS | |
34 | }; | |
35 | ||
36 | enum mtk_dpi_out_yc_map { | |
37 | MTK_DPI_OUT_YC_MAP_RGB, | |
38 | MTK_DPI_OUT_YC_MAP_CYCY, | |
39 | MTK_DPI_OUT_YC_MAP_YCYC, | |
40 | MTK_DPI_OUT_YC_MAP_CY, | |
41 | MTK_DPI_OUT_YC_MAP_YC | |
42 | }; | |
43 | ||
44 | enum mtk_dpi_out_channel_swap { | |
45 | MTK_DPI_OUT_CHANNEL_SWAP_RGB, | |
46 | MTK_DPI_OUT_CHANNEL_SWAP_GBR, | |
47 | MTK_DPI_OUT_CHANNEL_SWAP_BRG, | |
48 | MTK_DPI_OUT_CHANNEL_SWAP_RBG, | |
49 | MTK_DPI_OUT_CHANNEL_SWAP_GRB, | |
50 | MTK_DPI_OUT_CHANNEL_SWAP_BGR | |
51 | }; | |
52 | ||
53 | enum mtk_dpi_out_color_format { | |
54 | MTK_DPI_COLOR_FORMAT_RGB, | |
55 | MTK_DPI_COLOR_FORMAT_RGB_FULL, | |
56 | MTK_DPI_COLOR_FORMAT_YCBCR_444, | |
57 | MTK_DPI_COLOR_FORMAT_YCBCR_422, | |
58 | MTK_DPI_COLOR_FORMAT_XV_YCC, | |
59 | MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL, | |
60 | MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL | |
61 | }; | |
62 | ||
63 | struct mtk_dpi { | |
64 | struct mtk_ddp_comp ddp_comp; | |
65 | struct drm_encoder encoder; | |
66 | void __iomem *regs; | |
67 | struct device *dev; | |
68 | struct clk *engine_clk; | |
69 | struct clk *pixel_clk; | |
70 | struct clk *tvd_clk; | |
71 | int irq; | |
72 | struct drm_display_mode mode; | |
73 | enum mtk_dpi_out_color_format color_format; | |
74 | enum mtk_dpi_out_yc_map yc_map; | |
75 | enum mtk_dpi_out_bit_num bit_num; | |
76 | enum mtk_dpi_out_channel_swap channel_swap; | |
77 | bool power_sta; | |
78 | u8 power_ctl; | |
79 | }; | |
80 | ||
81 | static inline struct mtk_dpi *mtk_dpi_from_encoder(struct drm_encoder *e) | |
82 | { | |
83 | return container_of(e, struct mtk_dpi, encoder); | |
84 | } | |
85 | ||
86 | enum mtk_dpi_polarity { | |
87 | MTK_DPI_POLARITY_RISING, | |
88 | MTK_DPI_POLARITY_FALLING, | |
89 | }; | |
90 | ||
91 | enum mtk_dpi_power_ctl { | |
92 | DPI_POWER_START = BIT(0), | |
93 | DPI_POWER_ENABLE = BIT(1), | |
94 | }; | |
95 | ||
96 | struct mtk_dpi_polarities { | |
97 | enum mtk_dpi_polarity de_pol; | |
98 | enum mtk_dpi_polarity ck_pol; | |
99 | enum mtk_dpi_polarity hsync_pol; | |
100 | enum mtk_dpi_polarity vsync_pol; | |
101 | }; | |
102 | ||
103 | struct mtk_dpi_sync_param { | |
104 | u32 sync_width; | |
105 | u32 front_porch; | |
106 | u32 back_porch; | |
107 | bool shift_half_line; | |
108 | }; | |
109 | ||
110 | struct mtk_dpi_yc_limit { | |
111 | u16 y_top; | |
112 | u16 y_bottom; | |
113 | u16 c_top; | |
114 | u16 c_bottom; | |
115 | }; | |
116 | ||
117 | static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask) | |
118 | { | |
119 | u32 tmp = readl(dpi->regs + offset) & ~mask; | |
120 | ||
121 | tmp |= (val & mask); | |
122 | writel(tmp, dpi->regs + offset); | |
123 | } | |
124 | ||
125 | static void mtk_dpi_sw_reset(struct mtk_dpi *dpi, bool reset) | |
126 | { | |
127 | mtk_dpi_mask(dpi, DPI_RET, reset ? RST : 0, RST); | |
128 | } | |
129 | ||
130 | static void mtk_dpi_enable(struct mtk_dpi *dpi) | |
131 | { | |
132 | mtk_dpi_mask(dpi, DPI_EN, EN, EN); | |
133 | } | |
134 | ||
135 | static void mtk_dpi_disable(struct mtk_dpi *dpi) | |
136 | { | |
137 | mtk_dpi_mask(dpi, DPI_EN, 0, EN); | |
138 | } | |
139 | ||
140 | static void mtk_dpi_config_hsync(struct mtk_dpi *dpi, | |
141 | struct mtk_dpi_sync_param *sync) | |
142 | { | |
143 | mtk_dpi_mask(dpi, DPI_TGEN_HWIDTH, | |
144 | sync->sync_width << HPW, HPW_MASK); | |
145 | mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, | |
146 | sync->back_porch << HBP, HBP_MASK); | |
147 | mtk_dpi_mask(dpi, DPI_TGEN_HPORCH, sync->front_porch << HFP, | |
148 | HFP_MASK); | |
149 | } | |
150 | ||
151 | static void mtk_dpi_config_vsync(struct mtk_dpi *dpi, | |
152 | struct mtk_dpi_sync_param *sync, | |
153 | u32 width_addr, u32 porch_addr) | |
154 | { | |
155 | mtk_dpi_mask(dpi, width_addr, | |
156 | sync->sync_width << VSYNC_WIDTH_SHIFT, | |
157 | VSYNC_WIDTH_MASK); | |
158 | mtk_dpi_mask(dpi, width_addr, | |
159 | sync->shift_half_line << VSYNC_HALF_LINE_SHIFT, | |
160 | VSYNC_HALF_LINE_MASK); | |
161 | mtk_dpi_mask(dpi, porch_addr, | |
162 | sync->back_porch << VSYNC_BACK_PORCH_SHIFT, | |
163 | VSYNC_BACK_PORCH_MASK); | |
164 | mtk_dpi_mask(dpi, porch_addr, | |
165 | sync->front_porch << VSYNC_FRONT_PORCH_SHIFT, | |
166 | VSYNC_FRONT_PORCH_MASK); | |
167 | } | |
168 | ||
169 | static void mtk_dpi_config_vsync_lodd(struct mtk_dpi *dpi, | |
170 | struct mtk_dpi_sync_param *sync) | |
171 | { | |
172 | mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH, DPI_TGEN_VPORCH); | |
173 | } | |
174 | ||
175 | static void mtk_dpi_config_vsync_leven(struct mtk_dpi *dpi, | |
176 | struct mtk_dpi_sync_param *sync) | |
177 | { | |
178 | mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_LEVEN, | |
179 | DPI_TGEN_VPORCH_LEVEN); | |
180 | } | |
181 | ||
182 | static void mtk_dpi_config_vsync_rodd(struct mtk_dpi *dpi, | |
183 | struct mtk_dpi_sync_param *sync) | |
184 | { | |
185 | mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_RODD, | |
186 | DPI_TGEN_VPORCH_RODD); | |
187 | } | |
188 | ||
189 | static void mtk_dpi_config_vsync_reven(struct mtk_dpi *dpi, | |
190 | struct mtk_dpi_sync_param *sync) | |
191 | { | |
192 | mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_REVEN, | |
193 | DPI_TGEN_VPORCH_REVEN); | |
194 | } | |
195 | ||
196 | static void mtk_dpi_config_pol(struct mtk_dpi *dpi, | |
197 | struct mtk_dpi_polarities *dpi_pol) | |
198 | { | |
199 | unsigned int pol; | |
200 | ||
201 | pol = (dpi_pol->ck_pol == MTK_DPI_POLARITY_RISING ? 0 : CK_POL) | | |
202 | (dpi_pol->de_pol == MTK_DPI_POLARITY_RISING ? 0 : DE_POL) | | |
203 | (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HSYNC_POL) | | |
204 | (dpi_pol->vsync_pol == MTK_DPI_POLARITY_RISING ? 0 : VSYNC_POL); | |
205 | mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, pol, | |
206 | CK_POL | DE_POL | HSYNC_POL | VSYNC_POL); | |
207 | } | |
208 | ||
209 | static void mtk_dpi_config_3d(struct mtk_dpi *dpi, bool en_3d) | |
210 | { | |
211 | mtk_dpi_mask(dpi, DPI_CON, en_3d ? TDFP_EN : 0, TDFP_EN); | |
212 | } | |
213 | ||
214 | static void mtk_dpi_config_interface(struct mtk_dpi *dpi, bool inter) | |
215 | { | |
216 | mtk_dpi_mask(dpi, DPI_CON, inter ? INTL_EN : 0, INTL_EN); | |
217 | } | |
218 | ||
219 | static void mtk_dpi_config_fb_size(struct mtk_dpi *dpi, u32 width, u32 height) | |
220 | { | |
221 | mtk_dpi_mask(dpi, DPI_SIZE, width << HSIZE, HSIZE_MASK); | |
222 | mtk_dpi_mask(dpi, DPI_SIZE, height << VSIZE, VSIZE_MASK); | |
223 | } | |
224 | ||
225 | static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi, | |
226 | struct mtk_dpi_yc_limit *limit) | |
227 | { | |
228 | mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_bottom << Y_LIMINT_BOT, | |
229 | Y_LIMINT_BOT_MASK); | |
230 | mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_top << Y_LIMINT_TOP, | |
231 | Y_LIMINT_TOP_MASK); | |
232 | mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_bottom << C_LIMIT_BOT, | |
233 | C_LIMIT_BOT_MASK); | |
234 | mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_top << C_LIMIT_TOP, | |
235 | C_LIMIT_TOP_MASK); | |
236 | } | |
237 | ||
238 | static void mtk_dpi_config_bit_num(struct mtk_dpi *dpi, | |
239 | enum mtk_dpi_out_bit_num num) | |
240 | { | |
241 | u32 val; | |
242 | ||
243 | switch (num) { | |
244 | case MTK_DPI_OUT_BIT_NUM_8BITS: | |
245 | val = OUT_BIT_8; | |
246 | break; | |
247 | case MTK_DPI_OUT_BIT_NUM_10BITS: | |
248 | val = OUT_BIT_10; | |
249 | break; | |
250 | case MTK_DPI_OUT_BIT_NUM_12BITS: | |
251 | val = OUT_BIT_12; | |
252 | break; | |
253 | case MTK_DPI_OUT_BIT_NUM_16BITS: | |
254 | val = OUT_BIT_16; | |
255 | break; | |
256 | default: | |
257 | val = OUT_BIT_8; | |
258 | break; | |
259 | } | |
260 | mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << OUT_BIT, | |
261 | OUT_BIT_MASK); | |
262 | } | |
263 | ||
264 | static void mtk_dpi_config_yc_map(struct mtk_dpi *dpi, | |
265 | enum mtk_dpi_out_yc_map map) | |
266 | { | |
267 | u32 val; | |
268 | ||
269 | switch (map) { | |
270 | case MTK_DPI_OUT_YC_MAP_RGB: | |
271 | val = YC_MAP_RGB; | |
272 | break; | |
273 | case MTK_DPI_OUT_YC_MAP_CYCY: | |
274 | val = YC_MAP_CYCY; | |
275 | break; | |
276 | case MTK_DPI_OUT_YC_MAP_YCYC: | |
277 | val = YC_MAP_YCYC; | |
278 | break; | |
279 | case MTK_DPI_OUT_YC_MAP_CY: | |
280 | val = YC_MAP_CY; | |
281 | break; | |
282 | case MTK_DPI_OUT_YC_MAP_YC: | |
283 | val = YC_MAP_YC; | |
284 | break; | |
285 | default: | |
286 | val = YC_MAP_RGB; | |
287 | break; | |
288 | } | |
289 | ||
290 | mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << YC_MAP, YC_MAP_MASK); | |
291 | } | |
292 | ||
293 | static void mtk_dpi_config_channel_swap(struct mtk_dpi *dpi, | |
294 | enum mtk_dpi_out_channel_swap swap) | |
295 | { | |
296 | u32 val; | |
297 | ||
298 | switch (swap) { | |
299 | case MTK_DPI_OUT_CHANNEL_SWAP_RGB: | |
300 | val = SWAP_RGB; | |
301 | break; | |
302 | case MTK_DPI_OUT_CHANNEL_SWAP_GBR: | |
303 | val = SWAP_GBR; | |
304 | break; | |
305 | case MTK_DPI_OUT_CHANNEL_SWAP_BRG: | |
306 | val = SWAP_BRG; | |
307 | break; | |
308 | case MTK_DPI_OUT_CHANNEL_SWAP_RBG: | |
309 | val = SWAP_RBG; | |
310 | break; | |
311 | case MTK_DPI_OUT_CHANNEL_SWAP_GRB: | |
312 | val = SWAP_GRB; | |
313 | break; | |
314 | case MTK_DPI_OUT_CHANNEL_SWAP_BGR: | |
315 | val = SWAP_BGR; | |
316 | break; | |
317 | default: | |
318 | val = SWAP_RGB; | |
319 | break; | |
320 | } | |
321 | ||
322 | mtk_dpi_mask(dpi, DPI_OUTPUT_SETTING, val << CH_SWAP, CH_SWAP_MASK); | |
323 | } | |
324 | ||
325 | static void mtk_dpi_config_yuv422_enable(struct mtk_dpi *dpi, bool enable) | |
326 | { | |
327 | mtk_dpi_mask(dpi, DPI_CON, enable ? YUV422_EN : 0, YUV422_EN); | |
328 | } | |
329 | ||
330 | static void mtk_dpi_config_csc_enable(struct mtk_dpi *dpi, bool enable) | |
331 | { | |
332 | mtk_dpi_mask(dpi, DPI_CON, enable ? CSC_ENABLE : 0, CSC_ENABLE); | |
333 | } | |
334 | ||
335 | static void mtk_dpi_config_swap_input(struct mtk_dpi *dpi, bool enable) | |
336 | { | |
337 | mtk_dpi_mask(dpi, DPI_CON, enable ? IN_RB_SWAP : 0, IN_RB_SWAP); | |
338 | } | |
339 | ||
340 | static void mtk_dpi_config_2n_h_fre(struct mtk_dpi *dpi) | |
341 | { | |
342 | mtk_dpi_mask(dpi, DPI_H_FRE_CON, H_FRE_2N, H_FRE_2N); | |
343 | } | |
344 | ||
345 | static void mtk_dpi_config_color_format(struct mtk_dpi *dpi, | |
346 | enum mtk_dpi_out_color_format format) | |
347 | { | |
348 | if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_444) || | |
349 | (format == MTK_DPI_COLOR_FORMAT_YCBCR_444_FULL)) { | |
350 | mtk_dpi_config_yuv422_enable(dpi, false); | |
351 | mtk_dpi_config_csc_enable(dpi, true); | |
352 | mtk_dpi_config_swap_input(dpi, false); | |
353 | mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_BGR); | |
354 | } else if ((format == MTK_DPI_COLOR_FORMAT_YCBCR_422) || | |
355 | (format == MTK_DPI_COLOR_FORMAT_YCBCR_422_FULL)) { | |
356 | mtk_dpi_config_yuv422_enable(dpi, true); | |
357 | mtk_dpi_config_csc_enable(dpi, true); | |
358 | mtk_dpi_config_swap_input(dpi, true); | |
359 | mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB); | |
360 | } else { | |
361 | mtk_dpi_config_yuv422_enable(dpi, false); | |
362 | mtk_dpi_config_csc_enable(dpi, false); | |
363 | mtk_dpi_config_swap_input(dpi, false); | |
364 | mtk_dpi_config_channel_swap(dpi, MTK_DPI_OUT_CHANNEL_SWAP_RGB); | |
365 | } | |
366 | } | |
367 | ||
368 | static void mtk_dpi_power_off(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) | |
369 | { | |
370 | dpi->power_ctl &= ~pctl; | |
371 | ||
372 | if ((dpi->power_ctl & DPI_POWER_START) || | |
373 | (dpi->power_ctl & DPI_POWER_ENABLE)) | |
374 | return; | |
375 | ||
376 | if (!dpi->power_sta) | |
377 | return; | |
378 | ||
379 | mtk_dpi_disable(dpi); | |
380 | clk_disable_unprepare(dpi->pixel_clk); | |
381 | clk_disable_unprepare(dpi->engine_clk); | |
382 | dpi->power_sta = false; | |
383 | } | |
384 | ||
385 | static int mtk_dpi_power_on(struct mtk_dpi *dpi, enum mtk_dpi_power_ctl pctl) | |
386 | { | |
387 | int ret; | |
388 | ||
389 | dpi->power_ctl |= pctl; | |
390 | ||
391 | if (!(dpi->power_ctl & DPI_POWER_START) && | |
392 | !(dpi->power_ctl & DPI_POWER_ENABLE)) | |
393 | return 0; | |
394 | ||
395 | if (dpi->power_sta) | |
396 | return 0; | |
397 | ||
398 | ret = clk_prepare_enable(dpi->engine_clk); | |
399 | if (ret) { | |
400 | dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret); | |
401 | goto err_eng; | |
402 | } | |
403 | ||
404 | ret = clk_prepare_enable(dpi->pixel_clk); | |
405 | if (ret) { | |
406 | dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret); | |
407 | goto err_pixel; | |
408 | } | |
409 | ||
410 | mtk_dpi_enable(dpi); | |
411 | dpi->power_sta = true; | |
412 | return 0; | |
413 | ||
414 | err_pixel: | |
415 | clk_disable_unprepare(dpi->engine_clk); | |
416 | err_eng: | |
417 | dpi->power_ctl &= ~pctl; | |
418 | return ret; | |
419 | } | |
420 | ||
421 | static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, | |
422 | struct drm_display_mode *mode) | |
423 | { | |
424 | struct mtk_dpi_yc_limit limit; | |
425 | struct mtk_dpi_polarities dpi_pol; | |
426 | struct mtk_dpi_sync_param hsync; | |
427 | struct mtk_dpi_sync_param vsync_lodd = { 0 }; | |
428 | struct mtk_dpi_sync_param vsync_leven = { 0 }; | |
429 | struct mtk_dpi_sync_param vsync_rodd = { 0 }; | |
430 | struct mtk_dpi_sync_param vsync_reven = { 0 }; | |
431 | unsigned long pix_rate; | |
432 | unsigned long pll_rate; | |
433 | unsigned int factor; | |
434 | ||
9e629c17 JQ |
435 | pix_rate = 1000UL * mode->clock; |
436 | if (mode->clock <= 74000) | |
437 | factor = 8 * 3; | |
438 | else | |
439 | factor = 4 * 3; | |
440 | pll_rate = pix_rate * factor; | |
441 | ||
442 | dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n", | |
443 | pll_rate, pix_rate); | |
444 | ||
445 | clk_set_rate(dpi->tvd_clk, pll_rate); | |
446 | pll_rate = clk_get_rate(dpi->tvd_clk); | |
447 | ||
448 | pix_rate = pll_rate / factor; | |
449 | clk_set_rate(dpi->pixel_clk, pix_rate); | |
450 | pix_rate = clk_get_rate(dpi->pixel_clk); | |
451 | ||
452 | dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n", | |
453 | pll_rate, pix_rate); | |
454 | ||
455 | limit.c_bottom = 0x0010; | |
456 | limit.c_top = 0x0FE0; | |
457 | limit.y_bottom = 0x0010; | |
458 | limit.y_top = 0x0FE0; | |
459 | ||
460 | dpi_pol.ck_pol = MTK_DPI_POLARITY_FALLING; | |
461 | dpi_pol.de_pol = MTK_DPI_POLARITY_RISING; | |
462 | dpi_pol.hsync_pol = mode->flags & DRM_MODE_FLAG_PHSYNC ? | |
463 | MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING; | |
464 | dpi_pol.vsync_pol = mode->flags & DRM_MODE_FLAG_PVSYNC ? | |
465 | MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING; | |
466 | ||
467 | hsync.sync_width = mode->hsync_end - mode->hsync_start; | |
468 | hsync.back_porch = mode->htotal - mode->hsync_end; | |
469 | hsync.front_porch = mode->hsync_start - mode->hdisplay; | |
470 | hsync.shift_half_line = false; | |
471 | ||
472 | vsync_lodd.sync_width = mode->vsync_end - mode->vsync_start; | |
473 | vsync_lodd.back_porch = mode->vtotal - mode->vsync_end; | |
474 | vsync_lodd.front_porch = mode->vsync_start - mode->vdisplay; | |
475 | vsync_lodd.shift_half_line = false; | |
476 | ||
477 | if (mode->flags & DRM_MODE_FLAG_INTERLACE && | |
478 | mode->flags & DRM_MODE_FLAG_3D_MASK) { | |
479 | vsync_leven = vsync_lodd; | |
480 | vsync_rodd = vsync_lodd; | |
481 | vsync_reven = vsync_lodd; | |
482 | vsync_leven.shift_half_line = true; | |
483 | vsync_reven.shift_half_line = true; | |
484 | } else if (mode->flags & DRM_MODE_FLAG_INTERLACE && | |
485 | !(mode->flags & DRM_MODE_FLAG_3D_MASK)) { | |
486 | vsync_leven = vsync_lodd; | |
487 | vsync_leven.shift_half_line = true; | |
488 | } else if (!(mode->flags & DRM_MODE_FLAG_INTERLACE) && | |
489 | mode->flags & DRM_MODE_FLAG_3D_MASK) { | |
490 | vsync_rodd = vsync_lodd; | |
491 | } | |
492 | mtk_dpi_sw_reset(dpi, true); | |
493 | mtk_dpi_config_pol(dpi, &dpi_pol); | |
494 | ||
495 | mtk_dpi_config_hsync(dpi, &hsync); | |
496 | mtk_dpi_config_vsync_lodd(dpi, &vsync_lodd); | |
497 | mtk_dpi_config_vsync_rodd(dpi, &vsync_rodd); | |
498 | mtk_dpi_config_vsync_leven(dpi, &vsync_leven); | |
499 | mtk_dpi_config_vsync_reven(dpi, &vsync_reven); | |
500 | ||
501 | mtk_dpi_config_3d(dpi, !!(mode->flags & DRM_MODE_FLAG_3D_MASK)); | |
502 | mtk_dpi_config_interface(dpi, !!(mode->flags & | |
503 | DRM_MODE_FLAG_INTERLACE)); | |
504 | if (mode->flags & DRM_MODE_FLAG_INTERLACE) | |
505 | mtk_dpi_config_fb_size(dpi, mode->hdisplay, mode->vdisplay / 2); | |
506 | else | |
507 | mtk_dpi_config_fb_size(dpi, mode->hdisplay, mode->vdisplay); | |
508 | ||
509 | mtk_dpi_config_channel_limit(dpi, &limit); | |
510 | mtk_dpi_config_bit_num(dpi, dpi->bit_num); | |
511 | mtk_dpi_config_channel_swap(dpi, dpi->channel_swap); | |
512 | mtk_dpi_config_yc_map(dpi, dpi->yc_map); | |
513 | mtk_dpi_config_color_format(dpi, dpi->color_format); | |
514 | mtk_dpi_config_2n_h_fre(dpi); | |
515 | mtk_dpi_sw_reset(dpi, false); | |
516 | ||
517 | return 0; | |
518 | } | |
519 | ||
520 | static void mtk_dpi_encoder_destroy(struct drm_encoder *encoder) | |
521 | { | |
522 | drm_encoder_cleanup(encoder); | |
523 | } | |
524 | ||
525 | static const struct drm_encoder_funcs mtk_dpi_encoder_funcs = { | |
526 | .destroy = mtk_dpi_encoder_destroy, | |
527 | }; | |
528 | ||
529 | static bool mtk_dpi_encoder_mode_fixup(struct drm_encoder *encoder, | |
530 | const struct drm_display_mode *mode, | |
531 | struct drm_display_mode *adjusted_mode) | |
532 | { | |
533 | return true; | |
534 | } | |
535 | ||
536 | static void mtk_dpi_encoder_mode_set(struct drm_encoder *encoder, | |
537 | struct drm_display_mode *mode, | |
538 | struct drm_display_mode *adjusted_mode) | |
539 | { | |
540 | struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); | |
541 | ||
542 | drm_mode_copy(&dpi->mode, adjusted_mode); | |
543 | } | |
544 | ||
545 | static void mtk_dpi_encoder_disable(struct drm_encoder *encoder) | |
546 | { | |
547 | struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); | |
548 | ||
549 | mtk_dpi_power_off(dpi, DPI_POWER_ENABLE); | |
550 | } | |
551 | ||
552 | static void mtk_dpi_encoder_enable(struct drm_encoder *encoder) | |
553 | { | |
554 | struct mtk_dpi *dpi = mtk_dpi_from_encoder(encoder); | |
555 | ||
556 | mtk_dpi_power_on(dpi, DPI_POWER_ENABLE); | |
557 | mtk_dpi_set_display_mode(dpi, &dpi->mode); | |
558 | } | |
559 | ||
560 | static int mtk_dpi_atomic_check(struct drm_encoder *encoder, | |
561 | struct drm_crtc_state *crtc_state, | |
562 | struct drm_connector_state *conn_state) | |
563 | { | |
564 | return 0; | |
565 | } | |
566 | ||
567 | static const struct drm_encoder_helper_funcs mtk_dpi_encoder_helper_funcs = { | |
568 | .mode_fixup = mtk_dpi_encoder_mode_fixup, | |
569 | .mode_set = mtk_dpi_encoder_mode_set, | |
570 | .disable = mtk_dpi_encoder_disable, | |
571 | .enable = mtk_dpi_encoder_enable, | |
572 | .atomic_check = mtk_dpi_atomic_check, | |
573 | }; | |
574 | ||
575 | static void mtk_dpi_start(struct mtk_ddp_comp *comp) | |
576 | { | |
577 | struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); | |
578 | ||
579 | mtk_dpi_power_on(dpi, DPI_POWER_START); | |
580 | } | |
581 | ||
582 | static void mtk_dpi_stop(struct mtk_ddp_comp *comp) | |
583 | { | |
584 | struct mtk_dpi *dpi = container_of(comp, struct mtk_dpi, ddp_comp); | |
585 | ||
586 | mtk_dpi_power_off(dpi, DPI_POWER_START); | |
587 | } | |
588 | ||
589 | static const struct mtk_ddp_comp_funcs mtk_dpi_funcs = { | |
590 | .start = mtk_dpi_start, | |
591 | .stop = mtk_dpi_stop, | |
592 | }; | |
593 | ||
594 | static int mtk_dpi_bind(struct device *dev, struct device *master, void *data) | |
595 | { | |
596 | struct mtk_dpi *dpi = dev_get_drvdata(dev); | |
597 | struct drm_device *drm_dev = data; | |
598 | int ret; | |
599 | ||
600 | ret = mtk_ddp_comp_register(drm_dev, &dpi->ddp_comp); | |
601 | if (ret < 0) { | |
602 | dev_err(dev, "Failed to register component %s: %d\n", | |
603 | dev->of_node->full_name, ret); | |
604 | return ret; | |
605 | } | |
606 | ||
607 | ret = drm_encoder_init(drm_dev, &dpi->encoder, &mtk_dpi_encoder_funcs, | |
608 | DRM_MODE_ENCODER_TMDS, NULL); | |
609 | if (ret) { | |
610 | dev_err(dev, "Failed to initialize decoder: %d\n", ret); | |
611 | goto err_unregister; | |
612 | } | |
613 | drm_encoder_helper_add(&dpi->encoder, &mtk_dpi_encoder_helper_funcs); | |
614 | ||
615 | /* Currently DPI0 is fixed to be driven by OVL1 */ | |
616 | dpi->encoder.possible_crtcs = BIT(1); | |
617 | ||
618 | dpi->encoder.bridge->encoder = &dpi->encoder; | |
619 | ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge); | |
620 | if (ret) { | |
621 | dev_err(dev, "Failed to attach bridge: %d\n", ret); | |
622 | goto err_cleanup; | |
623 | } | |
624 | ||
625 | dpi->bit_num = MTK_DPI_OUT_BIT_NUM_8BITS; | |
626 | dpi->channel_swap = MTK_DPI_OUT_CHANNEL_SWAP_RGB; | |
627 | dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB; | |
628 | dpi->color_format = MTK_DPI_COLOR_FORMAT_RGB; | |
629 | ||
630 | return 0; | |
631 | ||
632 | err_cleanup: | |
633 | drm_encoder_cleanup(&dpi->encoder); | |
634 | err_unregister: | |
635 | mtk_ddp_comp_unregister(drm_dev, &dpi->ddp_comp); | |
636 | return ret; | |
637 | } | |
638 | ||
639 | static void mtk_dpi_unbind(struct device *dev, struct device *master, | |
640 | void *data) | |
641 | { | |
642 | struct mtk_dpi *dpi = dev_get_drvdata(dev); | |
643 | struct drm_device *drm_dev = data; | |
644 | ||
645 | drm_encoder_cleanup(&dpi->encoder); | |
646 | mtk_ddp_comp_unregister(drm_dev, &dpi->ddp_comp); | |
647 | } | |
648 | ||
649 | static const struct component_ops mtk_dpi_component_ops = { | |
650 | .bind = mtk_dpi_bind, | |
651 | .unbind = mtk_dpi_unbind, | |
652 | }; | |
653 | ||
654 | static int mtk_dpi_probe(struct platform_device *pdev) | |
655 | { | |
656 | struct device *dev = &pdev->dev; | |
657 | struct mtk_dpi *dpi; | |
658 | struct resource *mem; | |
659 | struct device_node *ep, *bridge_node = NULL; | |
660 | int comp_id; | |
661 | int ret; | |
662 | ||
663 | dpi = devm_kzalloc(dev, sizeof(*dpi), GFP_KERNEL); | |
664 | if (!dpi) | |
665 | return -ENOMEM; | |
666 | ||
667 | dpi->dev = dev; | |
668 | ||
669 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
670 | dpi->regs = devm_ioremap_resource(dev, mem); | |
671 | if (IS_ERR(dpi->regs)) { | |
672 | ret = PTR_ERR(dpi->regs); | |
673 | dev_err(dev, "Failed to ioremap mem resource: %d\n", ret); | |
674 | return ret; | |
675 | } | |
676 | ||
677 | dpi->engine_clk = devm_clk_get(dev, "engine"); | |
678 | if (IS_ERR(dpi->engine_clk)) { | |
679 | ret = PTR_ERR(dpi->engine_clk); | |
680 | dev_err(dev, "Failed to get engine clock: %d\n", ret); | |
681 | return ret; | |
682 | } | |
683 | ||
684 | dpi->pixel_clk = devm_clk_get(dev, "pixel"); | |
685 | if (IS_ERR(dpi->pixel_clk)) { | |
686 | ret = PTR_ERR(dpi->pixel_clk); | |
687 | dev_err(dev, "Failed to get pixel clock: %d\n", ret); | |
688 | return ret; | |
689 | } | |
690 | ||
691 | dpi->tvd_clk = devm_clk_get(dev, "pll"); | |
692 | if (IS_ERR(dpi->tvd_clk)) { | |
693 | ret = PTR_ERR(dpi->tvd_clk); | |
694 | dev_err(dev, "Failed to get tvdpll clock: %d\n", ret); | |
695 | return ret; | |
696 | } | |
697 | ||
698 | dpi->irq = platform_get_irq(pdev, 0); | |
699 | if (dpi->irq <= 0) { | |
700 | dev_err(dev, "Failed to get irq: %d\n", dpi->irq); | |
701 | return -EINVAL; | |
702 | } | |
703 | ||
704 | ep = of_graph_get_next_endpoint(dev->of_node, NULL); | |
705 | if (ep) { | |
706 | bridge_node = of_graph_get_remote_port_parent(ep); | |
707 | of_node_put(ep); | |
708 | } | |
709 | if (!bridge_node) { | |
710 | dev_err(dev, "Failed to find bridge node\n"); | |
711 | return -ENODEV; | |
712 | } | |
713 | ||
714 | dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name); | |
715 | ||
716 | dpi->encoder.bridge = of_drm_find_bridge(bridge_node); | |
717 | of_node_put(bridge_node); | |
718 | if (!dpi->encoder.bridge) | |
719 | return -EPROBE_DEFER; | |
720 | ||
721 | comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI); | |
722 | if (comp_id < 0) { | |
723 | dev_err(dev, "Failed to identify by alias: %d\n", comp_id); | |
724 | return comp_id; | |
725 | } | |
726 | ||
727 | ret = mtk_ddp_comp_init(dev, dev->of_node, &dpi->ddp_comp, comp_id, | |
728 | &mtk_dpi_funcs); | |
729 | if (ret) { | |
730 | dev_err(dev, "Failed to initialize component: %d\n", ret); | |
731 | return ret; | |
732 | } | |
733 | ||
734 | platform_set_drvdata(pdev, dpi); | |
735 | ||
736 | ret = component_add(dev, &mtk_dpi_component_ops); | |
737 | if (ret) { | |
738 | dev_err(dev, "Failed to add component: %d\n", ret); | |
739 | return ret; | |
740 | } | |
741 | ||
742 | return 0; | |
743 | } | |
744 | ||
745 | static int mtk_dpi_remove(struct platform_device *pdev) | |
746 | { | |
747 | component_del(&pdev->dev, &mtk_dpi_component_ops); | |
748 | ||
749 | return 0; | |
750 | } | |
751 | ||
752 | static const struct of_device_id mtk_dpi_of_ids[] = { | |
753 | { .compatible = "mediatek,mt8173-dpi", }, | |
754 | {} | |
755 | }; | |
756 | ||
757 | struct platform_driver mtk_dpi_driver = { | |
758 | .probe = mtk_dpi_probe, | |
759 | .remove = mtk_dpi_remove, | |
760 | .driver = { | |
761 | .name = "mediatek-dpi", | |
762 | .of_match_table = mtk_dpi_of_ids, | |
763 | }, | |
764 | }; |