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