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