blob: d679cfe5ccf7d8b09309343d7b59d1eaaa6b4999 [file] [log] [blame]
Angel Ponsbbc99cf2020-04-04 18:51:23 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Nickey Yangfe122d42017-04-27 09:38:06 +08002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Nickey Yangfe122d42017-04-27 09:38:06 +08004#include <console/console.h>
5#include <delay.h>
6#include <device/device.h>
7#include <edid.h>
8#include <gpio.h>
Nickey Yangfe122d42017-04-27 09:38:06 +08009#include <string.h>
10#include <soc/addressmap.h>
11#include <soc/clock.h>
12#include <soc/display.h>
13#include <soc/mipi.h>
14#include <soc/soc.h>
Elyes HAOUAS27d02d82019-05-15 21:11:39 +020015#include <types.h>
Nickey Yangfe122d42017-04-27 09:38:06 +080016#include <timer.h>
17
Lin Huang25fb09b2017-11-22 09:40:50 +080018static struct rk_mipi_dsi rk_mipi[2] = {
19 { .mipi_regs = (void *)MIPI0_BASE},
20 { .mipi_regs = (void *)MIPI1_BASE}
21};
Nickey Yangfe122d42017-04-27 09:38:06 +080022
23/*
24 * The controller should generate 2 frames before
25 * preparing the peripheral.
26 */
27static void rk_mipi_dsi_wait_for_two_frames(struct rk_mipi_dsi *dsi,
28 const struct edid *edid)
29{
30 int two_frames;
31 unsigned int refresh = edid->mode.refresh;
32
Elyes HAOUAS6df3b642018-11-26 22:53:49 +010033 two_frames = DIV_ROUND_UP(MSECS_PER_SEC * 2, refresh);
Nickey Yangfe122d42017-04-27 09:38:06 +080034 mdelay(two_frames);
35}
36
Lin Huang2e3ebb62017-10-30 17:40:19 +080037static const struct dphy_pll_parameter_map dppa_map[] = {
38 { 89, 0x00, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM},
39 { 99, 0x10, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM},
40 { 109, 0x20, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM},
41 { 129, 0x01, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
42 { 139, 0x11, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
43 { 149, 0x21, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
44 { 169, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
45 { 179, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
46 { 199, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM},
47 { 219, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
48 { 239, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
49 { 249, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM},
50 { 269, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
51 { 299, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM},
52 { 329, 0x05, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
53 { 359, 0x15, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
54 { 399, 0x25, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM},
55 { 449, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
56 { 499, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
57 { 549, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
58 { 599, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM},
59 { 649, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
60 { 699, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
61 { 749, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
62 { 799, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
63 { 849, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
64 { 899, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM},
65 { 949, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
66 { 999, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
67 {1049, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
68 {1099, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM},
69 {1149, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
70 {1199, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
71 {1249, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
72 {1299, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
73 {1349, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
74 {1399, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
75 {1449, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM},
76 {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM}
Nickey Yangfe122d42017-04-27 09:38:06 +080077};
78
Lin Huang2e3ebb62017-10-30 17:40:19 +080079static int max_mbps_to_parameter(unsigned int max_mbps)
Nickey Yangfe122d42017-04-27 09:38:06 +080080{
81 int i;
82
Lin Huang2e3ebb62017-10-30 17:40:19 +080083 for (i = 0; i < ARRAY_SIZE(dppa_map); i++) {
84 if (dppa_map[i].max_mbps >= max_mbps)
85 return i;
86 }
Nickey Yangfe122d42017-04-27 09:38:06 +080087
88 return -1;
89}
90
91static void rk_mipi_dsi_phy_write(struct rk_mipi_dsi *dsi,
92 u8 test_code,
93 u8 test_data)
94{
95 /*
96 * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
97 * is latched internally as the current test code. Test data is
98 * programmed internally by rising edge on TESTCLK.
99 */
Lin Huang25fb09b2017-11-22 09:40:50 +0800100 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0,
101 PHY_TESTCLK | PHY_UNTESTCLR);
Nickey Yangfe122d42017-04-27 09:38:06 +0800102
Lin Huang25fb09b2017-11-22 09:40:50 +0800103 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl1,
104 PHY_TESTEN | PHY_TESTDOUT(0) | PHY_TESTDIN(test_code));
Nickey Yangfe122d42017-04-27 09:38:06 +0800105
Lin Huang25fb09b2017-11-22 09:40:50 +0800106 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0,
107 PHY_UNTESTCLK | PHY_UNTESTCLR);
Nickey Yangfe122d42017-04-27 09:38:06 +0800108
Lin Huang25fb09b2017-11-22 09:40:50 +0800109 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl1,
110 PHY_UNTESTEN | PHY_TESTDOUT(0) | PHY_TESTDIN(test_data));
Nickey Yangfe122d42017-04-27 09:38:06 +0800111
Lin Huang25fb09b2017-11-22 09:40:50 +0800112 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0,
113 PHY_TESTCLK | PHY_UNTESTCLR);
Nickey Yangfe122d42017-04-27 09:38:06 +0800114}
115
Lin Huang45f1b012017-11-02 17:53:30 +0800116/* bytes_per_ns - Nanoseconds to byte clock cycles */
117static inline unsigned int bytes_per_ns(struct rk_mipi_dsi *dsi, int ns)
118{
119 return DIV_ROUND_UP((u64)ns * dsi->lane_bps, (u64)8 * NSECS_PER_SEC);
120}
121
122 /* bits_per_ns - Nanoseconds to bit time periods */
123static inline unsigned int bits_per_ns(struct rk_mipi_dsi *dsi, int ns)
124{
125 return DIV_ROUND_UP((u64)ns * dsi->lane_bps, NSECS_PER_SEC);
126}
127
128static int rk_mipi_dsi_wait_phy_lock(struct rk_mipi_dsi *dsi)
129{
130 struct stopwatch sw;
131 int val;
132
133 stopwatch_init_msecs_expire(&sw, 20);
134 do {
Lin Huang25fb09b2017-11-22 09:40:50 +0800135 val = read32(&dsi->mipi_regs->dsi_phy_status);
Lin Huang45f1b012017-11-02 17:53:30 +0800136 if (val & LOCK)
137 return 0;
138 } while (!stopwatch_expired(&sw));
139
140 return -1;
141}
142
Nickey Yangfe122d42017-04-27 09:38:06 +0800143static int rk_mipi_dsi_phy_init(struct rk_mipi_dsi *dsi)
144{
Lin Huang45f1b012017-11-02 17:53:30 +0800145 int i, vco, val;
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100146 int lane_mbps = DIV_ROUND_UP(dsi->lane_bps, USECS_PER_SEC);
Lin Huang45f1b012017-11-02 17:53:30 +0800147 struct stopwatch sw;
Lin Huang2e3ebb62017-10-30 17:40:19 +0800148
Nickey Yangfe122d42017-04-27 09:38:06 +0800149 vco = (lane_mbps < 200) ? 0 : (lane_mbps + 100) / 200;
150
Lin Huang2e3ebb62017-10-30 17:40:19 +0800151 i = max_mbps_to_parameter(lane_mbps);
152 if (i < 0) {
153 printk(BIOS_DEBUG,
154 "failed to get parameter for %dmbps clock\n", lane_mbps);
155 return i;
Nickey Yangfe122d42017-04-27 09:38:06 +0800156 }
157
158 /* Start by clearing PHY state */
Lin Huang25fb09b2017-11-22 09:40:50 +0800159 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0, PHY_UNTESTCLR);
160 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0, PHY_TESTCLR);
161 write32(&dsi->mipi_regs->dsi_phy_tst_ctrl0, PHY_UNTESTCLR);
Nickey Yangfe122d42017-04-27 09:38:06 +0800162
163 rk_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
164 BYPASS_VCO_RANGE |
165 VCO_RANGE_CON_SEL(vco) |
166 VCO_IN_CAP_CON_LOW |
167 REF_BIAS_CUR_SEL);
168
169 rk_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
Lin Huang2e3ebb62017-10-30 17:40:19 +0800170 CP_CURRENT_SEL(dppa_map[i].icpctrl));
Nickey Yangfe122d42017-04-27 09:38:06 +0800171 rk_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
172 CP_PROGRAM_EN |
173 LPF_PROGRAM_EN |
Lin Huang2e3ebb62017-10-30 17:40:19 +0800174 LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
Nickey Yangfe122d42017-04-27 09:38:06 +0800175 rk_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
Lin Huang2e3ebb62017-10-30 17:40:19 +0800176 HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
177
Nickey Yangfe122d42017-04-27 09:38:06 +0800178 rk_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
179 INPUT_DIVIDER(dsi->input_div));
180 rk_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
181 LOOP_DIV_LOW_SEL(dsi->feedback_div) |
182 LOW_PROGRAM_EN);
Lin Huangf4acb922017-11-16 10:03:47 +0800183
184 /*
185 * we need set divider control register immediately to make
186 * the configured LSB effective according to IP simulation
187 * and lab test results. Only in this way can we get correct
188 * mipi phy pll frequency.
189 */
190 rk_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
191 PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
Nickey Yangfe122d42017-04-27 09:38:06 +0800192 rk_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
193 LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
194 HIGH_PROGRAM_EN);
195 rk_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
196 PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
197 rk_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
198 LOW_PROGRAM_EN |
199 BIASEXTR_SEL(BIASEXTR_127_7));
200 rk_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
201 HIGH_PROGRAM_EN |
202 BANDGAP_SEL(BANDGAP_96_10));
203 rk_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
204 POWER_CONTROL | INTERNAL_REG_CURRENT |
205 BIAS_BLOCK_ON | BANDGAP_ON);
206 rk_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
207 TER_RESISTOR_LOW | TER_CAL_DONE |
208 SETRD_MAX | TER_RESISTORS_ON);
209 rk_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
210 TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
211 SETRD_MAX | POWER_MANAGE |
212 TER_RESISTORS_ON);
Lin Huang45f1b012017-11-02 17:53:30 +0800213 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
214 TLP_PROGRAM_EN | bytes_per_ns(dsi, 500));
215 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
216 THS_PRE_PROGRAM_EN | bits_per_ns(dsi, 40));
217 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
218 THS_ZERO_PROGRAM_EN | bytes_per_ns(dsi, 300));
219 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
220 THS_PRE_PROGRAM_EN | bits_per_ns(dsi, 100));
221 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
222 BIT(5) | bytes_per_ns(dsi, 100));
223 rk_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
224 BIT(5) | (bytes_per_ns(dsi, 60) + 7));
225 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
226 TLP_PROGRAM_EN | bytes_per_ns(dsi, 500));
227 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
228 THS_PRE_PROGRAM_EN | (bits_per_ns(dsi, 50) + 5));
229 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
230 THS_ZERO_PROGRAM_EN |
231 (bytes_per_ns(dsi, 140) + 2));
232 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
233 THS_PRE_PROGRAM_EN | (bits_per_ns(dsi, 60) + 8));
234 rk_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
235 BIT(5) | bytes_per_ns(dsi, 100));
Nickey Yangfe122d42017-04-27 09:38:06 +0800236
Lin Huang25fb09b2017-11-22 09:40:50 +0800237 write32(&dsi->mipi_regs->dsi_phy_rstz,
238 PHY_ENFORCEPLL | PHY_ENABLECLK |
239 PHY_UNRSTZ | PHY_UNSHUTDOWNZ);
Lin Huang45f1b012017-11-02 17:53:30 +0800240
241 if (rk_mipi_dsi_wait_phy_lock(dsi)) {
242 printk(BIOS_ERR, "failed to wait for phy lock state\n");
243 return -1;
244 }
245
246 stopwatch_init_msecs_expire(&sw, 20);
247 do {
Lin Huang25fb09b2017-11-22 09:40:50 +0800248 val = read32(&dsi->mipi_regs->dsi_phy_status);
Lin Huang45f1b012017-11-02 17:53:30 +0800249 if (val & STOP_STATE_CLK_LANE)
250 return 0;
251 } while (!stopwatch_expired(&sw));
252
253 printk(BIOS_ERR, "failed to wait for phy clk lane stop state");
254 return -1;
Nickey Yangfe122d42017-04-27 09:38:06 +0800255}
256
257static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt)
258{
259 switch (fmt) {
260 case MIPI_DSI_FMT_RGB888:
261 case MIPI_DSI_FMT_RGB666:
262 return 24;
263
264 case MIPI_DSI_FMT_RGB666_PACKED:
265 return 18;
266
267 case MIPI_DSI_FMT_RGB565:
268 return 16;
269 }
270
271 return -1;
272}
273
274static int rk_mipi_dsi_get_lane_bps(struct rk_mipi_dsi *dsi,
Lin Huang25fb09b2017-11-22 09:40:50 +0800275 const struct edid *edid,
276 const struct mipi_panel_data *panel_data)
Nickey Yangfe122d42017-04-27 09:38:06 +0800277{
Lin Huangf4acb922017-11-16 10:03:47 +0800278 u64 pclk, target_bps;
Lin Huang2e3ebb62017-10-30 17:40:19 +0800279 u32 max_bps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps * MHz;
Nickey Yangfe122d42017-04-27 09:38:06 +0800280 int bpp;
Lin Huangf4acb922017-11-16 10:03:47 +0800281 u64 best_freq = 0;
282 u64 fvco_min, fvco_max, fref;
283 u32 min_prediv, max_prediv;
284 u32 prediv, best_prediv;
285 u64 fbdiv, best_fbdiv;
286 u32 min_delta;
Nickey Yangfe122d42017-04-27 09:38:06 +0800287
288 bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
289 if (bpp < 0) {
290 printk(BIOS_DEBUG, "failed to get bpp for pixel format %d\n",
291 dsi->format);
292 return bpp;
293 }
Jacob Garbere24585c2019-07-23 11:55:04 -0600294 pclk = (u64)edid->mode.pixel_clock * MSECS_PER_SEC;
Lin Huangf4acb922017-11-16 10:03:47 +0800295
Nickey Yangfe122d42017-04-27 09:38:06 +0800296 /* take 1 / 0.8, since mbps must bigger than bandwidth of RGB */
Lin Huang25fb09b2017-11-22 09:40:50 +0800297 target_bps = pclk / panel_data->lanes * bpp / 8 * 10;
Nickey Yangfe122d42017-04-27 09:38:06 +0800298 if (target_bps >= max_bps) {
299 printk(BIOS_DEBUG, "DPHY clock frequency is out of range\n");
300 return -1;
301 }
Lin Huangf4acb922017-11-16 10:03:47 +0800302
303 fref = OSC_HZ;
304
305 /* constraint: 5Mhz <= Fref / N <= 40MHz */
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100306 min_prediv = DIV_ROUND_UP(fref, 40 * MHz);
Lin Huangf4acb922017-11-16 10:03:47 +0800307 max_prediv = fref / (5 * MHz);
308
Elyes HAOUAS8d1b0f12020-02-20 18:20:57 +0100309 /* constraint: 80MHz <= Fvco <= 1500MHz */
Lin Huangf4acb922017-11-16 10:03:47 +0800310 fvco_min = 80 * MHz;
311 fvco_max = 1500 * MHz;
312 min_delta = 1500 * MHz;
313
314 for (prediv = min_prediv; prediv <= max_prediv; prediv++) {
315 u64 freq;
316 int delta;
317
318 /* Fvco = Fref * M / N */
319 fbdiv = target_bps * prediv / fref;
320
321 /*
322 * Due to the use of a "by 2 pre-scaler", the range of the
323 * feedback multiplication value M is limited to even division
324 * numbers, and m must be in 6 <= m <= 512.
325 */
326 fbdiv += fbdiv % 2;
327 if (fbdiv < 6 || fbdiv > 512)
328 continue;
329
330 freq = (u64)fbdiv * fref / prediv;
331 if (freq < fvco_min || freq > fvco_max)
332 continue;
333
334 delta = target_bps - freq;
335 delta = ABS(delta);
336 if (delta >= min_delta)
337 continue;
338
339 best_prediv = prediv;
340 best_fbdiv = fbdiv;
341 min_delta = delta;
342 best_freq = freq;
Nickey Yangfe122d42017-04-27 09:38:06 +0800343 }
Lin Huangf4acb922017-11-16 10:03:47 +0800344
345 if (best_freq) {
346 dsi->lane_bps = best_freq;
347 dsi->input_div = best_prediv;
348 dsi->feedback_div = best_fbdiv;
349 } else {
350 printk(BIOS_ERR, "Can not find best_freq for DPHY\n");
351 return -1;
352 }
Nickey Yangfe122d42017-04-27 09:38:06 +0800353
354 return 0;
355}
356
357static void rk_mipi_dsi_dpi_config(struct rk_mipi_dsi *dsi)
358{
359 u32 color = 0;
360
361 switch (dsi->format) {
362 case MIPI_DSI_FMT_RGB888:
363 color = DPI_COLOR_CODING_24BIT;
364 break;
365 case MIPI_DSI_FMT_RGB666:
366 color = DPI_COLOR_CODING_18BIT_2 | EN18_LOOSELY;
367 break;
368 case MIPI_DSI_FMT_RGB666_PACKED:
369 color = DPI_COLOR_CODING_18BIT_1;
370 break;
371 case MIPI_DSI_FMT_RGB565:
372 color = DPI_COLOR_CODING_16BIT_1;
373 break;
374 }
375
Lin Huang25fb09b2017-11-22 09:40:50 +0800376 write32(&dsi->mipi_regs->dsi_dpi_vcid, 0);
377 write32(&dsi->mipi_regs->dsi_dpi_color_coding, color);
Nickey Yangfe122d42017-04-27 09:38:06 +0800378
Lin Huang25fb09b2017-11-22 09:40:50 +0800379 write32(&dsi->mipi_regs->dsi_dpi_cfg_pol, 0);
Nickey Yangfe122d42017-04-27 09:38:06 +0800380
Lin Huang25fb09b2017-11-22 09:40:50 +0800381 write32(&dsi->mipi_regs->dsi_dpi_lp_cmd_tim,
382 OUTVACT_LPCMD_TIME(4) | INVACT_LPCMD_TIME(4));
Nickey Yangfe122d42017-04-27 09:38:06 +0800383}
384
385static void rk_mipi_dsi_packet_handler_config(struct rk_mipi_dsi *dsi)
386{
Lin Huang25fb09b2017-11-22 09:40:50 +0800387 write32(&dsi->mipi_regs->dsi_pckhdl_cfg,
388 EN_CRC_RX | EN_ECC_RX | EN_BTA);
Nickey Yangfe122d42017-04-27 09:38:06 +0800389}
390
391static void rk_mipi_dsi_video_mode_config(struct rk_mipi_dsi *dsi)
392{
Lin Huang25fb09b2017-11-22 09:40:50 +0800393 write32(&dsi->mipi_regs->dsi_vid_mode_cfg,
Nickey Yangfe122d42017-04-27 09:38:06 +0800394 VID_MODE_TYPE_BURST_SYNC_PULSES | ENABLE_LOW_POWER);
395}
396
Lin Huang25fb09b2017-11-22 09:40:50 +0800397static void rk_mipi_dsi_video_packet_config(struct rk_mipi_dsi *dsi,
398 const struct edid *edid,
399 const struct mipi_panel_data *panel_data)
Nickey Yangfe122d42017-04-27 09:38:06 +0800400{
Lin Huang25fb09b2017-11-22 09:40:50 +0800401 int pkt_size;
402
403 if (panel_data->mipi_num > 1)
404 pkt_size = VID_PKT_SIZE(edid->mode.ha / 2 + 4);
405 else
406 pkt_size = VID_PKT_SIZE(edid->mode.ha);
407
408 write32(&dsi->mipi_regs->dsi_vid_pkt_size, pkt_size);
Nickey Yangfe122d42017-04-27 09:38:06 +0800409}
410
411static void rk_mipi_dsi_command_mode_config(struct rk_mipi_dsi *dsi)
412{
Lin Huang25fb09b2017-11-22 09:40:50 +0800413 write32(&dsi->mipi_regs->dsi_to_cnt_cfg,
Nickey Yangfe122d42017-04-27 09:38:06 +0800414 HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000));
Lin Huang25fb09b2017-11-22 09:40:50 +0800415 write32(&dsi->mipi_regs->dsi_bta_to_cnt, 0xd00);
416 write32(&dsi->mipi_regs->dsi_cmd_mode_cfg, CMD_MODE_ALL_LP);
417 write32(&dsi->mipi_regs->dsi_mode_cfg, ENABLE_CMD_MODE);
Nickey Yangfe122d42017-04-27 09:38:06 +0800418}
419
420/* Get lane byte clock cycles. */
421static u32 rk_mipi_dsi_get_hcomponent_lbcc(struct rk_mipi_dsi *dsi,
422 u32 hcomponent,
423 const struct edid *edid)
424{
425 u32 lbcc;
426 u64 lbcc_tmp;
427
428 lbcc_tmp = hcomponent * dsi->lane_bps / (8 * MSECS_PER_SEC);
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100429 lbcc = DIV_ROUND_UP(lbcc_tmp, edid->mode.pixel_clock);
Nickey Yangfe122d42017-04-27 09:38:06 +0800430
431 return lbcc;
432}
433
434static void rk_mipi_dsi_line_timer_config(struct rk_mipi_dsi *dsi,
435 const struct edid *edid)
436{
437 u32 htotal, hsa, hbp, lbcc;
438
439 htotal = edid->mode.ha + edid->mode.hbl;
440 hsa = edid->mode.hspw;
441 hbp = edid->mode.hbl - edid->mode.hso - edid->mode.hspw;
442
443 lbcc = rk_mipi_dsi_get_hcomponent_lbcc(dsi, htotal, edid);
Lin Huang25fb09b2017-11-22 09:40:50 +0800444 write32(&dsi->mipi_regs->dsi_vid_hline_time, lbcc);
Nickey Yangfe122d42017-04-27 09:38:06 +0800445
446 lbcc = rk_mipi_dsi_get_hcomponent_lbcc(dsi, hsa, edid);
Lin Huang25fb09b2017-11-22 09:40:50 +0800447 write32(&dsi->mipi_regs->dsi_vid_hsa_time, lbcc);
Nickey Yangfe122d42017-04-27 09:38:06 +0800448 lbcc = rk_mipi_dsi_get_hcomponent_lbcc(dsi, hbp, edid);
Lin Huang25fb09b2017-11-22 09:40:50 +0800449 write32(&dsi->mipi_regs->dsi_vid_hbp_time, lbcc);
Nickey Yangfe122d42017-04-27 09:38:06 +0800450}
451
452static void rk_mipi_dsi_vertical_timing_config(struct rk_mipi_dsi *dsi,
453 const struct edid *edid)
454{
455 u32 vactive, vsa, vfp, vbp;
456
457 vactive = edid->mode.va;
458 vsa = edid->mode.vspw;
459 vfp = edid->mode.vso;
460 vbp = edid->mode.vbl - edid->mode.vso - edid->mode.vspw;
461
Lin Huang25fb09b2017-11-22 09:40:50 +0800462 write32(&dsi->mipi_regs->dsi_vid_vactive_lines, vactive);
463 write32(&dsi->mipi_regs->dsi_vid_vsa_lines, vsa);
464 write32(&dsi->mipi_regs->dsi_vid_vfp_lines, vfp);
465 write32(&dsi->mipi_regs->dsi_vid_vbp_lines, vbp);
Nickey Yangfe122d42017-04-27 09:38:06 +0800466}
467
468static void rk_mipi_dsi_dphy_timing_config(struct rk_mipi_dsi *dsi)
469{
470 /*
471 * HS-PREPARE: 40ns + 4 * UI ~ 85ns + 6 * UI
472 * HS-EXIT: 100ns
473 */
Lin Huang25fb09b2017-11-22 09:40:50 +0800474 write32(&dsi->mipi_regs->dsi_phy_tmr_cfg, PHY_HS2LP_TIME(0x40) |
Nickey Yangfe122d42017-04-27 09:38:06 +0800475 PHY_LP2HS_TIME(0x40) |
476 MAX_RD_TIME(10000));
477
Lin Huang25fb09b2017-11-22 09:40:50 +0800478 write32(&dsi->mipi_regs->dsi_phy_tmr_lpclk_cfg,
479 PHY_CLKHS2LP_TIME(0x40) | PHY_CLKLP2HS_TIME(0x40));
Nickey Yangfe122d42017-04-27 09:38:06 +0800480}
481
482static void rk_mipi_dsi_clear_err(struct rk_mipi_dsi *dsi)
483{
Lin Huang25fb09b2017-11-22 09:40:50 +0800484 read32(&dsi->mipi_regs->dsi_int_st0);
485 read32(&dsi->mipi_regs->dsi_int_st1);
486 write32(&dsi->mipi_regs->dsi_int_msk0, 0);
487 write32(&dsi->mipi_regs->dsi_int_msk1, 0);
Nickey Yangfe122d42017-04-27 09:38:06 +0800488}
489
490static void rk_mipi_dsi_dphy_interface_config(struct rk_mipi_dsi *dsi)
491{
Lin Huang25fb09b2017-11-22 09:40:50 +0800492 write32(&dsi->mipi_regs->dsi_phy_if_cfg, PHY_STOP_WAIT_TIME(0x20) |
Nickey Yangfe122d42017-04-27 09:38:06 +0800493 N_LANES(dsi->lanes));
494}
495
496static void rk_mipi_dsi_set_mode(struct rk_mipi_dsi *dsi,
497 enum rk_mipi_dsi_mode mode)
498{
Lin Huang25fb09b2017-11-22 09:40:50 +0800499 write32(&dsi->mipi_regs->dsi_pwr_up, RESET);
Nickey Yangfe122d42017-04-27 09:38:06 +0800500 if (mode == MIPI_DSI_CMD_MODE) {
Lin Huang25fb09b2017-11-22 09:40:50 +0800501 write32(&dsi->mipi_regs->dsi_mode_cfg, ENABLE_CMD_MODE);
Nickey Yangfe122d42017-04-27 09:38:06 +0800502 } else {
Lin Huang25fb09b2017-11-22 09:40:50 +0800503 write32(&dsi->mipi_regs->dsi_mode_cfg, ENABLE_VIDEO_MODE);
Nickey Yangfe122d42017-04-27 09:38:06 +0800504 rk_mipi_dsi_video_mode_config(dsi);
Lin Huang25fb09b2017-11-22 09:40:50 +0800505 write32(&dsi->mipi_regs->dsi_lpclk_ctrl, PHY_TXREQUESTCLKHS);
Nickey Yangfe122d42017-04-27 09:38:06 +0800506 }
Lin Huang25fb09b2017-11-22 09:40:50 +0800507 write32(&dsi->mipi_regs->dsi_pwr_up, POWERUP);
Nickey Yangfe122d42017-04-27 09:38:06 +0800508}
509
510static void rk_mipi_dsi_init(struct rk_mipi_dsi *dsi)
511{
512 /*
513 * The maximum permitted escape clock is 20MHz and it is derived from
514 * lanebyteclk, which is running at "lane_mbps / 8". Thus we want:
515 *
516 * (lane_mbps >> 3) / esc_clk_division < 20
517 * which is:
518 * (lane_mbps >> 3) / 20 > esc_clk_division
519 */
Elyes HAOUAS6df3b642018-11-26 22:53:49 +0100520 u32 esc_clk_division = DIV_ROUND_UP(dsi->lane_bps,
Lin Huang25fb09b2017-11-22 09:40:50 +0800521 8 * 20 * USECS_PER_SEC);
Nickey Yangfe122d42017-04-27 09:38:06 +0800522
Lin Huang25fb09b2017-11-22 09:40:50 +0800523 write32(&dsi->mipi_regs->dsi_pwr_up, RESET);
524 write32(&dsi->mipi_regs->dsi_phy_rstz,
525 PHY_DISFORCEPLL | PHY_DISABLECLK | PHY_RSTZ | PHY_SHUTDOWNZ);
526 write32(&dsi->mipi_regs->dsi_clk_cfg,
Nickey Yangfe122d42017-04-27 09:38:06 +0800527 TO_CLK_DIVIDSION(10) |
528 TX_ESC_CLK_DIVIDSION(esc_clk_division));
529}
530
Lin Huang538b9ef2017-11-01 10:22:49 +0800531static void rk_mipi_message_config(struct rk_mipi_dsi *dsi)
Nickey Yangfe122d42017-04-27 09:38:06 +0800532{
Lin Huang25fb09b2017-11-22 09:40:50 +0800533 write32(&dsi->mipi_regs->dsi_lpclk_ctrl, 0);
534 write32(&dsi->mipi_regs->dsi_cmd_mode_cfg, CMD_MODE_ALL_LP);
Lin Huang538b9ef2017-11-01 10:22:49 +0800535}
536
Lin Huang0499ce92018-01-17 14:24:14 +0800537static int rk_mipi_dsi_check_fifo(struct rk_mipi_dsi *dsi, u32 flag)
Lin Huang538b9ef2017-11-01 10:22:49 +0800538{
539 struct stopwatch sw;
540 int val;
541
542 stopwatch_init_msecs_expire(&sw, 20);
543 do {
Lin Huang25fb09b2017-11-22 09:40:50 +0800544 val = read32(&dsi->mipi_regs->dsi_cmd_pkt_status);
Lin Huang0499ce92018-01-17 14:24:14 +0800545 if (!(val & flag))
Elyes Haouas4b6d3682023-08-13 12:49:16 +0200546 return 0;
Lin Huang538b9ef2017-11-01 10:22:49 +0800547 } while (!stopwatch_expired(&sw));
548
549 return -1;
550}
551
552static int rk_mipi_dsi_gen_pkt_hdr_write(struct rk_mipi_dsi *dsi, u32 hdr_val)
553{
554 int val;
555 struct stopwatch sw;
556 u32 mask;
557
Lin Huang0499ce92018-01-17 14:24:14 +0800558 if (rk_mipi_dsi_check_fifo(dsi, GEN_CMD_FULL)) {
Lin Huang538b9ef2017-11-01 10:22:49 +0800559 printk(BIOS_ERR, "failed to get available command FIFO\n");
560 return -1;
561 }
562
Lin Huang25fb09b2017-11-22 09:40:50 +0800563 write32(&dsi->mipi_regs->dsi_gen_hdr, hdr_val);
Nickey Yangfe122d42017-04-27 09:38:06 +0800564
Lin Huang538b9ef2017-11-01 10:22:49 +0800565 mask = GEN_CMD_EMPTY | GEN_PLD_W_EMPTY;
566 stopwatch_init_msecs_expire(&sw, 20);
567 do {
Lin Huang25fb09b2017-11-22 09:40:50 +0800568 val = read32(&dsi->mipi_regs->dsi_cmd_pkt_status);
Lin Huang538b9ef2017-11-01 10:22:49 +0800569 if ((val & mask) == mask)
Elyes Haouas4b6d3682023-08-13 12:49:16 +0200570 return 0;
Lin Huang538b9ef2017-11-01 10:22:49 +0800571 } while (!stopwatch_expired(&sw));
572 printk(BIOS_ERR, "failed to write command FIFO\n");
573
574 return -1;
575}
576
577static int rk_mipi_dsi_dcs_cmd(struct rk_mipi_dsi *dsi, u8 cmd)
578{
579 u32 val;
580
581 rk_mipi_message_config(dsi);
582
583 val = GEN_HDATA(cmd) | GEN_HTYPE(MIPI_DSI_DCS_SHORT_WRITE);
584
585 return rk_mipi_dsi_gen_pkt_hdr_write(dsi, val);
Nickey Yangfe122d42017-04-27 09:38:06 +0800586}
587
Lin Huang0499ce92018-01-17 14:24:14 +0800588static int rk_mipi_dsi_dci_long_write(struct rk_mipi_dsi *dsi,
589 char *data, u32 len)
Nickey Yangfe122d42017-04-27 09:38:06 +0800590{
Lin Huang0499ce92018-01-17 14:24:14 +0800591 u32 remainder;
592 int ret = 0;
593
594 while (len) {
595 if (len < 4) {
596 remainder = 0;
597 memcpy(&remainder, data, len);
598 write32(&dsi->mipi_regs->dsi_gen_pld_data, remainder);
599 len = 0;
600 } else {
601 remainder = *(u32 *)data;
602 write32(&dsi->mipi_regs->dsi_gen_pld_data, remainder);
603 data += 4;
604 len -= 4;
605 }
606
607 ret = rk_mipi_dsi_check_fifo(dsi, GEN_PLD_W_FULL);
608 if (ret) {
609 printk(BIOS_ERR, "Failed to write fifo\n");
610 return ret;
611 }
612 }
613
614 return ret;
615}
616
617static int rk_mipi_dsi_write(struct rk_mipi_dsi *dsi, char *data, int len)
618{
619 u16 buf = 0;
Lin Huang25fb09b2017-11-22 09:40:50 +0800620 u32 val;
Lin Huang0499ce92018-01-17 14:24:14 +0800621 int ret = 0;
Lin Huang25fb09b2017-11-22 09:40:50 +0800622
623 rk_mipi_message_config(dsi);
624
Lin Huang0499ce92018-01-17 14:24:14 +0800625 switch (len) {
626 case 0:
627 die("not data!");
628 case 1:
629 val = GEN_HDATA(*data) |
630 GEN_HTYPE(MIPI_DSI_DCS_SHORT_WRITE);
631 break;
632 case 2:
633 buf = *data++;
634 buf |= *data << 8;
635 val = GEN_HDATA(buf) |
636 GEN_HTYPE(MIPI_DSI_DCS_SHORT_WRITE_PARAM);
637 break;
638 default:
639 ret = rk_mipi_dsi_dci_long_write(dsi, data, len);
640 if (ret) {
641 printk(BIOS_ERR, "error happened during long write\n");
642 return ret;
643 }
644 val = GEN_HDATA(len) | GEN_HTYPE(MIPI_DSI_DCS_LONG_WRITE);
645 break;
646 }
Lin Huang25fb09b2017-11-22 09:40:50 +0800647
648 return rk_mipi_dsi_gen_pkt_hdr_write(dsi, val);
649}
650
651static void rk_mipi_enable(struct rk_mipi_dsi *dsi,
652 const struct edid *edid,
653 const struct mipi_panel_data *panel_data)
654{
655 if (rk_mipi_dsi_get_lane_bps(dsi, edid, panel_data) < 0)
Nickey Yangfe122d42017-04-27 09:38:06 +0800656 return;
657
Lin Huang25fb09b2017-11-22 09:40:50 +0800658 rk_mipi_dsi_init(dsi);
659 rk_mipi_dsi_dpi_config(dsi);
660 rk_mipi_dsi_packet_handler_config(dsi);
661 rk_mipi_dsi_video_mode_config(dsi);
662 rk_mipi_dsi_video_packet_config(dsi, edid, panel_data);
663 rk_mipi_dsi_command_mode_config(dsi);
664 rk_mipi_dsi_line_timer_config(dsi, edid);
665 rk_mipi_dsi_vertical_timing_config(dsi, edid);
666 rk_mipi_dsi_dphy_timing_config(dsi);
667 rk_mipi_dsi_dphy_interface_config(dsi);
668 rk_mipi_dsi_clear_err(dsi);
669 if (rk_mipi_dsi_phy_init(dsi) < 0)
Nickey Yang5be0b2e2017-05-25 11:23:23 +0800670 return;
Lin Huang25fb09b2017-11-22 09:40:50 +0800671 rk_mipi_dsi_wait_for_two_frames(dsi, edid);
Nickey Yangfe122d42017-04-27 09:38:06 +0800672
Lin Huang25fb09b2017-11-22 09:40:50 +0800673 rk_mipi_dsi_set_mode(dsi, MIPI_DSI_CMD_MODE);
674}
Lin Huang538b9ef2017-11-01 10:22:49 +0800675
Lin Huang25fb09b2017-11-22 09:40:50 +0800676void rk_mipi_prepare(const struct edid *edid,
677 const struct mipi_panel_data *panel_data)
678{
679 int i, num;
Lin Huang0499ce92018-01-17 14:24:14 +0800680 struct panel_init_command *cmds;
Lin Huang538b9ef2017-11-01 10:22:49 +0800681
Lin Huang25fb09b2017-11-22 09:40:50 +0800682 for (i = 0; i < panel_data->mipi_num; i++) {
683 rk_mipi[i].lanes = panel_data->lanes / panel_data->mipi_num;
684 rk_mipi[i].format = panel_data->format;
685 rk_mipi_enable(&rk_mipi[i], edid, panel_data);
686 }
Nickey Yangfe122d42017-04-27 09:38:06 +0800687
Lin Huang0499ce92018-01-17 14:24:14 +0800688 if (panel_data->init_cmd) {
689 cmds = panel_data->init_cmd;
690 for (num = 0; cmds[num].len != 0; num++) {
691 struct panel_init_command *cmd = &cmds[num];
692 for (i = 0; i < panel_data->mipi_num; i++) {
693 if (rk_mipi_dsi_write(&rk_mipi[i], cmd->data,
694 cmd->len))
695 return;
696
697 /* make sure panel picks up the command */
698 if (rk_mipi_dsi_dcs_cmd(&rk_mipi[i],
699 MIPI_DCS_NOP))
700 return;
701 }
702 }
Lin Huang25fb09b2017-11-22 09:40:50 +0800703 }
704
705 for (i = 0; i < panel_data->mipi_num; i++) {
706 if (rk_mipi_dsi_dcs_cmd(&rk_mipi[i],
707 MIPI_DCS_EXIT_SLEEP_MODE) < 0)
708 return;
709 }
710 udelay(panel_data->display_on_udelay);
711 for (i = 0; i < panel_data->mipi_num; i++) {
712 if (rk_mipi_dsi_dcs_cmd(&rk_mipi[i],
713 MIPI_DCS_SET_DISPLAY_ON) < 0)
714 return;
715 }
716 udelay(panel_data->video_mode_udelay);
717 for (i = 0; i < panel_data->mipi_num; i++)
718 rk_mipi_dsi_set_mode(&rk_mipi[i], MIPI_DSI_VID_MODE);
Nickey Yangfe122d42017-04-27 09:38:06 +0800719}