[U-Boot] [PATCH v5 1/2] usb: zynqmp: Add XHCI driver support

From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Added USB XHCI driver support for zynqmp.
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- Changes for v5: - Removed __board_usb_init() as per review comment Changes for v4: - Added sanity check for index as per review comment Changes for v3: - Decreased the phy reset delay to 10 micro secs - Defined base addresses in board config file as per review comment. Changes for v2: - Moved all from xhci-zynqmp.h to .c file as per review comment - Removed ad-hoc function zynqmp_xhci_core_exit() as per review comment --- drivers/usb/host/Makefile | 1 + drivers/usb/host/xhci-zynqmp.c | 143 ++++++++++++++++++++++++++++++++++++ include/configs/xilinx_zynqmp_ep.h | 2 + 3 files changed, 146 insertions(+), 0 deletions(-) create mode 100644 drivers/usb/host/xhci-zynqmp.c
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index f70f38c..645b990 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_USB_EHCI_ZYNQ) += ehci-zynq.o # xhci obj-$(CONFIG_USB_XHCI) += xhci.o xhci-mem.o xhci-ring.o obj-$(CONFIG_USB_XHCI_DWC3) += xhci-dwc3.o +obj-$(CONFIG_USB_XHCI_ZYNQMP) += xhci-zynqmp.o obj-$(CONFIG_USB_XHCI_KEYSTONE) += xhci-keystone.o obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o diff --git a/drivers/usb/host/xhci-zynqmp.c b/drivers/usb/host/xhci-zynqmp.c new file mode 100644 index 0000000..2664815 --- /dev/null +++ b/drivers/usb/host/xhci-zynqmp.c @@ -0,0 +1,143 @@ +/* + * Copyright 2015 Xilinx, Inc. + * + * Zynq USB HOST xHCI Controller + * + * Author: Siva Durga Prasad Paladugusivadur@xilinx.com + * + * This file was reused from Freescale USB xHCI + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <usb.h> +#include <asm-generic/errno.h> +#include <asm/arch-zynqmp/hardware.h> +#include <linux/compat.h> +#include <linux/usb/dwc3.h> +#include "xhci.h" + +/* Declare global data pointer */ +DECLARE_GLOBAL_DATA_PTR; + +/* Default to the ZYNQMP XHCI defines */ +#define USB3_PWRCTL_CLK_CMD_MASK 0x3FE000 +#define USB3_PWRCTL_CLK_FREQ_MASK 0xFFC +#define USB3_PHY_PARTIAL_RX_POWERON BIT(6) +#define USB3_PHY_RX_POWERON BIT(14) +#define USB3_PHY_TX_POWERON BIT(15) +#define USB3_PHY_TX_RX_POWERON (USB3_PHY_RX_POWERON | USB3_PHY_TX_POWERON) +#define USB3_PWRCTL_CLK_CMD_SHIFT 14 +#define USB3_PWRCTL_CLK_FREQ_SHIFT 22 + +/* USBOTGSS_WRAPPER definitions */ +#define USBOTGSS_WRAPRESET BIT(17) +#define USBOTGSS_DMADISABLE BIT(16) +#define USBOTGSS_STANDBYMODE_NO_STANDBY BIT(4) +#define USBOTGSS_STANDBYMODE_SMRT BIT(5) +#define USBOTGSS_STANDBYMODE_SMRT_WKUP (0x3 << 4) +#define USBOTGSS_IDLEMODE_NOIDLE BIT(2) +#define USBOTGSS_IDLEMODE_SMRT BIT(3) +#define USBOTGSS_IDLEMODE_SMRT_WKUP (0x3 << 2) + +/* USBOTGSS_IRQENABLE_SET_0 bit */ +#define USBOTGSS_COREIRQ_EN BIT(1) + +/* USBOTGSS_IRQENABLE_SET_1 bits */ +#define USBOTGSS_IRQ_SET_1_IDPULLUP_FALL_EN BIT(1) +#define USBOTGSS_IRQ_SET_1_DISCHRGVBUS_FALL_EN BIT(3) +#define USBOTGSS_IRQ_SET_1_CHRGVBUS_FALL_EN BIT(4) +#define USBOTGSS_IRQ_SET_1_DRVVBUS_FALL_EN BIT(5) +#define USBOTGSS_IRQ_SET_1_IDPULLUP_RISE_EN BIT(8) +#define USBOTGSS_IRQ_SET_1_DISCHRGVBUS_RISE_EN BIT(11) +#define USBOTGSS_IRQ_SET_1_CHRGVBUS_RISE_EN BIT(12) +#define USBOTGSS_IRQ_SET_1_DRVVBUS_RISE_EN BIT(13) +#define USBOTGSS_IRQ_SET_1_OEVT_EN BIT(16) +#define USBOTGSS_IRQ_SET_1_DMADISABLECLR_EN BIT(17) + +struct zynqmp_xhci { + struct xhci_hccr *hcd; + struct dwc3 *dwc3_reg; +}; + +static struct zynqmp_xhci zynqmp_xhci; + +unsigned long ctr_addr[] = CONFIG_ZYNQMP_XHCI_LIST; + +void usb_phy_reset(struct dwc3 *dwc3_reg) +{ + /* Assert USB3 PHY reset */ + setbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST); + + /* Assert USB2 PHY reset */ + setbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST); + + udelay(10); + + /* Clear USB3 PHY reset */ + clrbits_le32(&dwc3_reg->g_usb3pipectl[0], DWC3_GUSB3PIPECTL_PHYSOFTRST); + + /* Clear USB2 PHY reset */ + clrbits_le32(&dwc3_reg->g_usb2phycfg, DWC3_GUSB2PHYCFG_PHYSOFTRST); +} + +static int zynqmp_xhci_core_init(struct zynqmp_xhci *zynqmp_xhci) +{ + int ret = 0; + + ret = dwc3_core_init(zynqmp_xhci->dwc3_reg); + if (ret) { + debug("%s:failed to initialize core\n", __func__); + return ret; + } + + /* We are hard-coding DWC3 core to Host Mode */ + dwc3_set_mode(zynqmp_xhci->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); + + return ret; +} + +int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) +{ + struct zynqmp_xhci *ctx = &zynqmp_xhci; + int ret = 0; + + if (index < 0 || index >= ARRAY_SIZE(ctr_addr)) + return -EINVAL; + + ctx->hcd = (struct xhci_hccr *)ctr_addr[index]; + ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); + + ret = board_usb_init(index, USB_INIT_HOST); + if (ret != 0) { + puts("Failed to initialize board for USB\n"); + return ret; + } + + ret = zynqmp_xhci_core_init(ctx); + if (ret < 0) { + puts("Failed to initialize xhci\n"); + return ret; + } + + *hccr = (struct xhci_hccr *)ctx->hcd; + *hcor = (struct xhci_hcor *)((uint32_t) *hccr + + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); + + debug("zynqmp-xhci: init hccr %x and hcor %x hc_length %d\n", + (uint32_t)*hccr, (uint32_t)*hcor, + (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); + + return ret; +} + +void xhci_hcd_stop(int index) +{ + /* + * Currently zynqmp socs do not support PHY shutdown from + * sw. But this support may be added in future socs. + */ + + return 0; +} diff --git a/include/configs/xilinx_zynqmp_ep.h b/include/configs/xilinx_zynqmp_ep.h index ed6023a..1845622 100644 --- a/include/configs/xilinx_zynqmp_ep.h +++ b/include/configs/xilinx_zynqmp_ep.h @@ -23,6 +23,8 @@ #define CONFIG_SYS_I2C_ZYNQ #define CONFIG_ZYNQ_EEPROM #define CONFIG_AHCI +#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR, \ + ZYNQMP_USB1_XHCI_BASEADDR}
#include <configs/xilinx_zynqmp.h>

