aml usb wip

Change-Id: Ide2fdcfa7572e1b3dd55125f13b69fe9e98829d6
diff --git a/system/dev/board/aml-s905d2/aml-usb.c b/system/dev/board/aml-s905d2/aml-usb.c
index c6b1d24..82d4722 100644
--- a/system/dev/board/aml-s905d2/aml-usb.c
+++ b/system/dev/board/aml-s905d2/aml-usb.c
@@ -6,24 +6,22 @@
 #include <ddk/protocol/platform-defs.h>
 #include <hw/reg.h>
 
-#include <soc/aml-common/aml-usb-phy.h>
+#include <soc/aml-common/aml-usb-phy-v2.h>
+#include <soc/aml-s905d2/s905d2-gpio.h>
+#include <soc/aml-s905d2/s905d2-hw.h>
 
 #include "aml.h"
 
-#define BIT_MASK(start, count) (((1 << (count)) - 1) << (start))
-#define SET_BITS(dest, start, count, value) \
-        ((dest & ~BIT_MASK(start, count)) | (((value) << (start)) & BIT_MASK(start, count)))
-
 static const pbus_mmio_t xhci_mmios[] = {
     {
-        .base = 0xc9000000,
-        .length = 0x100000,
+        .base = S905D2_USB0_BASE,
+        .length = S905D2_USB0_LENGTH,
     },
 };
 
 static const pbus_irq_t xhci_irqs[] = {
     {
-        .irq = 62,
+        .irq = S905D2_USBH_IRQ,
         .mode = ZX_INTERRUPT_MODE_EDGE_HIGH,
     },
 };
