]>
Commit | Line | Data |
---|---|---|
e1e96ba6 SB |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (C) 2016 Nexell Co., Ltd. | |
4 | * | |
5 | * Author: junghyun, kim <jhkim@nexell.co.kr> | |
6 | */ | |
7 | ||
8 | #include <config.h> | |
d678a59d | 9 | #include <common.h> |
e1e96ba6 SB |
10 | #include <errno.h> |
11 | ||
12 | #include <asm/arch/nexell.h> | |
13 | #include <asm/arch/tieoff.h> | |
14 | #include <asm/arch/reset.h> | |
15 | #include <asm/arch/display.h> | |
16 | ||
17 | #include "soc/s5pxx18_soc_mipi.h" | |
18 | #include "soc/s5pxx18_soc_disptop.h" | |
19 | #include "soc/s5pxx18_soc_disptop_clk.h" | |
20 | ||
21 | #define PLLPMS_1000MHZ 0x33E8 | |
22 | #define BANDCTL_1000MHZ 0xF | |
23 | #define PLLPMS_960MHZ 0x2280 | |
24 | #define BANDCTL_960MHZ 0xF | |
25 | #define PLLPMS_900MHZ 0x2258 | |
26 | #define BANDCTL_900MHZ 0xE | |
27 | #define PLLPMS_840MHZ 0x2230 | |
28 | #define BANDCTL_840MHZ 0xD | |
29 | #define PLLPMS_750MHZ 0x43E8 | |
30 | #define BANDCTL_750MHZ 0xC | |
31 | #define PLLPMS_660MHZ 0x21B8 | |
32 | #define BANDCTL_660MHZ 0xB | |
33 | #define PLLPMS_600MHZ 0x2190 | |
34 | #define BANDCTL_600MHZ 0xA | |
35 | #define PLLPMS_540MHZ 0x2168 | |
36 | #define BANDCTL_540MHZ 0x9 | |
37 | #define PLLPMS_512MHZ 0x03200 | |
38 | #define BANDCTL_512MHZ 0x9 | |
39 | #define PLLPMS_480MHZ 0x2281 | |
40 | #define BANDCTL_480MHZ 0x8 | |
41 | #define PLLPMS_420MHZ 0x2231 | |
42 | #define BANDCTL_420MHZ 0x7 | |
43 | #define PLLPMS_402MHZ 0x2219 | |
44 | #define BANDCTL_402MHZ 0x7 | |
45 | #define PLLPMS_330MHZ 0x21B9 | |
46 | #define BANDCTL_330MHZ 0x6 | |
47 | #define PLLPMS_300MHZ 0x2191 | |
48 | #define BANDCTL_300MHZ 0x5 | |
49 | #define PLLPMS_210MHZ 0x2232 | |
50 | #define BANDCTL_210MHZ 0x4 | |
51 | #define PLLPMS_180MHZ 0x21E2 | |
52 | #define BANDCTL_180MHZ 0x3 | |
53 | #define PLLPMS_150MHZ 0x2192 | |
54 | #define BANDCTL_150MHZ 0x2 | |
55 | #define PLLPMS_100MHZ 0x3323 | |
56 | #define BANDCTL_100MHZ 0x1 | |
57 | #define PLLPMS_80MHZ 0x3283 | |
58 | #define BANDCTL_80MHZ 0x0 | |
59 | ||
60 | #define MIPI_INDEX 0 | |
61 | #define MIPI_EXC_PRE_VALUE 1 | |
62 | #define MIPI_DSI_IRQ_MASK 29 | |
63 | ||
64 | #define __io_address(a) (void *)(uintptr_t)(a) | |
65 | ||
66 | struct mipi_xfer_msg { | |
67 | u8 id, data[2]; | |
68 | u16 flags; | |
69 | const u8 *tx_buf; | |
70 | u16 tx_len; | |
71 | u8 *rx_buf; | |
72 | u16 rx_len; | |
73 | }; | |
74 | ||
75 | static void mipi_reset(void) | |
76 | { | |
77 | /* tieoff */ | |
78 | nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAA, 3); | |
79 | nx_tieoff_set(NX_TIEOFF_MIPI0_NX_DPSRAM_1R1W_EMAB, 3); | |
80 | ||
81 | /* reset */ | |
82 | nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_ASSERT); | |
83 | nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_ASSERT); | |
84 | nx_rstcon_setrst(RESET_ID_MIPI_CSI, RSTCON_ASSERT); | |
85 | nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_ASSERT); | |
86 | nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_ASSERT); | |
87 | ||
88 | nx_rstcon_setrst(RESET_ID_MIPI, RSTCON_NEGATE); | |
89 | nx_rstcon_setrst(RESET_ID_MIPI_DSI, RSTCON_NEGATE); | |
90 | nx_rstcon_setrst(RESET_ID_MIPI_PHY_S, RSTCON_NEGATE); | |
91 | nx_rstcon_setrst(RESET_ID_MIPI_PHY_M, RSTCON_NEGATE); | |
92 | } | |
93 | ||
94 | static void mipi_init(void) | |
95 | { | |
96 | int clkid = DP_CLOCK_MIPI; | |
97 | void *base; | |
98 | ||
99 | /* | |
100 | * neet to reset before open | |
101 | */ | |
102 | mipi_reset(); | |
103 | ||
104 | base = __io_address(nx_disp_top_clkgen_get_physical_address(clkid)); | |
105 | nx_disp_top_clkgen_set_base_address(clkid, base); | |
106 | nx_disp_top_clkgen_set_clock_pclk_mode(clkid, nx_pclkmode_always); | |
107 | ||
108 | base = __io_address(nx_mipi_get_physical_address(0)); | |
109 | nx_mipi_set_base_address(0, base); | |
110 | } | |
111 | ||
112 | static int mipi_get_phy_pll(int bitrate, unsigned int *pllpms, | |
113 | unsigned int *bandctl) | |
114 | { | |
115 | unsigned int pms, ctl; | |
116 | ||
117 | switch (bitrate) { | |
118 | case 1000: | |
119 | pms = PLLPMS_1000MHZ; | |
120 | ctl = BANDCTL_1000MHZ; | |
121 | break; | |
122 | case 960: | |
123 | pms = PLLPMS_960MHZ; | |
124 | ctl = BANDCTL_960MHZ; | |
125 | break; | |
126 | case 900: | |
127 | pms = PLLPMS_900MHZ; | |
128 | ctl = BANDCTL_900MHZ; | |
129 | break; | |
130 | case 840: | |
131 | pms = PLLPMS_840MHZ; | |
132 | ctl = BANDCTL_840MHZ; | |
133 | break; | |
134 | case 750: | |
135 | pms = PLLPMS_750MHZ; | |
136 | ctl = BANDCTL_750MHZ; | |
137 | break; | |
138 | case 660: | |
139 | pms = PLLPMS_660MHZ; | |
140 | ctl = BANDCTL_660MHZ; | |
141 | break; | |
142 | case 600: | |
143 | pms = PLLPMS_600MHZ; | |
144 | ctl = BANDCTL_600MHZ; | |
145 | break; | |
146 | case 540: | |
147 | pms = PLLPMS_540MHZ; | |
148 | ctl = BANDCTL_540MHZ; | |
149 | break; | |
150 | case 512: | |
151 | pms = PLLPMS_512MHZ; | |
152 | ctl = BANDCTL_512MHZ; | |
153 | break; | |
154 | case 480: | |
155 | pms = PLLPMS_480MHZ; | |
156 | ctl = BANDCTL_480MHZ; | |
157 | break; | |
158 | case 420: | |
159 | pms = PLLPMS_420MHZ; | |
160 | ctl = BANDCTL_420MHZ; | |
161 | break; | |
162 | case 402: | |
163 | pms = PLLPMS_402MHZ; | |
164 | ctl = BANDCTL_402MHZ; | |
165 | break; | |
166 | case 330: | |
167 | pms = PLLPMS_330MHZ; | |
168 | ctl = BANDCTL_330MHZ; | |
169 | break; | |
170 | case 300: | |
171 | pms = PLLPMS_300MHZ; | |
172 | ctl = BANDCTL_300MHZ; | |
173 | break; | |
174 | case 210: | |
175 | pms = PLLPMS_210MHZ; | |
176 | ctl = BANDCTL_210MHZ; | |
177 | break; | |
178 | case 180: | |
179 | pms = PLLPMS_180MHZ; | |
180 | ctl = BANDCTL_180MHZ; | |
181 | break; | |
182 | case 150: | |
183 | pms = PLLPMS_150MHZ; | |
184 | ctl = BANDCTL_150MHZ; | |
185 | break; | |
186 | case 100: | |
187 | pms = PLLPMS_100MHZ; | |
188 | ctl = BANDCTL_100MHZ; | |
189 | break; | |
190 | case 80: | |
191 | pms = PLLPMS_80MHZ; | |
192 | ctl = BANDCTL_80MHZ; | |
193 | break; | |
194 | default: | |
195 | return -EINVAL; | |
196 | } | |
197 | ||
198 | *pllpms = pms; | |
199 | *bandctl = ctl; | |
200 | ||
201 | return 0; | |
202 | } | |
203 | ||
204 | static int mipi_prepare(int module, int input, | |
205 | struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, | |
206 | struct dp_mipi_dev *mipi) | |
207 | { | |
208 | int index = MIPI_INDEX; | |
209 | u32 esc_pre_value = MIPI_EXC_PRE_VALUE; | |
210 | int lpm = mipi->lpm_trans; | |
211 | int ret = 0; | |
212 | ||
213 | ret = mipi_get_phy_pll(mipi->hs_bitrate, | |
214 | &mipi->hs_pllpms, &mipi->hs_bandctl); | |
215 | if (ret < 0) | |
216 | return ret; | |
217 | ||
218 | ret = mipi_get_phy_pll(mipi->lp_bitrate, | |
219 | &mipi->lp_pllpms, &mipi->lp_bandctl); | |
220 | if (ret < 0) | |
221 | return ret; | |
222 | ||
223 | debug("%s: mipi lp:%dmhz:0x%x:0x%x, hs:%dmhz:0x%x:0x%x, %s trans\n", | |
224 | __func__, mipi->lp_bitrate, mipi->lp_pllpms, mipi->lp_bandctl, | |
225 | mipi->hs_bitrate, mipi->hs_pllpms, mipi->hs_bandctl, | |
226 | lpm ? "low" : "high"); | |
227 | ||
228 | if (lpm) | |
229 | nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF, | |
230 | mipi->lp_pllpms, mipi->lp_bandctl, 0, 0); | |
231 | else | |
232 | nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF, | |
233 | mipi->hs_pllpms, mipi->hs_bandctl, 0, 0); | |
234 | ||
235 | #ifdef CONFIG_ARCH_S5P4418 | |
236 | /* | |
237 | * disable the escape clock generating prescaler | |
238 | * before soft reset. | |
239 | */ | |
240 | nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 0, 10); | |
241 | mdelay(1); | |
242 | #endif | |
243 | ||
244 | nx_mipi_dsi_software_reset(index); | |
245 | nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, 1, esc_pre_value); | |
246 | nx_mipi_dsi_set_phy(index, 0, 1, 1, 0, 0, 0, 0, 0); | |
247 | ||
248 | if (lpm) | |
249 | nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_lp, | |
250 | nx_mipi_dsi_lpmode_lp); | |
251 | else | |
252 | nx_mipi_dsi_set_escape_lp(index, nx_mipi_dsi_lpmode_hs, | |
253 | nx_mipi_dsi_lpmode_hs); | |
254 | mdelay(20); | |
255 | ||
256 | return 0; | |
257 | } | |
258 | ||
259 | static int mipi_enable(int module, int input, | |
260 | struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, | |
261 | struct dp_mipi_dev *mipi) | |
262 | { | |
263 | struct mipi_dsi_device *dsi = &mipi->dsi; | |
264 | int clkid = DP_CLOCK_MIPI; | |
265 | int index = MIPI_INDEX; | |
266 | int width = sync->h_active_len; | |
267 | int height = sync->v_active_len; | |
268 | int HFP = sync->h_front_porch; | |
269 | int HBP = sync->h_back_porch; | |
270 | int HS = sync->h_sync_width; | |
271 | int VFP = sync->v_front_porch; | |
272 | int VBP = sync->v_back_porch; | |
273 | int VS = sync->v_sync_width; | |
274 | int en_prescaler = 1; | |
275 | u32 esc_pre_value = MIPI_EXC_PRE_VALUE; | |
276 | ||
277 | int txhsclock = 1; | |
278 | int lpm = mipi->lpm_trans; | |
279 | bool command_mode = mipi->command_mode; | |
280 | ||
281 | enum nx_mipi_dsi_format dsi_format; | |
282 | int data_len = dsi->lanes - 1; | |
283 | bool burst = dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST ? true : false; | |
284 | bool eot_enable = dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET ? | |
285 | false : true; | |
286 | ||
287 | /* | |
288 | * disable the escape clock generating prescaler | |
289 | * before soft reset. | |
290 | */ | |
291 | #ifdef CONFIG_ARCH_S5P4418 | |
292 | en_prescaler = 0; | |
293 | #endif | |
294 | ||
295 | debug("%s: mode:%s, lanes.%d\n", __func__, | |
296 | command_mode ? "command" : "video", data_len + 1); | |
297 | ||
298 | if (lpm) | |
299 | nx_mipi_dsi_set_escape_lp(index, | |
300 | nx_mipi_dsi_lpmode_hs, | |
301 | nx_mipi_dsi_lpmode_hs); | |
302 | ||
303 | nx_mipi_dsi_set_pll(index, 1, 0xFFFFFFFF, | |
304 | mipi->hs_pllpms, mipi->hs_bandctl, 0, 0); | |
305 | mdelay(1); | |
306 | ||
307 | nx_mipi_dsi_set_clock(index, 0, 0, 1, 1, 1, 0, 0, 0, en_prescaler, 10); | |
308 | mdelay(1); | |
309 | ||
310 | nx_mipi_dsi_software_reset(index); | |
311 | nx_mipi_dsi_set_clock(index, txhsclock, 0, 1, | |
312 | 1, 1, 0, 0, 0, 1, esc_pre_value); | |
313 | ||
314 | switch (data_len) { | |
315 | case 0: /* 1 lane */ | |
316 | nx_mipi_dsi_set_phy(index, data_len, 1, 1, 0, 0, 0, 0, 0); | |
317 | break; | |
318 | case 1: /* 2 lane */ | |
319 | nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 0, 0, 0, 0); | |
320 | break; | |
321 | case 2: /* 3 lane */ | |
322 | nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 0, 0, 0); | |
323 | break; | |
324 | case 3: /* 3 lane */ | |
325 | nx_mipi_dsi_set_phy(index, data_len, 1, 1, 1, 1, 1, 0, 0); | |
326 | break; | |
327 | default: | |
328 | printf("%s: not support data lanes %d\n", | |
329 | __func__, data_len + 1); | |
330 | return -EINVAL; | |
331 | } | |
332 | ||
333 | switch (dsi->format) { | |
334 | case MIPI_DSI_FMT_RGB565: | |
335 | dsi_format = nx_mipi_dsi_format_rgb565; | |
336 | break; | |
337 | case MIPI_DSI_FMT_RGB666: | |
338 | dsi_format = nx_mipi_dsi_format_rgb666; | |
339 | break; | |
340 | case MIPI_DSI_FMT_RGB666_PACKED: | |
341 | dsi_format = nx_mipi_dsi_format_rgb666_packed; | |
342 | break; | |
343 | case MIPI_DSI_FMT_RGB888: | |
344 | dsi_format = nx_mipi_dsi_format_rgb888; | |
345 | break; | |
346 | default: | |
347 | printf("%s: not support format %d\n", __func__, dsi->format); | |
348 | return -EINVAL; | |
349 | } | |
350 | ||
351 | nx_mipi_dsi_set_config_video_mode(index, 1, 0, burst, | |
352 | nx_mipi_dsi_syncmode_event, | |
353 | eot_enable, 1, 1, 1, 1, 0, dsi_format, | |
354 | HFP, HBP, HS, VFP, VBP, VS, 0); | |
355 | ||
356 | nx_mipi_dsi_set_size(index, width, height); | |
357 | ||
358 | /* set mux */ | |
359 | nx_disp_top_set_mipimux(1, module); | |
360 | ||
361 | /* 0 is spdif, 1 is mipi vclk */ | |
362 | nx_disp_top_clkgen_set_clock_source(clkid, 1, ctrl->clk_src_lv0); | |
363 | nx_disp_top_clkgen_set_clock_divisor(clkid, 1, | |
364 | ctrl->clk_div_lv1 * | |
365 | ctrl->clk_div_lv0); | |
366 | ||
367 | /* SPDIF and MIPI */ | |
368 | nx_disp_top_clkgen_set_clock_divisor_enable(clkid, 1); | |
369 | ||
370 | /* START: CLKGEN, MIPI is started in setup function */ | |
371 | nx_disp_top_clkgen_set_clock_divisor_enable(clkid, true); | |
372 | nx_mipi_dsi_set_enable(index, true); | |
373 | ||
374 | return 0; | |
375 | } | |
376 | ||
377 | static int nx_mipi_transfer_tx(struct mipi_dsi_device *dsi, | |
378 | struct mipi_xfer_msg *xfer) | |
379 | { | |
380 | const u8 *txb; | |
381 | int size, index = 0; | |
382 | u32 data; | |
383 | ||
384 | if (xfer->tx_len > DSI_TX_FIFO_SIZE) | |
385 | printf("warn: tx %d size over fifo %d\n", | |
386 | (int)xfer->tx_len, DSI_TX_FIFO_SIZE); | |
387 | ||
388 | /* write payload */ | |
389 | size = xfer->tx_len; | |
390 | txb = xfer->tx_buf; | |
391 | ||
392 | while (size >= 4) { | |
393 | data = (txb[3] << 24) | (txb[2] << 16) | | |
394 | (txb[1] << 8) | (txb[0]); | |
395 | nx_mipi_dsi_write_payload(index, data); | |
396 | txb += 4, size -= 4; | |
397 | data = 0; | |
398 | } | |
399 | ||
400 | switch (size) { | |
401 | case 3: | |
402 | data |= txb[2] << 16; | |
403 | case 2: | |
404 | data |= txb[1] << 8; | |
405 | case 1: | |
406 | data |= txb[0]; | |
407 | nx_mipi_dsi_write_payload(index, data); | |
408 | break; | |
409 | case 0: | |
410 | break; /* no payload */ | |
411 | } | |
412 | ||
413 | /* write packet hdr */ | |
414 | data = (xfer->data[1] << 16) | (xfer->data[0] << 8) | xfer->id; | |
415 | ||
416 | nx_mipi_dsi_write_pkheader(index, data); | |
417 | ||
418 | return 0; | |
419 | } | |
420 | ||
421 | static int nx_mipi_transfer_done(struct mipi_dsi_device *dsi) | |
422 | { | |
423 | int index = 0, count = 100; | |
424 | u32 value; | |
425 | ||
426 | do { | |
427 | mdelay(1); | |
428 | value = nx_mipi_dsi_read_fifo_status(index); | |
429 | if (((1 << 22) & value)) | |
430 | break; | |
431 | } while (count-- > 0); | |
432 | ||
433 | if (count < 0) | |
434 | return -EINVAL; | |
435 | ||
436 | return 0; | |
437 | } | |
438 | ||
439 | static int nx_mipi_transfer_rx(struct mipi_dsi_device *dsi, | |
440 | struct mipi_xfer_msg *xfer) | |
441 | { | |
442 | u8 *rxb = xfer->rx_buf; | |
443 | int index = 0, rx_len = 0; | |
444 | u32 data, count = 0; | |
445 | u16 size; | |
446 | int err = -EINVAL; | |
447 | ||
448 | nx_mipi_dsi_clear_interrupt_pending(index, 18); | |
449 | ||
450 | while (1) { | |
451 | /* Completes receiving data. */ | |
452 | if (nx_mipi_dsi_get_interrupt_pending(index, 18)) | |
453 | break; | |
454 | ||
455 | mdelay(1); | |
456 | ||
457 | if (count > 500) { | |
458 | printf("%s: error recevice data\n", __func__); | |
459 | err = -EINVAL; | |
460 | goto clear_fifo; | |
461 | } else { | |
462 | count++; | |
463 | } | |
464 | } | |
465 | ||
466 | data = nx_mipi_dsi_read_fifo(index); | |
467 | ||
468 | switch (data & 0x3f) { | |
469 | case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE: | |
470 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE: | |
471 | if (xfer->rx_len >= 2) { | |
472 | rxb[1] = data >> 16; | |
473 | rx_len++; | |
474 | } | |
475 | ||
476 | /* Fall through */ | |
477 | case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE: | |
478 | case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE: | |
479 | rxb[0] = data >> 8; | |
480 | rx_len++; | |
481 | xfer->rx_len = rx_len; | |
482 | err = rx_len; | |
483 | goto clear_fifo; | |
484 | ||
485 | case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT: | |
486 | printf("DSI Error Report: 0x%04x\n", (data >> 8) & 0xffff); | |
487 | err = rx_len; | |
488 | goto clear_fifo; | |
489 | } | |
490 | ||
491 | size = (data >> 8) & 0xffff; | |
492 | ||
493 | if (size > xfer->rx_len) | |
494 | size = xfer->rx_len; | |
495 | else if (size < xfer->rx_len) | |
496 | xfer->rx_len = size; | |
497 | ||
498 | size = xfer->rx_len - rx_len; | |
499 | rx_len += size; | |
500 | ||
501 | /* Receive payload */ | |
502 | while (size >= 4) { | |
503 | data = nx_mipi_dsi_read_fifo(index); | |
504 | rxb[0] = (data >> 0) & 0xff; | |
505 | rxb[1] = (data >> 8) & 0xff; | |
506 | rxb[2] = (data >> 16) & 0xff; | |
507 | rxb[3] = (data >> 24) & 0xff; | |
508 | rxb += 4, size -= 4; | |
509 | } | |
510 | ||
511 | if (size) { | |
512 | data = nx_mipi_dsi_read_fifo(index); | |
513 | switch (size) { | |
514 | case 3: | |
515 | rxb[2] = (data >> 16) & 0xff; | |
516 | case 2: | |
517 | rxb[1] = (data >> 8) & 0xff; | |
518 | case 1: | |
519 | rxb[0] = data & 0xff; | |
520 | } | |
521 | } | |
522 | ||
523 | if (rx_len == xfer->rx_len) | |
524 | err = rx_len; | |
525 | ||
526 | clear_fifo: | |
527 | size = DSI_RX_FIFO_SIZE / 4; | |
528 | do { | |
529 | data = nx_mipi_dsi_read_fifo(index); | |
530 | if (data == DSI_RX_FIFO_EMPTY) | |
531 | break; | |
532 | } while (--size); | |
533 | ||
534 | return err; | |
535 | } | |
536 | ||
537 | #define IS_SHORT(t) (9 > ((t) & 0x0f)) | |
538 | ||
539 | static int nx_mipi_transfer(struct mipi_dsi_device *dsi, | |
540 | const struct mipi_dsi_msg *msg) | |
541 | { | |
542 | struct mipi_xfer_msg xfer; | |
543 | int err; | |
544 | ||
545 | if (!msg->tx_len) | |
546 | return -EINVAL; | |
547 | ||
548 | /* set id */ | |
549 | xfer.id = msg->type | (msg->channel << 6); | |
550 | ||
551 | /* short type msg */ | |
552 | if (IS_SHORT(msg->type)) { | |
553 | const char *txb = msg->tx_buf; | |
554 | ||
555 | if (msg->tx_len > 2) | |
556 | return -EINVAL; | |
557 | ||
558 | xfer.tx_len = 0; /* no payload */ | |
559 | xfer.data[0] = txb[0]; | |
560 | xfer.data[1] = (msg->tx_len == 2) ? txb[1] : 0; | |
561 | xfer.tx_buf = NULL; | |
562 | } else { | |
563 | xfer.tx_len = msg->tx_len; | |
564 | xfer.data[0] = msg->tx_len & 0xff; | |
565 | xfer.data[1] = msg->tx_len >> 8; | |
566 | xfer.tx_buf = msg->tx_buf; | |
567 | } | |
568 | ||
569 | xfer.rx_len = msg->rx_len; | |
570 | xfer.rx_buf = msg->rx_buf; | |
571 | xfer.flags = msg->flags; | |
572 | ||
573 | err = nx_mipi_transfer_tx(dsi, &xfer); | |
574 | ||
575 | if (xfer.rx_len) | |
576 | err = nx_mipi_transfer_rx(dsi, &xfer); | |
577 | ||
578 | nx_mipi_transfer_done(dsi); | |
579 | ||
580 | return err; | |
581 | } | |
582 | ||
583 | static ssize_t nx_mipi_write_buffer(struct mipi_dsi_device *dsi, | |
584 | const void *data, size_t len) | |
585 | { | |
586 | struct mipi_dsi_msg msg = { | |
587 | .channel = dsi->channel, | |
588 | .tx_buf = data, | |
589 | .tx_len = len | |
590 | }; | |
591 | ||
592 | switch (len) { | |
593 | case 0: | |
594 | return -EINVAL; | |
595 | case 1: | |
596 | msg.type = MIPI_DSI_DCS_SHORT_WRITE; | |
597 | break; | |
598 | case 2: | |
599 | msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM; | |
600 | break; | |
601 | default: | |
602 | msg.type = MIPI_DSI_DCS_LONG_WRITE; | |
603 | break; | |
604 | } | |
605 | ||
606 | if (dsi->mode_flags & MIPI_DSI_MODE_LPM) | |
607 | msg.flags |= MIPI_DSI_MSG_USE_LPM; | |
608 | ||
609 | return nx_mipi_transfer(dsi, &msg); | |
610 | } | |
611 | ||
612 | __weak int nx_mipi_dsi_lcd_bind(struct mipi_dsi_device *dsi) | |
613 | { | |
614 | return 0; | |
615 | } | |
616 | ||
617 | /* | |
618 | * disply | |
619 | * MIPI DSI Setting | |
620 | * (1) Initiallize MIPI(DSIM,DPHY,PLL) | |
621 | * (2) Initiallize LCD | |
622 | * (3) ReInitiallize MIPI(DSIM only) | |
623 | * (4) Turn on display(MLC,DPC,...) | |
624 | */ | |
625 | void nx_mipi_display(int module, | |
626 | struct dp_sync_info *sync, struct dp_ctrl_info *ctrl, | |
627 | struct dp_plane_top *top, struct dp_plane_info *planes, | |
628 | struct dp_mipi_dev *dev) | |
629 | { | |
630 | struct dp_plane_info *plane = planes; | |
631 | struct mipi_dsi_device *dsi = &dev->dsi; | |
632 | int input = module == 0 ? DP_DEVICE_DP0 : DP_DEVICE_DP1; | |
633 | int count = top->plane_num; | |
634 | int i = 0, ret; | |
635 | ||
636 | printf("MIPI: dp.%d\n", module); | |
637 | ||
638 | /* map mipi-dsi write callback func */ | |
639 | dsi->write_buffer = nx_mipi_write_buffer; | |
640 | ||
641 | ret = nx_mipi_dsi_lcd_bind(dsi); | |
642 | if (ret) { | |
643 | printf("Error: bind mipi-dsi lcd driver !\n"); | |
644 | return; | |
645 | } | |
646 | ||
647 | dp_control_init(module); | |
648 | dp_plane_init(module); | |
649 | ||
650 | mipi_init(); | |
651 | ||
652 | /* set plane */ | |
653 | dp_plane_screen_setup(module, top); | |
654 | ||
655 | for (i = 0; count > i; i++, plane++) { | |
656 | if (!plane->enable) | |
657 | continue; | |
658 | dp_plane_layer_setup(module, plane); | |
659 | dp_plane_layer_enable(module, plane, 1); | |
660 | } | |
661 | dp_plane_screen_enable(module, 1); | |
662 | ||
663 | /* set mipi */ | |
664 | mipi_prepare(module, input, sync, ctrl, dev); | |
665 | ||
666 | if (dsi->ops && dsi->ops->prepare) | |
667 | dsi->ops->prepare(dsi); | |
668 | ||
669 | if (dsi->ops && dsi->ops->enable) | |
670 | dsi->ops->enable(dsi); | |
671 | ||
672 | mipi_enable(module, input, sync, ctrl, dev); | |
673 | ||
674 | /* set dp control */ | |
675 | dp_control_setup(module, sync, ctrl); | |
676 | dp_control_enable(module, 1); | |
677 | } |