From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Enable USB XHCI support for ZynqMP
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com --- Changes for v5: - None Changes for v4: - None Changes for v3: - Removed extra space between # and define as per review comment Changes for v2: - None --- include/configs/xilinx_zynqmp.h | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h index 1f17adb..3d388e2 100644 --- a/include/configs/xilinx_zynqmp.h +++ b/include/configs/xilinx_zynqmp.h @@ -114,6 +114,14 @@ #define CONFIG_SYS_LOAD_ADDR 0x8000000
#if defined(CONFIG_ZYNQMP_USB) +#define CONFIG_USB_XHCI_DWC3 +#define CONFIG_USB_XHCI +#define CONFIG_USB_MAX_CONTROLLER_COUNT 1 +#define CONFIG_SYS_USB_XHCI_MAX_ROOT_PORTS 2 +#define CONFIG_CMD_USB +#define CONFIG_USB_STORAGE +#define CONFIG_USB_XHCI_ZYNQMP + #define CONFIG_USB_DWC3 #define CONFIG_USB_DWC3_GADGET

On Monday, November 16, 2015 at 06:59:13 AM, Siva Durga Prasad Paladugu wrote:
From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Added USB XHCI driver support for zynqmp.
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com
Hi!
[...]
+static struct zynqmp_xhci zynqmp_xhci;
+unsigned long ctr_addr[] = CONFIG_ZYNQMP_XHCI_LIST;
Still no DM/DT support on Xilinx parts, huh ? :)
[...]
+int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) +{
- struct zynqmp_xhci *ctx = &zynqmp_xhci;
- int ret = 0;
- if (index < 0 || index >= ARRAY_SIZE(ctr_addr))
return -EINVAL;
- ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
- ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET);
Should be void *, not char * I think. Also, the parenthesis around ctx->hcd are not needed.
- ret = board_usb_init(index, USB_INIT_HOST);
- if (ret != 0) {
puts("Failed to initialize board for USB\n");
return ret;
- }
- ret = zynqmp_xhci_core_init(ctx);
- if (ret < 0) {
puts("Failed to initialize xhci\n");
return ret;
- }
- *hccr = (struct xhci_hccr *)ctx->hcd;
- *hcor = (struct xhci_hcor *)((uint32_t) *hccr
+ HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
You want to use uintptr_t for the same of 64bit parts.
- debug("zynqmp-xhci: init hccr %x and hcor %x hc_length %d\n",
(uint32_t)*hccr, (uint32_t)*hcor,
(uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
We have %p for printing pointers, so drop the casts.
Also, since you're using HC_LENGTH() here twice, you might as well put it's value into temporary variable and use it in both places, it might make the code slightly more readable.
- return ret;
+}
+void xhci_hcd_stop(int index) +{
- /*
* Currently zynqmp socs do not support PHY shutdown from
* sw. But this support may be added in future socs.
*/
- return 0;
+} diff --git a/include/configs/xilinx_zynqmp_ep.h b/include/configs/xilinx_zynqmp_ep.h index ed6023a..1845622 100644 --- a/include/configs/xilinx_zynqmp_ep.h +++ b/include/configs/xilinx_zynqmp_ep.h @@ -23,6 +23,8 @@ #define CONFIG_SYS_I2C_ZYNQ #define CONFIG_ZYNQ_EEPROM #define CONFIG_AHCI +#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR, \
ZYNQMP_USB1_XHCI_BASEADDR}
#include <configs/xilinx_zynqmp.h>

Hi Marek,
-----Original Message----- From: Marek Vasut [mailto:marex@denx.de] Sent: Monday, November 16, 2015 11:39 AM To: Siva Durga Prasad Paladugu Cc: u-boot@lists.denx.de; Siva Durga Prasad Paladugu Subject: Re: [PATCH v5 1/2] usb: zynqmp: Add XHCI driver support
On Monday, November 16, 2015 at 06:59:13 AM, Siva Durga Prasad Paladugu wrote:
From: Siva Durga Prasad Paladugu siva.durga.paladugu@xilinx.com
Added USB XHCI driver support for zynqmp.
Signed-off-by: Siva Durga Prasad Paladugu sivadur@xilinx.com
Hi!
[...]
+static struct zynqmp_xhci zynqmp_xhci;
+unsigned long ctr_addr[] = CONFIG_ZYNQMP_XHCI_LIST;
Still no DM/DT support on Xilinx parts, huh ? :)
We have this support for Zynq but not for ZynqMP yet as this is new and this patch is related to ZynqMP.
[...]
+int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct +xhci_hcor **hcor) +{
- struct zynqmp_xhci *ctx = &zynqmp_xhci;
- int ret = 0;
- if (index < 0 || index >= ARRAY_SIZE(ctr_addr))
return -EINVAL;
- ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
- ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) +
+DWC3_REG_OFFSET);
Should be void *, not char * I think. Also, the parenthesis around ctx->hcd are not needed.
I think keeping char* would be good for easy understanding and readability.
- ret = board_usb_init(index, USB_INIT_HOST);
- if (ret != 0) {
puts("Failed to initialize board for USB\n");
return ret;
- }
- ret = zynqmp_xhci_core_init(ctx);
- if (ret < 0) {
puts("Failed to initialize xhci\n");
return ret;
- }
- *hccr = (struct xhci_hccr *)ctx->hcd;
- *hcor = (struct xhci_hcor *)((uint32_t) *hccr
+ HC_LENGTH(xhci_readl(&(*hccr)-
cr_capbase)));
You want to use uintptr_t for the same of 64bit parts.
Ok
- debug("zynqmp-xhci: init hccr %x and hcor %x hc_length %d\n",
(uint32_t)*hccr, (uint32_t)*hcor,
(uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
We have %p for printing pointers, so drop the casts.
Also, since you're using HC_LENGTH() here twice, you might as well put it's value into temporary variable and use it in both places, it might make the code slightly more readable.
Ok, will take care in next version
Regards, Siva
- return ret;
+}
+void xhci_hcd_stop(int index) +{
- /*
* Currently zynqmp socs do not support PHY shutdown from
* sw. But this support may be added in future socs.
*/
- return 0;
+} diff --git a/include/configs/xilinx_zynqmp_ep.h b/include/configs/xilinx_zynqmp_ep.h index ed6023a..1845622 100644 --- a/include/configs/xilinx_zynqmp_ep.h +++ b/include/configs/xilinx_zynqmp_ep.h @@ -23,6 +23,8 @@ #define CONFIG_SYS_I2C_ZYNQ #define CONFIG_ZYNQ_EEPROM #define CONFIG_AHCI +#define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR,
\
ZYNQMP_USB1_XHCI_BASEADDR}
#include <configs/xilinx_zynqmp.h>