@@ -50,15 +48,22 @@
 
 zx_status_t aml_usb_init(aml_bus_t* bus) {
     zx_status_t status;
-
+    io_buffer_t reset_buf;
+    io_buffer_t usbctrl_buf;
     zx_handle_t bti;
+
+    // FIXME - move to board hardware header
+    gpio_config(&bus->gpio, S905D2_GPIOH(6), GPIO_DIR_OUT);
+    gpio_write(&bus->gpio, S905D2_GPIOH(6), 1);
+
     status = iommu_get_bti(&bus->iommu, 0, BTI_BOARD, &bti);
     if (status != ZX_OK) {
-        zxlogf(ERROR, "aml_bus_bind: iommu_get_bti failed: %d\n", status);
+        zxlogf(ERROR, "aml_usb_init: iommu_get_bti failed: %d\n", status);
         return status;
     }
-    io_buffer_t usb_phy;
-    status = io_buffer_init_physical(&usb_phy, bti, 0xd0078000, 4096,  get_root_resource(),
+
+    status = io_buffer_init_physical(&reset_buf, bti, S905D2_RESET_BASE, S905D2_RESET_LENGTH,
+                                     get_root_resource(),
                                      ZX_CACHE_POLICY_UNCACHED_DEVICE);
     if (status != ZX_OK) {
         zxlogf(ERROR, "aml_usb_init io_buffer_init_physical failed %d\n", status);
@@ -66,45 +71,66 @@
         return status;
     }
 
-    volatile void* regs = io_buffer_virt(&usb_phy);
-
-    // amlogic_new_usb2_init
-    for (int i = 0; i < 4; i++) {
-        volatile void* addr = regs + (i * PHY_REGISTER_SIZE) + U2P_R0_OFFSET;
-        uint32_t temp = readl(addr);
-        temp |= U2P_R0_POR;
-        temp |= U2P_R0_DMPULLDOWN;
-        temp |= U2P_R0_DPPULLDOWN;
-        if (i == 1) {
-            temp |= U2P_R0_IDPULLUP;
-        }
-        writel(temp, addr);
-        zx_nanosleep(zx_deadline_after(ZX_USEC(500)));
-        temp = readl(addr);
-        temp &= ~U2P_R0_POR;
-        writel(temp, addr);
-    }
-
-    // amlogic_new_usb3_init
-    volatile void* addr = regs + (4 * PHY_REGISTER_SIZE);
-
-    uint32_t temp = readl(addr + USB_R1_OFFSET);
-    temp = SET_BITS(temp, USB_R1_U3H_FLADJ_30MHZ_REG_START, USB_R1_U3H_FLADJ_30MHZ_REG_BITS, 0x20);
-    writel(temp, addr + USB_R1_OFFSET);
-
-    temp = readl(addr + USB_R5_OFFSET);
-    temp |= USB_R5_IDDIG_EN0;
-    temp |= USB_R5_IDDIG_EN1;
-    temp = SET_BITS(temp, USB_R5_IDDIG_TH_START, USB_R5_IDDIG_TH_BITS, 255);
-    writel(temp, addr + USB_R5_OFFSET);
-
-    io_buffer_release(&usb_phy);
-    zx_handle_close(bti);
-
-    if ((status = pbus_device_add(&bus->pbus, &xhci_dev, 0)) != ZX_OK) {
-        zxlogf(ERROR, "aml_usb_init could not add xhci_dev: %d\n", status);
+    status = io_buffer_init_physical(&usbctrl_buf, bti, S905D2_USBCTRL_BASE, S905D2_USBCTRL_LENGTH,
+                                     get_root_resource(),
+                                     ZX_CACHE_POLICY_UNCACHED_DEVICE);
+    if (status != ZX_OK) {
+        zxlogf(ERROR, "aml_usb_init io_buffer_init_physical failed %d\n", status);
+        io_buffer_release(&reset_buf);
+        zx_handle_close(bti);
         return status;
     }
 
-    return ZX_OK;
+    volatile void* reset_regs = io_buffer_virt(&reset_buf);
+    volatile void* usbctrl_regs = io_buffer_virt(&usbctrl_buf);
+
+    // first reset USB
+	uint32_t val = readl(reset_regs + 0x21 * 4);
+	writel((val | (0x3 << 16)), reset_regs + 0x21 * 4);
+
+    volatile uint32_t* reset_1 = (uint32_t *)(reset_regs + S905D2_RESET1_REGISTER);
+    writel(readl(reset_1) | S905D2_RESET1_USB, reset_1);
+    // FIXME(voydanoff) this delay is very long, but it is what the Amlogic Linux kernel is doing.
+    zx_nanosleep(zx_deadline_after(ZX_MSEC(500)));
+
+    // amlogic_new_usb2_init
+    for (int i = 0; i < 2; i++) {
+        volatile void* addr = usbctrl_regs + (i * PHY_REGISTER_SIZE) + U2P_R0_OFFSET;
+        uint32_t temp = readl(addr);
+        temp |= U2P_R0_POR;
+        temp |= U2P_R0_HOST_DEVICE;
+        if (i == 1) {
+            temp |= U2P_R0_IDPULLUP0;
+            temp |= U2P_R0_DRVVBUS0;
+        }
+        writel(temp, addr);
+
+        zx_nanosleep(zx_deadline_after(ZX_USEC(10)));
+
+        writel(readl(reset_1) | (1 << (16 + i)), reset_1);
+
+        zx_nanosleep(zx_deadline_after(ZX_USEC(50)));
+
+        addr = usbctrl_regs + (i * PHY_REGISTER_SIZE) + USB_R1_OFFSET;
+
+        temp = readl(addr);
+        int cnt = 0;
+        while (!(temp & U2P_R1_PHY_RDY)) {
+            temp = readl(addr);
+            //we wait phy ready max 1ms, common is 100us
+            if (cnt > 200) {
+printf("XXXXXX usb loop failed!\n");
+                break;
+            }
+
+            cnt++;
+            zx_nanosleep(zx_deadline_after(ZX_USEC(5)));
+        }        
+    }
+
+    io_buffer_release(&reset_buf);
+    io_buffer_release(&usbctrl_buf);
+    zx_handle_close(bti);
+
+    return pbus_device_add(&bus->pbus, &xhci_dev, 0);
 }
diff --git a/system/dev/board/aml-s905d2/aml.c b/system/dev/board/aml-s905d2/aml.c
index 13f76f1..9d92a73 100644
--- a/system/dev/board/aml-s905d2/aml.c
+++ b/system/dev/board/aml-s905d2/aml.c
@@ -51,11 +51,11 @@
         zxlogf(ERROR, "aml_i2c_init failed: %d\n", status);
         goto fail;
     }
+*/
     if ((status = aml_usb_init(bus)) != ZX_OK) {
         zxlogf(ERROR, "aml_usb_init failed: %d\n", status);
         goto fail;
     }
-*/
 
     return ZX_OK;
 fail:
diff --git a/system/dev/soc/amlogic/include/soc/aml-common/aml-usb-phy-v2.h b/system/dev/soc/amlogic/include/soc/aml-common/aml-usb-phy-v2.h
new file mode 100644
index 0000000..ea4d592
--- /dev/null
+++ b/system/dev/soc/amlogic/include/soc/aml-common/aml-usb-phy-v2.h
@@ -0,0 +1,89 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+/*
+// usb2
+phy->regs 0xffe09000 0x80
+phy->reset_regs 0xffd01008 0x4 // used in amlogic_new_usbphy_reset_v2()
+phy->phy_cfg[0] 0xff636000 0x2000
+phy->phy_cfg[1] 0xff63a000 0x2000
+
+				0x0 0xff636000 0x0 0x2000
+				0x0 0xff63a000 0x0 0x2000>;
+		pll-setting-1 = <0x09400414>;
+		pll-setting-2 = <0x927E0000>;
+		pll-setting-3 = <0xac5f49e5>;
+
+
+// usb3
+phy->regs = <0x0 0xffe09080 0x0 0x20>;
+phy->phy3_cfg = <0xff646000>; // used in amlogic_new_usb3_v2_probe - set the phy from pcie to usb3 
+*/
+
+// size of phy port register block
+#define PHY_REGISTER_SIZE 32
+#define U2P_R0_OFFSET   0x0
+#define U2P_R1_OFFSET   0x4
+
+#define USB_R0_OFFSET   0x80
+#define USB_R1_OFFSET   0x84
+#define USB_R2_OFFSET   0x88
+#define USB_R3_OFFSET   0x8c
+#define USB_R4_OFFSET   0x90
+#define USB_R5_OFFSET   0x94
+
+#define U2P_R0_HOST_DEVICE                          (1 << 0)
+#define U2P_R0_POWER_OK                             (1 << 1)
+#define U2P_R0_HOST_MODE                            (1 << 2)
+#define U2P_R0_POR                                  (1 << 3)
+#define U2P_R0_IDPULLUP0                            (1 << 4)
+#define U2P_R0_DRVVBUS0                             (1 << 5)
+
+#define U2P_R1_PHY_RDY                              (1 << 0)
+#define U2P_R1_IDDIG0                               (1 << 1)
+#define U2P_R1_OTGSESSVLD0                          (1 << 2)
+#define U2P_R1_VBUSVALID0                           (1 << 3)
+
+#define USB_R0_P30_LANE0_TX2RX_LOOPBACK             (1 << 17)
+#define USB_R0_P30_LANE0_EXT_PCLK_REG               (1 << 18)
+#define USB_R0_P30_PCS_RX_LOS_MASK_VAL              (1 << 19)   // 10 bits
+#define USB_R0_U2D_SS_SCALEDOWN_MODE                (1 << 29)   // 2 bits
+#define USB_R0_U2D_ACT                              (1 << 31)
+
+#define USB_R1_U3H_BIGENDIAN_GS                     (1 << 0)
+#define USB_R1_U3H_PME_EN                           (1 << 1)
+#define USB_R1_U3H_HUB_PORT_OVERCURRENT             (1 << 2)    // 3 bits
+#define USB_R1_U3H_HUB_PORT_PERM_ATTACH             (1 << 7)    // 3 bits
+#define USB_R1_U3H_HOST_U2_PORT_DISABLE             (1 << 12)   // 2 bits
+#define USB_R1_U3H_HOST_U3_PORT_DISABLE             (1 << 16)
+#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT  (1 << 17)
+#define USB_R1_U3H_HOST_MSI_ENABLE                  (1 << 18)
+#define USB_R1_U3H_FLADJ_30MHZ_REG                  (1 << 19)   // 6 bits
+#define USB_R1_P30_PCS_TX_SWING_FULL                (1 << 25)   // 7 bits
+
+#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB              (1 << 20)   // 6 bits
+#define USB_R2_P30_PCS_TX_DEEMPH_6DB                (1 << 26)   // 6 bits
+
+#define USB_R3_P30_SSC_EN                           (1 << 0)
+#define USB_R3_P30_SSC_RANGE                        (1 << 1)    // 3 bits
+#define USB_R3_P30_SSC_REF_CLK_SEL                  (1 << 4)    // 9 bits
+#define USB_R3_P30_REF_SSP_EN                       (1 << 13)
+
+#define USB_R4_P21_PORTRESET0                       (1 << 0)
+#define USB_R4_P21_SLEEPM0                          (1 << 1)
+#define USB_R4_MEM_PD                               (1 << 2)    // 2 bits
+#define USB_R4_P21_ONLY                             (1 << 4)
+
+#define USB_R5_IDDIG_SYNC                           (1 << 0)
+#define USB_R5_IDDIG_REG                            (1 << 1)
+#define USB_R5_IDDIG_CFG                            (1 << 2)    // 2 bits
+#define USB_R5_IDDIG_EN0                            (1 << 4)
+#define USB_R5_IDDIG_EN1                            (1 << 5)
+#define USB_R5_IDDIG_CURR                           (1 << 6)
+#define USB_R5_USB_IDDIG_IRQ                        (1 << 7)
+#define USB_R5_IDDIG_TH                             (1 << 8)    // 8 bits
+#define USB_R5_IDDIG_CNT                            (1 << 16)   // 8 bits
+
diff --git a/system/dev/soc/amlogic/include/soc/aml-s905d2/s905d2-hw.h b/system/dev/soc/amlogic/include/soc/aml-s905d2/s905d2-hw.h
index 38d992c..5e13558 100644
--- a/system/dev/soc/amlogic/include/soc/aml-s905d2/s905d2-hw.h
+++ b/system/dev/soc/amlogic/include/soc/aml-s905d2/s905d2-hw.h
@@ -9,6 +9,47 @@
 #define S905D2_GPIO_A0_BASE             0xff800000
 #define S905D2_GPIO_AO_LENGTH           0x1000
 
+#define S905D2_USB0_BASE                0xff500000
+#define S905D2_USB0_LENGTH              0x100000
+#define S905D2_USB1_BASE                0xff400000
+#define S905D2_USB1_LENGTH              0x100000
+
+#define S905D2_USBPHY20_BASE            0xff636000
+#define S905D2_USBPHY20_LENGTH          0x2000
+#define S905D2_USBPHY21_BASE            0xff63a000
+#define S905D2_USBPHY21_LENGTH          0x2000
+#define S905D2_USBCTRL_BASE             0xffe09000
+#define S905D2_USBCTRL_LENGTH           0x2000
+
+#define S905D2_RESET_BASE               0xffd01000
+#define S905D2_RESET_LENGTH             0x1000
+
+// Reset register offsets
+#define S905D2_RESET0_REGISTER          0x04
+#define S905D2_RESET1_REGISTER          0x08
+#define S905D2_RESET1_USB               (1 << 2)    // bit to reset USB
+#define S905D2_RESET2_REGISTER          0x0c
+#define S905D2_RESET3_REGISTER          0x10
+#define S905D2_RESET4_REGISTER          0x14
+#define S905D2_RESET6_REGISTER          0x1c
+#define S905D2_RESET7_REGISTER          0x20
+#define S905D2_RESET0_MASK              0x40
+#define S905D2_RESET1_MASK              0x44
+#define S905D2_RESET2_MASK              0x48
+#define S905D2_RESET3_MASK              0x4c
+#define S905D2_RESET4_MASK              0x50
+#define S905D2_RESET6_MASK              0x58
+#define S905D2_RESET7_MASK              0x5c
+#define S905D2_RESET0_LEVEL             0x80
+#define S905D2_RESET1_LEVEL             0x84
+#define S905D2_RESET2_LEVEL             0x88
+#define S905D2_RESET3_LEVEL             0x8c
+#define S905D2_RESET4_LEVEL             0x90
+#define S905D2_RESET6_LEVEL             0x98
+#define S905D2_RESET7_LEVEL             0x9c
+
+#define S905D2_USBH_IRQ                 58
+#define S905D2_USBD_IRQ                 59
 #define S905D2_GPIO_IRQ_0               94
 #define S905D2_GPIO_IRQ_1               95
 #define S905D2_GPIO_IRQ_2               96