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