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