On Monday, November 16, 2015 at 08:23:24 AM, Siva Durga Prasad Paladugu wrote:
Hi Marek,
Hi,
[...]
- ctx->hcd = (struct xhci_hccr *)ctr_addr[index];
- ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) +
+DWC3_REG_OFFSET);
Should be void *, not char * I think. Also, the parenthesis around ctx->hcd are not needed.
I think keeping char* would be good for easy understanding and readability.
Using bogus casts is never good for anything.
- ret = board_usb_init(index, USB_INIT_HOST);
- if (ret != 0) {
puts("Failed to initialize board for USB\n");
return ret;
- }
- ret = zynqmp_xhci_core_init(ctx);
- if (ret < 0) {
puts("Failed to initialize xhci\n");
return ret;
- }
- *hccr = (struct xhci_hccr *)ctx->hcd;
- *hcor = (struct xhci_hcor *)((uint32_t) *hccr
+ HC_LENGTH(xhci_readl(&(*hccr)-
cr_capbase)));
You want to use uintptr_t for the same of 64bit parts.
Ok
- debug("zynqmp-xhci: init hccr %x and hcor %x hc_length %d\n",
(uint32_t)*hccr, (uint32_t)*hcor,
(uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase)));
We have %p for printing pointers, so drop the casts.
Also, since you're using HC_LENGTH() here twice, you might as well put it's value into temporary variable and use it in both places, it might make the code slightly more readable.
Ok, will take care in next version
Thanks!
Best regards, Marek Vasut
participants (2)
-
Marek Vasut
-
Siva Durga Prasad Paladugu