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