xref: /rk3399_rockchip-uboot/drivers/video/drm/rohm-bu18tl82.c (revision edbf2db2657c2d32af85569cab702995505b2d66)
1b80a334aSGuochun Huang // SPDX-License-Identifier: GPL-2.0+
2b80a334aSGuochun Huang /*
3b80a334aSGuochun Huang  * (C) Copyright 2022 Rockchip Electronics Co., Ltd
4b80a334aSGuochun Huang  */
5b80a334aSGuochun Huang 
6b80a334aSGuochun Huang #include <common.h>
7b80a334aSGuochun Huang #include <dm.h>
8b80a334aSGuochun Huang #include <errno.h>
9b80a334aSGuochun Huang #include <i2c.h>
10fa0df57cSGuochun Huang #include <drm/drm_mipi_dsi.h>
11b80a334aSGuochun Huang #include <video_bridge.h>
12b80a334aSGuochun Huang #include <asm/unaligned.h>
13b80a334aSGuochun Huang #include <linux/media-bus-format.h>
14b80a334aSGuochun Huang #include <power/regulator.h>
15b80a334aSGuochun Huang 
16b80a334aSGuochun Huang #include "rockchip_bridge.h"
17b80a334aSGuochun Huang #include "rockchip_display.h"
18b80a334aSGuochun Huang #include "rockchip_panel.h"
19b80a334aSGuochun Huang 
20b80a334aSGuochun Huang struct ser_reg_sequence {
21b80a334aSGuochun Huang 	uint reg;
22b80a334aSGuochun Huang 	uint def;
23b80a334aSGuochun Huang };
24b80a334aSGuochun Huang 
25b80a334aSGuochun Huang struct serdes_init_seq {
26b80a334aSGuochun Huang 	struct ser_reg_sequence *reg_sequence;
27b80a334aSGuochun Huang 	uint reg_seq_cnt;
28b80a334aSGuochun Huang };
29b80a334aSGuochun Huang 
30b80a334aSGuochun Huang struct bu18tl82_priv {
31b80a334aSGuochun Huang 	struct udevice *dev;
32b80a334aSGuochun Huang 	struct udevice *power_supply;
33b80a334aSGuochun Huang 	struct gpio_desc enable_gpio;
34b80a334aSGuochun Huang 	struct serdes_init_seq *serdes_init_seq;
35fa0df57cSGuochun Huang 	bool sel_mipi;
36b80a334aSGuochun Huang };
37b80a334aSGuochun Huang 
bu18tl82_bridge_reset(struct rockchip_bridge * bridge)38806b8544SLuo Wei static void bu18tl82_bridge_reset(struct rockchip_bridge *bridge)
39806b8544SLuo Wei {
40806b8544SLuo Wei 	int ret = 0;
41806b8544SLuo Wei 	struct udevice *dev = bridge->dev;
42806b8544SLuo Wei 	struct udevice *bus = dev_get_parent(dev);
43806b8544SLuo Wei 
44806b8544SLuo Wei 	ret = dm_i2c_reg_write(dev, 0x0011, 0x007f);
45806b8544SLuo Wei 	if (ret < 0)
46806b8544SLuo Wei 		printf("%s: failed to reset bu18tl82(%s) 0x11 ret=%d\n", __func__, bus->name, ret);
47806b8544SLuo Wei 
48806b8544SLuo Wei 	ret = dm_i2c_reg_write(dev, 0x0012, 0x0003);
49806b8544SLuo Wei 	if (ret < 0)
50806b8544SLuo Wei 		printf("%s: failed to reset bu18tl82(%s) 0x12 ret=%d\n", __func__, bus->name, ret);
51806b8544SLuo Wei 
52806b8544SLuo Wei 	mdelay(10);
53806b8544SLuo Wei }
54806b8544SLuo Wei 
bu18tl82_serdes_init_sequence_write(struct bu18tl82_priv * priv)55806b8544SLuo Wei static int bu18tl82_serdes_init_sequence_write(struct bu18tl82_priv *priv)
56b80a334aSGuochun Huang {
57b80a334aSGuochun Huang 	struct serdes_init_seq *serdes_init_seq = priv->serdes_init_seq;
58b80a334aSGuochun Huang 	struct ser_reg_sequence *reg_sequence =  serdes_init_seq->reg_sequence;
59b80a334aSGuochun Huang 	uint cnt = serdes_init_seq->reg_seq_cnt;
60b80a334aSGuochun Huang 	struct udevice *dev = priv->dev;
61b80a334aSGuochun Huang 	uint i;
62806b8544SLuo Wei 	int ret = 0;
63b80a334aSGuochun Huang 
64cb87f8eaSGuochun Huang 	for (i = 0; i < cnt; i++) {
65cb87f8eaSGuochun Huang 		ret = dm_i2c_reg_write(dev, reg_sequence[i].reg, reg_sequence[i].def);
66806b8544SLuo Wei 		if (ret < 0) {
67806b8544SLuo Wei 			dev_err(priv->dev, "failed to write reg: 0x%04x\n", reg_sequence[i].reg);
68806b8544SLuo Wei 			return ret;
69806b8544SLuo Wei 		}
70cb87f8eaSGuochun Huang 	}
71b80a334aSGuochun Huang 
72806b8544SLuo Wei 	return ret;
73806b8544SLuo Wei }
74806b8544SLuo Wei 
bu18tl82_serdes_init(struct rockchip_bridge * bridge)75806b8544SLuo Wei static void bu18tl82_serdes_init(struct rockchip_bridge *bridge)
76806b8544SLuo Wei {
77806b8544SLuo Wei 	struct udevice *dev = bridge->dev;
78806b8544SLuo Wei 	struct bu18tl82_priv *priv = dev_get_priv(dev);
79806b8544SLuo Wei 	uint i;
80806b8544SLuo Wei 	int ret;
81806b8544SLuo Wei 
82806b8544SLuo Wei 	for (i = 0; i < 10; i++) {
83806b8544SLuo Wei 		ret = bu18tl82_serdes_init_sequence_write(priv);
84806b8544SLuo Wei 		if (ret < 0) {
85806b8544SLuo Wei 			mdelay(100);
86806b8544SLuo Wei 			continue;
87806b8544SLuo Wei 		}
88806b8544SLuo Wei 
89806b8544SLuo Wei 		break;
90806b8544SLuo Wei 	}
91b80a334aSGuochun Huang }
92b80a334aSGuochun Huang 
bu18tl82_bridge_enable(struct rockchip_bridge * bridge)93b80a334aSGuochun Huang static void bu18tl82_bridge_enable(struct rockchip_bridge *bridge)
94b80a334aSGuochun Huang {
95b80a334aSGuochun Huang }
96b80a334aSGuochun Huang 
bu18tl82_bridge_disable(struct rockchip_bridge * bridge)97b80a334aSGuochun Huang static void bu18tl82_bridge_disable(struct rockchip_bridge *bridge)
98b80a334aSGuochun Huang {
99b80a334aSGuochun Huang }
100b80a334aSGuochun Huang 
bu18tl82_bridge_init(struct rockchip_bridge * bridge)101806b8544SLuo Wei static void bu18tl82_bridge_init(struct rockchip_bridge *bridge)
102b80a334aSGuochun Huang {
103b80a334aSGuochun Huang 	struct udevice *dev = bridge->dev;
104b80a334aSGuochun Huang 	struct bu18tl82_priv *priv = dev_get_priv(dev);
105b80a334aSGuochun Huang 
106b80a334aSGuochun Huang 	if (priv->power_supply)
107b80a334aSGuochun Huang 		regulator_set_enable(priv->power_supply, true);
108b80a334aSGuochun Huang 
109b80a334aSGuochun Huang 	if (dm_gpio_is_valid(&priv->enable_gpio))
110b80a334aSGuochun Huang 		dm_gpio_set_value(&priv->enable_gpio, 1);
111b80a334aSGuochun Huang 
112806b8544SLuo Wei 	mdelay(5);
113b80a334aSGuochun Huang 
114b80a334aSGuochun Huang 	video_bridge_set_active(priv->dev, true);
115b80a334aSGuochun Huang 
116806b8544SLuo Wei 	bu18tl82_serdes_init(bridge);
117b80a334aSGuochun Huang }
118b80a334aSGuochun Huang 
119b80a334aSGuochun Huang static const struct rockchip_bridge_funcs bu18tl82_bridge_funcs = {
120b80a334aSGuochun Huang 	.enable = bu18tl82_bridge_enable,
121b80a334aSGuochun Huang 	.disable = bu18tl82_bridge_disable,
122b80a334aSGuochun Huang };
123b80a334aSGuochun Huang 
bu18tl82_parse_init_seq(struct udevice * dev,const u16 * data,int length,struct serdes_init_seq * seq)124b80a334aSGuochun Huang static int bu18tl82_parse_init_seq(struct udevice *dev, const u16 *data,
125b80a334aSGuochun Huang 				   int length, struct serdes_init_seq *seq)
126b80a334aSGuochun Huang {
127b80a334aSGuochun Huang 	struct ser_reg_sequence *reg_sequence;
128b80a334aSGuochun Huang 	u16 *buf, *d;
129b80a334aSGuochun Huang 	unsigned int i, cnt;
130b80a334aSGuochun Huang 	int ret;
131b80a334aSGuochun Huang 
132b80a334aSGuochun Huang 	if (!seq)
133b80a334aSGuochun Huang 		return -EINVAL;
134b80a334aSGuochun Huang 
135b80a334aSGuochun Huang 	buf = calloc(1, length);
136b80a334aSGuochun Huang 	if (!buf)
137b80a334aSGuochun Huang 		return -ENOMEM;
138b80a334aSGuochun Huang 
139b80a334aSGuochun Huang 	memcpy(buf, data, length);
140b80a334aSGuochun Huang 
141b80a334aSGuochun Huang 	d = buf;
142b80a334aSGuochun Huang 	cnt = length / 4;
143b80a334aSGuochun Huang 	seq->reg_seq_cnt = cnt;
144b80a334aSGuochun Huang 
145b80a334aSGuochun Huang 	seq->reg_sequence = calloc(cnt, sizeof(struct ser_reg_sequence));
146b80a334aSGuochun Huang 	if (!seq->reg_sequence) {
147b80a334aSGuochun Huang 		ret = -ENOMEM;
148b80a334aSGuochun Huang 		goto free_buf;
149b80a334aSGuochun Huang 	}
150b80a334aSGuochun Huang 
151b80a334aSGuochun Huang 	for (i = 0; i < cnt; i++) {
152b80a334aSGuochun Huang 		reg_sequence = &seq->reg_sequence[i];
153b80a334aSGuochun Huang 		reg_sequence->reg = get_unaligned_be16(&d[0]);
154b80a334aSGuochun Huang 		reg_sequence->def = get_unaligned_be16(&d[1]);
155b80a334aSGuochun Huang 		d += 2;
156b80a334aSGuochun Huang 	}
157b80a334aSGuochun Huang 
158b80a334aSGuochun Huang 	return 0;
159b80a334aSGuochun Huang 
160b80a334aSGuochun Huang free_buf:
161b80a334aSGuochun Huang 	free(buf);
162b80a334aSGuochun Huang 
163b80a334aSGuochun Huang 	return ret;
164b80a334aSGuochun Huang }
165b80a334aSGuochun Huang 
bu18tl82_get_init_seq(struct bu18tl82_priv * priv)166b80a334aSGuochun Huang static int bu18tl82_get_init_seq(struct bu18tl82_priv *priv)
167b80a334aSGuochun Huang {
168b80a334aSGuochun Huang 	const void *data = NULL;
169b80a334aSGuochun Huang 	int len, err;
170b80a334aSGuochun Huang 
171b80a334aSGuochun Huang 	data = dev_read_prop(priv->dev, "serdes-init-sequence", &len);
172b80a334aSGuochun Huang 	if (!data) {
173b80a334aSGuochun Huang 		printf("failed to get serdes-init-sequence\n");
174b80a334aSGuochun Huang 		return -EINVAL;
175b80a334aSGuochun Huang 	}
176b80a334aSGuochun Huang 
177b80a334aSGuochun Huang 	priv->serdes_init_seq = calloc(1, sizeof(*priv->serdes_init_seq));
178b80a334aSGuochun Huang 	if (!priv->serdes_init_seq)
179b80a334aSGuochun Huang 		return -ENOMEM;
180b80a334aSGuochun Huang 
181b80a334aSGuochun Huang 	err = bu18tl82_parse_init_seq(priv->dev, data, len, priv->serdes_init_seq);
182b80a334aSGuochun Huang 	if (err) {
183b80a334aSGuochun Huang 		printf("failed to parse serdes-init-sequence\n");
184b80a334aSGuochun Huang 		goto free_init_seq;
185b80a334aSGuochun Huang 	}
186b80a334aSGuochun Huang 
187b80a334aSGuochun Huang 	return 0;
188b80a334aSGuochun Huang 
189b80a334aSGuochun Huang free_init_seq:
190b80a334aSGuochun Huang 	free(priv->serdes_init_seq);
191b80a334aSGuochun Huang 
192b80a334aSGuochun Huang 	return err;
193b80a334aSGuochun Huang }
194b80a334aSGuochun Huang 
bu18tl82_probe(struct udevice * dev)195b80a334aSGuochun Huang static int bu18tl82_probe(struct udevice *dev)
196b80a334aSGuochun Huang {
197b80a334aSGuochun Huang 	struct bu18tl82_priv *priv = dev_get_priv(dev);
198b80a334aSGuochun Huang 	struct rockchip_bridge *bridge;
199b80a334aSGuochun Huang 	int ret;
200b80a334aSGuochun Huang 
201b80a334aSGuochun Huang 	ret = i2c_set_chip_offset_len(dev, 2);
202b80a334aSGuochun Huang 	if (ret)
203b80a334aSGuochun Huang 		return ret;
204b80a334aSGuochun Huang 
205b80a334aSGuochun Huang 	priv->dev = dev;
206b80a334aSGuochun Huang 
207b80a334aSGuochun Huang 	ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
208b80a334aSGuochun Huang 					   "power-supply", &priv->power_supply);
209b80a334aSGuochun Huang 	if (ret && ret != -ENOENT) {
210b80a334aSGuochun Huang 		printf("%s: Cannot get power supply: %d\n", __func__, ret);
211b80a334aSGuochun Huang 		return ret;
212b80a334aSGuochun Huang 	}
213b80a334aSGuochun Huang 
214b80a334aSGuochun Huang 	ret = gpio_request_by_name(dev, "enable-gpios", 0,
215b80a334aSGuochun Huang 				   &priv->enable_gpio, GPIOD_IS_OUT);
216b80a334aSGuochun Huang 	if (ret && ret != -ENOENT) {
217b80a334aSGuochun Huang 		dev_err(dev, "%s: failed to get enable GPIO: %d\n", __func__, ret);
218b80a334aSGuochun Huang 		return ret;
219b80a334aSGuochun Huang 	}
220b80a334aSGuochun Huang 
221fa0df57cSGuochun Huang 	priv->sel_mipi = dev_read_bool(dev, "sel-mipi");
222fa0df57cSGuochun Huang 	if (priv->sel_mipi) {
223fa0df57cSGuochun Huang 		struct mipi_dsi_device *device = dev_get_platdata(dev);
224fa0df57cSGuochun Huang 
225fa0df57cSGuochun Huang 		device->dev = dev;
226fa0df57cSGuochun Huang 		device->lanes = dev_read_u32_default(dev, "dsi,lanes", 4);
227fa0df57cSGuochun Huang 		device->format = dev_read_u32_default(dev, "dsi,format",
228fa0df57cSGuochun Huang 						      MIPI_DSI_FMT_RGB888);
229fa0df57cSGuochun Huang 		device->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
230*edbf2db2SGuochun Huang 				     MIPI_DSI_MODE_VIDEO_NO_HBP | MIPI_DSI_MODE_LPM |
231*edbf2db2SGuochun Huang 				     MIPI_DSI_MODE_NO_EOT_PACKET;
232fa0df57cSGuochun Huang 		device->channel = dev_read_u32_default(dev, "reg", 0);
233fa0df57cSGuochun Huang 	}
234fa0df57cSGuochun Huang 
235b80a334aSGuochun Huang 	bridge = calloc(1, sizeof(*bridge));
236b80a334aSGuochun Huang 	if (!bridge)
237b80a334aSGuochun Huang 		return -ENOMEM;
238b80a334aSGuochun Huang 
239b80a334aSGuochun Huang 	ret = bu18tl82_get_init_seq(priv);
240b80a334aSGuochun Huang 	if (ret)
241b80a334aSGuochun Huang 		goto free_bridge;
242b80a334aSGuochun Huang 
243b80a334aSGuochun Huang 	dev->driver_data = (ulong)bridge;
244b80a334aSGuochun Huang 	bridge->dev = dev;
245b80a334aSGuochun Huang 	bridge->funcs = &bu18tl82_bridge_funcs;
246b80a334aSGuochun Huang 
247806b8544SLuo Wei 	bu18tl82_bridge_reset(bridge);
248806b8544SLuo Wei 	bu18tl82_bridge_init(bridge);
249806b8544SLuo Wei 
250b80a334aSGuochun Huang 	return 0;
251b80a334aSGuochun Huang 
252b80a334aSGuochun Huang free_bridge:
253b80a334aSGuochun Huang 	free(bridge);
254b80a334aSGuochun Huang 
255b80a334aSGuochun Huang 	return ret;
256b80a334aSGuochun Huang }
257b80a334aSGuochun Huang 
258b80a334aSGuochun Huang static const struct udevice_id bu18tl82_of_match[] = {
259b80a334aSGuochun Huang 	{ .compatible = "rohm,bu18tl82", },
260b80a334aSGuochun Huang 	{}
261b80a334aSGuochun Huang };
262b80a334aSGuochun Huang 
263b80a334aSGuochun Huang U_BOOT_DRIVER(bu18tl82) = {
264b80a334aSGuochun Huang 	.name = "bu18tl82",
265b80a334aSGuochun Huang 	.id = UCLASS_VIDEO_BRIDGE,
266b80a334aSGuochun Huang 	.of_match = bu18tl82_of_match,
267b80a334aSGuochun Huang 	.probe = bu18tl82_probe,
268b80a334aSGuochun Huang 	.priv_auto_alloc_size = sizeof(struct bu18tl82_priv),
269fa0df57cSGuochun Huang 	.platdata_auto_alloc_size = sizeof(struct mipi_dsi_device),
270b80a334aSGuochun Huang };
271