From 693765a720ba4f116923372deb0c32488f031cf8 Mon Sep 17 00:00:00 2001 From: Jim Liu Date: Tue, 21 Jun 2022 17:09:02 +0800 Subject: [PATCH 1/2] usb: host: nuvoton: Add nuvoton NPCM7xx ehci/ohci driver Add nuvoton BMC NPCM750 ehci/ohci driver Signed-off-by: Jim Liu --- drivers/usb/host/Kconfig | 16 +++++ drivers/usb/host/Makefile | 2 + drivers/usb/host/ehci-npcm.c | 119 +++++++++++++++++++++++++++++++++++ drivers/usb/host/ohci-npcm.c | 108 +++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 drivers/usb/host/ehci-npcm.c create mode 100644 drivers/usb/host/ohci-npcm.c diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index a0f48f09a7..1aabe062fb 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -214,6 +214,14 @@ config USB_EHCI_MXS Enables support for the on-chip EHCI controller on i.MX23 and i.MX28 SoCs. +config USB_EHCI_NPCM + bool "Support for Nuvoton NPCM on-chip EHCI USB controller" + depends on ARCH_NPCM + default n + ---help--- + Enables support for the on-chip EHCI controller on + Nuvoton NPCM chips. + config USB_EHCI_OMAP bool "Support for OMAP3+ on-chip EHCI USB controller" depends on ARCH_OMAP2PLUS @@ -343,6 +351,14 @@ config USB_OHCI_DA8XX help Enable support for the da850 USB controller. +config USB_OHCI_NPCM + bool "Support for Nuvoton NPCM on-chip OHCI USB controller" + depends on ARCH_NPCM + default n + ---help--- + Enables support for the on-chip OHCI controller on + Nuvoton NPCM chips. + endif # USB_OHCI_HCD config SYS_USB_OHCI_SLOT_NAME diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 5fdb804116..ddc3663206 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_USB_SL811HS) += sl811-hcd.o obj-$(CONFIG_USB_OHCI_LPC32XX) += ohci-lpc32xx.o obj-$(CONFIG_USB_OHCI_PCI) += ohci-pci.o obj-$(CONFIG_USB_OHCI_GENERIC) += ohci-generic.o +obj-$(CONFIG_USB_OHCI_NPCM) += ohci-npcm.o # echi obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o @@ -34,6 +35,7 @@ obj-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o obj-$(CONFIG_USB_EHCI_MX5) += ehci-mx5.o obj-$(CONFIG_USB_EHCI_MX6) += ehci-mx6.o obj-$(CONFIG_USB_EHCI_MX7) += ehci-mx6.o +obj-$(CONFIG_USB_EHCI_NPCM) += ehci-npcm.o obj-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o obj-$(CONFIG_USB_EHCI_MSM) += ehci-msm.o diff --git a/drivers/usb/host/ehci-npcm.c b/drivers/usb/host/ehci-npcm.c new file mode 100644 index 0000000000..357a5614ed --- /dev/null +++ b/drivers/usb/host/ehci-npcm.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 Nuvoton Technology Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ehci.h" + +struct npcm_ehci_priv { + struct ehci_ctrl ctrl; + struct ehci_hccr *hcd; + struct phy phy; +}; + +static int npcm_ehci_setup_phy(struct udevice *dev, struct phy *phy) +{ + int ret; + + if (!phy) + return 0; + + ret = generic_phy_get_by_index(dev, 0, phy); + if (ret) { + if (ret != -ENOENT) { + dev_err(dev, "failed to get usb phy\n"); + return ret; + } + } else { + ret = generic_phy_init(phy); + if (ret) { + dev_err(dev, "failed to init usb phy\n"); + return ret; + } + } + + return 0; +} + +static int npcm_ehci_init(struct udevice *dev) +{ + struct npcm_ehci_priv *priv = dev_get_priv(dev); + struct reset_ctl reset; + int ret; + + ret = reset_get_by_index(dev, 0, &reset); + if (ret && ret != -ENOENT && ret != -ENOTSUPP) { + dev_err(dev, "failed to get reset\n"); + return ret; + } + + /* reset controller */ + if (reset_valid(&reset)) + reset_assert(&reset); + + /* setup phy */ + ret = npcm_ehci_setup_phy(dev, &priv->phy); + if (ret) + return ret; + + /* release controller from reset */ + if (reset_valid(&reset)) + reset_deassert(&reset); + + return 0; +} + +static int npcm_ehci_probe(struct udevice *dev) +{ + struct npcm_ehci_priv *priv = dev_get_priv(dev); + struct ehci_hcor *hcor; + enum usb_init_type type = dev_get_driver_data(dev); + int ret; + + ret = npcm_ehci_init(dev); + if (ret) + return ret; + + priv->hcd = (struct ehci_hccr *)dev_read_addr_ptr(dev); + debug("USB HCD @0x%p\n", priv->hcd); + hcor = (struct ehci_hcor *)((uintptr_t)priv->hcd + + HC_LENGTH(ehci_readl(&priv->hcd->cr_capbase))); + + return ehci_register(dev, priv->hcd, hcor, NULL, 0, type); +} + +static int npcm_ehci_remove(struct udevice *dev) +{ + struct npcm_ehci_priv *priv = dev_get_priv(dev); + + generic_phy_exit(&priv->phy); + + return ehci_deregister(dev); +} + +static const struct udevice_id npcm_ehci_ids[] = { + { .compatible = "nuvoton,npcm845-ehci", .data = USB_INIT_HOST }, + { .compatible = "nuvoton,npcm845-udc", .data = USB_INIT_DEVICE }, + { .compatible = "nuvoton,npcm750-ehci", .data = USB_INIT_HOST }, + { .compatible = "nuvoton,npcm750-udc", .data = USB_INIT_DEVICE }, + { } +}; + +U_BOOT_DRIVER(ehci_npcm) = { + .name = "ehci_npcm", + .id = UCLASS_USB, + .of_match = npcm_ehci_ids, + .probe = npcm_ehci_probe, + .remove = npcm_ehci_remove, + .ops = &ehci_usb_ops, + .priv_auto = sizeof(struct npcm_ehci_priv), + .plat_auto = sizeof(struct usb_plat), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; diff --git a/drivers/usb/host/ohci-npcm.c b/drivers/usb/host/ohci-npcm.c new file mode 100644 index 0000000000..9e1d529880 --- /dev/null +++ b/drivers/usb/host/ohci-npcm.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2021 Nuvoton Technology Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "ohci.h" + +struct npcm_ohci_priv { + ohci_t ohci; + struct phy phy; +}; + +static int npcm_ohci_setup_phy(struct udevice *dev, struct phy *phy) +{ + int ret; + + if (!phy) + return 0; + + ret = generic_phy_get_by_index(dev, 0, phy); + if (ret) { + if (ret != -ENOENT) { + dev_err(dev, "failed to get usb phy\n"); + return ret; + } + } else { + ret = generic_phy_init(phy); + if (ret) { + dev_err(dev, "failed to init usb phy\n"); + return ret; + } + } + + return 0; +} + +static int npcm_ohci_init(struct udevice *dev) +{ + struct npcm_ohci_priv *priv = dev_get_priv(dev); + struct reset_ctl reset; + int ret; + + ret = reset_get_by_index(dev, 0, &reset); + if (ret && ret != -ENOENT && ret != -ENOTSUPP) { + dev_err(dev, "failed to get reset\n"); + return ret; + } + + /* reset controller */ + if (reset_valid(&reset)) + reset_assert(&reset); + + /* setup phy */ + ret = npcm_ohci_setup_phy(dev, &priv->phy); + if (ret) + return ret; + + /* release controller from reset */ + if (reset_valid(&reset)) + reset_deassert(&reset); + + return 0; +} + +static int npcm_ohci_probe(struct udevice *dev) +{ + struct ohci_regs *regs = dev_read_addr_ptr(dev); + int ret; + + ret = npcm_ohci_init(dev); + if (ret) + return ret; + + return ohci_register(dev, regs); +} + +static int npcm_ohci_remove(struct udevice *dev) +{ + struct npcm_ohci_priv *priv = dev_get_priv(dev); + + generic_phy_exit(&priv->phy); + + return ohci_deregister(dev); +} + +static const struct udevice_id npcm_ohci_ids[] = { + { .compatible = "nuvoton,npcm845-ohci" }, + { .compatible = "nuvoton,npcm750-ohci" }, + { } +}; + +U_BOOT_DRIVER(ohci_npcm) = { + .name = "ohci_npcm", + .id = UCLASS_USB, + .of_match = npcm_ohci_ids, + .probe = npcm_ohci_probe, + .remove = npcm_ohci_remove, + .ops = &ohci_usb_ops, + .priv_auto = sizeof(struct npcm_ohci_priv), + .flags = DM_FLAG_ALLOC_PRIV_DMA, +}; From 206af3dec00071ec96c0fdec6c8dda3a039c07cf Mon Sep 17 00:00:00 2001 From: Alison Huffman Date: Thu, 22 Sep 2022 04:01:32 +0000 Subject: [PATCH 2/2] Fix out of bound access of ep array. When processing USB_REQ_CLEAR_FEATURE, USB_REQ_SET_FEATURE, and USB_REQ_GET_STATUS packets in dwc2_ep0_setup an out of bounds access can occur. This is caused by the wIndex field of the usb control packet being used as an index into an array whose size is DWC2_MAX_ENDPOINTS (4). Signed-off-by: Alison Huffman --- drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c index f17009a29e..1c34b75351 100644 --- a/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c +++ b/drivers/usb/gadget/dwc2_udc_otg_xfer_dma.c @@ -890,7 +890,7 @@ static int dwc2_ep0_write(struct dwc2_udc *dev) static int dwc2_udc_get_status(struct dwc2_udc *dev, struct usb_ctrlrequest *crq) { - u8 ep_num = crq->wIndex & 0x7F; + u8 ep_num = crq->wIndex & 0x3; u16 g_status = 0; u32 ep_ctrl; @@ -1418,7 +1418,7 @@ static void dwc2_ep0_setup(struct dwc2_udc *dev) break; case USB_REQ_CLEAR_FEATURE: - ep_num = usb_ctrl->wIndex & 0x7f; + ep_num = usb_ctrl->wIndex & 0x3; if (!dwc2_udc_clear_feature(&dev->ep[ep_num].ep)) return; @@ -1426,7 +1426,7 @@ static void dwc2_ep0_setup(struct dwc2_udc *dev) break; case USB_REQ_SET_FEATURE: - ep_num = usb_ctrl->wIndex & 0x7f; + ep_num = usb_ctrl->wIndex & 0x3; if (!dwc2_udc_set_feature(&dev->ep[ep_num].ep)) return;