blob: 813746e01ec1633f9120825c4bc1adf7b7122dbb [file] [log] [blame]
Nickey Yangfe122d42017-04-27 09:38:06 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright 2017 Rockchip Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <arch/io.h>
17#include <assert.h>
18#include <console/console.h>
19#include <delay.h>
20#include <device/device.h>
21#include <edid.h>
22#include <gpio.h>
23#include <stdlib.h>
24#include <stdint.h>
25#include <string.h>
26#include <soc/addressmap.h>
27#include <soc/clock.h>
28#include <soc/display.h>
29#include <soc/mipi.h>
30#include <soc/soc.h>
31#include <timer.h>
32
Lin Huang25fb09b2017-11-22 09:40:50 +080033static struct rk_mipi_dsi rk_mipi[2] = {
34 { .mipi_regs = (void *)MIPI0_BASE},
35 { .mipi_regs = (void *)MIPI1_BASE}
36};
Nickey Yangfe122d42017-04-27 09:38:06 +080037
38/*
39 * The controller should generate 2 frames before
40 * preparing the peripheral.
41 */
42static void rk_mipi_dsi_wait_for_two_frames(struct rk_mipi_dsi *dsi,
43 const struct edid *edid)
44{
45 int two_frames;
46 unsigned int refresh = edid->mode.refresh;
47
48 two_frames = div_round_up(MSECS_PER_SEC * 2, refresh);
49 mdelay(two_frames);
50}
51
Lin Huang2e3ebb62017-10-30 17:40:19 +080052static const struct dphy_pll_parameter_map dppa_map[] = {
53 { 89, 0x00, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM},
54 { 99, 0x10, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM},
55 { 109, 0x20, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM},
56 { 129, 0x01, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
57 { 139, 0x11, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
58 { 149, 0x21, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
59 { 169, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
60 { 179, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
61 { 199, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
62 { 219, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
63 { 239, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
64 { 249, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
65 { 269, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
66 { 299, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
67 { 329, 0x05, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
68 { 359, 0x15, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
69 { 399, 0x25, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
70 { 449, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
71 { 499, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
72 { 549, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
73 { 599, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
74 { 649, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
75 { 699, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
76 { 749, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
77 { 799, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
78 { 849, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
79 { 899, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
80 { 949, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
81 { 999, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
82 {1049, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
83 {1099, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
84 {1149, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
85 {1199, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
86 {1249, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
87 {1299, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
88 {1349, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
89 {1399, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
90 {1449, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
91 {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM}
Nickey Yangfe122d42017-04-27 09:38:06 +080092};
93
Lin Huang2e3ebb62017-10-30 17:40:19 +080094static int max_mbps_to_parameter(unsigned int max_mbps)
Nickey Yangfe122d42017-04-27 09:38:06 +080095{
96 int i;
97
Lin Huang2e3ebb62017-10-30 17:40:19 +080098 for (i = 0; i < ARRAY_SIZE(dppa_map); i++) {
99 if (dppa_map[i].max_mbps >= max_mbps)
100 return i;
101 }
Nickey Yangfe122d42017-04-27 09:38:06 +0800102
103 return -1;
104}
105
106static void rk_mipi_dsi_phy_write(struct rk_mipi_dsi *dsi,
107 u8 test_code,
108 u8 test_data)
109{
110 /*
111 * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
112 * is latched internally as the current test code. Test data is
113 * programmed internally by rising edge on TESTCLK.
114 */
Lin Huang25fb09b2017-11-22 09:40:50 +0800115 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0,
116 PHY_TESTCLK | PHY_UNTESTCLR);
Nickey Yangfe122d42017-04-27 09:38:06 +0800117
Lin Huang25fb09b2017-11-22 09:40:50 +0800118 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl1,
119 PHY_TESTEN | PHY_TESTDOUT(0) | PHY_TESTDIN(test_code));
Nickey Yangfe122d42017-04-27 09:38:06 +0800120
Lin Huang25fb09b2017-11-22 09:40:50 +0800121 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0,
122 PHY_UNTESTCLK | PHY_UNTESTCLR);
Nickey Yangfe122d42017-04-27 09:38:06 +0800123
Lin Huang25fb09b2017-11-22 09:40:50 +0800124 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl1,
125 PHY_UNTESTEN | PHY_TESTDOUT(0) | PHY_TESTDIN(test_data));
Nickey Yangfe122d42017-04-27 09:38:06 +0800126
Lin Huang25fb09b2017-11-22 09:40:50 +0800127 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0,
128 PHY_TESTCLK | PHY_UNTESTCLR);
Nickey Yangfe122d42017-04-27 09:38:06 +0800129}
130
Lin Huang45f1b012017-11-02 17:53:30 +0800131/* bytes_per_ns - Nanoseconds to byte clock cycles */
132static inline unsigned int bytes_per_ns(struct rk_mipi_dsi *dsi, int ns)
133{
134 return DIV_ROUND_UP((u64)ns * dsi->lane_bps, (u64)8 * NSECS_PER_SEC);
135}
136
137 /* bits_per_ns - Nanoseconds to bit time periods */
138static inline unsigned int bits_per_ns(struct rk_mipi_dsi *dsi, int ns)
139{
140 return DIV_ROUND_UP((u64)ns * dsi->lane_bps, NSECS_PER_SEC);
141}
142
143static int rk_mipi_dsi_wait_phy_lock(struct rk_mipi_dsi *dsi)
144{
145 struct stopwatch sw;
146 int val;
147
148 stopwatch_init_msecs_expire(&sw, 20);
149 do {
Lin Huang25fb09b2017-11-22 09:40:50 +0800150 val = read32(&dsi->mipi_regs->dsi_phy_status);
Lin Huang45f1b012017-11-02 17:53:30 +0800151 if (val & LOCK)
152 return 0;
153 } while (!stopwatch_expired(&sw));
154
155 return -1;
156}
157
Nickey Yangfe122d42017-04-27 09:38:06 +0800158static int rk_mipi_dsi_phy_init(struct rk_mipi_dsi *dsi)
159{
Lin Huang45f1b012017-11-02 17:53:30 +0800160 int i, vco, val;
Nickey Yangfe122d42017-04-27 09:38:06 +0800161 int lane_mbps = div_round_up(dsi->lane_bps, USECS_PER_SEC);
Lin Huang45f1b012017-11-02 17:53:30 +0800162 struct stopwatch sw;
Lin Huang2e3ebb62017-10-30 17:40:19 +0800163
Nickey Yangfe122d42017-04-27 09:38:06 +0800164 vco = (lane_mbps < 200) ? 0 : (lane_mbps + 100) / 200;
165
Lin Huang2e3ebb62017-10-30 17:40:19 +0800166 i = max_mbps_to_parameter(lane_mbps);
167 if (i < 0) {
168 printk(BIOS_DEBUG,
169 "failed to get parameter for %dmbps clock\n", lane_mbps);
170 return i;
Nickey Yangfe122d42017-04-27 09:38:06 +0800171 }
172
173 /* Start by clearing PHY state */
Lin Huang25fb09b2017-11-22 09:40:50 +0800174 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0, PHY_UNTESTCLR);
175 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0, PHY_TESTCLR);
176 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0, PHY_UNTESTCLR);
Nickey Yangfe122d42017-04-27 09:38:06 +0800177
178 rk_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
179 BYPASS_VCO_RANGE |
180 VCO_RANGE_CON_SEL(vco) |
181 VCO_IN_CAP_CON_LOW |
182 REF_BIAS_CUR_SEL);
183
184 rk_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
Lin Huang2e3ebb62017-10-30 17:40:19 +0800185 CP_CURRENT_SEL(dppa_map[i].icpctrl));
Nickey Yangfe122d42017-04-27 09:38:06 +0800186 rk_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
187 CP_PROGRAM_EN |
188 LPF_PROGRAM_EN |
Lin Huang2e3ebb62017-10-30 17:40:19 +0800189 LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
Nickey Yangfe122d42017-04-27 09:38:06 +0800190 rk_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
Lin Huang2e3ebb62017-10-30 17:40:19 +0800191 HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
192
Nickey Yangfe122d42017-04-27 09:38:06 +0800193 rk_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
194 INPUT_DIVIDER(dsi->input_div));
195 rk_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
196 LOOP_DIV_LOW_SEL(dsi->feedback_div) |
197 LOW_PROGRAM_EN);
Lin Huangf4acb922017-11-16 10:03:47 +0800198
199 /*
200 * we need set divider control register immediately to make
201 * the configured LSB effective according to IP simulation
202 * and lab test results. Only in this way can we get correct
203 * mipi phy pll frequency.
204 */
205 rk_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
206 PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
Nickey Yangfe122d42017-04-27 09:38:06 +0800207 rk_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
208 LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
209 HIGH_PROGRAM_EN);
210 rk_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
211 PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
212 rk_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
213 LOW_PROGRAM_EN |
214 BIASEXTR_SEL(BIASEXTR_127_7));
215 rk_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
216 HIGH_PROGRAM_EN |
217 BANDGAP_SEL(BANDGAP_96_10));
218 rk_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
219 POWER_CONTROL | INTERNAL_REG_CURRENT |
220 BIAS_BLOCK_ON | BANDGAP_ON);
221 rk_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
222 TER_RESISTOR_LOW | TER_CAL_DONE |
223 SETRD_MAX | TER_RESISTORS_ON);
224 rk_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
225 TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
226 SETRD_MAX | POWER_MANAGE |
227 TER_RESISTORS_ON);
Lin Huang45f1b012017-11-02 17:53:30 +0800228 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
229 TLP_PROGRAM_EN | bytes_per_ns(dsi, 500));
230 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
231 THS_PRE_PROGRAM_EN | bits_per_ns(dsi, 40));
232 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
233 THS_ZERO_PROGRAM_EN | bytes_per_ns(dsi, 300));
234 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
235 THS_PRE_PROGRAM_EN | bits_per_ns(dsi, 100));
236 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
237 BIT(5) | bytes_per_ns(dsi, 100));
238 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
239 BIT(5) | (bytes_per_ns(dsi, 60) + 7));
240 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
241 TLP_PROGRAM_EN | bytes_per_ns(dsi, 500));
242 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
243 THS_PRE_PROGRAM_EN | (bits_per_ns(dsi, 50) + 5));
244 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
245 THS_ZERO_PROGRAM_EN |
246 (bytes_per_ns(dsi, 140) + 2));
247 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
248 THS_PRE_PROGRAM_EN | (bits_per_ns(dsi, 60) + 8));
249 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
250 BIT(5) | bytes_per_ns(dsi, 100));
Nickey Yangfe122d42017-04-27 09:38:06 +0800251
Lin Huang25fb09b2017-11-22 09:40:50 +0800252 write32(&dsi->mipi_regs->dsi_phy_rstz,
253 PHY_ENFORCEPLL | PHY_ENABLECLK |
254 PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
Lin Huang45f1b012017-11-02 17:53:30 +0800255
256 if (rk_mipi_dsi_wait_phy_lock(dsi)) {
257 printk(BIOS_ERR, "failed to wait for phy lock state\n");
258 return -1;
259 }
260
261 stopwatch_init_msecs_expire(&sw, 20);
262 do {
Lin Huang25fb09b2017-11-22 09:40:50 +0800263 val = read32(&dsi->mipi_regs->dsi_phy_status);
Lin Huang45f1b012017-11-02 17:53:30 +0800264 if (val & STOP_STATE_CLK_LANE)
265 return 0;
266 } while (!stopwatch_expired(&sw));
267
268 printk(BIOS_ERR, "failed to wait for phy clk lane stop state");
269 return -1;
Nickey Yangfe122d42017-04-27 09:38:06 +0800270}
271
272static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
273{
274 switch (fmt) {
275 case MIPI_DSI_FMT_RGB888:
276 case MIPI_DSI_FMT_RGB666:
277 return 24;
278
279 case MIPI_DSI_FMT_RGB666_PACKED:
280 return 18;
281
282 case MIPI_DSI_FMT_RGB565:
283 return 16;
284 }
285
286 return -1;
287}
288
289static int rk_mipi_dsi_get_lane_bps(struct rk_mipi_dsi *dsi,
Lin Huang25fb09b2017-11-22 09:40:50 +0800290 const struct edid *edid,
291 const struct mipi_panel_data *panel_data)
Nickey Yangfe122d42017-04-27 09:38:06 +0800292{
Lin Huangf4acb922017-11-16 10:03:47 +0800293 u64 pclk, target_bps;
Lin Huang2e3ebb62017-10-30 17:40:19 +0800294 u32 max_bps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps * MHz;
Nickey Yangfe122d42017-04-27 09:38:06 +0800295 int bpp;
Lin Huangf4acb922017-11-16 10:03:47 +0800296 u64 best_freq = 0;
297 u64 fvco_min, fvco_max, fref;
298 u32 min_prediv, max_prediv;
299 u32 prediv, best_prediv;
300 u64 fbdiv, best_fbdiv;
301 u32 min_delta;
Nickey Yangfe122d42017-04-27 09:38:06 +0800302
303 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
304 if (bpp < 0) {
305 printk(BIOS_DEBUG, "failed to get bpp for pixel format %d\n",
306 dsi->format);
307 return bpp;
308 }
309 pclk = edid->mode.pixel_clock * MSECS_PER_SEC;
Lin Huangf4acb922017-11-16 10:03:47 +0800310
Nickey Yangfe122d42017-04-27 09:38:06 +0800311 /* take 1 / 0.8, since mbps must bigger than bandwidth of RGB */
Lin Huang25fb09b2017-11-22 09:40:50 +0800312 target_bps = pclk / panel_data->lanes * bpp / 8 * 10;
Nickey Yangfe122d42017-04-27 09:38:06 +0800313 if (target_bps >= max_bps) {
314 printk(BIOS_DEBUG, "DPHY clock frequency is out of range\n");
315 return -1;
316 }
Lin Huangf4acb922017-11-16 10:03:47 +0800317
318 fref = OSC_HZ;
319
320 /* constraint: 5Mhz <= Fref / N <= 40MHz */
321 min_prediv = div_round_up(fref, 40 * MHz);
322 max_prediv = fref / (5 * MHz);
323
324 /* constraint: 80MHz <= Fvco <= 1500Mhz */
325 fvco_min = 80 * MHz;
326 fvco_max = 1500 * MHz;
327 min_delta = 1500 * MHz;
328
329 for (prediv = min_prediv; prediv <= max_prediv; prediv++) {
330 u64 freq;
331 int delta;
332
333 /* Fvco = Fref * M / N */
334 fbdiv = target_bps * prediv / fref;
335
336 /*
337 * Due to the use of a "by 2 pre-scaler", the range of the
338 * feedback multiplication value M is limited to even division
339 * numbers, and m must be in 6 <= m <= 512.
340 */
341 fbdiv += fbdiv % 2;
342 if (fbdiv < 6 || fbdiv > 512)
343 continue;
344
345 freq = (u64)fbdiv * fref / prediv;
346 if (freq < fvco_min || freq > fvco_max)
347 continue;
348
349 delta = target_bps - freq;
350 delta = ABS(delta);
351 if (delta >= min_delta)
352 continue;
353
354 best_prediv = prediv;
355 best_fbdiv = fbdiv;
356 min_delta = delta;
357 best_freq = freq;
Nickey Yangfe122d42017-04-27 09:38:06 +0800358 }
Lin Huangf4acb922017-11-16 10:03:47 +0800359
360 if (best_freq) {
361 dsi->lane_bps = best_freq;
362 dsi->input_div = best_prediv;
363 dsi->feedback_div = best_fbdiv;
364 } else {
365 printk(BIOS_ERR, "Can not find best_freq for DPHY\n");
366 return -1;
367 }
Nickey Yangfe122d42017-04-27 09:38:06 +0800368
369 return 0;
370}
371
372static void rk_mipi_dsi_dpi_config(struct rk_mipi_dsi *dsi)
373{
374 u32 color = 0;
375
376 switch (dsi->format) {
377 case MIPI_DSI_FMT_RGB888:
378 color = DPI_COLOR_CODING_24BIT;
379 break;
380 case MIPI_DSI_FMT_RGB666:
381 color = DPI_COLOR_CODING_18BIT_2 | EN18_LOOSELY;
382 break;
383 case MIPI_DSI_FMT_RGB666_PACKED:
384 color = DPI_COLOR_CODING_18BIT_1;
385 break;
386 case MIPI_DSI_FMT_RGB565:
387 color = DPI_COLOR_CODING_16BIT_1;
388 break;
389 }
390
Lin Huang25fb09b2017-11-22 09:40:50 +0800391 write32(&dsi->mipi_regs->dsi_dpi_vcid, 0);
392 write32(&dsi->mipi_regs->dsi_dpi_color_coding, color);
Nickey Yangfe122d42017-04-27 09:38:06 +0800393
Lin Huang25fb09b2017-11-22 09:40:50 +0800394 write32(&dsi->mipi_regs->dsi_dpi_cfg_pol, 0);
Nickey Yangfe122d42017-04-27 09:38:06 +0800395
Lin Huang25fb09b2017-11-22 09:40:50 +0800396 write32(&dsi->mipi_regs->dsi_dpi_lp_cmd_tim,
397 OUTVACT_LPCMD_TIME(4) | INVACT_LPCMD_TIME(4));
Nickey Yangfe122d42017-04-27 09:38:06 +0800398}
399
400static void rk_mipi_dsi_packet_handler_config(struct rk_mipi_dsi *dsi)
401{
Lin Huang25fb09b2017-11-22 09:40:50 +0800402 write32(&dsi->mipi_regs->dsi_pckhdl_cfg,
403 EN_CRC_RX | EN_ECC_RX | EN_BTA);
Nickey Yangfe122d42017-04-27 09:38:06 +0800404}
405
406static void rk_mipi_dsi_video_mode_config(struct rk_mipi_dsi *dsi)
407{
Lin Huang25fb09b2017-11-22 09:40:50 +0800408 write32(&dsi->mipi_regs->dsi_vid_mode_cfg,
Nickey Yangfe122d42017-04-27 09:38:06 +0800409 VID_MODE_TYPE_BURST_SYNC_PULSES | ENABLE_LOW_POWER);
410}
411
Lin Huang25fb09b2017-11-22 09:40:50 +0800412static void rk_mipi_dsi_video_packet_config(struct rk_mipi_dsi *dsi,
413 const struct edid *edid,
414 const struct mipi_panel_data *panel_data)
Nickey Yangfe122d42017-04-27 09:38:06 +0800415{
Lin Huang25fb09b2017-11-22 09:40:50 +0800416 int pkt_size;
417
418 if (panel_data->mipi_num > 1)
419 pkt_size = VID_PKT_SIZE(edid->mode.ha / 2 + 4);
420 else
421 pkt_size = VID_PKT_SIZE(edid->mode.ha);
422
423 write32(&dsi->mipi_regs->dsi_vid_pkt_size, pkt_size);
Nickey Yangfe122d42017-04-27 09:38:06 +0800424}
425
426static void rk_mipi_dsi_command_mode_config(struct rk_mipi_dsi *dsi)
427{
Lin Huang25fb09b2017-11-22 09:40:50 +0800428 write32(&dsi->mipi_regs->dsi_to_cnt_cfg,
Nickey Yangfe122d42017-04-27 09:38:06 +0800429 HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000));
Lin Huang25fb09b2017-11-22 09:40:50 +0800430 write32(&dsi->mipi_regs->dsi_bta_to_cnt, 0xd00);
431 write32(&dsi->mipi_regs->dsi_cmd_mode_cfg, CMD_MODE_ALL_LP);
432 write32(&dsi->mipi_regs->dsi_mode_cfg, ENABLE_CMD_MODE);
Nickey Yangfe122d42017-04-27 09:38:06 +0800433}
434
435/* Get lane byte clock cycles. */
436static u32 rk_mipi_dsi_get_hcomponent_lbcc(struct rk_mipi_dsi *dsi,
437 u32 hcomponent,
438 const struct edid *edid)
439{
440 u32 lbcc;
441 u64 lbcc_tmp;
442
443 lbcc_tmp = hcomponent * dsi->lane_bps / (8 * MSECS_PER_SEC);
444 lbcc = div_round_up(lbcc_tmp, edid->mode.pixel_clock);
445
446 return lbcc;
447}
448
449static void rk_mipi_dsi_line_timer_config(struct rk_mipi_dsi *dsi,
450 const struct edid *edid)
451{
452 u32 htotal, hsa, hbp, lbcc;
453
454 htotal = edid->mode.ha + edid->mode.hbl;
455 hsa = edid->mode.hspw;
456 hbp = edid->mode.hbl - edid->mode.hso - edid->mode.hspw;
457
458 lbcc = rk_mipi_dsi_get_hcomponent_lbcc(dsi, htotal, edid);
Lin Huang25fb09b2017-11-22 09:40:50 +0800459 write32(&dsi->mipi_regs->dsi_vid_hline_time, lbcc);
Nickey Yangfe122d42017-04-27 09:38:06 +0800460
461 lbcc = rk_mipi_dsi_get_hcomponent_lbcc(dsi, hsa, edid);
Lin Huang25fb09b2017-11-22 09:40:50 +0800462 write32(&dsi->mipi_regs->dsi_vid_hsa_time, lbcc);
Nickey Yangfe122d42017-04-27 09:38:06 +0800463 lbcc = rk_mipi_dsi_get_hcomponent_lbcc(dsi, hbp, edid);
Lin Huang25fb09b2017-11-22 09:40:50 +0800464 write32(&dsi->mipi_regs->dsi_vid_hbp_time, lbcc);
Nickey Yangfe122d42017-04-27 09:38:06 +0800465}
466
467static void rk_mipi_dsi_vertical_timing_config(struct rk_mipi_dsi *dsi,
468 const struct edid *edid)
469{
470 u32 vactive, vsa, vfp, vbp;
471
472 vactive = edid->mode.va;
473 vsa = edid->mode.vspw;
474 vfp = edid->mode.vso;
475 vbp = edid->mode.vbl - edid->mode.vso - edid->mode.vspw;
476
Lin Huang25fb09b2017-11-22 09:40:50 +0800477 write32(&dsi->mipi_regs->dsi_vid_vactive_lines, vactive);
478 write32(&dsi->mipi_regs->dsi_vid_vsa_lines, vsa);
479 write32(&dsi->mipi_regs->dsi_vid_vfp_lines, vfp);
480 write32(&dsi->mipi_regs->dsi_vid_vbp_lines, vbp);
Nickey Yangfe122d42017-04-27 09:38:06 +0800481}
482
483static void rk_mipi_dsi_dphy_timing_config(struct rk_mipi_dsi *dsi)
484{
485 /*
486 * HS-PREPARE: 40ns + 4 * UI ~ 85ns + 6 * UI
487 * HS-EXIT: 100ns
488 */
Lin Huang25fb09b2017-11-22 09:40:50 +0800489 write32(&dsi->mipi_regs->dsi_phy_tmr_cfg, PHY_HS2LP_TIME(0x40) |
Nickey Yangfe122d42017-04-27 09:38:06 +0800490 PHY_LP2HS_TIME(0x40) |
491 MAX_RD_TIME(10000));
492
Lin Huang25fb09b2017-11-22 09:40:50 +0800493 write32(&dsi->mipi_regs->dsi_phy_tmr_lpclk_cfg,
494 PHY_CLKHS2LP_TIME(0x40) | PHY_CLKLP2HS_TIME(0x40));
Nickey Yangfe122d42017-04-27 09:38:06 +0800495}
496
497static void rk_mipi_dsi_clear_err(struct rk_mipi_dsi *dsi)
498{
Lin Huang25fb09b2017-11-22 09:40:50 +0800499 read32(&dsi->mipi_regs->dsi_int_st0);
500 read32(&dsi->mipi_regs->dsi_int_st1);
501 write32(&dsi->mipi_regs->dsi_int_msk0, 0);
502 write32(&dsi->mipi_regs->dsi_int_msk1, 0);
Nickey Yangfe122d42017-04-27 09:38:06 +0800503}
504
505static void rk_mipi_dsi_dphy_interface_config(struct rk_mipi_dsi *dsi)
506{
Lin Huang25fb09b2017-11-22 09:40:50 +0800507 write32(&dsi->mipi_regs->dsi_phy_if_cfg, PHY_STOP_WAIT_TIME(0x20) |
Nickey Yangfe122d42017-04-27 09:38:06 +0800508 N_LANES(dsi->lanes));
509}
510
511static void rk_mipi_dsi_set_mode(struct rk_mipi_dsi *dsi,
512 enum rk_mipi_dsi_mode mode)
513{
Lin Huang25fb09b2017-11-22 09:40:50 +0800514 write32(&dsi->mipi_regs->dsi_pwr_up, RESET);
Nickey Yangfe122d42017-04-27 09:38:06 +0800515 if (mode == MIPI_DSI_CMD_MODE) {
Lin Huang25fb09b2017-11-22 09:40:50 +0800516 write32(&dsi->mipi_regs->dsi_mode_cfg, ENABLE_CMD_MODE);
Nickey Yangfe122d42017-04-27 09:38:06 +0800517 } else {
Lin Huang25fb09b2017-11-22 09:40:50 +0800518 write32(&dsi->mipi_regs->dsi_mode_cfg, ENABLE_VIDEO_MODE);
Nickey Yangfe122d42017-04-27 09:38:06 +0800519 rk_mipi_dsi_video_mode_config(dsi);
Lin Huang25fb09b2017-11-22 09:40:50 +0800520 write32(&dsi->mipi_regs->dsi_lpclk_ctrl, PHY_TXREQUESTCLKHS);
Nickey Yangfe122d42017-04-27 09:38:06 +0800521 }
Lin Huang25fb09b2017-11-22 09:40:50 +0800522 write32(&dsi->mipi_regs->dsi_pwr_up, POWERUP);
Nickey Yangfe122d42017-04-27 09:38:06 +0800523}
524
525static void rk_mipi_dsi_init(struct rk_mipi_dsi *dsi)
526{
527 /*
528 * The maximum permitted escape clock is 20MHz and it is derived from
529 * lanebyteclk, which is running at "lane_mbps / 8". Thus we want:
530 *
531 * (lane_mbps >> 3) / esc_clk_division < 20
532 * which is:
533 * (lane_mbps >> 3) / 20 > esc_clk_division
534 */
Lin Huang25fb09b2017-11-22 09:40:50 +0800535 u32 esc_clk_division = div_round_up(dsi->lane_bps,
536 8 * 20 * USECS_PER_SEC);
Nickey Yangfe122d42017-04-27 09:38:06 +0800537
Lin Huang25fb09b2017-11-22 09:40:50 +0800538 write32(&dsi->mipi_regs->dsi_pwr_up, RESET);
539 write32(&dsi->mipi_regs->dsi_phy_rstz,
540 PHY_DISFORCEPLL | PHY_DISABLECLK | PHY_RSTZ | PHY_SHUTDOWNZ);
541 write32(&dsi->mipi_regs->dsi_clk_cfg,
Nickey Yangfe122d42017-04-27 09:38:06 +0800542 TO_CLK_DIVIDSION(10) |
543 TX_ESC_CLK_DIVIDSION(esc_clk_division));
544}
545
Lin Huang538b9ef2017-11-01 10:22:49 +0800546static void rk_mipi_message_config(struct rk_mipi_dsi *dsi)
Nickey Yangfe122d42017-04-27 09:38:06 +0800547{
Lin Huang25fb09b2017-11-22 09:40:50 +0800548 write32(&dsi->mipi_regs->dsi_lpclk_ctrl, 0);
549 write32(&dsi->mipi_regs->dsi_cmd_mode_cfg, CMD_MODE_ALL_LP);
Lin Huang538b9ef2017-11-01 10:22:49 +0800550}
551
Lin Huang0499ce92018-01-17 14:24:14 +0800552static int rk_mipi_dsi_check_fifo(struct rk_mipi_dsi *dsi, u32 flag)
Lin Huang538b9ef2017-11-01 10:22:49 +0800553{
554 struct stopwatch sw;
555 int val;
556
557 stopwatch_init_msecs_expire(&sw, 20);
558 do {
Lin Huang25fb09b2017-11-22 09:40:50 +0800559 val = read32(&dsi->mipi_regs->dsi_cmd_pkt_status);
Lin Huang0499ce92018-01-17 14:24:14 +0800560 if (!(val & flag))
Lin Huang538b9ef2017-11-01 10:22:49 +0800561 return 0 ;
562 } while (!stopwatch_expired(&sw));
563
564 return -1;
565}
566
567static int rk_mipi_dsi_gen_pkt_hdr_write(struct rk_mipi_dsi *dsi, u32 hdr_val)
568{
569 int val;
570 struct stopwatch sw;
571 u32 mask;
572
Lin Huang0499ce92018-01-17 14:24:14 +0800573 if (rk_mipi_dsi_check_fifo(dsi, GEN_CMD_FULL)) {
Lin Huang538b9ef2017-11-01 10:22:49 +0800574 printk(BIOS_ERR, "failed to get available command FIFO\n");
575 return -1;
576 }
577
Lin Huang25fb09b2017-11-22 09:40:50 +0800578 write32(&dsi->mipi_regs->dsi_gen_hdr, hdr_val);
Nickey Yangfe122d42017-04-27 09:38:06 +0800579
Lin Huang538b9ef2017-11-01 10:22:49 +0800580 mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY;
581 stopwatch_init_msecs_expire(&sw, 20);
582 do {
Lin Huang25fb09b2017-11-22 09:40:50 +0800583 val = read32(&dsi->mipi_regs->dsi_cmd_pkt_status);
Lin Huang538b9ef2017-11-01 10:22:49 +0800584 if ((val & mask) == mask)
585 return 0 ;
586 } while (!stopwatch_expired(&sw));
587 printk(BIOS_ERR, "failed to write command FIFO\n");
588
589 return -1;
590}
591
592static int rk_mipi_dsi_dcs_cmd(struct rk_mipi_dsi *dsi, u8 cmd)
593{
594 u32 val;
595
596 rk_mipi_message_config(dsi);
597
598 val = GEN_HDATA(cmd) | GEN_HTYPE(MIPI_DSI_DCS_SHORT_WRITE);
599
600 return rk_mipi_dsi_gen_pkt_hdr_write(dsi, val);
Nickey Yangfe122d42017-04-27 09:38:06 +0800601}
602
Lin Huang0499ce92018-01-17 14:24:14 +0800603static int rk_mipi_dsi_dci_long_write(struct rk_mipi_dsi *dsi,
604 char *data, u32 len)
Nickey Yangfe122d42017-04-27 09:38:06 +0800605{
Lin Huang0499ce92018-01-17 14:24:14 +0800606 u32 remainder;
607 int ret = 0;
608
609 while (len) {
610 if (len < 4) {
611 remainder = 0;
612 memcpy(&remainder, data, len);
613 write32(&dsi->mipi_regs->dsi_gen_pld_data, remainder);
614 len = 0;
615 } else {
616 remainder = *(u32 *)data;
617 write32(&dsi->mipi_regs->dsi_gen_pld_data, remainder);
618 data += 4;
619 len -= 4;
620 }
621
622 ret = rk_mipi_dsi_check_fifo(dsi, GEN_PLD_W_FULL);
623 if (ret) {
624 printk(BIOS_ERR, "Failed to write fifo\n");
625 return ret;
626 }
627 }
628
629 return ret;
630}
631
632static int rk_mipi_dsi_write(struct rk_mipi_dsi *dsi, char *data, int len)
633{
634 u16 buf = 0;
Lin Huang25fb09b2017-11-22 09:40:50 +0800635 u32 val;
Lin Huang0499ce92018-01-17 14:24:14 +0800636 int ret = 0;
Lin Huang25fb09b2017-11-22 09:40:50 +0800637
638 rk_mipi_message_config(dsi);
639
Lin Huang0499ce92018-01-17 14:24:14 +0800640 switch (len) {
641 case 0:
642 die("not data!");
643 case 1:
644 val = GEN_HDATA(*data) |
645 GEN_HTYPE(MIPI_DSI_DCS_SHORT_WRITE);
646 break;
647 case 2:
648 buf = *data++;
649 buf |= *data << 8;
650 val = GEN_HDATA(buf) |
651 GEN_HTYPE(MIPI_DSI_DCS_SHORT_WRITE_PARAM);
652 break;
653 default:
654 ret = rk_mipi_dsi_dci_long_write(dsi, data, len);
655 if (ret) {
656 printk(BIOS_ERR, "error happened during long write\n");
657 return ret;
658 }
659 val = GEN_HDATA(len) | GEN_HTYPE(MIPI_DSI_DCS_LONG_WRITE);
660 break;
661 }
Lin Huang25fb09b2017-11-22 09:40:50 +0800662
663 return rk_mipi_dsi_gen_pkt_hdr_write(dsi, val);
664}
665
666static void rk_mipi_enable(struct rk_mipi_dsi *dsi,
667 const struct edid *edid,
668 const struct mipi_panel_data *panel_data)
669{
670 if (rk_mipi_dsi_get_lane_bps(dsi, edid, panel_data) < 0)
Nickey Yangfe122d42017-04-27 09:38:06 +0800671 return;
672
Lin Huang25fb09b2017-11-22 09:40:50 +0800673 rk_mipi_dsi_init(dsi);
674 rk_mipi_dsi_dpi_config(dsi);
675 rk_mipi_dsi_packet_handler_config(dsi);
676 rk_mipi_dsi_video_mode_config(dsi);
677 rk_mipi_dsi_video_packet_config(dsi, edid, panel_data);
678 rk_mipi_dsi_command_mode_config(dsi);
679 rk_mipi_dsi_line_timer_config(dsi, edid);
680 rk_mipi_dsi_vertical_timing_config(dsi, edid);
681 rk_mipi_dsi_dphy_timing_config(dsi);
682 rk_mipi_dsi_dphy_interface_config(dsi);
683 rk_mipi_dsi_clear_err(dsi);
684 if (rk_mipi_dsi_phy_init(dsi) < 0)
Nickey Yang5be0b2e2017-05-25 11:23:23 +0800685 return;
Lin Huang25fb09b2017-11-22 09:40:50 +0800686 rk_mipi_dsi_wait_for_two_frames(dsi, edid);
Nickey Yangfe122d42017-04-27 09:38:06 +0800687
Lin Huang25fb09b2017-11-22 09:40:50 +0800688 rk_mipi_dsi_set_mode(dsi, MIPI_DSI_CMD_MODE);
689}
Lin Huang538b9ef2017-11-01 10:22:49 +0800690
Lin Huang25fb09b2017-11-22 09:40:50 +0800691void rk_mipi_prepare(const struct edid *edid,
692 const struct mipi_panel_data *panel_data)
693{
694 int i, num;
Lin Huang0499ce92018-01-17 14:24:14 +0800695 struct panel_init_command *cmds;
Lin Huang538b9ef2017-11-01 10:22:49 +0800696
Lin Huang25fb09b2017-11-22 09:40:50 +0800697 for (i = 0; i < panel_data->mipi_num; i++) {
698 rk_mipi[i].lanes = panel_data->lanes / panel_data->mipi_num;
699 rk_mipi[i].format = panel_data->format;
700 rk_mipi_enable(&rk_mipi[i], edid, panel_data);
701 }
Nickey Yangfe122d42017-04-27 09:38:06 +0800702
Lin Huang0499ce92018-01-17 14:24:14 +0800703 if (panel_data->init_cmd) {
704 cmds = panel_data->init_cmd;
705 for (num = 0; cmds[num].len != 0; num++) {
706 struct panel_init_command *cmd = &cmds[num];
707 for (i = 0; i < panel_data->mipi_num; i++) {
708 if (rk_mipi_dsi_write(&rk_mipi[i], cmd->data,
709 cmd->len))
710 return;
711
712 /* make sure panel picks up the command */
713 if (rk_mipi_dsi_dcs_cmd(&rk_mipi[i],
714 MIPI_DCS_NOP))
715 return;
716 }
717 }
Lin Huang25fb09b2017-11-22 09:40:50 +0800718 }
719
720 for (i = 0; i < panel_data->mipi_num; i++) {
721 if (rk_mipi_dsi_dcs_cmd(&rk_mipi[i],
722 MIPI_DCS_EXIT_SLEEP_MODE) < 0)
723 return;
724 }
725 udelay(panel_data->display_on_udelay);
726 for (i = 0; i < panel_data->mipi_num; i++) {
727 if (rk_mipi_dsi_dcs_cmd(&rk_mipi[i],
728 MIPI_DCS_SET_DISPLAY_ON) < 0)
729 return;
730 }
731 udelay(panel_data->video_mode_udelay);
732 for (i = 0; i < panel_data->mipi_num; i++)
733 rk_mipi_dsi_set_mode(&rk_mipi[i], MIPI_DSI_VID_MODE);
Nickey Yangfe122d42017-04-27 09:38:06 +0800734}