1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <ddk/debug.h>
6 #include <ddk/mmio-buffer.h>
7 #include <hw/reg.h>
8 #include <zircon/syscalls.h>
9 #include <soc/aml-common/aml-usb-phy-v2-regs.h>
10 #include <soc/aml-s905d2/s905d2-hw.h>
11 
12 // from mesong12a.dtsi
13 #define PLL_SETTING_0   0x09400414
14 #define PLL_SETTING_1   0x927E0000
15 #define PLL_SETTING_2   0xac5f49e5
16 
17 // set_usb_pll() in phy_aml_new_usb2_v2.c
set_usb_pll(zx_paddr_t reg_base)18 static zx_status_t set_usb_pll(zx_paddr_t reg_base) {
19     mmio_buffer_t buf;
20     zx_status_t status;
21 
22     status = mmio_buffer_init_physical(&buf, reg_base, ZX_PAGE_SIZE, get_root_resource(),
23                                        ZX_CACHE_POLICY_UNCACHED_DEVICE);
24     if (status != ZX_OK) {
25         return status;
26     }
27     void* reg = buf.vaddr;
28 
29     writel((0x30000000 | PLL_SETTING_0), reg + 0x40);
30     writel(PLL_SETTING_1, reg + 0x44);
31     writel(PLL_SETTING_2, reg + 0x48);
32     zx_nanosleep(zx_deadline_after(ZX_USEC(100)));
33     writel((0x10000000 | PLL_SETTING_0), reg + 0x40);
34 
35     mmio_buffer_release(&buf);
36     return ZX_OK;
37 }
38 
aml_usb_phy_v2_init(zx_handle_t bti)39 zx_status_t aml_usb_phy_v2_init(zx_handle_t bti) {
40     zx_status_t status;
41     mmio_buffer_t reset_buf;
42     mmio_buffer_t usbctrl_buf;
43 
44     status = mmio_buffer_init_physical(&reset_buf, S905D2_RESET_BASE, S905D2_RESET_LENGTH,
45                                        get_root_resource(), ZX_CACHE_POLICY_UNCACHED_DEVICE);
46     if (status != ZX_OK) {
47         zxlogf(ERROR, "aml_usb_init io_buffer_init_physical failed %d\n", status);
48         return status;
49     }
50 
51     status = mmio_buffer_init_physical(&usbctrl_buf, S905D2_USBCTRL_BASE, S905D2_USBCTRL_LENGTH,
52                                        get_root_resource(), ZX_CACHE_POLICY_UNCACHED_DEVICE);
53     if (status != ZX_OK) {
54         zxlogf(ERROR, "aml_usb_init io_buffer_init_physical failed %d\n", status);
55         mmio_buffer_release(&reset_buf);
56         return status;
57     }
58 
59     volatile void* reset_regs = reset_buf.vaddr;
60     volatile void* usbctrl_regs = usbctrl_buf.vaddr;
61 
62     // first reset USB
63     uint32_t val = readl(reset_regs + 0x21 * 4);
64     writel((val | (0x3 << 16)), reset_regs + 0x21 * 4);
65 
66     // amlogic_new_usbphy_reset_v2()
67     volatile uint32_t* reset_1 = (uint32_t *)(reset_regs + S905D2_RESET1_REGISTER);
68     set_bitsl(S905D2_RESET1_USB, reset_1);
69     // FIXME(voydanoff) this delay is very long, but it is what the Amlogic Linux kernel is doing.
70     zx_nanosleep(zx_deadline_after(ZX_MSEC(500)));
71 
72     // amlogic_new_usb2_init()
73     for (int i = 0; i < 2; i++) {
74         volatile void* addr = usbctrl_regs + (i * PHY_REGISTER_SIZE) + U2P_R0_OFFSET;
75         uint32_t temp = readl(addr);
76         temp |= U2P_R0_POR;
77         temp |= U2P_R0_HOST_DEVICE;
78         if (i == 1) {
79             temp |= U2P_R0_IDPULLUP0;
80             temp |= U2P_R0_DRVVBUS0;
81         }
82         writel(temp, addr);
83 
84         zx_nanosleep(zx_deadline_after(ZX_USEC(10)));
85 
86         // amlogic_new_usbphy_reset_phycfg_v2()
87         set_bitsl((1 << (16 + 0 /*i is always zero here */)), reset_1);
88 
89         zx_nanosleep(zx_deadline_after(ZX_USEC(50)));
90 
91         addr = usbctrl_regs + (i * PHY_REGISTER_SIZE) + U2P_R1_OFFSET;
92 
93         temp = readl(addr);
94         int cnt = 0;
95         while (!(temp & U2P_R1_PHY_RDY)) {
96             temp = readl(addr);
97             // wait phy ready max 1ms, common is 100us
98             if (cnt > 200) {
99                 zxlogf(ERROR, "aml_usb_init U2P_R1_PHY_RDY wait failed\n");
100                 break;
101             }
102 
103             cnt++;
104             zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
105         }
106     }
107 
108     // set up PLLs
109     if ((status = set_usb_pll(S905D2_USBPHY20_BASE)) != ZX_OK ||
110         (status = set_usb_pll(S905D2_USBPHY21_BASE)) != ZX_OK) {
111         zxlogf(ERROR, "aml_usb_init: set_usb_pll failed: %d\n", status);
112     }
113 
114     mmio_buffer_release(&reset_buf);
115     mmio_buffer_release(&usbctrl_buf);
116 
117     return ZX_OK;
118 }
119