]>
Commit | Line | Data |
---|---|---|
2c7396cb DL |
1 | /* |
2 | * Copyright (C) 2012 Samsung Electronics | |
3 | * | |
4 | * Author: InKi Dae <[email protected]> | |
5 | * Author: Donghwa Lee <[email protected]> | |
6 | * | |
1a459660 | 7 | * SPDX-License-Identifier: GPL-2.0+ |
2c7396cb DL |
8 | */ |
9 | ||
10 | #include <common.h> | |
11 | #include <lcd.h> | |
12 | #include <linux/err.h> | |
13 | #include <asm/arch/dsim.h> | |
14 | #include <asm/arch/mipi_dsim.h> | |
15 | ||
16 | #include "exynos_mipi_dsi_lowlevel.h" | |
17 | ||
18 | #define MHZ (1000 * 1000) | |
19 | #define FIN_HZ (24 * MHZ) | |
20 | ||
21 | #define DFIN_PLL_MIN_HZ (6 * MHZ) | |
22 | #define DFIN_PLL_MAX_HZ (12 * MHZ) | |
23 | ||
24 | #define DFVCO_MIN_HZ (500 * MHZ) | |
25 | #define DFVCO_MAX_HZ (1000 * MHZ) | |
26 | ||
27 | #define TRY_GET_FIFO_TIMEOUT (5000 * 2) | |
28 | ||
29 | /* MIPI-DSIM status types. */ | |
30 | enum { | |
31 | DSIM_STATE_INIT, /* should be initialized. */ | |
32 | DSIM_STATE_STOP, /* CPU and LCDC are LP mode. */ | |
33 | DSIM_STATE_HSCLKEN, /* HS clock was enabled. */ | |
34 | DSIM_STATE_ULPS | |
35 | }; | |
36 | ||
37 | /* define DSI lane types. */ | |
38 | enum { | |
39 | DSIM_LANE_CLOCK = (1 << 0), | |
40 | DSIM_LANE_DATA0 = (1 << 1), | |
41 | DSIM_LANE_DATA1 = (1 << 2), | |
42 | DSIM_LANE_DATA2 = (1 << 3), | |
43 | DSIM_LANE_DATA3 = (1 << 4) | |
44 | }; | |
45 | ||
46 | static unsigned int dpll_table[15] = { | |
47 | 100, 120, 170, 220, 270, | |
48 | 320, 390, 450, 510, 560, | |
49 | 640, 690, 770, 870, 950 | |
50 | }; | |
51 | ||
52 | static void exynos_mipi_dsi_long_data_wr(struct mipi_dsim_device *dsim, | |
53 | unsigned int data0, unsigned int data1) | |
54 | { | |
55 | unsigned int data_cnt = 0, payload = 0; | |
56 | ||
57 | /* in case that data count is more then 4 */ | |
58 | for (data_cnt = 0; data_cnt < data1; data_cnt += 4) { | |
59 | /* | |
60 | * after sending 4bytes per one time, | |
61 | * send remainder data less then 4. | |
62 | */ | |
63 | if ((data1 - data_cnt) < 4) { | |
64 | if ((data1 - data_cnt) == 3) { | |
65 | payload = *(u8 *)(data0 + data_cnt) | | |
66 | (*(u8 *)(data0 + (data_cnt + 1))) << 8 | | |
67 | (*(u8 *)(data0 + (data_cnt + 2))) << 16; | |
68 | debug("count = 3 payload = %x, %x %x %x\n", | |
69 | payload, *(u8 *)(data0 + data_cnt), | |
70 | *(u8 *)(data0 + (data_cnt + 1)), | |
71 | *(u8 *)(data0 + (data_cnt + 2))); | |
72 | } else if ((data1 - data_cnt) == 2) { | |
73 | payload = *(u8 *)(data0 + data_cnt) | | |
74 | (*(u8 *)(data0 + (data_cnt + 1))) << 8; | |
75 | debug("count = 2 payload = %x, %x %x\n", payload, | |
76 | *(u8 *)(data0 + data_cnt), | |
77 | *(u8 *)(data0 + (data_cnt + 1))); | |
78 | } else if ((data1 - data_cnt) == 1) { | |
79 | payload = *(u8 *)(data0 + data_cnt); | |
80 | } | |
81 | } else { | |
82 | /* send 4bytes per one time. */ | |
83 | payload = *(u8 *)(data0 + data_cnt) | | |
84 | (*(u8 *)(data0 + (data_cnt + 1))) << 8 | | |
85 | (*(u8 *)(data0 + (data_cnt + 2))) << 16 | | |
86 | (*(u8 *)(data0 + (data_cnt + 3))) << 24; | |
87 | ||
88 | debug("count = 4 payload = %x, %x %x %x %x\n", | |
89 | payload, *(u8 *)(data0 + data_cnt), | |
90 | *(u8 *)(data0 + (data_cnt + 1)), | |
91 | *(u8 *)(data0 + (data_cnt + 2)), | |
92 | *(u8 *)(data0 + (data_cnt + 3))); | |
93 | ||
94 | } | |
95 | exynos_mipi_dsi_wr_tx_data(dsim, payload); | |
96 | } | |
97 | } | |
98 | ||
99 | int exynos_mipi_dsi_wr_data(struct mipi_dsim_device *dsim, unsigned int data_id, | |
100 | unsigned int data0, unsigned int data1) | |
101 | { | |
102 | unsigned int timeout = TRY_GET_FIFO_TIMEOUT; | |
103 | unsigned long delay_val, delay; | |
104 | unsigned int check_rx_ack = 0; | |
105 | ||
106 | if (dsim->state == DSIM_STATE_ULPS) { | |
107 | debug("state is ULPS.\n"); | |
108 | ||
109 | return -EINVAL; | |
110 | } | |
111 | ||
112 | delay_val = MHZ / dsim->dsim_config->esc_clk; | |
113 | delay = 10 * delay_val; | |
114 | ||
115 | mdelay(delay); | |
116 | ||
117 | /* only if transfer mode is LPDT, wait SFR becomes empty. */ | |
118 | if (dsim->state == DSIM_STATE_STOP) { | |
119 | while (!(exynos_mipi_dsi_get_fifo_state(dsim) & | |
120 | SFR_HEADER_EMPTY)) { | |
121 | if ((timeout--) > 0) | |
122 | mdelay(1); | |
123 | else { | |
124 | debug("SRF header fifo is not empty.\n"); | |
125 | return -EINVAL; | |
126 | } | |
127 | } | |
128 | } | |
129 | ||
130 | switch (data_id) { | |
131 | /* short packet types of packet types for command. */ | |
132 | case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM: | |
133 | case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM: | |
134 | case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM: | |
135 | case MIPI_DSI_DCS_SHORT_WRITE: | |
136 | case MIPI_DSI_DCS_SHORT_WRITE_PARAM: | |
137 | case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE: | |
138 | debug("data0 = %x data1 = %x\n", | |
139 | data0, data1); | |
140 | exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1); | |
141 | if (check_rx_ack) { | |
142 | /* process response func should be implemented */ | |
143 | return 0; | |
144 | } else { | |
145 | return -EINVAL; | |
146 | } | |
147 | ||
148 | /* general command */ | |
149 | case MIPI_DSI_COLOR_MODE_OFF: | |
150 | case MIPI_DSI_COLOR_MODE_ON: | |
151 | case MIPI_DSI_SHUTDOWN_PERIPHERAL: | |
152 | case MIPI_DSI_TURN_ON_PERIPHERAL: | |
153 | exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1); | |
154 | if (check_rx_ack) { | |
155 | /* process response func should be implemented. */ | |
156 | return 0; | |
157 | } else { | |
158 | return -EINVAL; | |
159 | } | |
160 | ||
161 | /* packet types for video data */ | |
162 | case MIPI_DSI_V_SYNC_START: | |
163 | case MIPI_DSI_V_SYNC_END: | |
164 | case MIPI_DSI_H_SYNC_START: | |
165 | case MIPI_DSI_H_SYNC_END: | |
166 | case MIPI_DSI_END_OF_TRANSMISSION: | |
167 | return 0; | |
168 | ||
169 | /* short and response packet types for command */ | |
170 | case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM: | |
171 | case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM: | |
172 | case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM: | |
173 | case MIPI_DSI_DCS_READ: | |
174 | exynos_mipi_dsi_clear_all_interrupt(dsim); | |
175 | exynos_mipi_dsi_wr_tx_header(dsim, data_id, data0, data1); | |
176 | /* process response func should be implemented. */ | |
177 | return 0; | |
178 | ||
179 | /* long packet type and null packet */ | |
180 | case MIPI_DSI_NULL_PACKET: | |
181 | case MIPI_DSI_BLANKING_PACKET: | |
182 | return 0; | |
183 | case MIPI_DSI_GENERIC_LONG_WRITE: | |
184 | case MIPI_DSI_DCS_LONG_WRITE: | |
185 | { | |
186 | unsigned int data_cnt = 0, payload = 0; | |
187 | ||
188 | /* if data count is less then 4, then send 3bytes data. */ | |
189 | if (data1 < 4) { | |
190 | payload = *(u8 *)(data0) | | |
191 | *(u8 *)(data0 + 1) << 8 | | |
192 | *(u8 *)(data0 + 2) << 16; | |
193 | ||
194 | exynos_mipi_dsi_wr_tx_data(dsim, payload); | |
195 | ||
196 | debug("count = %d payload = %x,%x %x %x\n", | |
197 | data1, payload, | |
198 | *(u8 *)(data0 + data_cnt), | |
199 | *(u8 *)(data0 + (data_cnt + 1)), | |
200 | *(u8 *)(data0 + (data_cnt + 2))); | |
201 | } else { | |
202 | /* in case that data count is more then 4 */ | |
203 | exynos_mipi_dsi_long_data_wr(dsim, data0, data1); | |
204 | } | |
205 | ||
206 | /* put data into header fifo */ | |
207 | exynos_mipi_dsi_wr_tx_header(dsim, data_id, data1 & 0xff, | |
208 | (data1 & 0xff00) >> 8); | |
209 | ||
210 | } | |
211 | if (check_rx_ack) | |
212 | /* process response func should be implemented. */ | |
213 | return 0; | |
214 | else | |
215 | return -EINVAL; | |
216 | ||
217 | /* packet typo for video data */ | |
218 | case MIPI_DSI_PACKED_PIXEL_STREAM_16: | |
219 | case MIPI_DSI_PACKED_PIXEL_STREAM_18: | |
220 | case MIPI_DSI_PIXEL_STREAM_3BYTE_18: | |
221 | case MIPI_DSI_PACKED_PIXEL_STREAM_24: | |
222 | if (check_rx_ack) { | |
223 | /* process response func should be implemented. */ | |
224 | return 0; | |
225 | } else { | |
226 | return -EINVAL; | |
227 | } | |
228 | default: | |
229 | debug("data id %x is not supported current DSI spec.\n", | |
230 | data_id); | |
231 | ||
232 | return -EINVAL; | |
233 | } | |
234 | ||
235 | return 0; | |
236 | } | |
237 | ||
238 | int exynos_mipi_dsi_pll_on(struct mipi_dsim_device *dsim, unsigned int enable) | |
239 | { | |
240 | int sw_timeout; | |
241 | ||
242 | if (enable) { | |
243 | sw_timeout = 1000; | |
244 | ||
245 | exynos_mipi_dsi_clear_interrupt(dsim); | |
246 | exynos_mipi_dsi_enable_pll(dsim, 1); | |
247 | while (1) { | |
248 | sw_timeout--; | |
249 | if (exynos_mipi_dsi_is_pll_stable(dsim)) | |
250 | return 0; | |
251 | if (sw_timeout == 0) | |
252 | return -EINVAL; | |
253 | } | |
254 | } else | |
255 | exynos_mipi_dsi_enable_pll(dsim, 0); | |
256 | ||
257 | return 0; | |
258 | } | |
259 | ||
260 | unsigned long exynos_mipi_dsi_change_pll(struct mipi_dsim_device *dsim, | |
261 | unsigned int pre_divider, unsigned int main_divider, | |
262 | unsigned int scaler) | |
263 | { | |
264 | unsigned long dfin_pll, dfvco, dpll_out; | |
265 | unsigned int i, freq_band = 0xf; | |
266 | ||
267 | dfin_pll = (FIN_HZ / pre_divider); | |
268 | ||
269 | /****************************************************** | |
270 | * Serial Clock(=ByteClk X 8) FreqBand[3:0] * | |
271 | ****************************************************** | |
272 | * ~ 99.99 MHz 0000 | |
273 | * 100 ~ 119.99 MHz 0001 | |
274 | * 120 ~ 159.99 MHz 0010 | |
275 | * 160 ~ 199.99 MHz 0011 | |
276 | * 200 ~ 239.99 MHz 0100 | |
277 | * 140 ~ 319.99 MHz 0101 | |
278 | * 320 ~ 389.99 MHz 0110 | |
279 | * 390 ~ 449.99 MHz 0111 | |
280 | * 450 ~ 509.99 MHz 1000 | |
281 | * 510 ~ 559.99 MHz 1001 | |
282 | * 560 ~ 639.99 MHz 1010 | |
283 | * 640 ~ 689.99 MHz 1011 | |
284 | * 690 ~ 769.99 MHz 1100 | |
285 | * 770 ~ 869.99 MHz 1101 | |
286 | * 870 ~ 949.99 MHz 1110 | |
287 | * 950 ~ 1000 MHz 1111 | |
288 | ******************************************************/ | |
289 | if (dfin_pll < DFIN_PLL_MIN_HZ || dfin_pll > DFIN_PLL_MAX_HZ) { | |
290 | debug("fin_pll range should be 6MHz ~ 12MHz\n"); | |
291 | exynos_mipi_dsi_enable_afc(dsim, 0, 0); | |
292 | } else { | |
293 | if (dfin_pll < 7 * MHZ) | |
294 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x1); | |
295 | else if (dfin_pll < 8 * MHZ) | |
296 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x0); | |
297 | else if (dfin_pll < 9 * MHZ) | |
298 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x3); | |
299 | else if (dfin_pll < 10 * MHZ) | |
300 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x2); | |
301 | else if (dfin_pll < 11 * MHZ) | |
302 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x5); | |
303 | else | |
304 | exynos_mipi_dsi_enable_afc(dsim, 1, 0x4); | |
305 | } | |
306 | ||
307 | dfvco = dfin_pll * main_divider; | |
308 | debug("dfvco = %lu, dfin_pll = %lu, main_divider = %d\n", | |
309 | dfvco, dfin_pll, main_divider); | |
310 | if (dfvco < DFVCO_MIN_HZ || dfvco > DFVCO_MAX_HZ) | |
311 | debug("fvco range should be 500MHz ~ 1000MHz\n"); | |
312 | ||
313 | dpll_out = dfvco / (1 << scaler); | |
314 | debug("dpll_out = %lu, dfvco = %lu, scaler = %d\n", | |
315 | dpll_out, dfvco, scaler); | |
316 | ||
317 | for (i = 0; i < ARRAY_SIZE(dpll_table); i++) { | |
318 | if (dpll_out < dpll_table[i] * MHZ) { | |
319 | freq_band = i; | |
320 | break; | |
321 | } | |
322 | } | |
323 | ||
324 | debug("freq_band = %d\n", freq_band); | |
325 | ||
326 | exynos_mipi_dsi_pll_freq(dsim, pre_divider, main_divider, scaler); | |
327 | ||
328 | exynos_mipi_dsi_hs_zero_ctrl(dsim, 0); | |
329 | exynos_mipi_dsi_prep_ctrl(dsim, 0); | |
330 | ||
331 | /* Freq Band */ | |
332 | exynos_mipi_dsi_pll_freq_band(dsim, freq_band); | |
333 | ||
334 | /* Stable time */ | |
335 | exynos_mipi_dsi_pll_stable_time(dsim, | |
336 | dsim->dsim_config->pll_stable_time); | |
337 | ||
338 | /* Enable PLL */ | |
339 | debug("FOUT of mipi dphy pll is %luMHz\n", | |
340 | (dpll_out / MHZ)); | |
341 | ||
342 | return dpll_out; | |
343 | } | |
344 | ||
345 | int exynos_mipi_dsi_set_clock(struct mipi_dsim_device *dsim, | |
346 | unsigned int byte_clk_sel, unsigned int enable) | |
347 | { | |
348 | unsigned int esc_div; | |
349 | unsigned long esc_clk_error_rate; | |
350 | unsigned long hs_clk = 0, byte_clk = 0, escape_clk = 0; | |
351 | ||
352 | if (enable) { | |
353 | dsim->e_clk_src = byte_clk_sel; | |
354 | ||
355 | /* Escape mode clock and byte clock source */ | |
356 | exynos_mipi_dsi_set_byte_clock_src(dsim, byte_clk_sel); | |
357 | ||
358 | /* DPHY, DSIM Link : D-PHY clock out */ | |
359 | if (byte_clk_sel == DSIM_PLL_OUT_DIV8) { | |
360 | hs_clk = exynos_mipi_dsi_change_pll(dsim, | |
361 | dsim->dsim_config->p, dsim->dsim_config->m, | |
362 | dsim->dsim_config->s); | |
363 | if (hs_clk == 0) { | |
364 | debug("failed to get hs clock.\n"); | |
365 | return -EINVAL; | |
366 | } | |
367 | ||
368 | byte_clk = hs_clk / 8; | |
369 | exynos_mipi_dsi_enable_pll_bypass(dsim, 0); | |
370 | exynos_mipi_dsi_pll_on(dsim, 1); | |
371 | /* DPHY : D-PHY clock out, DSIM link : external clock out */ | |
372 | } else if (byte_clk_sel == DSIM_EXT_CLK_DIV8) | |
373 | debug("not support EXT CLK source for MIPI DSIM\n"); | |
374 | else if (byte_clk_sel == DSIM_EXT_CLK_BYPASS) | |
375 | debug("not support EXT CLK source for MIPI DSIM\n"); | |
376 | ||
377 | /* escape clock divider */ | |
378 | esc_div = byte_clk / (dsim->dsim_config->esc_clk); | |
379 | debug("esc_div = %d, byte_clk = %lu, esc_clk = %lu\n", | |
380 | esc_div, byte_clk, dsim->dsim_config->esc_clk); | |
381 | if ((byte_clk / esc_div) >= (20 * MHZ) || | |
382 | (byte_clk / esc_div) > dsim->dsim_config->esc_clk) | |
383 | esc_div += 1; | |
384 | ||
385 | escape_clk = byte_clk / esc_div; | |
386 | debug("escape_clk = %lu, byte_clk = %lu, esc_div = %d\n", | |
387 | escape_clk, byte_clk, esc_div); | |
388 | ||
389 | /* enable escape clock. */ | |
390 | exynos_mipi_dsi_enable_byte_clock(dsim, 1); | |
391 | ||
392 | /* enable byte clk and escape clock */ | |
393 | exynos_mipi_dsi_set_esc_clk_prs(dsim, 1, esc_div); | |
394 | /* escape clock on lane */ | |
395 | exynos_mipi_dsi_enable_esc_clk_on_lane(dsim, | |
396 | (DSIM_LANE_CLOCK | dsim->data_lane), 1); | |
397 | ||
398 | debug("byte clock is %luMHz\n", | |
399 | (byte_clk / MHZ)); | |
400 | debug("escape clock that user's need is %lu\n", | |
401 | (dsim->dsim_config->esc_clk / MHZ)); | |
402 | debug("escape clock divider is %x\n", esc_div); | |
403 | debug("escape clock is %luMHz\n", | |
404 | ((byte_clk / esc_div) / MHZ)); | |
405 | ||
406 | if ((byte_clk / esc_div) > escape_clk) { | |
407 | esc_clk_error_rate = escape_clk / | |
408 | (byte_clk / esc_div); | |
409 | debug("error rate is %lu over.\n", | |
410 | (esc_clk_error_rate / 100)); | |
411 | } else if ((byte_clk / esc_div) < (escape_clk)) { | |
412 | esc_clk_error_rate = (byte_clk / esc_div) / | |
413 | escape_clk; | |
414 | debug("error rate is %lu under.\n", | |
415 | (esc_clk_error_rate / 100)); | |
416 | } | |
417 | } else { | |
418 | exynos_mipi_dsi_enable_esc_clk_on_lane(dsim, | |
419 | (DSIM_LANE_CLOCK | dsim->data_lane), 0); | |
420 | exynos_mipi_dsi_set_esc_clk_prs(dsim, 0, 0); | |
421 | ||
422 | /* disable escape clock. */ | |
423 | exynos_mipi_dsi_enable_byte_clock(dsim, 0); | |
424 | ||
425 | if (byte_clk_sel == DSIM_PLL_OUT_DIV8) | |
426 | exynos_mipi_dsi_pll_on(dsim, 0); | |
427 | } | |
428 | ||
429 | return 0; | |
430 | } | |
431 | ||
432 | int exynos_mipi_dsi_init_dsim(struct mipi_dsim_device *dsim) | |
433 | { | |
434 | dsim->state = DSIM_STATE_INIT; | |
435 | ||
436 | switch (dsim->dsim_config->e_no_data_lane) { | |
437 | case DSIM_DATA_LANE_1: | |
438 | dsim->data_lane = DSIM_LANE_DATA0; | |
439 | break; | |
440 | case DSIM_DATA_LANE_2: | |
441 | dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1; | |
442 | break; | |
443 | case DSIM_DATA_LANE_3: | |
444 | dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | | |
445 | DSIM_LANE_DATA2; | |
446 | break; | |
447 | case DSIM_DATA_LANE_4: | |
448 | dsim->data_lane = DSIM_LANE_DATA0 | DSIM_LANE_DATA1 | | |
449 | DSIM_LANE_DATA2 | DSIM_LANE_DATA3; | |
450 | break; | |
451 | default: | |
452 | debug("data lane is invalid.\n"); | |
453 | return -EINVAL; | |
454 | }; | |
455 | ||
456 | exynos_mipi_dsi_sw_reset(dsim); | |
457 | exynos_mipi_dsi_dp_dn_swap(dsim, 0); | |
458 | ||
459 | return 0; | |
460 | } | |
461 | ||
462 | int exynos_mipi_dsi_enable_frame_done_int(struct mipi_dsim_device *dsim, | |
463 | unsigned int enable) | |
464 | { | |
465 | /* enable only frame done interrupt */ | |
466 | exynos_mipi_dsi_set_interrupt_mask(dsim, INTMSK_FRAME_DONE, enable); | |
467 | ||
468 | return 0; | |
469 | } | |
470 | ||
471 | static void convert_to_fb_videomode(struct fb_videomode *mode1, | |
472 | vidinfo_t *mode2) | |
473 | { | |
474 | mode1->xres = mode2->vl_width; | |
475 | mode1->yres = mode2->vl_height; | |
476 | mode1->upper_margin = mode2->vl_vfpd; | |
477 | mode1->lower_margin = mode2->vl_vbpd; | |
478 | mode1->left_margin = mode2->vl_hfpd; | |
479 | mode1->right_margin = mode2->vl_hbpd; | |
480 | mode1->vsync_len = mode2->vl_vspw; | |
481 | mode1->hsync_len = mode2->vl_hspw; | |
482 | } | |
483 | ||
484 | int exynos_mipi_dsi_set_display_mode(struct mipi_dsim_device *dsim, | |
485 | struct mipi_dsim_config *dsim_config) | |
486 | { | |
487 | struct exynos_platform_mipi_dsim *dsim_pd; | |
488 | struct fb_videomode lcd_video; | |
489 | vidinfo_t *vid; | |
490 | ||
491 | dsim_pd = (struct exynos_platform_mipi_dsim *)dsim->pd; | |
492 | vid = (vidinfo_t *)dsim_pd->lcd_panel_info; | |
493 | ||
494 | convert_to_fb_videomode(&lcd_video, vid); | |
495 | ||
496 | /* in case of VIDEO MODE (RGB INTERFACE), it sets polarities. */ | |
497 | if (dsim->dsim_config->e_interface == (u32) DSIM_VIDEO) { | |
498 | if (dsim->dsim_config->auto_vertical_cnt == 0) { | |
499 | exynos_mipi_dsi_set_main_disp_vporch(dsim, | |
500 | vid->vl_cmd_allow_len, | |
501 | lcd_video.upper_margin, | |
502 | lcd_video.lower_margin); | |
503 | exynos_mipi_dsi_set_main_disp_hporch(dsim, | |
504 | lcd_video.left_margin, | |
505 | lcd_video.right_margin); | |
506 | exynos_mipi_dsi_set_main_disp_sync_area(dsim, | |
507 | lcd_video.vsync_len, | |
508 | lcd_video.hsync_len); | |
509 | } | |
510 | } | |
511 | ||
512 | exynos_mipi_dsi_set_main_disp_resol(dsim, lcd_video.xres, | |
513 | lcd_video.yres); | |
514 | ||
515 | exynos_mipi_dsi_display_config(dsim, dsim->dsim_config); | |
516 | ||
517 | debug("lcd panel ==> width = %d, height = %d\n", | |
518 | lcd_video.xres, lcd_video.yres); | |
519 | ||
520 | return 0; | |
521 | } | |
522 | ||
523 | int exynos_mipi_dsi_init_link(struct mipi_dsim_device *dsim) | |
524 | { | |
525 | unsigned int time_out = 100; | |
526 | ||
527 | switch (dsim->state) { | |
528 | case DSIM_STATE_INIT: | |
529 | exynos_mipi_dsi_init_fifo_pointer(dsim, 0x1f); | |
530 | ||
531 | /* dsi configuration */ | |
532 | exynos_mipi_dsi_init_config(dsim); | |
533 | exynos_mipi_dsi_enable_lane(dsim, DSIM_LANE_CLOCK, 1); | |
534 | exynos_mipi_dsi_enable_lane(dsim, dsim->data_lane, 1); | |
535 | ||
536 | /* set clock configuration */ | |
537 | exynos_mipi_dsi_set_clock(dsim, | |
538 | dsim->dsim_config->e_byte_clk, 1); | |
539 | ||
540 | /* check clock and data lane state are stop state */ | |
541 | while (!(exynos_mipi_dsi_is_lane_state(dsim))) { | |
542 | time_out--; | |
543 | if (time_out == 0) { | |
544 | debug("DSI Master is not stop state.\n"); | |
545 | debug("Check initialization process\n"); | |
546 | ||
547 | return -EINVAL; | |
548 | } | |
549 | } | |
550 | ||
551 | dsim->state = DSIM_STATE_STOP; | |
552 | ||
553 | /* BTA sequence counters */ | |
554 | exynos_mipi_dsi_set_stop_state_counter(dsim, | |
555 | dsim->dsim_config->stop_holding_cnt); | |
556 | exynos_mipi_dsi_set_bta_timeout(dsim, | |
557 | dsim->dsim_config->bta_timeout); | |
558 | exynos_mipi_dsi_set_lpdr_timeout(dsim, | |
559 | dsim->dsim_config->rx_timeout); | |
560 | ||
561 | return 0; | |
562 | default: | |
563 | debug("DSI Master is already init.\n"); | |
564 | return 0; | |
565 | } | |
566 | ||
567 | return 0; | |
568 | } | |
569 | ||
570 | int exynos_mipi_dsi_set_hs_enable(struct mipi_dsim_device *dsim) | |
571 | { | |
572 | if (dsim->state == DSIM_STATE_STOP) { | |
573 | if (dsim->e_clk_src != DSIM_EXT_CLK_BYPASS) { | |
574 | dsim->state = DSIM_STATE_HSCLKEN; | |
575 | ||
576 | /* set LCDC and CPU transfer mode to HS. */ | |
577 | exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0); | |
578 | exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0); | |
579 | ||
580 | exynos_mipi_dsi_enable_hs_clock(dsim, 1); | |
581 | ||
582 | return 0; | |
583 | } else | |
584 | debug("clock source is external bypass.\n"); | |
585 | } else | |
586 | debug("DSIM is not stop state.\n"); | |
587 | ||
588 | return 0; | |
589 | } | |
590 | ||
591 | int exynos_mipi_dsi_set_data_transfer_mode(struct mipi_dsim_device *dsim, | |
592 | unsigned int mode) | |
593 | { | |
594 | if (mode) { | |
595 | if (dsim->state != DSIM_STATE_HSCLKEN) { | |
596 | debug("HS Clock lane is not enabled.\n"); | |
597 | return -EINVAL; | |
598 | } | |
599 | ||
600 | exynos_mipi_dsi_set_lcdc_transfer_mode(dsim, 0); | |
601 | } else { | |
602 | if (dsim->state == DSIM_STATE_INIT || dsim->state == | |
603 | DSIM_STATE_ULPS) { | |
604 | debug("DSI Master is not STOP or HSDT state.\n"); | |
605 | return -EINVAL; | |
606 | } | |
607 | ||
608 | exynos_mipi_dsi_set_cpu_transfer_mode(dsim, 0); | |
609 | } | |
610 | ||
611 | return 0; | |
612 | } | |
613 | ||
614 | int exynos_mipi_dsi_get_frame_done_status(struct mipi_dsim_device *dsim) | |
615 | { | |
616 | return _exynos_mipi_dsi_get_frame_done_status(dsim); | |
617 | } | |
618 | ||
619 | int exynos_mipi_dsi_clear_frame_done(struct mipi_dsim_device *dsim) | |
620 | { | |
621 | _exynos_mipi_dsi_clear_frame_done(dsim); | |
622 | ||
623 | return 0; | |
624 | } |