Googler | 25e92cf | 2023-12-13 10:05:01 +0000 | [diff] [blame^] | 1 | // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| 2 | /* |
| 3 | * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| 4 | */ |
| 5 | |
| 6 | #include <common.h> |
| 7 | #include <asm/io.h> |
| 8 | #include <bitfield.h> |
| 9 | #include <dm.h> |
| 10 | #include <errno.h> |
| 11 | #include <generic-phy.h> |
| 12 | #include <regmap.h> |
| 13 | #include <power/regulator.h> |
| 14 | #include <clk.h> |
| 15 | #include <asm/arch/usb.h> |
| 16 | #include <amlogic/cpu_id.h> |
| 17 | |
| 18 | #include <linux/compat.h> |
| 19 | #include <linux/ioport.h> |
| 20 | #include <asm-generic/gpio.h> |
| 21 | |
| 22 | #define PHY20_RESET_LEVEL_BIT 8 |
| 23 | #define PHY21_RESET_LEVEL_BIT 9 |
| 24 | #define USB_RESET_BIT 4 |
| 25 | |
| 26 | #define USB2_PHY_PLL_OFFSET_40 (0x09400414) |
| 27 | #define USB2_PHY_PLL_OFFSET_44 (0x927E0000) |
| 28 | #define USB2_PHY_PLL_OFFSET_48 (0xac5f69e5) |
| 29 | |
| 30 | #define USB2_PHY_PLL_OFFSET_10 (0x80000fff) |
| 31 | #define USB2_PHY_PLL_OFFSET_34 (0x78000) |
| 32 | #define USB2_REVB_PHY_PLL_OFFSET_34 (0x70000) |
| 33 | |
| 34 | #define USB2_PHY_PLL_OFFSET_38_CLEAR (0) |
| 35 | #define USB2_PHY_PLL_OFFSET_38_SET (0xe0004) |
| 36 | #define USB2_PHY_PLL_OFFSET_50 (0xfe18) |
| 37 | #define USB2_PHY_PLL_OFFSET_54 (0x2a) |
| 38 | |
| 39 | #define TUNING_DISCONNECT_THRESHOLD 0x3C |
| 40 | |
| 41 | #define PHY_21_BASE 0xfe03e000 |
| 42 | #define PHY_20_BASE 0xfe03c000 |
| 43 | #define PHY_COMP_BASE 0xfe03a000 |
| 44 | #define RESET_BASE 0xFE002000 |
| 45 | |
| 46 | static int Rev_flag = 0; |
| 47 | |
| 48 | static struct phy usb_phys[4]; |
| 49 | |
| 50 | /*Rev_flag == 0XB, g12b and revB, tl1 */ |
| 51 | /*Rev_flag == 1, sm1 */ |
| 52 | static void phy_aml_usb2_check_rev (void) |
| 53 | { |
| 54 | cpu_id_t cpu_id = get_cpu_id(); |
| 55 | |
| 56 | if (cpu_id.family_id == MESON_CPU_MAJOR_ID_G12B) { |
| 57 | if (cpu_id.chip_rev == 0xb) |
| 58 | Rev_flag = 0xb; |
| 59 | else |
| 60 | Rev_flag = 0; |
| 61 | } else if (cpu_id.family_id == MESON_CPU_MAJOR_ID_SM1) { |
| 62 | Rev_flag = MESON_CPU_MAJOR_ID_SM1; |
| 63 | } else if (cpu_id.family_id == MESON_CPU_MAJOR_ID_A1) { |
| 64 | Rev_flag = MESON_CPU_MAJOR_ID_A1; |
| 65 | } else if (cpu_id.family_id == MESON_CPU_MAJOR_ID_C1) { |
| 66 | Rev_flag = MESON_CPU_MAJOR_ID_C1; |
| 67 | } else if (cpu_id.family_id == MESON_CPU_MAJOR_ID_SC2) { |
| 68 | Rev_flag = MESON_CPU_MAJOR_ID_SC2; |
| 69 | } else if (cpu_id.family_id == MESON_CPU_MAJOR_ID_T7) { |
| 70 | Rev_flag = MESON_CPU_MAJOR_ID_T7; |
| 71 | } |
| 72 | |
| 73 | return; |
| 74 | } |
| 75 | |
| 76 | static int phy_aml_usb2_get_rev_type (void) |
| 77 | { |
| 78 | int val = 0; |
| 79 | |
| 80 | switch (Rev_flag) { |
| 81 | case MESON_CPU_MAJOR_ID_SM1: |
| 82 | case MESON_CPU_MAJOR_ID_A1: |
| 83 | case MESON_CPU_MAJOR_ID_C1: |
| 84 | case MESON_CPU_MAJOR_ID_SC2: |
| 85 | case MESON_CPU_MAJOR_ID_T7: |
| 86 | case 0xb: |
| 87 | val = 1; |
| 88 | break; |
| 89 | default: |
| 90 | printk("amlogic usb phy need tuning\n"); |
| 91 | val = 0; |
| 92 | break; |
| 93 | } |
| 94 | |
| 95 | return val; |
| 96 | } |
| 97 | |
| 98 | int get_usbphy_baseinfo(struct phy *usb_phys) |
| 99 | { |
| 100 | struct udevice *bus; |
| 101 | struct uclass *uc; |
| 102 | int ret, i; |
| 103 | int count; |
| 104 | |
| 105 | if (usb_phys[0].dev && usb_phys[1].dev) |
| 106 | return 0; |
| 107 | |
| 108 | ret = uclass_get(UCLASS_USB, &uc); |
| 109 | if (ret) |
| 110 | return ret; |
| 111 | uclass_foreach_dev(bus, uc) { |
| 112 | debug("bus->name=%s, bus->driver->name =%s\n", |
| 113 | bus->name, bus->driver->name); |
| 114 | count = dev_count_phandle_with_args(bus, "phys", "#phy-cells"); |
| 115 | debug("usb phy count=%u\n", count); |
| 116 | if (count <= 0) |
| 117 | return count; |
| 118 | for (i = 0; i < count; i++) { |
| 119 | ret = generic_phy_get_by_index(bus, i, &usb_phys[i]); |
| 120 | if (ret && ret != -ENOENT) { |
| 121 | pr_err("Failed to get USB PHY%d for %s\n", |
| 122 | i, bus->name); |
| 123 | return ret; |
| 124 | } |
| 125 | ret = generic_phy_getinfo(&usb_phys[i]); |
| 126 | if (ret) |
| 127 | return ret; |
| 128 | } |
| 129 | } |
| 130 | return 0; |
| 131 | } |
| 132 | |
| 133 | void usb_aml_detect_operation(int argc, char * const argv[]) |
| 134 | { |
| 135 | struct phy_aml_usb2_priv *usb2_priv; |
| 136 | struct phy_aml_usb3_priv *usb3_priv; |
| 137 | int ret; |
| 138 | |
| 139 | ret = get_usbphy_baseinfo(usb_phys); |
| 140 | if (ret) { |
| 141 | printf("get usb dts failed\n"); |
| 142 | return; |
| 143 | } |
| 144 | usb2_priv = dev_get_priv(usb_phys[0].dev); |
| 145 | usb3_priv = dev_get_priv(usb_phys[1].dev); |
| 146 | |
| 147 | if (usb3_priv) { |
| 148 | printf("priv->usb3 port num = %d, config addr=0x%08x\n", |
| 149 | usb3_priv->usb3_port_num, usb3_priv->base_addr); |
| 150 | } |
| 151 | if (usb2_priv) { |
| 152 | printf("usb2 phy: config addr = 0x%08x, reset addr=0x%08x\n", |
| 153 | usb2_priv->base_addr, usb2_priv->reset_addr); |
| 154 | |
| 155 | printf("usb2 phy: portnum=%d, phy-addr1= 0x%08x, phy-addr2= 0x%08x\n", |
| 156 | usb2_priv->u2_port_num, usb2_priv->usb_phy2_pll_base_addr[0], |
| 157 | usb2_priv->usb_phy2_pll_base_addr[1]); |
| 158 | printf("dwc2_a base addr: 0x%08x\n", usb2_priv->dwc2_a_addr); |
| 159 | } |
| 160 | phy_aml_usb2_check_rev(); |
| 161 | printf("PHY version is 0x%02x\n", Rev_flag); |
| 162 | } |
| 163 | |
| 164 | static void set_pll_Calibration_default(uint32_t phy2_pll_base) |
| 165 | { |
| 166 | u32 tmp; |
| 167 | |
| 168 | tmp = (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x8)); |
| 169 | tmp &= 0xfff; |
| 170 | tmp |= (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x10)); |
| 171 | (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x10)) |
| 172 | = tmp; |
| 173 | } |
| 174 | |
| 175 | void usb_reset(unsigned int reset_addr, int bit){ |
| 176 | *(volatile unsigned int *)(unsigned long)reset_addr = (1 << bit); |
| 177 | } |
| 178 | |
| 179 | static void usb_enable_phy_pll (u32 base_addr) |
| 180 | { |
| 181 | if (base_addr == PHY_20_BASE) { |
| 182 | *(volatile uint32_t *)(unsigned long) |
| 183 | RESETCTRL_RESET0_LEVEL |= (1 << PHY20_RESET_LEVEL_BIT); |
| 184 | } else if (base_addr == PHY_21_BASE) { |
| 185 | *(volatile uint32_t *)(unsigned long) |
| 186 | RESETCTRL_RESET0_LEVEL |= (1 << PHY21_RESET_LEVEL_BIT); |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | void set_usb_pll(uint32_t phy2_pll_base) |
| 191 | { |
| 192 | int hardware_rev; |
| 193 | |
| 194 | (*(volatile uint32_t *)((unsigned long)phy2_pll_base + 0x40)) |
| 195 | = (USB2_PHY_PLL_OFFSET_40 | USB_PHY2_RESET | USB_PHY2_ENABLE); |
| 196 | (*(volatile uint32_t *)((unsigned long)phy2_pll_base + 0x44)) = |
| 197 | USB2_PHY_PLL_OFFSET_44; |
| 198 | hardware_rev = phy_aml_usb2_get_rev_type(); |
| 199 | (*(volatile uint32_t *)((unsigned long)phy2_pll_base + 0x48)) = |
| 200 | USB2_PHY_PLL_OFFSET_48; |
| 201 | udelay(100); |
| 202 | (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x40)) |
| 203 | = (((USB2_PHY_PLL_OFFSET_40) | (USB_PHY2_ENABLE)) |
| 204 | & (~(USB_PHY2_RESET))); |
| 205 | |
| 206 | if (hardware_rev) { |
| 207 | (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x50)) |
| 208 | = USB2_PHY_PLL_OFFSET_50; |
| 209 | (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x54)) |
| 210 | = USB2_PHY_PLL_OFFSET_54; |
| 211 | set_pll_Calibration_default(phy2_pll_base); |
| 212 | } else { |
| 213 | (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x50)) |
| 214 | = USB2_PHY_PLL_OFFSET_50; |
| 215 | (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x10)) |
| 216 | = USB2_PHY_PLL_OFFSET_10; |
| 217 | (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x38)) |
| 218 | = USB2_PHY_PLL_OFFSET_38_CLEAR; |
| 219 | } |
| 220 | |
| 221 | (*(volatile uint32_t *)((unsigned long)phy2_pll_base + 0xc)) = |
| 222 | TUNING_DISCONNECT_THRESHOLD; |
| 223 | (*(volatile uint32_t *)(unsigned long)((unsigned long)phy2_pll_base + 0x34)) |
| 224 | = USB2_PHY_PLL_OFFSET_34; |
| 225 | debug("tuning_disconnect_threshold=0x%x\n", TUNING_DISCONNECT_THRESHOLD); |
| 226 | } |
| 227 | |
| 228 | int usb_save_phy_dev (unsigned int number, struct phy *phy) |
| 229 | { |
| 230 | usb_phys[number].dev = phy->dev; |
| 231 | usb_phys[number].id = phy->id; |
| 232 | return 0; |
| 233 | } |
| 234 | |
| 235 | void power_down_usb3(void) |
| 236 | { |
| 237 | u32 val; |
| 238 | #define USB_PHY30_BASE 0xFE062000 |
| 239 | |
| 240 | val = readl(USB_PHY30_BASE); |
| 241 | val &= (~(3 << 5)); |
| 242 | val |= 0x1; |
| 243 | writel(val, USB_PHY30_BASE); |
| 244 | udelay(12); |
| 245 | |
| 246 | val = readl(USB_PHY30_BASE + 0x18); |
| 247 | val &= (~(0x3 << 17)); |
| 248 | val |= (0x1 << 17); |
| 249 | writel(val, USB_PHY30_BASE + 0x18); |
| 250 | udelay(12); |
| 251 | } |
| 252 | |
| 253 | int usb2_phy_init (struct phy *phy) { |
| 254 | struct phy_aml_usb2_priv *priv = dev_get_priv(phy->dev); |
| 255 | struct u2p_aml_regs *u2p_aml_reg; |
| 256 | u2p_r0_t dev_u2p_r0; |
| 257 | u2p_r1_t dev_u2p_r1; |
| 258 | int i,cnt; |
| 259 | |
| 260 | power_down_usb3(); |
| 261 | usb_save_phy_dev(0, phy); |
| 262 | usb_enable_phy_pll(priv->base_addr); |
| 263 | //usb_set_power_domain(); |
| 264 | phy_aml_usb2_check_rev(); |
| 265 | |
| 266 | if (priv->usb_phy2_pll_base_addr[0] == PHY_20_BASE) { |
| 267 | *(volatile unsigned int *)(unsigned long)priv->reset_addr = (1 << 6); |
| 268 | |
| 269 | udelay(500); |
| 270 | priv->usbphy_reset_bit[0] = PHY20_RESET_LEVEL_BIT; |
| 271 | } else if (priv->usb_phy2_pll_base_addr[0] == PHY_21_BASE) { |
| 272 | *(volatile unsigned int *)(unsigned long)priv->reset_addr = (1 << 5); |
| 273 | |
| 274 | udelay(500); |
| 275 | priv->usbphy_reset_bit[0] = PHY21_RESET_LEVEL_BIT; |
| 276 | } |
| 277 | |
| 278 | for (i = 0; i < priv->u2_port_num; i++) { |
| 279 | u2p_aml_reg = (struct u2p_aml_regs *)((ulong)(priv->base_addr + i * PHY_REGISTER_SIZE)); |
| 280 | dev_u2p_r0.d32 = u2p_aml_reg->u2p_r0; |
| 281 | dev_u2p_r0.b.host_device= 1; |
| 282 | dev_u2p_r0.b.POR= 0; |
| 283 | u2p_aml_reg->u2p_r0 = dev_u2p_r0.d32; |
| 284 | udelay(10); |
| 285 | *(volatile unsigned int *)(unsigned long)priv->reset_addr = (1 << priv->usbphy_reset_bit[i]); |
| 286 | udelay(50); |
| 287 | |
| 288 | /* wait for phy ready */ |
| 289 | dev_u2p_r1.d32 = u2p_aml_reg->u2p_r1; |
| 290 | cnt = 0; |
| 291 | while (dev_u2p_r1.b.phy_rdy != 1) { |
| 292 | dev_u2p_r1.d32 = u2p_aml_reg->u2p_r1; |
| 293 | /*we wait phy ready max 1ms, common is 100us*/ |
| 294 | if (cnt > 200) |
| 295 | break; |
| 296 | else { |
| 297 | cnt++; |
| 298 | udelay(5); |
| 299 | } |
| 300 | } |
| 301 | } |
| 302 | |
| 303 | for (i = 0; i < priv->u2_port_num; i++) { |
| 304 | debug("------set usb pll\n"); |
| 305 | set_usb_pll(priv->usb_phy2_pll_base_addr[i]); |
| 306 | } |
| 307 | return 0; |
| 308 | |
| 309 | } |
| 310 | |
| 311 | int usb2_phy_tuning(uint32_t phy2_pll_base, int port) |
| 312 | { |
| 313 | return 0; |
| 314 | } |
| 315 | |
| 316 | /**************************************************************/ |
| 317 | /* device mode config */ |
| 318 | /**************************************************************/ |
| 319 | void usb_device_mode_init(int phy_num) { |
| 320 | u2p_r0_t dev_u2p_r0; |
| 321 | u2p_r1_t dev_u2p_r1; |
| 322 | |
| 323 | usb_r0_t dev_usb_r0; |
| 324 | usb_r4_t dev_usb_r4; |
| 325 | int cnt; |
| 326 | u2p_aml_regs_t * u2p_aml_regs; |
| 327 | usb_aml_regs_t *usb_aml_regs; |
| 328 | unsigned int phy_base_addr, reset_addr; |
| 329 | |
| 330 | phy_aml_usb2_check_rev(); |
| 331 | if (phy_num == 1) { |
| 332 | u2p_aml_regs = (u2p_aml_regs_t * )((unsigned long)(PHY_COMP_BASE + PHY_REGISTER_SIZE)); |
| 333 | usb_aml_regs = (usb_aml_regs_t * )((ulong)(PHY_COMP_BASE + 0x80)); |
| 334 | phy_base_addr = PHY_21_BASE; |
| 335 | reset_addr = RESET_BASE; |
| 336 | } else { |
| 337 | u2p_aml_regs = (u2p_aml_regs_t * )((unsigned long)(PHY_COMP_BASE)); |
| 338 | usb_aml_regs = (usb_aml_regs_t * )((ulong)(PHY_COMP_BASE + 0x80)); |
| 339 | phy_base_addr = PHY_20_BASE; |
| 340 | reset_addr = RESET_BASE; |
| 341 | } |
| 342 | |
| 343 | //printf("PHY2=0x%08x,PHY3=0x%08x\n", u2p_aml_regs, usb_aml_regs); |
| 344 | printf("PHY2=%p,PHY3=%p\n", u2p_aml_regs, usb_aml_regs); |
| 345 | //if ((*(volatile uint32_t *)(unsigned long)(phy_base_addr + 0x38)) != 0) { |
| 346 | //usb_phy_tuning_reset(phy_num); |
| 347 | //mdelay(150); |
| 348 | //} |
| 349 | |
| 350 | //step 1: usb controller reset |
| 351 | usb_reset(reset_addr, USB_RESET_BIT); |
| 352 | |
| 353 | // step 3: enable usb INT internal USB |
| 354 | dev_usb_r0.d32 = usb_aml_regs->usb_r0; |
| 355 | dev_usb_r0.b.u2d_ss_scaledown_mode = 0; |
| 356 | dev_usb_r0.b.u2d_act = 1; |
| 357 | usb_aml_regs->usb_r0 = dev_usb_r0.d32; |
| 358 | |
| 359 | // step 4: disable usb phy sleep |
| 360 | dev_usb_r4.d32 = usb_aml_regs->usb_r4; |
| 361 | dev_usb_r4.b.p21_SLEEPM0 = 1; |
| 362 | usb_aml_regs->usb_r4 = dev_usb_r4.d32; |
| 363 | |
| 364 | // step 5: config phy21 device mode |
| 365 | dev_u2p_r0.d32 = u2p_aml_regs->u2p_r0; |
| 366 | dev_u2p_r0.b.host_device= 0; |
| 367 | dev_u2p_r0.b.POR= 0; |
| 368 | u2p_aml_regs->u2p_r0 = dev_u2p_r0.d32; |
| 369 | |
| 370 | udelay(10); |
| 371 | //step 6: phy21 reset |
| 372 | if (phy_num == 1) { |
| 373 | usb_reset(reset_addr, PHY21_RESET_LEVEL_BIT); |
| 374 | } else { |
| 375 | usb_reset(reset_addr, PHY20_RESET_LEVEL_BIT); |
| 376 | } |
| 377 | udelay(50); |
| 378 | |
| 379 | // step 6: wait for phy ready |
| 380 | dev_u2p_r1.d32 = u2p_aml_regs->u2p_r1; |
| 381 | cnt = 0; |
| 382 | while ((dev_u2p_r1.d32 & 0x00000001) != 1) { |
| 383 | dev_u2p_r1.d32 = u2p_aml_regs->u2p_r1; |
| 384 | if (cnt > 200) |
| 385 | break; |
| 386 | else { |
| 387 | cnt++; |
| 388 | udelay(5); |
| 389 | } |
| 390 | } |
| 391 | |
| 392 | //set_usb_phy21_pll(); |
| 393 | set_usb_pll(phy_base_addr); |
| 394 | //-------------------------------------------------- |
| 395 | |
| 396 | // ------------- usb phy21 initinal end ---------- |
| 397 | |
| 398 | //-------------------------------------------------- |
| 399 | } |