1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2022 Rockchip Electronics Co., Ltd 4 */ 5 6 #include <common.h> 7 #include <dm.h> 8 #include <errno.h> 9 #include <i2c.h> 10 #include <video_bridge.h> 11 #include <asm/unaligned.h> 12 #include <linux/media-bus-format.h> 13 #include <power/regulator.h> 14 15 #include "rockchip_bridge.h" 16 #include "rockchip_display.h" 17 #include "rockchip_panel.h" 18 19 struct ser_reg_sequence { 20 uint reg; 21 uint def; 22 }; 23 24 struct serdes_init_seq { 25 struct ser_reg_sequence *reg_sequence; 26 uint reg_seq_cnt; 27 }; 28 29 struct bu18tl82_priv { 30 struct udevice *dev; 31 struct udevice *power_supply; 32 struct gpio_desc enable_gpio; 33 struct serdes_init_seq *serdes_init_seq; 34 }; 35 36 static void bu18tl82_bridge_reset(struct rockchip_bridge *bridge) 37 { 38 int ret = 0; 39 struct udevice *dev = bridge->dev; 40 struct udevice *bus = dev_get_parent(dev); 41 42 ret = dm_i2c_reg_write(dev, 0x0011, 0x007f); 43 if (ret < 0) 44 printf("%s: failed to reset bu18tl82(%s) 0x11 ret=%d\n", __func__, bus->name, ret); 45 46 ret = dm_i2c_reg_write(dev, 0x0012, 0x0003); 47 if (ret < 0) 48 printf("%s: failed to reset bu18tl82(%s) 0x12 ret=%d\n", __func__, bus->name, ret); 49 50 mdelay(10); 51 } 52 53 static int bu18tl82_serdes_init_sequence_write(struct bu18tl82_priv *priv) 54 { 55 struct serdes_init_seq *serdes_init_seq = priv->serdes_init_seq; 56 struct ser_reg_sequence *reg_sequence = serdes_init_seq->reg_sequence; 57 uint cnt = serdes_init_seq->reg_seq_cnt; 58 struct udevice *dev = priv->dev; 59 uint i; 60 int ret = 0; 61 62 for (i = 0; i < cnt; i++) { 63 ret = dm_i2c_reg_write(dev, reg_sequence[i].reg, reg_sequence[i].def); 64 if (ret < 0) { 65 dev_err(priv->dev, "failed to write reg: 0x%04x\n", reg_sequence[i].reg); 66 return ret; 67 } 68 } 69 70 return ret; 71 } 72 73 static void bu18tl82_serdes_init(struct rockchip_bridge *bridge) 74 { 75 struct udevice *dev = bridge->dev; 76 struct bu18tl82_priv *priv = dev_get_priv(dev); 77 uint i; 78 int ret; 79 80 for (i = 0; i < 10; i++) { 81 ret = bu18tl82_serdes_init_sequence_write(priv); 82 if (ret < 0) { 83 mdelay(100); 84 continue; 85 } 86 87 break; 88 } 89 } 90 91 static void bu18tl82_bridge_enable(struct rockchip_bridge *bridge) 92 { 93 } 94 95 static void bu18tl82_bridge_disable(struct rockchip_bridge *bridge) 96 { 97 } 98 99 static void bu18tl82_bridge_init(struct rockchip_bridge *bridge) 100 { 101 struct udevice *dev = bridge->dev; 102 struct bu18tl82_priv *priv = dev_get_priv(dev); 103 104 if (priv->power_supply) 105 regulator_set_enable(priv->power_supply, true); 106 107 if (dm_gpio_is_valid(&priv->enable_gpio)) 108 dm_gpio_set_value(&priv->enable_gpio, 1); 109 110 mdelay(5); 111 112 video_bridge_set_active(priv->dev, true); 113 114 bu18tl82_serdes_init(bridge); 115 } 116 117 static const struct rockchip_bridge_funcs bu18tl82_bridge_funcs = { 118 .enable = bu18tl82_bridge_enable, 119 .disable = bu18tl82_bridge_disable, 120 }; 121 122 static int bu18tl82_parse_init_seq(struct udevice *dev, const u16 *data, 123 int length, struct serdes_init_seq *seq) 124 { 125 struct ser_reg_sequence *reg_sequence; 126 u16 *buf, *d; 127 unsigned int i, cnt; 128 int ret; 129 130 if (!seq) 131 return -EINVAL; 132 133 buf = calloc(1, length); 134 if (!buf) 135 return -ENOMEM; 136 137 memcpy(buf, data, length); 138 139 d = buf; 140 cnt = length / 4; 141 seq->reg_seq_cnt = cnt; 142 143 seq->reg_sequence = calloc(cnt, sizeof(struct ser_reg_sequence)); 144 if (!seq->reg_sequence) { 145 ret = -ENOMEM; 146 goto free_buf; 147 } 148 149 for (i = 0; i < cnt; i++) { 150 reg_sequence = &seq->reg_sequence[i]; 151 reg_sequence->reg = get_unaligned_be16(&d[0]); 152 reg_sequence->def = get_unaligned_be16(&d[1]); 153 d += 2; 154 } 155 156 return 0; 157 158 free_buf: 159 free(buf); 160 161 return ret; 162 } 163 164 static int bu18tl82_get_init_seq(struct bu18tl82_priv *priv) 165 { 166 const void *data = NULL; 167 int len, err; 168 169 data = dev_read_prop(priv->dev, "serdes-init-sequence", &len); 170 if (!data) { 171 printf("failed to get serdes-init-sequence\n"); 172 return -EINVAL; 173 } 174 175 priv->serdes_init_seq = calloc(1, sizeof(*priv->serdes_init_seq)); 176 if (!priv->serdes_init_seq) 177 return -ENOMEM; 178 179 err = bu18tl82_parse_init_seq(priv->dev, data, len, priv->serdes_init_seq); 180 if (err) { 181 printf("failed to parse serdes-init-sequence\n"); 182 goto free_init_seq; 183 } 184 185 return 0; 186 187 free_init_seq: 188 free(priv->serdes_init_seq); 189 190 return err; 191 } 192 193 static int bu18tl82_probe(struct udevice *dev) 194 { 195 struct bu18tl82_priv *priv = dev_get_priv(dev); 196 struct rockchip_bridge *bridge; 197 int ret; 198 199 ret = i2c_set_chip_offset_len(dev, 2); 200 if (ret) 201 return ret; 202 203 priv->dev = dev; 204 205 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev, 206 "power-supply", &priv->power_supply); 207 if (ret && ret != -ENOENT) { 208 printf("%s: Cannot get power supply: %d\n", __func__, ret); 209 return ret; 210 } 211 212 ret = gpio_request_by_name(dev, "enable-gpios", 0, 213 &priv->enable_gpio, GPIOD_IS_OUT); 214 if (ret && ret != -ENOENT) { 215 dev_err(dev, "%s: failed to get enable GPIO: %d\n", __func__, ret); 216 return ret; 217 } 218 219 bridge = calloc(1, sizeof(*bridge)); 220 if (!bridge) 221 return -ENOMEM; 222 223 ret = bu18tl82_get_init_seq(priv); 224 if (ret) 225 goto free_bridge; 226 227 dev->driver_data = (ulong)bridge; 228 bridge->dev = dev; 229 bridge->funcs = &bu18tl82_bridge_funcs; 230 231 bu18tl82_bridge_reset(bridge); 232 bu18tl82_bridge_init(bridge); 233 234 return 0; 235 236 free_bridge: 237 free(bridge); 238 239 return ret; 240 } 241 242 static const struct udevice_id bu18tl82_of_match[] = { 243 { .compatible = "rohm,bu18tl82", }, 244 {} 245 }; 246 247 U_BOOT_DRIVER(bu18tl82) = { 248 .name = "bu18tl82", 249 .id = UCLASS_VIDEO_BRIDGE, 250 .of_match = bu18tl82_of_match, 251 .probe = bu18tl82_probe, 252 .priv_auto_alloc_size = sizeof(struct bu18tl82_priv), 253 }; 254