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