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 #define BU18RL82_REG_RESET 0X000E 20 21 #define BU18RL82_SWRST_REG BIT(0) 22 #define BU18RL82_SWRST_EXCREG BIT(1) 23 #define BU18RL82_SWRST_ALL BIT(7) 24 25 struct des_reg_sequence { 26 uint reg; 27 uint def; 28 }; 29 30 struct serdes_init_seq { 31 struct des_reg_sequence *reg_sequence; 32 uint reg_seq_cnt; 33 }; 34 35 struct bu18rl82_priv { 36 struct udevice *dev; 37 struct serdes_init_seq *serdes_init_seq; 38 }; 39 40 static void bu18rl82_bridge_reset(struct rockchip_bridge *bridge) 41 { 42 int ret = 0; 43 struct udevice *dev = bridge->dev; 44 struct udevice *bus = dev_get_parent(dev); 45 46 ret = dm_i2c_reg_write(dev, BU18RL82_REG_RESET, 47 (BU18RL82_SWRST_REG | BU18RL82_SWRST_EXCREG | BU18RL82_SWRST_ALL)); 48 if (ret < 0) 49 printf("failed to reset bu18rl82(%s) ret=%d\n", bus->name, ret); 50 mdelay(5); 51 } 52 53 static int bu18rl82_serdes_init_sequence_write(struct bu18rl82_priv *priv) 54 { 55 struct serdes_init_seq *serdes_init_seq = priv->serdes_init_seq; 56 struct des_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 write reg: 0x%04x value: 0x%04x\n", 66 reg_sequence[i].reg, reg_sequence[i].def); 67 break; 68 } 69 } 70 71 return ret; 72 } 73 74 static void bu18rl82_bridge_enable(struct rockchip_bridge *bridge) 75 { 76 struct udevice *dev = bridge->dev; 77 struct bu18rl82_priv *priv = dev_get_priv(dev); 78 struct udevice *bus = dev_get_parent(dev); 79 int i; 80 int ret; 81 82 for (i = 0; i < 10; i++) { 83 ret = bu18rl82_serdes_init_sequence_write(priv); 84 if (ret < 0) { 85 dev_err(priv->dev, "%s ret=%d\n", bus->name, ret); 86 continue; 87 } 88 89 break; 90 } 91 } 92 93 static const struct rockchip_bridge_funcs bu18rl82_bridge_funcs = { 94 .enable = bu18rl82_bridge_enable, 95 }; 96 97 static int bu18rl82_parse_init_seq(struct udevice *dev, const u16 *data, 98 int length, struct serdes_init_seq *seq) 99 { 100 struct des_reg_sequence *reg_sequence; 101 u16 *buf, *d; 102 unsigned int i, cnt; 103 int ret; 104 105 if (!seq) 106 return -EINVAL; 107 108 buf = calloc(1, length); 109 if (!buf) 110 return -ENOMEM; 111 112 memcpy(buf, data, length); 113 114 d = buf; 115 cnt = length / 4; 116 seq->reg_seq_cnt = cnt; 117 118 seq->reg_sequence = calloc(cnt, sizeof(struct des_reg_sequence)); 119 if (!seq->reg_sequence) { 120 ret = -ENOMEM; 121 goto free_buf; 122 } 123 124 for (i = 0; i < cnt; i++) { 125 reg_sequence = &seq->reg_sequence[i]; 126 reg_sequence->reg = get_unaligned_be16(&d[0]); 127 reg_sequence->def = get_unaligned_be16(&d[1]); 128 d += 2; 129 } 130 131 return 0; 132 133 free_buf: 134 free(buf); 135 136 return ret; 137 } 138 139 static int bu18rl82_get_init_seq(struct bu18rl82_priv *priv) 140 { 141 const void *data = NULL; 142 int len, err; 143 144 data = dev_read_prop(priv->dev, "serdes-init-sequence", &len); 145 if (!data) { 146 printf("failed to get serdes-init-sequence\n"); 147 return -EINVAL; 148 } 149 150 priv->serdes_init_seq = calloc(1, sizeof(*priv->serdes_init_seq)); 151 if (!priv->serdes_init_seq) 152 return -ENOMEM; 153 154 err = bu18rl82_parse_init_seq(priv->dev, data, len, priv->serdes_init_seq); 155 if (err) { 156 printf("failed to parse serdes-init-sequence\n"); 157 goto free_init_seq; 158 } 159 160 return 0; 161 162 free_init_seq: 163 free(priv->serdes_init_seq); 164 165 return err; 166 } 167 168 static int bu18rl82_probe(struct udevice *dev) 169 { 170 struct bu18rl82_priv *priv = dev_get_priv(dev); 171 struct rockchip_bridge *bridge; 172 int ret; 173 174 ret = i2c_set_chip_offset_len(dev, 2); 175 if (ret) 176 return ret; 177 178 priv->dev = dev; 179 180 bridge = calloc(1, sizeof(*bridge)); 181 if (!bridge) 182 return -ENOMEM; 183 184 ret = bu18rl82_get_init_seq(priv); 185 if (ret) 186 goto free_bridge; 187 188 dev->driver_data = (ulong)bridge; 189 bridge->dev = dev; 190 bridge->funcs = &bu18rl82_bridge_funcs; 191 192 bu18rl82_bridge_reset(bridge); 193 194 return 0; 195 196 free_bridge: 197 free(bridge); 198 199 return ret; 200 } 201 202 static const struct udevice_id bu18rl82_of_match[] = { 203 { .compatible = "rohm,bu18rl82", }, 204 {} 205 }; 206 207 U_BOOT_DRIVER(bu18rl82) = { 208 .name = "bu18rl82", 209 .id = UCLASS_VIDEO_BRIDGE, 210 .of_match = bu18rl82_of_match, 211 .probe = bu18rl82_probe, 212 .priv_auto_alloc_size = sizeof(struct bu18rl82_priv), 213 }; 214