blob: 0852b53ebed5125cd371e9e4a8f68e82eceffc58 [file] [log] [blame]
Chris Morgan8895dd32023-03-24 13:53:07 -05001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Author(s): Chris Morgan <macromorgan@hotmail.com>
4 *
5 * This MIPI DSI controller driver is heavily based on the Linux Kernel
6 * driver from drivers/gpu/drm/rockchip/dw-mipi-dsi-rockchip.c and the
7 * U-Boot driver from drivers/video/stm32/stm32_dsi.c.
8 */
9
10#define LOG_CATEGORY UCLASS_VIDEO_BRIDGE
11
12#include <clk.h>
13#include <dm.h>
14#include <div64.h>
15#include <dsi_host.h>
16#include <generic-phy.h>
17#include <mipi_dsi.h>
18#include <panel.h>
19#include <phy-mipi-dphy.h>
20#include <reset.h>
Ondrej Jirmanc61f4f72023-05-22 23:47:08 +020021#include <syscon.h>
Chris Morgan8895dd32023-03-24 13:53:07 -050022#include <video_bridge.h>
23#include <dm/device_compat.h>
24#include <dm/lists.h>
25#include <linux/iopoll.h>
26
27#include <common.h>
28#include <log.h>
29#include <video.h>
30#include <asm/io.h>
31#include <dm/device-internal.h>
32#include <linux/bitops.h>
33
Ondrej Jirmanc61f4f72023-05-22 23:47:08 +020034#include <asm/arch-rockchip/clock.h>
35#include <asm/arch-rockchip/hardware.h>
36
Chris Morgan8895dd32023-03-24 13:53:07 -050037#define USEC_PER_SEC 1000000L
38
39/*
40 * DSI wrapper registers & bit definitions
41 * Note: registers are named as in the Reference Manual
42 */
43#define DSI_WCR 0x0404 /* Wrapper Control Reg */
44#define WCR_DSIEN BIT(3) /* DSI ENable */
45
46#define DSI_PHY_TST_CTRL0 0xb4
47#define PHY_TESTCLK BIT(1)
48#define PHY_UNTESTCLK 0
49#define PHY_TESTCLR BIT(0)
50#define PHY_UNTESTCLR 0
51
52#define DSI_PHY_TST_CTRL1 0xb8
53#define PHY_TESTEN BIT(16)
54#define PHY_UNTESTEN 0
55#define PHY_TESTDOUT(n) (((n) & 0xff) << 8)
56#define PHY_TESTDIN(n) (((n) & 0xff) << 0)
57
58#define BYPASS_VCO_RANGE BIT(7)
59#define VCO_RANGE_CON_SEL(val) (((val) & 0x7) << 3)
60#define VCO_IN_CAP_CON_DEFAULT (0x0 << 1)
61#define VCO_IN_CAP_CON_LOW (0x1 << 1)
62#define VCO_IN_CAP_CON_HIGH (0x2 << 1)
63#define REF_BIAS_CUR_SEL BIT(0)
64
65#define CP_CURRENT_3UA 0x1
66#define CP_CURRENT_4_5UA 0x2
67#define CP_CURRENT_7_5UA 0x6
68#define CP_CURRENT_6UA 0x9
69#define CP_CURRENT_12UA 0xb
70#define CP_CURRENT_SEL(val) ((val) & 0xf)
71#define CP_PROGRAM_EN BIT(7)
72
73#define LPF_RESISTORS_15_5KOHM 0x1
74#define LPF_RESISTORS_13KOHM 0x2
75#define LPF_RESISTORS_11_5KOHM 0x4
76#define LPF_RESISTORS_10_5KOHM 0x8
77#define LPF_RESISTORS_8KOHM 0x10
78#define LPF_PROGRAM_EN BIT(6)
79#define LPF_RESISTORS_SEL(val) ((val) & 0x3f)
80
81#define HSFREQRANGE_SEL(val) (((val) & 0x3f) << 1)
82
83#define INPUT_DIVIDER(val) (((val) - 1) & 0x7f)
84#define LOW_PROGRAM_EN 0
85#define HIGH_PROGRAM_EN BIT(7)
86#define LOOP_DIV_LOW_SEL(val) (((val) - 1) & 0x1f)
87#define LOOP_DIV_HIGH_SEL(val) ((((val) - 1) >> 5) & 0xf)
88#define PLL_LOOP_DIV_EN BIT(5)
89#define PLL_INPUT_DIV_EN BIT(4)
90
91#define POWER_CONTROL BIT(6)
92#define INTERNAL_REG_CURRENT BIT(3)
93#define BIAS_BLOCK_ON BIT(2)
94#define BANDGAP_ON BIT(0)
95
96#define TER_RESISTOR_HIGH BIT(7)
97#define TER_RESISTOR_LOW 0
98#define LEVEL_SHIFTERS_ON BIT(6)
99#define TER_CAL_DONE BIT(5)
100#define SETRD_MAX (0x7 << 2)
101#define POWER_MANAGE BIT(1)
102#define TER_RESISTORS_ON BIT(0)
103
104#define BIASEXTR_SEL(val) ((val) & 0x7)
105#define BANDGAP_SEL(val) ((val) & 0x7)
106#define TLP_PROGRAM_EN BIT(7)
107#define THS_PRE_PROGRAM_EN BIT(7)
108#define THS_ZERO_PROGRAM_EN BIT(6)
109
110#define PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL 0x10
111#define PLL_CP_CONTROL_PLL_LOCK_BYPASS 0x11
112#define PLL_LPF_AND_CP_CONTROL 0x12
113#define PLL_INPUT_DIVIDER_RATIO 0x17
114#define PLL_LOOP_DIVIDER_RATIO 0x18
115#define PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL 0x19
116#define BANDGAP_AND_BIAS_CONTROL 0x20
117#define TERMINATION_RESISTER_CONTROL 0x21
118#define AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY 0x22
119#define HS_RX_CONTROL_OF_LANE_CLK 0x34
120#define HS_RX_CONTROL_OF_LANE_0 0x44
121#define HS_RX_CONTROL_OF_LANE_1 0x54
122#define HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL 0x60
123#define HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL 0x61
124#define HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL 0x62
125#define HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL 0x63
126#define HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL 0x64
127#define HS_TX_CLOCK_LANE_POST_TIME_CONTROL 0x65
128#define HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL 0x70
129#define HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL 0x71
130#define HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL 0x72
131#define HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL 0x73
132#define HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL 0x74
133#define HS_RX_DATA_LANE_THS_SETTLE_CONTROL 0x75
134#define HS_RX_CONTROL_OF_LANE_2 0x84
135#define HS_RX_CONTROL_OF_LANE_3 0x94
136
Ondrej Jirmanf1ecb852023-05-25 14:29:03 +0200137#define DW_MIPI_NEEDS_PHY_CFG_CLK BIT(0)
138#define DW_MIPI_NEEDS_GRF_CLK BIT(1)
139
140#define RK3399_GRF_SOC_CON20 0x6250
141#define RK3399_DSI0_LCDC_SEL BIT(0)
142#define RK3399_DSI1_LCDC_SEL BIT(4)
143
144#define RK3399_GRF_SOC_CON22 0x6258
145#define RK3399_DSI0_TURNREQUEST (0xf << 12)
146#define RK3399_DSI0_TURNDISABLE (0xf << 8)
147#define RK3399_DSI0_FORCETXSTOPMODE (0xf << 4)
148#define RK3399_DSI0_FORCERXMODE (0xf << 0)
149
150#define RK3399_GRF_SOC_CON23 0x625c
151#define RK3399_DSI1_TURNDISABLE (0xf << 12)
152#define RK3399_DSI1_FORCETXSTOPMODE (0xf << 8)
153#define RK3399_DSI1_FORCERXMODE (0xf << 4)
154#define RK3399_DSI1_ENABLE (0xf << 0)
155
156#define RK3399_GRF_SOC_CON24 0x6260
157#define RK3399_TXRX_MASTERSLAVEZ BIT(7)
158#define RK3399_TXRX_ENABLECLK BIT(6)
159#define RK3399_TXRX_BASEDIR BIT(5)
160#define RK3399_TXRX_SRC_SEL_ISP0 BIT(4)
161#define RK3399_TXRX_TURNREQUEST GENMASK(3, 0)
162
Chris Morgan8895dd32023-03-24 13:53:07 -0500163#define RK3568_GRF_VO_CON2 0x0368
164#define RK3568_DSI0_SKEWCALHS (0x1f << 11)
165#define RK3568_DSI0_FORCETXSTOPMODE (0xf << 4)
166#define RK3568_DSI0_TURNDISABLE BIT(2)
167#define RK3568_DSI0_FORCERXMODE BIT(0)
168
169/*
170 * Note these registers do not appear in the datasheet, they are
171 * however present in the BSP driver which is where these values
172 * come from. Name GRF_VO_CON3 is assumed.
173 */
174#define RK3568_GRF_VO_CON3 0x36c
175#define RK3568_DSI1_SKEWCALHS (0x1f << 11)
176#define RK3568_DSI1_FORCETXSTOPMODE (0xf << 4)
177#define RK3568_DSI1_TURNDISABLE BIT(2)
178#define RK3568_DSI1_FORCERXMODE BIT(0)
179
180#define HIWORD_UPDATE(val, mask) (val | (mask) << 16)
181
182/* Timeout for regulator on/off, pll lock/unlock & fifo empty */
183#define TIMEOUT_US 200000
184
185enum {
186 BANDGAP_97_07,
187 BANDGAP_98_05,
188 BANDGAP_99_02,
189 BANDGAP_100_00,
190 BANDGAP_93_17,
191 BANDGAP_94_15,
192 BANDGAP_95_12,
193 BANDGAP_96_10,
194};
195
196enum {
197 BIASEXTR_87_1,
198 BIASEXTR_91_5,
199 BIASEXTR_95_9,
200 BIASEXTR_100,
201 BIASEXTR_105_94,
202 BIASEXTR_111_88,
203 BIASEXTR_118_8,
204 BIASEXTR_127_7,
205};
206
207struct rockchip_dw_dsi_chip_data {
208 u32 reg;
209
210 u32 lcdsel_grf_reg;
211 u32 lcdsel_big;
212 u32 lcdsel_lit;
213
214 u32 enable_grf_reg;
215 u32 enable;
216
217 u32 lanecfg1_grf_reg;
218 u32 lanecfg1;
219 u32 lanecfg2_grf_reg;
220 u32 lanecfg2;
221
222 unsigned int flags;
223 unsigned int max_data_lanes;
224};
225
226struct dw_rockchip_dsi_priv {
227 struct mipi_dsi_device device;
228 void __iomem *base;
229 struct udevice *panel;
Ondrej Jirmanc61f4f72023-05-22 23:47:08 +0200230 void __iomem *grf;
Chris Morgan8895dd32023-03-24 13:53:07 -0500231
232 /* Optional external dphy */
233 struct phy phy;
234 struct phy_configure_opts_mipi_dphy phy_opts;
235
236 struct clk *pclk;
237 struct clk *ref;
Ondrej Jirmanf1ecb852023-05-25 14:29:03 +0200238 struct clk *grf_clk;
239 struct clk *phy_cfg_clk;
Chris Morgan8895dd32023-03-24 13:53:07 -0500240 struct reset_ctl *rst;
241 unsigned int lane_mbps; /* per lane */
242 u16 input_div;
243 u16 feedback_div;
244 const struct rockchip_dw_dsi_chip_data *cdata;
245 struct udevice *dsi_host;
246};
247
248static inline void dsi_write(struct dw_rockchip_dsi_priv *dsi, u32 reg, u32 val)
249{
250 writel(val, dsi->base + reg);
251}
252
253static inline u32 dsi_read(struct dw_rockchip_dsi_priv *dsi, u32 reg)
254{
255 return readl(dsi->base + reg);
256}
257
258static inline void dsi_set(struct dw_rockchip_dsi_priv *dsi, u32 reg, u32 mask)
259{
260 dsi_write(dsi, reg, dsi_read(dsi, reg) | mask);
261}
262
263static inline void dsi_clear(struct dw_rockchip_dsi_priv *dsi, u32 reg, u32 mask)
264{
265 dsi_write(dsi, reg, dsi_read(dsi, reg) & ~mask);
266}
267
268static inline void dsi_update_bits(struct dw_rockchip_dsi_priv *dsi, u32 reg,
269 u32 mask, u32 val)
270{
271 dsi_write(dsi, reg, (dsi_read(dsi, reg) & ~mask) | val);
272}
273
274static void dw_mipi_dsi_phy_write(struct dw_rockchip_dsi_priv *dsi,
275 u8 test_code,
276 u8 test_data)
277{
278 /*
279 * With the falling edge on TESTCLK, the TESTDIN[7:0] signal content
280 * is latched internally as the current test code. Test data is
281 * programmed internally by rising edge on TESTCLK.
282 */
283 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
284
285 dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_TESTEN | PHY_TESTDOUT(0) |
286 PHY_TESTDIN(test_code));
287
288 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_UNTESTCLK | PHY_UNTESTCLR);
289
290 dsi_write(dsi, DSI_PHY_TST_CTRL1, PHY_UNTESTEN | PHY_TESTDOUT(0) |
291 PHY_TESTDIN(test_data));
292
293 dsi_write(dsi, DSI_PHY_TST_CTRL0, PHY_TESTCLK | PHY_UNTESTCLR);
294}
295
296struct dphy_pll_parameter_map {
297 unsigned int max_mbps;
298 u8 hsfreqrange;
299 u8 icpctrl;
300 u8 lpfctrl;
301};
302
303/* The table is based on 27MHz DPHY pll reference clock. */
304static const struct dphy_pll_parameter_map dppa_map[] = {
305 { 89, 0x00, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
306 { 99, 0x10, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
307 { 109, 0x20, CP_CURRENT_3UA, LPF_RESISTORS_13KOHM },
308 { 129, 0x01, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
309 { 139, 0x11, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
310 { 149, 0x21, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
311 { 169, 0x02, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
312 { 179, 0x12, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
313 { 199, 0x22, CP_CURRENT_6UA, LPF_RESISTORS_13KOHM },
314 { 219, 0x03, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
315 { 239, 0x13, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
316 { 249, 0x23, CP_CURRENT_4_5UA, LPF_RESISTORS_13KOHM },
317 { 269, 0x04, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM },
318 { 299, 0x14, CP_CURRENT_6UA, LPF_RESISTORS_11_5KOHM },
319 { 329, 0x05, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
320 { 359, 0x15, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
321 { 399, 0x25, CP_CURRENT_3UA, LPF_RESISTORS_15_5KOHM },
322 { 449, 0x06, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
323 { 499, 0x16, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
324 { 549, 0x07, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM },
325 { 599, 0x17, CP_CURRENT_7_5UA, LPF_RESISTORS_10_5KOHM },
326 { 649, 0x08, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
327 { 699, 0x18, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
328 { 749, 0x09, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
329 { 799, 0x19, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
330 { 849, 0x29, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
331 { 899, 0x39, CP_CURRENT_7_5UA, LPF_RESISTORS_11_5KOHM },
332 { 949, 0x0a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
333 { 999, 0x1a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
334 {1049, 0x2a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
335 {1099, 0x3a, CP_CURRENT_12UA, LPF_RESISTORS_8KOHM },
336 {1149, 0x0b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
337 {1199, 0x1b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
338 {1249, 0x2b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
339 {1299, 0x3b, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
340 {1349, 0x0c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
341 {1399, 0x1c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
342 {1449, 0x2c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM },
343 {1500, 0x3c, CP_CURRENT_12UA, LPF_RESISTORS_10_5KOHM }
344};
345
346static int max_mbps_to_parameter(unsigned int max_mbps)
347{
348 int i;
349
350 for (i = 0; i < ARRAY_SIZE(dppa_map); i++)
351 if (dppa_map[i].max_mbps >= max_mbps)
352 return i;
353
354 return -EINVAL;
355}
356
357/*
358 * ns2bc - Nanoseconds to byte clock cycles
359 */
360static inline unsigned int ns2bc(struct dw_rockchip_dsi_priv *dsi, int ns)
361{
362 return DIV_ROUND_UP(ns * dsi->lane_mbps / 8, 1000);
363}
364
365/*
366 * ns2ui - Nanoseconds to UI time periods
367 */
368static inline unsigned int ns2ui(struct dw_rockchip_dsi_priv *dsi, int ns)
369{
370 return DIV_ROUND_UP(ns * dsi->lane_mbps, 1000);
371}
372
373static int dsi_phy_init(void *priv_data)
374{
375 struct mipi_dsi_device *device = priv_data;
376 struct udevice *dev = device->dev;
377 struct dw_rockchip_dsi_priv *dsi = dev_get_priv(dev);
378 int ret, i, vco;
379
Ondrej Jirman6518b732023-05-22 23:47:03 +0200380 if (dsi->phy.dev) {
Chris Morgan8895dd32023-03-24 13:53:07 -0500381 ret = generic_phy_configure(&dsi->phy, &dsi->phy_opts);
382 if (ret) {
383 dev_err(dsi->dsi_host,
384 "Configure external dphy fail %d\n",
385 ret);
386 return ret;
387 }
388
389 ret = generic_phy_power_on(&dsi->phy);
390 if (ret) {
391 dev_err(dsi->dsi_host,
392 "Generic phy power on fail %d\n", ret);
393 return ret;
394 }
395
396 return 0;
397 }
398
399 /*
400 * Get vco from frequency(lane_mbps)
401 * vco frequency table
402 * 000 - between 80 and 200 MHz
403 * 001 - between 200 and 300 MHz
404 * 010 - between 300 and 500 MHz
405 * 011 - between 500 and 700 MHz
406 * 100 - between 700 and 900 MHz
407 * 101 - between 900 and 1100 MHz
408 * 110 - between 1100 and 1300 MHz
409 * 111 - between 1300 and 1500 MHz
410 */
411 vco = (dsi->lane_mbps < 200) ? 0 : (dsi->lane_mbps + 100) / 200;
412
413 i = max_mbps_to_parameter(dsi->lane_mbps);
414 if (i < 0) {
415 dev_err(dsi->dsi_host,
416 "failed to get parameter for %dmbps clock\n",
417 dsi->lane_mbps);
418 return i;
419 }
420
421 dw_mipi_dsi_phy_write(dsi, PLL_BIAS_CUR_SEL_CAP_VCO_CONTROL,
422 BYPASS_VCO_RANGE |
423 VCO_RANGE_CON_SEL(vco) |
424 VCO_IN_CAP_CON_LOW |
425 REF_BIAS_CUR_SEL);
426
427 dw_mipi_dsi_phy_write(dsi, PLL_CP_CONTROL_PLL_LOCK_BYPASS,
428 CP_CURRENT_SEL(dppa_map[i].icpctrl));
429 dw_mipi_dsi_phy_write(dsi, PLL_LPF_AND_CP_CONTROL,
430 CP_PROGRAM_EN | LPF_PROGRAM_EN |
431 LPF_RESISTORS_SEL(dppa_map[i].lpfctrl));
432
433 dw_mipi_dsi_phy_write(dsi, HS_RX_CONTROL_OF_LANE_0,
434 HSFREQRANGE_SEL(dppa_map[i].hsfreqrange));
435
436 dw_mipi_dsi_phy_write(dsi, PLL_INPUT_DIVIDER_RATIO,
437 INPUT_DIVIDER(dsi->input_div));
438 dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
439 LOOP_DIV_LOW_SEL(dsi->feedback_div) |
440 LOW_PROGRAM_EN);
441 /*
442 * We need set PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL immediately
443 * to make the configured LSB effective according to IP simulation
444 * and lab test results.
445 * Only in this way can we get correct mipi phy pll frequency.
446 */
447 dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
448 PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
449 dw_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO,
450 LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
451 HIGH_PROGRAM_EN);
452 dw_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL,
453 PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
454
455 dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
456 LOW_PROGRAM_EN | BIASEXTR_SEL(BIASEXTR_127_7));
457 dw_mipi_dsi_phy_write(dsi, AFE_BIAS_BANDGAP_ANALOG_PROGRAMMABILITY,
458 HIGH_PROGRAM_EN | BANDGAP_SEL(BANDGAP_96_10));
459
460 dw_mipi_dsi_phy_write(dsi, BANDGAP_AND_BIAS_CONTROL,
461 POWER_CONTROL | INTERNAL_REG_CURRENT |
462 BIAS_BLOCK_ON | BANDGAP_ON);
463
464 dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
465 TER_RESISTOR_LOW | TER_CAL_DONE |
466 SETRD_MAX | TER_RESISTORS_ON);
467 dw_mipi_dsi_phy_write(dsi, TERMINATION_RESISTER_CONTROL,
468 TER_RESISTOR_HIGH | LEVEL_SHIFTERS_ON |
469 SETRD_MAX | POWER_MANAGE |
470 TER_RESISTORS_ON);
471
472 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_REQUEST_STATE_TIME_CONTROL,
473 TLP_PROGRAM_EN | ns2bc(dsi, 500));
474 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_PREPARE_STATE_TIME_CONTROL,
475 THS_PRE_PROGRAM_EN | ns2ui(dsi, 40));
476 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_HS_ZERO_STATE_TIME_CONTROL,
477 THS_ZERO_PROGRAM_EN | ns2bc(dsi, 300));
478 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_TRAIL_STATE_TIME_CONTROL,
479 THS_PRE_PROGRAM_EN | ns2ui(dsi, 100));
480 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_EXIT_STATE_TIME_CONTROL,
481 BIT(5) | ns2bc(dsi, 100));
482 dw_mipi_dsi_phy_write(dsi, HS_TX_CLOCK_LANE_POST_TIME_CONTROL,
483 BIT(5) | (ns2bc(dsi, 60) + 7));
484
485 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_REQUEST_STATE_TIME_CONTROL,
486 TLP_PROGRAM_EN | ns2bc(dsi, 500));
487 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_PREPARE_STATE_TIME_CONTROL,
488 THS_PRE_PROGRAM_EN | (ns2ui(dsi, 50) + 20));
489 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_HS_ZERO_STATE_TIME_CONTROL,
490 THS_ZERO_PROGRAM_EN | (ns2bc(dsi, 140) + 2));
491 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_TRAIL_STATE_TIME_CONTROL,
492 THS_PRE_PROGRAM_EN | (ns2ui(dsi, 60) + 8));
493 dw_mipi_dsi_phy_write(dsi, HS_TX_DATA_LANE_EXIT_STATE_TIME_CONTROL,
494 BIT(5) | ns2bc(dsi, 100));
495
Ondrej Jirmanc6835442023-05-22 23:47:05 +0200496 return 0;
Chris Morgan8895dd32023-03-24 13:53:07 -0500497}
498
499static void dsi_phy_post_set_mode(void *priv_data, unsigned long mode_flags)
500{
501 struct mipi_dsi_device *device = priv_data;
502 struct udevice *dev = device->dev;
503 struct dw_rockchip_dsi_priv *dsi = dev_get_priv(dev);
504
505 dev_dbg(dev, "Set mode %p enable %ld\n", dsi,
506 mode_flags & MIPI_DSI_MODE_VIDEO);
507
508 if (!dsi)
509 return;
510
511 /*
512 * DSI wrapper must be enabled in video mode & disabled in command mode.
513 * If wrapper is enabled in command mode, the display controller
514 * register access will hang. Note that this was carried over from the
515 * stm32 dsi driver and is unknown if necessary for Rockchip.
516 */
517
518 if (mode_flags & MIPI_DSI_MODE_VIDEO)
519 dsi_set(dsi, DSI_WCR, WCR_DSIEN);
520 else
521 dsi_clear(dsi, DSI_WCR, WCR_DSIEN);
522}
523
524static int
525dw_mipi_dsi_get_lane_mbps(void *priv_data, struct display_timing *timings,
526 u32 lanes, u32 format, unsigned int *lane_mbps)
527{
528 struct mipi_dsi_device *device = priv_data;
529 struct udevice *dev = device->dev;
530 struct dw_rockchip_dsi_priv *dsi = dev_get_priv(dev);
531 int bpp;
532 unsigned long mpclk, tmp;
533 unsigned int target_mbps = 1000;
534 unsigned int max_mbps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps;
535 unsigned long best_freq = 0;
536 unsigned long fvco_min, fvco_max, fin, fout;
537 unsigned int min_prediv, max_prediv;
538 unsigned int _prediv, best_prediv;
539 unsigned long _fbdiv, best_fbdiv;
540 unsigned long min_delta = ULONG_MAX;
Chris Morgan8895dd32023-03-24 13:53:07 -0500541
542 bpp = mipi_dsi_pixel_format_to_bpp(format);
543 if (bpp < 0) {
544 dev_err(dsi->dsi_host,
545 "failed to get bpp for pixel format %d\n",
546 format);
547 return bpp;
548 }
549
550 mpclk = DIV_ROUND_UP(timings->pixelclock.typ, 1000);
551 if (mpclk) {
552 /* take 1 / 0.8, since mbps must big than bandwidth of RGB */
553 tmp = (mpclk * (bpp / lanes) * 10 / 8) / 1000;
554 if (tmp < max_mbps)
555 target_mbps = tmp;
556 else
557 dev_err(dsi->dsi_host,
558 "DPHY clock frequency is out of range\n");
559 }
560
561 /* for external phy only the mipi_dphy_config is necessary */
Ondrej Jirman6518b732023-05-22 23:47:03 +0200562 if (dsi->phy.dev) {
Chris Morgan8895dd32023-03-24 13:53:07 -0500563 phy_mipi_dphy_get_default_config(timings->pixelclock.typ * 10 / 8,
564 bpp, lanes,
565 &dsi->phy_opts);
566 dsi->lane_mbps = target_mbps;
567 *lane_mbps = dsi->lane_mbps;
568
569 return 0;
570 }
571
Ondrej Jirmanc27db342023-05-22 23:47:06 +0200572 fin = clk_get_rate(dsi->ref);
Chris Morgan8895dd32023-03-24 13:53:07 -0500573 fout = target_mbps * USEC_PER_SEC;
574
575 /* constraint: 5Mhz <= Fref / N <= 40MHz */
576 min_prediv = DIV_ROUND_UP(fin, 40 * USEC_PER_SEC);
577 max_prediv = fin / (5 * USEC_PER_SEC);
578
579 /* constraint: 80MHz <= Fvco <= 1500Mhz */
580 fvco_min = 80 * USEC_PER_SEC;
581 fvco_max = 1500 * USEC_PER_SEC;
582
583 for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) {
584 u64 tmp;
585 u32 delta;
586 /* Fvco = Fref * M / N */
587 tmp = (u64)fout * _prediv;
588 do_div(tmp, fin);
589 _fbdiv = tmp;
590 /*
591 * Due to the use of a "by 2 pre-scaler," the range of the
592 * feedback multiplication value M is limited to even division
593 * numbers, and m must be greater than 6, not bigger than 512.
594 */
595 if (_fbdiv < 6 || _fbdiv > 512)
596 continue;
597
598 _fbdiv += _fbdiv % 2;
599
600 tmp = (u64)_fbdiv * fin;
601 do_div(tmp, _prediv);
602 if (tmp < fvco_min || tmp > fvco_max)
603 continue;
604
605 delta = abs(fout - tmp);
606 if (delta < min_delta) {
607 best_prediv = _prediv;
608 best_fbdiv = _fbdiv;
609 min_delta = delta;
610 best_freq = tmp;
611 }
612 }
613
614 if (best_freq) {
615 dsi->lane_mbps = DIV_ROUND_UP(best_freq, USEC_PER_SEC);
616 *lane_mbps = dsi->lane_mbps;
617 dsi->input_div = best_prediv;
618 dsi->feedback_div = best_fbdiv;
619 } else {
620 dev_err(dsi->dsi_host, "Can not find best_freq for DPHY\n");
621 return -EINVAL;
622 }
623
624 return 0;
625}
626
627struct hstt {
628 unsigned int maxfreq;
629 struct mipi_dsi_phy_timing timing;
630};
631
632#define HSTT(_maxfreq, _c_lp2hs, _c_hs2lp, _d_lp2hs, _d_hs2lp) \
633{ \
634 .maxfreq = _maxfreq, \
635 .timing = { \
636 .clk_lp2hs = _c_lp2hs, \
637 .clk_hs2lp = _c_hs2lp, \
638 .data_lp2hs = _d_lp2hs, \
639 .data_hs2lp = _d_hs2lp, \
640 } \
641}
642
643/*
644 * Table A-3 High-Speed Transition Times
645 * (Note spacing is deliberate for readability).
646 */
647static struct hstt hstt_table[] = {
648 HSTT( 90, 32, 20, 26, 13),
649 HSTT( 100, 35, 23, 28, 14),
650 HSTT( 110, 32, 22, 26, 13),
651 HSTT( 130, 31, 20, 27, 13),
652 HSTT( 140, 33, 22, 26, 14),
653 HSTT( 150, 33, 21, 26, 14),
654 HSTT( 170, 32, 20, 27, 13),
655 HSTT( 180, 36, 23, 30, 15),
656 HSTT( 200, 40, 22, 33, 15),
657 HSTT( 220, 40, 22, 33, 15),
658 HSTT( 240, 44, 24, 36, 16),
659 HSTT( 250, 48, 24, 38, 17),
660 HSTT( 270, 48, 24, 38, 17),
661 HSTT( 300, 50, 27, 41, 18),
662 HSTT( 330, 56, 28, 45, 18),
663 HSTT( 360, 59, 28, 48, 19),
664 HSTT( 400, 61, 30, 50, 20),
665 HSTT( 450, 67, 31, 55, 21),
666 HSTT( 500, 73, 31, 59, 22),
667 HSTT( 550, 79, 36, 63, 24),
668 HSTT( 600, 83, 37, 68, 25),
669 HSTT( 650, 90, 38, 73, 27),
670 HSTT( 700, 95, 40, 77, 28),
671 HSTT( 750, 102, 40, 84, 28),
672 HSTT( 800, 106, 42, 87, 30),
673 HSTT( 850, 113, 44, 93, 31),
674 HSTT( 900, 118, 47, 98, 32),
675 HSTT( 950, 124, 47, 102, 34),
676 HSTT(1000, 130, 49, 107, 35),
677 HSTT(1050, 135, 51, 111, 37),
678 HSTT(1100, 139, 51, 114, 38),
679 HSTT(1150, 146, 54, 120, 40),
680 HSTT(1200, 153, 57, 125, 41),
681 HSTT(1250, 158, 58, 130, 42),
682 HSTT(1300, 163, 58, 135, 44),
683 HSTT(1350, 168, 60, 140, 45),
684 HSTT(1400, 172, 64, 144, 47),
685 HSTT(1450, 176, 65, 148, 48),
686 HSTT(1500, 181, 66, 153, 50)
687};
688
689static int dw_mipi_dsi_rockchip_get_timing(void *priv_data,
690 unsigned int lane_mbps,
691 struct mipi_dsi_phy_timing *timing)
692{
693 int i;
694
695 for (i = 0; i < ARRAY_SIZE(hstt_table); i++)
696 if (lane_mbps < hstt_table[i].maxfreq)
697 break;
698
699 if (i == ARRAY_SIZE(hstt_table))
700 i--;
701
702 *timing = hstt_table[i].timing;
703
704 return 0;
705}
706
707static const struct mipi_dsi_phy_ops dsi_rockchip_phy_ops = {
708 .init = dsi_phy_init,
709 .get_lane_mbps = dw_mipi_dsi_get_lane_mbps,
710 .get_timing = dw_mipi_dsi_rockchip_get_timing,
711 .post_set_mode = dsi_phy_post_set_mode,
712};
713
714static int dw_mipi_dsi_rockchip_attach(struct udevice *dev)
715{
716 struct dw_rockchip_dsi_priv *priv = dev_get_priv(dev);
717 struct mipi_dsi_device *device = &priv->device;
718 struct mipi_dsi_panel_plat *mplat;
719 struct display_timing timings;
720 int ret;
721
722 ret = uclass_first_device_err(UCLASS_PANEL, &priv->panel);
723 if (ret) {
724 dev_err(dev, "panel device error %d\n", ret);
725 return ret;
726 }
727
728 mplat = dev_get_plat(priv->panel);
729 mplat->device = &priv->device;
730 device->lanes = mplat->lanes;
731 device->format = mplat->format;
732 device->mode_flags = mplat->mode_flags;
733
734 ret = panel_get_display_timing(priv->panel, &timings);
735 if (ret) {
736 ret = ofnode_decode_display_timing(dev_ofnode(priv->panel),
737 0, &timings);
738 if (ret) {
739 dev_err(dev, "decode display timing error %d\n", ret);
740 return ret;
741 }
742 }
743
744 ret = uclass_get_device(UCLASS_DSI_HOST, 0, &priv->dsi_host);
745 if (ret) {
746 dev_err(dev, "No video dsi host detected %d\n", ret);
747 return ret;
748 }
749
750 ret = dsi_host_init(priv->dsi_host, device, &timings, 4,
751 &dsi_rockchip_phy_ops);
752 if (ret) {
753 dev_err(dev, "failed to initialize mipi dsi host\n");
754 return ret;
755 }
756
757 return 0;
758}
759
760static int dw_mipi_dsi_rockchip_set_bl(struct udevice *dev, int percent)
761{
762 struct dw_rockchip_dsi_priv *priv = dev_get_priv(dev);
763 int ret;
764
765 /*
766 * Allow backlight to be optional, since this driver may be
767 * used to simply detect a panel rather than bring one up.
768 */
769 ret = panel_enable_backlight(priv->panel);
770 if ((ret) && (ret != -ENOSYS)) {
771 dev_err(dev, "panel %s enable backlight error %d\n",
772 priv->panel->name, ret);
773 return ret;
774 }
775
776 ret = dsi_host_enable(priv->dsi_host);
777 if (ret) {
778 dev_err(dev, "failed to enable mipi dsi host\n");
779 return ret;
780 }
781
782 return 0;
783}
784
785static void dw_mipi_dsi_rockchip_config(struct dw_rockchip_dsi_priv *dsi)
786{
787 if (dsi->cdata->lanecfg1_grf_reg)
Ondrej Jirmanc61f4f72023-05-22 23:47:08 +0200788 rk_setreg(dsi->grf + dsi->cdata->lanecfg1_grf_reg, dsi->cdata->lanecfg1);
Chris Morgan8895dd32023-03-24 13:53:07 -0500789
790 if (dsi->cdata->lanecfg2_grf_reg)
Ondrej Jirmanc61f4f72023-05-22 23:47:08 +0200791 rk_setreg(dsi->grf + dsi->cdata->lanecfg2_grf_reg, dsi->cdata->lanecfg2);
Chris Morgan8895dd32023-03-24 13:53:07 -0500792
793 if (dsi->cdata->enable_grf_reg)
Ondrej Jirmanc61f4f72023-05-22 23:47:08 +0200794 rk_setreg(dsi->grf + dsi->cdata->enable_grf_reg, dsi->cdata->enable);
Chris Morgan8895dd32023-03-24 13:53:07 -0500795}
796
797static int dw_mipi_dsi_rockchip_bind(struct udevice *dev)
798{
799 int ret;
800
801 ret = device_bind_driver_to_node(dev, "dw_mipi_dsi", "dsihost",
802 dev_ofnode(dev), NULL);
803 if (ret) {
804 dev_err(dev, "failed to bind driver to node\n");
805 return ret;
806 }
807
808 return dm_scan_fdt_dev(dev);
809}
810
811static int dw_mipi_dsi_rockchip_probe(struct udevice *dev)
812{
813 struct dw_rockchip_dsi_priv *priv = dev_get_priv(dev);
814 struct mipi_dsi_device *device = &priv->device;
815 int ret, i;
816 const struct rockchip_dw_dsi_chip_data *cdata =
817 (const struct rockchip_dw_dsi_chip_data *)dev_get_driver_data(dev);
818
819 device->dev = dev;
820
821 priv->base = (void *)dev_read_addr(dev);
822 if ((fdt_addr_t)priv->base == FDT_ADDR_T_NONE) {
823 dev_err(dev, "dsi dt register address error\n");
824 return -EINVAL;
825 }
826
Ondrej Jirmanc61f4f72023-05-22 23:47:08 +0200827 priv->grf = syscon_get_first_range(ROCKCHIP_SYSCON_GRF);
828
Chris Morgan8895dd32023-03-24 13:53:07 -0500829 i = 0;
830 while (cdata[i].reg) {
831 if (cdata[i].reg == (fdt_addr_t)priv->base) {
832 priv->cdata = &cdata[i];
833 break;
834 }
835
836 i++;
837 }
838
839 if (!priv->cdata) {
840 dev_err(dev, "no dsi-config for %s node\n", dev->name);
841 return -EINVAL;
842 }
843
844 /*
845 * Get an optional external dphy. The external dphy stays as
846 * NULL if it's not initialized.
847 */
848 ret = generic_phy_get_by_name(dev, "dphy", &priv->phy);
Ondrej Jirman81162942023-05-22 23:47:07 +0200849 if (ret && ret != -ENODATA) {
Chris Morgan8895dd32023-03-24 13:53:07 -0500850 dev_err(dev, "failed to get mipi dphy: %d\n", ret);
Ondrej Jirman81162942023-05-22 23:47:07 +0200851 return ret;
Chris Morgan8895dd32023-03-24 13:53:07 -0500852 }
853
854 priv->pclk = devm_clk_get(dev, "pclk");
855 if (IS_ERR(priv->pclk)) {
Ondrej Jirman139edfc2023-05-22 23:47:04 +0200856 ret = PTR_ERR(priv->pclk);
Chris Morgan8895dd32023-03-24 13:53:07 -0500857 dev_err(dev, "peripheral clock get error %d\n", ret);
858 return ret;
859 }
860
861 /* Get a ref clock only if not using an external phy. */
Ondrej Jirman6518b732023-05-22 23:47:03 +0200862 if (priv->phy.dev) {
Chris Morgan8895dd32023-03-24 13:53:07 -0500863 dev_dbg(dev, "setting priv->ref to NULL\n");
864 priv->ref = NULL;
865
866 } else {
867 priv->ref = devm_clk_get(dev, "ref");
Ondrej Jirman139edfc2023-05-22 23:47:04 +0200868 if (IS_ERR(priv->ref)) {
869 ret = PTR_ERR(priv->ref);
Chris Morgan8895dd32023-03-24 13:53:07 -0500870 dev_err(dev, "pll reference clock get error %d\n", ret);
871 return ret;
872 }
Ondrej Jirmanf1ecb852023-05-25 14:29:03 +0200873 }
874
875 if (cdata->flags & DW_MIPI_NEEDS_PHY_CFG_CLK) {
876 priv->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
877 if (IS_ERR(priv->phy_cfg_clk)) {
878 ret = PTR_ERR(priv->phy_cfg_clk);
879 dev_err(dev, "phy_cfg_clk clock get error %d\n", ret);
880 return ret;
881 }
882
883 clk_enable(priv->phy_cfg_clk);
884 }
885
886 if (cdata->flags & DW_MIPI_NEEDS_GRF_CLK) {
887 priv->grf_clk = devm_clk_get(dev, "grf");
888 if (IS_ERR(priv->grf_clk)) {
889 ret = PTR_ERR(priv->grf_clk);
890 dev_err(dev, "grf_clk clock get error %d\n", ret);
891 return ret;
892 }
893
894 clk_enable(priv->grf_clk);
Chris Morgan8895dd32023-03-24 13:53:07 -0500895 }
896
897 priv->rst = devm_reset_control_get_by_index(device->dev, 0);
898 if (IS_ERR(priv->rst)) {
Ondrej Jirman139edfc2023-05-22 23:47:04 +0200899 ret = PTR_ERR(priv->rst);
900 dev_err(dev, "missing dsi hardware reset %d\n", ret);
Chris Morgan8895dd32023-03-24 13:53:07 -0500901 return ret;
902 }
903
904 /* Reset */
905 reset_deassert(priv->rst);
906
907 dw_mipi_dsi_rockchip_config(priv);
908
909 return 0;
910}
911
912struct video_bridge_ops dw_mipi_dsi_rockchip_ops = {
913 .attach = dw_mipi_dsi_rockchip_attach,
914 .set_backlight = dw_mipi_dsi_rockchip_set_bl,
915};
916
Ondrej Jirmanf1ecb852023-05-25 14:29:03 +0200917static const struct rockchip_dw_dsi_chip_data rk3399_chip_data[] = {
918 {
919 .reg = 0xff960000,
920 .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
921 .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI0_LCDC_SEL),
922 .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI0_LCDC_SEL,
923 RK3399_DSI0_LCDC_SEL),
924
925 .lanecfg1_grf_reg = RK3399_GRF_SOC_CON22,
926 .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI0_TURNREQUEST |
927 RK3399_DSI0_TURNDISABLE |
928 RK3399_DSI0_FORCETXSTOPMODE |
929 RK3399_DSI0_FORCERXMODE),
930
931 .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
932 .max_data_lanes = 4,
933 },
934 {
935 .reg = 0xff968000,
936 .lcdsel_grf_reg = RK3399_GRF_SOC_CON20,
937 .lcdsel_big = HIWORD_UPDATE(0, RK3399_DSI1_LCDC_SEL),
938 .lcdsel_lit = HIWORD_UPDATE(RK3399_DSI1_LCDC_SEL,
939 RK3399_DSI1_LCDC_SEL),
940
941 .lanecfg1_grf_reg = RK3399_GRF_SOC_CON23,
942 .lanecfg1 = HIWORD_UPDATE(0, RK3399_DSI1_TURNDISABLE |
943 RK3399_DSI1_FORCETXSTOPMODE |
944 RK3399_DSI1_FORCERXMODE |
945 RK3399_DSI1_ENABLE),
946
947 .lanecfg2_grf_reg = RK3399_GRF_SOC_CON24,
948 .lanecfg2 = HIWORD_UPDATE(RK3399_TXRX_MASTERSLAVEZ |
949 RK3399_TXRX_ENABLECLK,
950 RK3399_TXRX_MASTERSLAVEZ |
951 RK3399_TXRX_ENABLECLK |
952 RK3399_TXRX_BASEDIR),
953
954 .enable_grf_reg = RK3399_GRF_SOC_CON23,
955 .enable = HIWORD_UPDATE(RK3399_DSI1_ENABLE, RK3399_DSI1_ENABLE),
956
957 .flags = DW_MIPI_NEEDS_PHY_CFG_CLK | DW_MIPI_NEEDS_GRF_CLK,
958 .max_data_lanes = 4,
959 },
960 { /* sentinel */ }
961};
962
Chris Morgan8895dd32023-03-24 13:53:07 -0500963static const struct rockchip_dw_dsi_chip_data rk3568_chip_data[] = {
964 {
965 .reg = 0xfe060000,
966 .lanecfg1_grf_reg = RK3568_GRF_VO_CON2,
967 .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI0_SKEWCALHS |
968 RK3568_DSI0_FORCETXSTOPMODE |
969 RK3568_DSI0_TURNDISABLE |
970 RK3568_DSI0_FORCERXMODE),
971 .max_data_lanes = 4,
972 },
973 {
974 .reg = 0xfe070000,
975 .lanecfg1_grf_reg = RK3568_GRF_VO_CON3,
976 .lanecfg1 = HIWORD_UPDATE(0, RK3568_DSI1_SKEWCALHS |
977 RK3568_DSI1_FORCETXSTOPMODE |
978 RK3568_DSI1_TURNDISABLE |
979 RK3568_DSI1_FORCERXMODE),
980 .max_data_lanes = 4,
981 },
982 { /* sentinel */ }
983};
984
985static const struct udevice_id dw_mipi_dsi_rockchip_dt_ids[] = {
Ondrej Jirmanf1ecb852023-05-25 14:29:03 +0200986 { .compatible = "rockchip,rk3399-mipi-dsi",
987 .data = (long)&rk3399_chip_data,
988 },
Chris Morgan8895dd32023-03-24 13:53:07 -0500989 { .compatible = "rockchip,rk3568-mipi-dsi",
990 .data = (long)&rk3568_chip_data,
991 },
992 { /* sentinel */ }
993};
994
995U_BOOT_DRIVER(dw_mipi_dsi_rockchip) = {
996 .name = "dw-mipi-dsi-rockchip",
997 .id = UCLASS_VIDEO_BRIDGE,
998 .of_match = dw_mipi_dsi_rockchip_dt_ids,
999 .bind = dw_mipi_dsi_rockchip_bind,
1000 .probe = dw_mipi_dsi_rockchip_probe,
1001 .ops = &dw_mipi_dsi_rockchip_ops,
1002 .priv_auto = sizeof(struct dw_rockchip_dsi_priv),
1003};