1 // Copyright 2017 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/platform-defs.h>
7 #include <hw/reg.h>
8 
9 #include <soc/aml-common/aml-usb-phy.h>
10 #include <soc/aml-s912/s912-hw.h>
11 
12 #include "vim.h"
13 
14 #define BIT_MASK(start, count) (((1 << (count)) - 1) << (start))
15 #define SET_BITS(dest, start, count, value) \
16         ((dest & ~BIT_MASK(start, count)) | (((value) << (start)) & BIT_MASK(start, count)))
17 
18 static const pbus_mmio_t xhci_mmios[] = {
19     {
20         .base = S912_USB0_BASE,
21         .length = S912_USB0_LENGTH,
22     },
23 };
24 
25 static const pbus_irq_t xhci_irqs[] = {
26     {
27         .irq = S912_USBH_IRQ,
28         .mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
29     },
30 };
31 
32 static const pbus_bti_t xhci_btis[] = {
33     {
34         .iommu_index = 0,
35         .bti_id = BTI_USB_XHCI,
36     },
37 };
38 
39 static const pbus_dev_t xhci_dev = {
40     .name = "xhci",
41     .vid = PDEV_VID_GENERIC,
42     .pid = PDEV_PID_GENERIC,
43     .did = PDEV_DID_USB_XHCI,
44     .mmio_list = xhci_mmios,
45     .mmio_count = countof(xhci_mmios),
46     .irq_list = xhci_irqs,
47     .irq_count = countof(xhci_irqs),
48     .bti_list = xhci_btis,
49     .bti_count = countof(xhci_btis),
50 };
51 
vim_usb_init(vim_bus_t * bus)52 zx_status_t vim_usb_init(vim_bus_t* bus) {
53     zx_status_t status;
54 
55     zx_handle_t bti;
56     status = iommu_get_bti(&bus->iommu, 0, BTI_BOARD, &bti);
57     if (status != ZX_OK) {
58         zxlogf(ERROR, "vim_bus_bind: iommu_get_bti failed: %d\n", status);
59         return status;
60     }
61     io_buffer_t usb_phy;
62     status = io_buffer_init_physical(&usb_phy, bti, S912_USB_PHY_BASE, S912_USB_PHY_LENGTH,
63                                      get_root_resource(),
64                                      ZX_CACHE_POLICY_UNCACHED_DEVICE);
65     if (status != ZX_OK) {
66         zxlogf(ERROR, "vim_usb_init io_buffer_init_physical failed %d\n", status);
67         zx_handle_close(bti);
68         return status;
69     }
70 
71     volatile void* regs = io_buffer_virt(&usb_phy);
72 
73     // amlogic_new_usb2_init
74     for (int i = 0; i < 4; i++) {
75         volatile void* addr = regs + (i * PHY_REGISTER_SIZE) + U2P_R0_OFFSET;
76         uint32_t temp = readl(addr);
77         temp |= U2P_R0_POR;
78         temp |= U2P_R0_DMPULLDOWN;
79         temp |= U2P_R0_DPPULLDOWN;
80         if (i == 1) {
81             temp |= U2P_R0_IDPULLUP;
82         }
83         writel(temp, addr);
84         zx_nanosleep(zx_deadline_after(ZX_USEC(500)));
85         temp = readl(addr);
86         temp &= ~U2P_R0_POR;
87         writel(temp, addr);
88     }
89 
90     // amlogic_new_usb3_init
91     volatile void* addr = regs + (4 * PHY_REGISTER_SIZE);
92 
93     uint32_t temp = readl(addr + USB_R1_OFFSET);
94     temp = SET_BITS(temp, USB_R1_U3H_FLADJ_30MHZ_REG_START, USB_R1_U3H_FLADJ_30MHZ_REG_BITS, 0x20);
95     writel(temp, addr + USB_R1_OFFSET);
96 
97     temp = readl(addr + USB_R5_OFFSET);
98     temp |= USB_R5_IDDIG_EN0;
99     temp |= USB_R5_IDDIG_EN1;
100     temp = SET_BITS(temp, USB_R5_IDDIG_TH_START, USB_R5_IDDIG_TH_BITS, 255);
101     writel(temp, addr + USB_R5_OFFSET);
102 
103     io_buffer_release(&usb_phy);
104     zx_handle_close(bti);
105 
106     if ((status = pbus_device_add(&bus->pbus, &xhci_dev)) != ZX_OK) {
107         zxlogf(ERROR, "vim_usb_init could not add xhci_dev: %d\n", status);
108         return status;
109     }
110 
111     return ZX_OK;
112 }
113