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