xref: /rk3399_rockchip-uboot/drivers/video/drm/rohm-bu18rl82.c (revision 52ca514586c0afa8a281e4c7ea5685ba98a54c58)
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