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