]> git.kernelconcepts.de Git - karo-tx-uboot.git/commitdiff
ARM: zynq: ehci: Added USB host driver support
authorMichal Simek <monstr@monstr.eu>
Fri, 25 Apr 2014 10:21:04 +0000 (12:21 +0200)
committerMichal Simek <michal.simek@xilinx.com>
Wed, 14 May 2014 05:43:35 +0000 (07:43 +0200)
Added USB host driver for zynq.

Signed-off-by: Siva Durga Prasad Paladugu <sivadur@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
arch/arm/cpu/armv7/zynq/slcr.c
arch/arm/include/asm/arch-zynq/hardware.h
drivers/usb/host/Makefile
drivers/usb/host/ehci-zynq.c [new file with mode: 0644]

index 51894f923975d575b00ab0523ce2923e30b57e3d..934ccc31c86fd80723afa6c89be03c5651600cb9 100644 (file)
@@ -14,6 +14,8 @@
 #define SLCR_LOCK_MAGIC                0x767B
 #define SLCR_UNLOCK_MAGIC      0xDF0D
 
 #define SLCR_LOCK_MAGIC                0x767B
 #define SLCR_UNLOCK_MAGIC      0xDF0D
 
+#define SLCR_USB_L1_SEL                        0x04
+
 #define SLCR_IDCODE_MASK       0x1F000
 #define SLCR_IDCODE_SHIFT      12
 
 #define SLCR_IDCODE_MASK       0x1F000
 #define SLCR_IDCODE_SHIFT      12
 
@@ -34,7 +36,29 @@ struct zynq_slcr_mio_get_status {
        u32 check_val;
 };
 
        u32 check_val;
 };
 
+static const int usb0_pins[] = {
+       28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39
+};
+
+static const int usb1_pins[] = {
+       40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+};
+
 static const struct zynq_slcr_mio_get_status mio_periphs[] = {
 static const struct zynq_slcr_mio_get_status mio_periphs[] = {
+       {
+               "usb0",
+               usb0_pins,
+               ARRAY_SIZE(usb0_pins),
+               SLCR_USB_L1_SEL,
+               SLCR_USB_L1_SEL,
+       },
+       {
+               "usb1",
+               usb1_pins,
+               ARRAY_SIZE(usb1_pins),
+               SLCR_USB_L1_SEL,
+               SLCR_USB_L1_SEL,
+       },
 };
 
 static int slcr_lock = 1; /* 1 means locked, 0 means unlocked */
 };
 
 static int slcr_lock = 1; /* 1 means locked, 0 means unlocked */
index a9d091f141efa629c73807075f3c5e60e16b9594..2aede0c552c62a4956028afd36a03ce411d5d55b 100644 (file)
@@ -23,6 +23,8 @@
 #define ZYNQ_SPI_BASEADDR1             0xE0007000
 #define ZYNQ_DDRC_BASEADDR             0xF8006000
 #define ZYNQ_EFUSE_BASEADDR            0xF800D000
 #define ZYNQ_SPI_BASEADDR1             0xE0007000
 #define ZYNQ_DDRC_BASEADDR             0xF8006000
 #define ZYNQ_EFUSE_BASEADDR            0xF800D000
+#define ZYNQ_USB_BASEADDR0             0xE0002000
+#define ZYNQ_USB_BASEADDR1             0xE0003000
 
 /* Bootmode setting values */
 #define ZYNQ_BM_MASK           0x7
 
 /* Bootmode setting values */
 #define ZYNQ_BM_MASK           0x7
index b301e28252bc31c34e6f7fcd0df95a6127fcd427..7211c6ad964162222f9fc73e380e30a212f24eca 100644 (file)
@@ -37,6 +37,7 @@ obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
 obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
 obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
 obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
 obj-$(CONFIG_USB_EHCI_TEGRA) += ehci-tegra.o
 obj-$(CONFIG_USB_EHCI_VCT) += ehci-vct.o
 obj-$(CONFIG_USB_EHCI_RMOBILE) += ehci-rmobile.o
+obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o
 
 # xhci
 obj-$(CONFIG_USB_XHCI) += xhci.o xhci-mem.o xhci-ring.o
 
 # xhci
 obj-$(CONFIG_USB_XHCI) += xhci.o xhci-mem.o xhci-ring.o
diff --git a/drivers/usb/host/ehci-zynq.c b/drivers/usb/host/ehci-zynq.c
new file mode 100644 (file)
index 0000000..7770d05
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2014, Xilinx, Inc
+ *
+ * USB Low level initialization(Specific to zynq)
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/ehci-fsl.h>
+#include <usb/ulpi.h>
+
+#include "ehci.h"
+
+#define ZYNQ_USB_USBCMD_RST                    0x0000002
+#define ZYNQ_USB_USBCMD_STOP                   0x0000000
+#define ZYNQ_USB_NUM_MIO                       12
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index,  enum usb_init_type init, struct ehci_hccr **hccr,
+                 struct ehci_hcor **hcor)
+{
+       struct usb_ehci *ehci;
+       struct ulpi_viewport ulpi_vp;
+       int ret, mio_usb;
+       /* Used for writing the ULPI data address */
+       struct ulpi_regs *ulpi = (struct ulpi_regs *)0;
+
+       if (!index) {
+               mio_usb = zynq_slcr_get_mio_pin_status("usb0");
+               if (mio_usb != ZYNQ_USB_NUM_MIO) {
+                       printf("usb0 wrong num MIO: %d, Index %d\n", mio_usb,
+                              index);
+                       return -1;
+               }
+               ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR0;
+       } else {
+               mio_usb = zynq_slcr_get_mio_pin_status("usb1");
+               if (mio_usb != ZYNQ_USB_NUM_MIO) {
+                       printf("usb1 wrong num MIO: %d, Index %d\n", mio_usb,
+                              index);
+                       return -1;
+               }
+               ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR1;
+       }
+
+       *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength);
+       *hcor = (struct ehci_hcor *)((uint32_t) *hccr +
+                       HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+
+       ulpi_vp.viewport_addr = (u32)&ehci->ulpi_viewpoint;
+       ulpi_vp.port_num = 0;
+
+       ret = ulpi_init(&ulpi_vp);
+       if (ret) {
+               puts("zynq ULPI viewport init failed\n");
+               return -1;
+       }
+
+       /* ULPI set flags */
+       ulpi_write(&ulpi_vp, &ulpi->otg_ctrl,
+                  ULPI_OTG_DP_PULLDOWN | ULPI_OTG_DM_PULLDOWN |
+                  ULPI_OTG_EXTVBUSIND);
+       ulpi_write(&ulpi_vp, &ulpi->function_ctrl,
+                  ULPI_FC_FULL_SPEED | ULPI_FC_OPMODE_NORMAL |
+                  ULPI_FC_SUSPENDM);
+       ulpi_write(&ulpi_vp, &ulpi->iface_ctrl, 0);
+
+       /* Set VBus */
+       ulpi_write(&ulpi_vp, &ulpi->otg_ctrl_set,
+                  ULPI_OTG_DRVVBUS | ULPI_OTG_DRVVBUS_EXT);
+
+       return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+       struct usb_ehci *ehci;
+
+       if (!index)
+               ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR0;
+       else
+               ehci = (struct usb_ehci *)ZYNQ_USB_BASEADDR1;
+
+       /* Stop controller */
+       writel(ZYNQ_USB_USBCMD_STOP, &ehci->usbcmd);
+       udelay(1000);
+
+       /* Initiate controller reset */
+       writel(ZYNQ_USB_USBCMD_RST, &ehci->usbcmd);
+
+       return 0;
+}