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>
10b80a334aSGuochun Huang #include <video_bridge.h>
11b80a334aSGuochun Huang #include <asm/unaligned.h>
12b80a334aSGuochun Huang #include <linux/media-bus-format.h>
13b80a334aSGuochun Huang #include <power/regulator.h>
14b80a334aSGuochun Huang
15b80a334aSGuochun Huang #include "rockchip_bridge.h"
16b80a334aSGuochun Huang #include "rockchip_display.h"
17b80a334aSGuochun Huang #include "rockchip_panel.h"
18b80a334aSGuochun Huang
19806b8544SLuo Wei #define BU18RL82_REG_RESET 0X000E
20806b8544SLuo Wei
21806b8544SLuo Wei #define BU18RL82_SWRST_REG BIT(0)
22806b8544SLuo Wei #define BU18RL82_SWRST_EXCREG BIT(1)
23806b8544SLuo Wei #define BU18RL82_SWRST_ALL BIT(7)
24806b8544SLuo Wei
25b80a334aSGuochun Huang struct des_reg_sequence {
26b80a334aSGuochun Huang uint reg;
27b80a334aSGuochun Huang uint def;
28b80a334aSGuochun Huang };
29b80a334aSGuochun Huang
30b80a334aSGuochun Huang struct serdes_init_seq {
31b80a334aSGuochun Huang struct des_reg_sequence *reg_sequence;
32b80a334aSGuochun Huang uint reg_seq_cnt;
33b80a334aSGuochun Huang };
34b80a334aSGuochun Huang
35b80a334aSGuochun Huang struct bu18rl82_priv {
36b80a334aSGuochun Huang struct udevice *dev;
37b80a334aSGuochun Huang struct serdes_init_seq *serdes_init_seq;
38b80a334aSGuochun Huang };
39b80a334aSGuochun Huang
bu18rl82_bridge_reset(struct rockchip_bridge * bridge)40806b8544SLuo Wei static void bu18rl82_bridge_reset(struct rockchip_bridge *bridge)
41806b8544SLuo Wei {
42806b8544SLuo Wei int ret = 0;
43806b8544SLuo Wei struct udevice *dev = bridge->dev;
44806b8544SLuo Wei struct udevice *bus = dev_get_parent(dev);
45806b8544SLuo Wei
46ee32db20SLuo Wei ret = dm_i2c_reg_write(dev, BU18RL82_REG_RESET,
47ee32db20SLuo Wei (BU18RL82_SWRST_REG | BU18RL82_SWRST_EXCREG | BU18RL82_SWRST_ALL));
48806b8544SLuo Wei if (ret < 0)
49806b8544SLuo Wei printf("failed to reset bu18rl82(%s) ret=%d\n", bus->name, ret);
50*52ca5145SLuo Wei mdelay(5);
51806b8544SLuo Wei }
52806b8544SLuo Wei
bu18rl82_serdes_init_sequence_write(struct bu18rl82_priv * priv)53806b8544SLuo Wei static int bu18rl82_serdes_init_sequence_write(struct bu18rl82_priv *priv)
54b80a334aSGuochun Huang {
55b80a334aSGuochun Huang struct serdes_init_seq *serdes_init_seq = priv->serdes_init_seq;
56b80a334aSGuochun Huang struct des_reg_sequence *reg_sequence = serdes_init_seq->reg_sequence;
57b80a334aSGuochun Huang uint cnt = serdes_init_seq->reg_seq_cnt;
58b80a334aSGuochun Huang struct udevice *dev = priv->dev;
59b80a334aSGuochun Huang uint i;
60806b8544SLuo Wei int ret = 0;
61b80a334aSGuochun Huang
62cb87f8eaSGuochun Huang for (i = 0; i < cnt; i++) {
63cb87f8eaSGuochun Huang ret = dm_i2c_reg_write(dev, reg_sequence[i].reg, reg_sequence[i].def);
64806b8544SLuo Wei if (ret < 0) {
65ee32db20SLuo Wei dev_err(priv->dev, "failed write reg: 0x%04x value: 0x%04x\n",
66ee32db20SLuo Wei reg_sequence[i].reg, reg_sequence[i].def);
67806b8544SLuo Wei break;
68cb87f8eaSGuochun Huang }
69b80a334aSGuochun Huang }
70b80a334aSGuochun Huang
71806b8544SLuo Wei return ret;
72806b8544SLuo Wei }
73806b8544SLuo Wei
bu18rl82_bridge_enable(struct rockchip_bridge * bridge)74b80a334aSGuochun Huang static void bu18rl82_bridge_enable(struct rockchip_bridge *bridge)
75b80a334aSGuochun Huang {
76b80a334aSGuochun Huang struct udevice *dev = bridge->dev;
77b80a334aSGuochun Huang struct bu18rl82_priv *priv = dev_get_priv(dev);
78806b8544SLuo Wei struct udevice *bus = dev_get_parent(dev);
79806b8544SLuo Wei int i;
80806b8544SLuo Wei int ret;
81b80a334aSGuochun Huang
82806b8544SLuo Wei for (i = 0; i < 10; i++) {
83806b8544SLuo Wei ret = bu18rl82_serdes_init_sequence_write(priv);
84806b8544SLuo Wei if (ret < 0) {
85806b8544SLuo Wei dev_err(priv->dev, "%s ret=%d\n", bus->name, ret);
86806b8544SLuo Wei continue;
87806b8544SLuo Wei }
88806b8544SLuo Wei
89806b8544SLuo Wei break;
90806b8544SLuo Wei }
91b80a334aSGuochun Huang }
92b80a334aSGuochun Huang
93b80a334aSGuochun Huang static const struct rockchip_bridge_funcs bu18rl82_bridge_funcs = {
94b80a334aSGuochun Huang .enable = bu18rl82_bridge_enable,
95b80a334aSGuochun Huang };
96b80a334aSGuochun Huang
bu18rl82_parse_init_seq(struct udevice * dev,const u16 * data,int length,struct serdes_init_seq * seq)97b80a334aSGuochun Huang static int bu18rl82_parse_init_seq(struct udevice *dev, const u16 *data,
98b80a334aSGuochun Huang int length, struct serdes_init_seq *seq)
99b80a334aSGuochun Huang {
100b80a334aSGuochun Huang struct des_reg_sequence *reg_sequence;
101b80a334aSGuochun Huang u16 *buf, *d;
102b80a334aSGuochun Huang unsigned int i, cnt;
103b80a334aSGuochun Huang int ret;
104b80a334aSGuochun Huang
105b80a334aSGuochun Huang if (!seq)
106b80a334aSGuochun Huang return -EINVAL;
107b80a334aSGuochun Huang
108b80a334aSGuochun Huang buf = calloc(1, length);
109b80a334aSGuochun Huang if (!buf)
110b80a334aSGuochun Huang return -ENOMEM;
111b80a334aSGuochun Huang
112b80a334aSGuochun Huang memcpy(buf, data, length);
113b80a334aSGuochun Huang
114b80a334aSGuochun Huang d = buf;
115b80a334aSGuochun Huang cnt = length / 4;
116b80a334aSGuochun Huang seq->reg_seq_cnt = cnt;
117b80a334aSGuochun Huang
118b80a334aSGuochun Huang seq->reg_sequence = calloc(cnt, sizeof(struct des_reg_sequence));
119b80a334aSGuochun Huang if (!seq->reg_sequence) {
120b80a334aSGuochun Huang ret = -ENOMEM;
121b80a334aSGuochun Huang goto free_buf;
122b80a334aSGuochun Huang }
123b80a334aSGuochun Huang
124b80a334aSGuochun Huang for (i = 0; i < cnt; i++) {
125b80a334aSGuochun Huang reg_sequence = &seq->reg_sequence[i];
126b80a334aSGuochun Huang reg_sequence->reg = get_unaligned_be16(&d[0]);
127b80a334aSGuochun Huang reg_sequence->def = get_unaligned_be16(&d[1]);
128b80a334aSGuochun Huang d += 2;
129b80a334aSGuochun Huang }
130b80a334aSGuochun Huang
131b80a334aSGuochun Huang return 0;
132b80a334aSGuochun Huang
133b80a334aSGuochun Huang free_buf:
134b80a334aSGuochun Huang free(buf);
135b80a334aSGuochun Huang
136b80a334aSGuochun Huang return ret;
137b80a334aSGuochun Huang }
138b80a334aSGuochun Huang
bu18rl82_get_init_seq(struct bu18rl82_priv * priv)139b80a334aSGuochun Huang static int bu18rl82_get_init_seq(struct bu18rl82_priv *priv)
140b80a334aSGuochun Huang {
141b80a334aSGuochun Huang const void *data = NULL;
142b80a334aSGuochun Huang int len, err;
143b80a334aSGuochun Huang
144b80a334aSGuochun Huang data = dev_read_prop(priv->dev, "serdes-init-sequence", &len);
145b80a334aSGuochun Huang if (!data) {
146b80a334aSGuochun Huang printf("failed to get serdes-init-sequence\n");
147b80a334aSGuochun Huang return -EINVAL;
148b80a334aSGuochun Huang }
149b80a334aSGuochun Huang
150b80a334aSGuochun Huang priv->serdes_init_seq = calloc(1, sizeof(*priv->serdes_init_seq));
151b80a334aSGuochun Huang if (!priv->serdes_init_seq)
152b80a334aSGuochun Huang return -ENOMEM;
153b80a334aSGuochun Huang
154b80a334aSGuochun Huang err = bu18rl82_parse_init_seq(priv->dev, data, len, priv->serdes_init_seq);
155b80a334aSGuochun Huang if (err) {
156b80a334aSGuochun Huang printf("failed to parse serdes-init-sequence\n");
157b80a334aSGuochun Huang goto free_init_seq;
158b80a334aSGuochun Huang }
159b80a334aSGuochun Huang
160b80a334aSGuochun Huang return 0;
161b80a334aSGuochun Huang
162b80a334aSGuochun Huang free_init_seq:
163b80a334aSGuochun Huang free(priv->serdes_init_seq);
164b80a334aSGuochun Huang
165b80a334aSGuochun Huang return err;
166b80a334aSGuochun Huang }
167b80a334aSGuochun Huang
bu18rl82_probe(struct udevice * dev)168b80a334aSGuochun Huang static int bu18rl82_probe(struct udevice *dev)
169b80a334aSGuochun Huang {
170b80a334aSGuochun Huang struct bu18rl82_priv *priv = dev_get_priv(dev);
171b80a334aSGuochun Huang struct rockchip_bridge *bridge;
172b80a334aSGuochun Huang int ret;
173b80a334aSGuochun Huang
174b80a334aSGuochun Huang ret = i2c_set_chip_offset_len(dev, 2);
175b80a334aSGuochun Huang if (ret)
176b80a334aSGuochun Huang return ret;
177b80a334aSGuochun Huang
178b80a334aSGuochun Huang priv->dev = dev;
179b80a334aSGuochun Huang
180b80a334aSGuochun Huang bridge = calloc(1, sizeof(*bridge));
181b80a334aSGuochun Huang if (!bridge)
182b80a334aSGuochun Huang return -ENOMEM;
183b80a334aSGuochun Huang
184b80a334aSGuochun Huang ret = bu18rl82_get_init_seq(priv);
185b80a334aSGuochun Huang if (ret)
186b80a334aSGuochun Huang goto free_bridge;
187b80a334aSGuochun Huang
188b80a334aSGuochun Huang dev->driver_data = (ulong)bridge;
189b80a334aSGuochun Huang bridge->dev = dev;
190b80a334aSGuochun Huang bridge->funcs = &bu18rl82_bridge_funcs;
191b80a334aSGuochun Huang
192806b8544SLuo Wei bu18rl82_bridge_reset(bridge);
193806b8544SLuo Wei
194b80a334aSGuochun Huang return 0;
195b80a334aSGuochun Huang
196b80a334aSGuochun Huang free_bridge:
197b80a334aSGuochun Huang free(bridge);
198b80a334aSGuochun Huang
199b80a334aSGuochun Huang return ret;
200b80a334aSGuochun Huang }
201b80a334aSGuochun Huang
202b80a334aSGuochun Huang static const struct udevice_id bu18rl82_of_match[] = {
203b80a334aSGuochun Huang { .compatible = "rohm,bu18rl82", },
204b80a334aSGuochun Huang {}
205b80a334aSGuochun Huang };
206b80a334aSGuochun Huang
207b80a334aSGuochun Huang U_BOOT_DRIVER(bu18rl82) = {
208b80a334aSGuochun Huang .name = "bu18rl82",
209b80a334aSGuochun Huang .id = UCLASS_VIDEO_BRIDGE,
210b80a334aSGuochun Huang .of_match = bu18rl82_of_match,
211b80a334aSGuochun Huang .probe = bu18rl82_probe,
212b80a334aSGuochun Huang .priv_auto_alloc_size = sizeof(struct bu18rl82_priv),
213b80a334aSGuochun Huang };
214