xref: /rk3399_rockchip-uboot/drivers/video/drm/max96755f.c (revision e2c0a7ff3bf3535b38ddbfb9fd42525e2cea2507)
1*e2c0a7ffSGuochun Huang // SPDX-License-Identifier: GPL-2.0+
2*e2c0a7ffSGuochun Huang /*
3*e2c0a7ffSGuochun Huang  * (C) Copyright 2022 Rockchip Electronics Co., Ltd
4*e2c0a7ffSGuochun Huang  */
5*e2c0a7ffSGuochun Huang 
6*e2c0a7ffSGuochun Huang #include <common.h>
7*e2c0a7ffSGuochun Huang #include <dm.h>
8*e2c0a7ffSGuochun Huang #include <errno.h>
9*e2c0a7ffSGuochun Huang #include <i2c.h>
10*e2c0a7ffSGuochun Huang #include <max96755f.h>
11*e2c0a7ffSGuochun Huang #include <video_bridge.h>
12*e2c0a7ffSGuochun Huang #include <dm/of_access.h>
13*e2c0a7ffSGuochun Huang #include <linux/media-bus-format.h>
14*e2c0a7ffSGuochun Huang 
15*e2c0a7ffSGuochun Huang #include "rockchip_bridge.h"
16*e2c0a7ffSGuochun Huang #include "rockchip_display.h"
17*e2c0a7ffSGuochun Huang #include "rockchip_panel.h"
18*e2c0a7ffSGuochun Huang 
19*e2c0a7ffSGuochun Huang static void max96755f_mipi_dsi_rx_config(struct max96755f_priv *priv)
20*e2c0a7ffSGuochun Huang {
21*e2c0a7ffSGuochun Huang 	struct drm_display_mode *mode = &priv->mode;
22*e2c0a7ffSGuochun Huang 	u32 hfp, hsa, hbp, hact;
23*e2c0a7ffSGuochun Huang 	u32 vact, vsa, vfp, vbp;
24*e2c0a7ffSGuochun Huang 
25*e2c0a7ffSGuochun Huang 	dm_i2c_reg_clrset(priv->dev, 0x0331, NUM_LANES,
26*e2c0a7ffSGuochun Huang 			  FIELD_PREP(NUM_LANES, priv->num_lanes - 1));
27*e2c0a7ffSGuochun Huang 	if (!priv->dpi_deskew_en)
28*e2c0a7ffSGuochun Huang 		return;
29*e2c0a7ffSGuochun Huang 
30*e2c0a7ffSGuochun Huang 	vact = mode->vdisplay;
31*e2c0a7ffSGuochun Huang 	vsa = mode->vsync_end - mode->vsync_start;
32*e2c0a7ffSGuochun Huang 	vfp = mode->vsync_start - mode->vdisplay;
33*e2c0a7ffSGuochun Huang 	vbp = mode->vtotal - mode->vsync_end;
34*e2c0a7ffSGuochun Huang 	hact = mode->hdisplay;
35*e2c0a7ffSGuochun Huang 	hsa = mode->hsync_end - mode->hsync_start;
36*e2c0a7ffSGuochun Huang 	hfp = mode->hsync_start - mode->hdisplay;
37*e2c0a7ffSGuochun Huang 	hbp = mode->htotal - mode->hsync_end;
38*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03A4, 0xc1);
39*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x0385, FIELD_PREP(DPI_HSYNC_WIDTH_L, hsa));
40*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x0386, FIELD_PREP(DPI_VYSNC_WIDTH_L, vsa));
41*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x0387,
42*e2c0a7ffSGuochun Huang 			 FIELD_PREP(DPI_VSYNC_WIDTH_H, (vsa >> 8)) |
43*e2c0a7ffSGuochun Huang 			 FIELD_PREP(DPI_HSYNC_WIDTH_H, (hsa >> 8)));
44*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03a5, FIELD_PREP(DPI_VFP_L, vfp));
45*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03a6,
46*e2c0a7ffSGuochun Huang 			 FIELD_PREP(DPI_VBP_L, vbp) |
47*e2c0a7ffSGuochun Huang 			 FIELD_PREP(DPI_VFP_H, (vfp >> 8)));
48*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03a7, FIELD_PREP(DPI_VBP_H, (vbp >> 4)));
49*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03a8, FIELD_PREP(DPI_VACT_L, vact));
50*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03a9, FIELD_PREP(DPI_VACT_H, (vact >> 8)));
51*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03aa, FIELD_PREP(DPI_HFP_L, hfp));
52*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03ab,
53*e2c0a7ffSGuochun Huang 			 FIELD_PREP(DPI_HBP_L, hbp) |
54*e2c0a7ffSGuochun Huang 			 FIELD_PREP(DPI_HFP_H, (hfp >> 7)));
55*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03ac, FIELD_PREP(DPI_HBP_H, (hbp >> 4)));
56*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03ad, FIELD_PREP(DPI_HACT_L, hact));
57*e2c0a7ffSGuochun Huang 	dm_i2c_reg_write(priv->dev, 0x03ae, FIELD_PREP(DPI_HACT_H, (hact >> 8)));
58*e2c0a7ffSGuochun Huang }
59*e2c0a7ffSGuochun Huang 
60*e2c0a7ffSGuochun Huang static void max96755f_bridge_enable(struct rockchip_bridge *bridge)
61*e2c0a7ffSGuochun Huang {
62*e2c0a7ffSGuochun Huang 	struct udevice *dev = bridge->dev;
63*e2c0a7ffSGuochun Huang 	struct max96755f_priv *priv = dev_get_priv(dev->parent);
64*e2c0a7ffSGuochun Huang 
65*e2c0a7ffSGuochun Huang 	max96755f_mipi_dsi_rx_config(priv);
66*e2c0a7ffSGuochun Huang 	if (priv->split_mode) {
67*e2c0a7ffSGuochun Huang 		dm_i2c_reg_clrset(dev->parent, 0x0010,
68*e2c0a7ffSGuochun Huang 				  RESET_ONESHOT | AUTO_LINK | LINK_CFG,
69*e2c0a7ffSGuochun Huang 				  FIELD_PREP(RESET_ONESHOT, 1) |
70*e2c0a7ffSGuochun Huang 				  FIELD_PREP(AUTO_LINK, 0) |
71*e2c0a7ffSGuochun Huang 				  FIELD_PREP(LINK_CFG, SPLITTER_MODE));
72*e2c0a7ffSGuochun Huang 		mdelay(50);
73*e2c0a7ffSGuochun Huang 		dm_i2c_reg_clrset(dev->parent, 0x0053,
74*e2c0a7ffSGuochun Huang 				  TX_SPLIT_MASK_B | TX_SPLIT_MASK_A | TX_STR_SEL,
75*e2c0a7ffSGuochun Huang 				  FIELD_PREP(TX_SPLIT_MASK_B, 0) |
76*e2c0a7ffSGuochun Huang 				  FIELD_PREP(TX_SPLIT_MASK_A, 1) |
77*e2c0a7ffSGuochun Huang 				  FIELD_PREP(TX_STR_SEL, 0));
78*e2c0a7ffSGuochun Huang 		dm_i2c_reg_clrset(dev->parent, 0x0057,
79*e2c0a7ffSGuochun Huang 				  TX_SPLIT_MASK_B | TX_SPLIT_MASK_A | TX_STR_SEL,
80*e2c0a7ffSGuochun Huang 				  FIELD_PREP(TX_SPLIT_MASK_B, 1) |
81*e2c0a7ffSGuochun Huang 				  FIELD_PREP(TX_SPLIT_MASK_A, 0) |
82*e2c0a7ffSGuochun Huang 				  FIELD_PREP(TX_STR_SEL, 1));
83*e2c0a7ffSGuochun Huang 		dm_i2c_reg_clrset(dev->parent, 0x032a,
84*e2c0a7ffSGuochun Huang 				  DV_SWP_AB | DV_CONV | DV_SPL | DV_EN,
85*e2c0a7ffSGuochun Huang 				  FIELD_PREP(DV_SWP_AB, priv->dv_swp_ab) |
86*e2c0a7ffSGuochun Huang 				  FIELD_PREP(DV_CONV, 1) |
87*e2c0a7ffSGuochun Huang 				  FIELD_PREP(DV_SPL, 1) |
88*e2c0a7ffSGuochun Huang 				  FIELD_PREP(DV_EN, 1));
89*e2c0a7ffSGuochun Huang 		dm_i2c_reg_clrset(dev->parent, 0x0311,
90*e2c0a7ffSGuochun Huang 				  START_PORTAX | START_PORTAY,
91*e2c0a7ffSGuochun Huang 				  FIELD_PREP(START_PORTAX, 1) |
92*e2c0a7ffSGuochun Huang 				  FIELD_PREP(START_PORTAY, 1));
93*e2c0a7ffSGuochun Huang 		dm_i2c_reg_clrset(dev->parent, 0x0002,
94*e2c0a7ffSGuochun Huang 				  VID_TX_EN_X | VID_TX_EN_Y,
95*e2c0a7ffSGuochun Huang 				  FIELD_PREP(VID_TX_EN_X, 1) |
96*e2c0a7ffSGuochun Huang 				  FIELD_PREP(VID_TX_EN_Y, 1));
97*e2c0a7ffSGuochun Huang 
98*e2c0a7ffSGuochun Huang 	} else {
99*e2c0a7ffSGuochun Huang 		dm_i2c_reg_clrset(dev->parent, 0x0002, VID_TX_EN_X,
100*e2c0a7ffSGuochun Huang 				  FIELD_PREP(VID_TX_EN_X, 1));
101*e2c0a7ffSGuochun Huang 		dm_i2c_reg_clrset(dev->parent, 0x0311, START_PORTAX,
102*e2c0a7ffSGuochun Huang 				  FIELD_PREP(START_PORTAX, 1));
103*e2c0a7ffSGuochun Huang 	}
104*e2c0a7ffSGuochun Huang 
105*e2c0a7ffSGuochun Huang 	dm_i2c_reg_clrset(dev->parent, 0x0010, RESET_ONESHOT,
106*e2c0a7ffSGuochun Huang 			  FIELD_PREP(RESET_ONESHOT, 1));
107*e2c0a7ffSGuochun Huang 	mdelay(100);
108*e2c0a7ffSGuochun Huang }
109*e2c0a7ffSGuochun Huang 
110*e2c0a7ffSGuochun Huang static void max96755f_bridge_disable(struct rockchip_bridge *bridge)
111*e2c0a7ffSGuochun Huang {
112*e2c0a7ffSGuochun Huang 	struct udevice *dev = bridge->dev;
113*e2c0a7ffSGuochun Huang 	struct max96755f_priv *priv = dev_get_priv(dev->parent);
114*e2c0a7ffSGuochun Huang 
115*e2c0a7ffSGuochun Huang 	dm_i2c_reg_clrset(dev->parent, 0x0002, VID_TX_EN_X,
116*e2c0a7ffSGuochun Huang 			  FIELD_PREP(VID_TX_EN_X, 0));
117*e2c0a7ffSGuochun Huang 
118*e2c0a7ffSGuochun Huang 	if (priv->split_mode)
119*e2c0a7ffSGuochun Huang 		dm_i2c_reg_clrset(dev->parent, 0x0010,
120*e2c0a7ffSGuochun Huang 				  AUTO_LINK | LINK_CFG,
121*e2c0a7ffSGuochun Huang 				  FIELD_PREP(AUTO_LINK, 0) |
122*e2c0a7ffSGuochun Huang 				  FIELD_PREP(LINK_CFG, LINKA));
123*e2c0a7ffSGuochun Huang }
124*e2c0a7ffSGuochun Huang 
125*e2c0a7ffSGuochun Huang static void max96755f_bridge_mode_set(struct rockchip_bridge *bridge,
126*e2c0a7ffSGuochun Huang 				      const struct drm_display_mode *mode)
127*e2c0a7ffSGuochun Huang {
128*e2c0a7ffSGuochun Huang 	struct udevice *dev = bridge->dev;
129*e2c0a7ffSGuochun Huang 	struct max96755f_priv *priv = dev_get_priv(dev->parent);
130*e2c0a7ffSGuochun Huang 
131*e2c0a7ffSGuochun Huang 	memcpy(&priv->mode, mode, sizeof(struct drm_display_mode));
132*e2c0a7ffSGuochun Huang }
133*e2c0a7ffSGuochun Huang 
134*e2c0a7ffSGuochun Huang static const struct rockchip_bridge_funcs max96755f_bridge_funcs = {
135*e2c0a7ffSGuochun Huang 	.enable = max96755f_bridge_enable,
136*e2c0a7ffSGuochun Huang 	.disable = max96755f_bridge_disable,
137*e2c0a7ffSGuochun Huang 	.mode_set = max96755f_bridge_mode_set,
138*e2c0a7ffSGuochun Huang };
139*e2c0a7ffSGuochun Huang 
140*e2c0a7ffSGuochun Huang static int max96755f_bridge_probe(struct udevice *dev)
141*e2c0a7ffSGuochun Huang {
142*e2c0a7ffSGuochun Huang 	struct rockchip_bridge *bridge;
143*e2c0a7ffSGuochun Huang 	struct max96755f_priv *priv = dev_get_priv(dev->parent);
144*e2c0a7ffSGuochun Huang 
145*e2c0a7ffSGuochun Huang 	bridge = calloc(1, sizeof(*bridge));
146*e2c0a7ffSGuochun Huang 	if (!bridge)
147*e2c0a7ffSGuochun Huang 		return -ENOMEM;
148*e2c0a7ffSGuochun Huang 
149*e2c0a7ffSGuochun Huang 	dev->driver_data = (ulong)bridge;
150*e2c0a7ffSGuochun Huang 	bridge->dev = dev;
151*e2c0a7ffSGuochun Huang 	bridge->funcs = &max96755f_bridge_funcs;
152*e2c0a7ffSGuochun Huang 
153*e2c0a7ffSGuochun Huang 	priv->num_lanes = dev_read_u32_default(dev, "dsi,lanes", 4);
154*e2c0a7ffSGuochun Huang 	priv->dv_swp_ab = dev_read_bool(dev, "vd-swap-ab");
155*e2c0a7ffSGuochun Huang 	priv->dpi_deskew_en = dev_read_bool(dev, "dpi-deskew-en");
156*e2c0a7ffSGuochun Huang 
157*e2c0a7ffSGuochun Huang 	return 0;
158*e2c0a7ffSGuochun Huang }
159*e2c0a7ffSGuochun Huang 
160*e2c0a7ffSGuochun Huang static const struct udevice_id max96755f_bridge_of_match[] = {
161*e2c0a7ffSGuochun Huang 	{ .compatible = "maxim,max96755f-bridge", },
162*e2c0a7ffSGuochun Huang 	{ }
163*e2c0a7ffSGuochun Huang };
164*e2c0a7ffSGuochun Huang 
165*e2c0a7ffSGuochun Huang U_BOOT_DRIVER(max96755f_bridge) = {
166*e2c0a7ffSGuochun Huang 	.name = "max96755f_bridge",
167*e2c0a7ffSGuochun Huang 	.id = UCLASS_VIDEO_BRIDGE,
168*e2c0a7ffSGuochun Huang 	.of_match = max96755f_bridge_of_match,
169*e2c0a7ffSGuochun Huang 	.probe = max96755f_bridge_probe,
170*e2c0a7ffSGuochun Huang };
171