1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2008-2018 Fuzhou Rockchip Electronics Co., Ltd 4 * 5 * Author: Wyon Bi <bivvy.bi@rock-chips.com> 6 */ 7 8 #include <config.h> 9 #include <common.h> 10 #include <errno.h> 11 #include <dm.h> 12 #include <asm/io.h> 13 #include <linux/iopoll.h> 14 15 #include "rockchip_phy.h" 16 17 /* Register: 0x0030 */ 18 #define DISABLE_PLL BIT(3) 19 /* Register: 0x003c */ 20 #define PLL_LOCK BIT(1) 21 /* Register: 0x0084 */ 22 #define ENABLE_TX BIT(7) 23 24 struct inno_video_phy { 25 void __iomem *base; 26 enum phy_mode mode; 27 bool dual_channel; 28 }; 29 30 struct reg_sequence { 31 unsigned int reg; 32 unsigned int def; 33 unsigned int delay_us; 34 }; 35 36 static const struct reg_sequence ttl_mode[] = { 37 { 0x0000, 0x7f }, 38 { 0x0004, 0x3f }, 39 { 0x0008, 0x80 }, 40 { 0x0010, 0x3f }, 41 { 0x0014, 0x3f }, 42 { 0x0080, 0x44 }, 43 44 { 0x0100, 0x7f }, 45 { 0x0104, 0x3f }, 46 { 0x0108, 0x80 }, 47 { 0x0110, 0x3f }, 48 { 0x0114, 0x3f }, 49 { 0x0180, 0x44 }, 50 }; 51 52 static const struct reg_sequence lvds_mode_single_channel[] = { 53 { 0x0000, 0xbf }, 54 { 0x0004, 0x3f }, 55 { 0x0008, 0xfe }, 56 { 0x0010, 0x00 }, 57 { 0x0014, 0x00 }, 58 { 0x0080, 0x44 }, 59 60 { 0x0100, 0x00 }, 61 { 0x0104, 0x00 }, 62 { 0x0108, 0x00 }, 63 { 0x0110, 0x00 }, 64 { 0x0114, 0x00 }, 65 { 0x0180, 0x44 }, 66 }; 67 68 static const struct reg_sequence lvds_mode_dual_channel[] = { 69 { 0x0000, 0xbf }, 70 { 0x0004, 0x3f }, 71 { 0x0008, 0xfe }, 72 { 0x0010, 0x00 }, 73 { 0x0014, 0x00 }, 74 { 0x0080, 0x44 }, 75 76 { 0x0100, 0xbf }, 77 { 0x0104, 0x3f }, 78 { 0x0108, 0xfe }, 79 { 0x0110, 0x00 }, 80 { 0x0114, 0x00 }, 81 { 0x0180, 0x44 }, 82 }; 83 84 static inline void phy_write(struct inno_video_phy *inno, u32 reg, u32 val) 85 { 86 writel(val, inno->base + reg); 87 } 88 89 static inline u32 phy_read(struct inno_video_phy *inno, u32 reg) 90 { 91 return readl(inno->base + reg); 92 } 93 94 static inline void phy_update_bits(struct inno_video_phy *inno, 95 u32 reg, u32 mask, u32 val) 96 { 97 u32 tmp, orig; 98 99 orig = phy_read(inno, reg); 100 tmp = orig & ~mask; 101 tmp |= val & mask; 102 phy_write(inno, reg, tmp); 103 } 104 105 static void phy_multi_write(struct inno_video_phy *inno, 106 const struct reg_sequence *regs, int num_regs) 107 { 108 int i; 109 110 for (i = 0; i < num_regs; i++) { 111 phy_write(inno, regs[i].reg, regs[i].def); 112 113 if (regs[i].delay_us) 114 udelay(regs[i].delay_us); 115 } 116 } 117 118 static int inno_video_phy_power_on(struct rockchip_phy *phy) 119 { 120 struct inno_video_phy *inno = dev_get_priv(phy->dev); 121 const struct reg_sequence *wseq; 122 int nregs; 123 u32 status; 124 int ret; 125 126 switch (inno->mode) { 127 case PHY_MODE_VIDEO_LVDS: 128 if (inno->dual_channel) { 129 wseq = lvds_mode_dual_channel; 130 nregs = ARRAY_SIZE(lvds_mode_dual_channel); 131 } else { 132 wseq = lvds_mode_single_channel; 133 nregs = ARRAY_SIZE(lvds_mode_single_channel); 134 } 135 break; 136 case PHY_MODE_VIDEO_TTL: 137 wseq = ttl_mode; 138 nregs = ARRAY_SIZE(ttl_mode); 139 break; 140 default: 141 return -EINVAL; 142 } 143 144 phy_multi_write(inno, wseq, nregs); 145 146 phy_update_bits(inno, 0x0030, DISABLE_PLL, 0); 147 ret = readl_poll_timeout(inno->base + 0x003c, status, 148 status & PLL_LOCK, 10000); 149 if (ret) { 150 dev_err(phy->dev, "PLL is not lock\n"); 151 return ret; 152 } 153 154 phy_update_bits(inno, 0x0084, ENABLE_TX, ENABLE_TX); 155 156 return 0; 157 } 158 159 static int inno_video_phy_power_off(struct rockchip_phy *phy) 160 { 161 struct inno_video_phy *inno = dev_get_priv(phy->dev); 162 163 phy_update_bits(inno, 0x0084, ENABLE_TX, 0); 164 phy_update_bits(inno, 0x0030, DISABLE_PLL, DISABLE_PLL); 165 166 return 0; 167 } 168 169 static int inno_video_phy_set_mode(struct rockchip_phy *phy, 170 enum phy_mode mode) 171 { 172 struct inno_video_phy *inno = dev_get_priv(phy->dev); 173 174 switch (mode) { 175 case PHY_MODE_VIDEO_LVDS: 176 case PHY_MODE_VIDEO_TTL: 177 inno->mode = mode; 178 break; 179 default: 180 return -EINVAL; 181 } 182 183 return 0; 184 } 185 186 static int 187 inno_video_phy_set_bus_width(struct rockchip_phy *phy, u32 bus_width) 188 { 189 struct inno_video_phy *inno = dev_get_priv(phy->dev); 190 191 inno->dual_channel = (bus_width == 2) ? true : false; 192 193 return 0; 194 } 195 196 static const struct rockchip_phy_funcs inno_video_phy_funcs = { 197 .power_on = inno_video_phy_power_on, 198 .power_off = inno_video_phy_power_off, 199 .set_mode = inno_video_phy_set_mode, 200 .set_bus_width = inno_video_phy_set_bus_width, 201 }; 202 203 static int inno_video_phy_probe(struct udevice *dev) 204 { 205 struct inno_video_phy *inno = dev_get_priv(dev); 206 struct rockchip_phy *phy = 207 (struct rockchip_phy *)dev_get_driver_data(dev); 208 209 inno->base = dev_read_addr_ptr(dev); 210 phy->dev = dev; 211 212 return 0; 213 } 214 215 static struct rockchip_phy inno_video_phy_driver_data = { 216 .funcs = &inno_video_phy_funcs, 217 }; 218 219 static const struct udevice_id inno_video_phy_ids[] = { 220 { 221 .compatible = "rockchip,rk3288-video-phy", 222 .data = (ulong)&inno_video_phy_driver_data, 223 }, 224 {} 225 }; 226 227 U_BOOT_DRIVER(inno_video_phy) = { 228 .name = "inno_video_phy", 229 .id = UCLASS_PHY, 230 .of_match = inno_video_phy_ids, 231 .probe = inno_video_phy_probe, 232 .priv_auto_alloc_size = sizeof(struct inno_video_phy), 233 }; 234