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