On 06/01/2017 02:05 PM, patrice.chot...@st.com wrote: > From: Patrice Chotard <patrice.chot...@st.com> > > This patch adds the ST glue logic to manage the DWC3 HC > on STiH407 SoC family. It configures the internal glue > logic and syscfg registers. > > Part of this code been extracted from kernel.org driver > (drivers/usb/dwc3/dwc3-st.c) > > Signed-off-by: Patrice Chotard <patrice.chot...@st.com> > Reviewed-by: Simon Glass <s...@chromium.org> > --- > > v7: _ none > > v6: _ add reviewed-by Simon Glass > _ put #define <common.h> first > > v5: _ none > > v4: _ none > > v3: _ rename dwc3-sti.c to dwc3-sti-glue.c > _ respect device tree hierarchy, this driver is now responsible > for xhci-sti binding (done in sti_dwc3_glue_bind()) > > v2: _ use setbits_le32() instead of read, modify, write sequence > _ add missing parenthesis > > arch/arm/include/asm/arch-stih410/sys_proto.h | 11 ++ > doc/device-tree-bindings/usb/dwc3-st.txt | 60 ++++++ > drivers/usb/host/Kconfig | 9 + > drivers/usb/host/Makefile | 1 + > drivers/usb/host/dwc3-sti-glue.c | 256 > ++++++++++++++++++++++++++ > include/dwc3-sti-glue.h | 43 +++++ > 6 files changed, 380 insertions(+) > create mode 100644 arch/arm/include/asm/arch-stih410/sys_proto.h > create mode 100644 doc/device-tree-bindings/usb/dwc3-st.txt > create mode 100644 drivers/usb/host/dwc3-sti-glue.c > create mode 100644 include/dwc3-sti-glue.h > > diff --git a/arch/arm/include/asm/arch-stih410/sys_proto.h > b/arch/arm/include/asm/arch-stih410/sys_proto.h > new file mode 100644 > index 0000000..5c40d3b > --- /dev/null > +++ b/arch/arm/include/asm/arch-stih410/sys_proto.h > @@ -0,0 +1,11 @@ > +/* > + * Copyright (c) 2017 > + * Patrice Chotard <patrice.chot...@st.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#ifndef _ASM_ARCH_SYS_PROTO_H > +#define _ASM_ARCH_SYS_PROTO_H > + > +#endif /* _ASM_ARCH_SYS_PROTO_H */ > diff --git a/doc/device-tree-bindings/usb/dwc3-st.txt > b/doc/device-tree-bindings/usb/dwc3-st.txt > new file mode 100644 > index 0000000..a26a139 > --- /dev/null > +++ b/doc/device-tree-bindings/usb/dwc3-st.txt > @@ -0,0 +1,60 @@ > +ST DWC3 glue logic
Is this DT binding imported from Linux ? > +This file documents the parameters for the dwc3-st driver. > +This driver controls the glue logic used to configure the dwc3 core on > +STiH407 based platforms. > + > +Required properties: > + - compatible : must be "st,stih407-dwc3" > + - reg : glue logic base address and USB syscfg ctrl register > offset > + - reg-names : should be "reg-glue" and "syscfg-reg" > + - st,syscon : should be phandle to system configuration node which > + encompasses the glue registers > + - resets : list of phandle and reset specifier pairs. There should be > two entries, one > + for the powerdown and softreset lines of the usb3 IP > + - reset-names : list of reset signal names. Names should be > "powerdown" and "softreset" > + > + - #address-cells, #size-cells : should be '1' if the device has sub-nodes > + with 'reg' property > + > + - pinctl-names : A pinctrl state named "default" must be defined > + > + - pinctrl-0 : Pin control group > + > + - ranges : allows valid 1:1 translation between child's address space and > + parent's address space > + > +Sub-nodes: > +The dwc3 core should be added as subnode to ST DWC3 glue as shown in the > +example below. > + > +NB: The dr_mode property is NOT optional for this driver, as the default > value > +is "otg", which isn't supported by this SoC. Valid dr_mode values for > dwc3-st are > +either "host" or "device". > + > +Example: > + > +st_dwc3: dwc3@8f94000 { > + status = "disabled"; > + compatible = "st,stih407-dwc3"; > + reg = <0x08f94000 0x1000>, <0x110 0x4>; > + reg-names = "reg-glue", "syscfg-reg"; > + st,syscfg = <&syscfg_core>; > + resets = <&powerdown STIH407_USB3_POWERDOWN>, > + <&softreset STIH407_MIPHY2_SOFTRESET>; > + reset-names = "powerdown", "softreset"; > + #address-cells = <1>; > + #size-cells = <1>; > + pinctrl-names = "default"; > + pinctrl-0 = <&pinctrl_usb3>; > + ranges; > + > + dwc3: dwc3@9900000 { > + compatible = "snps,dwc3"; > + reg = <0x09900000 0x100000>; > + interrupts = <GIC_SPI 155 IRQ_TYPE_NONE>; > + dr_mode = "host"; > + phy-names = "usb2-phy", "usb3-phy"; > + phys = <&usb2_picophy2>, <&phy_port2 PHY_TYPE_USB3>; > + }; > +}; > diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig > index b824eec..80589cf 100644 > --- a/drivers/usb/host/Kconfig > +++ b/drivers/usb/host/Kconfig > @@ -38,6 +38,15 @@ config USB_XHCI_ROCKCHIP > help > Enables support for the on-chip xHCI controller on Rockchip SoCs. > > +config USB_XHCI_STI > + bool "Support for STMicroelectronics STiH407 family on-chip xHCI USB > controller" > + depends on ARCH_STI > + default y > + help > + Enables support for the on-chip xHCI controller on STMicroelectronics > + STiH407 family SoCs. This is a driver for the dwc3 to provide the > glue logic > + to configure the controller. > + > config USB_XHCI_ZYNQMP > bool "Support for Xilinx ZynqMP on-chip xHCI USB controller" > depends on ARCH_ZYNQMP > diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile > index 4ece0a2..1bf66fa 100644 > --- a/drivers/usb/host/Makefile > +++ b/drivers/usb/host/Makefile > @@ -65,6 +65,7 @@ obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o > obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o > obj-$(CONFIG_USB_XHCI_OMAP) += xhci-omap.o > obj-$(CONFIG_USB_XHCI_PCI) += xhci-pci.o > +obj-$(CONFIG_USB_XHCI_STI) += dwc3-sti-glue.o > > # designware > obj-$(CONFIG_USB_DWC2) += dwc2.o > diff --git a/drivers/usb/host/dwc3-sti-glue.c > b/drivers/usb/host/dwc3-sti-glue.c > new file mode 100644 > index 0000000..1c593fe > --- /dev/null > +++ b/drivers/usb/host/dwc3-sti-glue.c > @@ -0,0 +1,256 @@ > +/* > + * STiH407 family DWC3 specific Glue layer > + * > + * Copyright (c) 2017 > + * Patrice Chotard <patrice.chot...@st.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#include <common.h> > +#include <asm/io.h> > +#include <dm.h> > +#include <dwc3-sti-glue.h> > +#include <errno.h> > +#include <fdtdec.h> > +#include <libfdt.h> > +#include <dm/lists.h> > +#include <regmap.h> > +#include <reset-uclass.h> > +#include <syscon.h> > +#include <usb.h> > + > +#include <linux/usb/dwc3.h> > + > +DECLARE_GLOBAL_DATA_PTR; > + > +/* > + * struct sti_dwc3_glue_platdata - dwc3 STi glue driver private structure > + * @syscfg_base: addr for the glue syscfg > + * @glue_base: addr for the glue registers > + * @syscfg_offset: usb syscfg control offset > + * @powerdown_ctl: rest controller for powerdown signal > + * @softreset_ctl: reset controller for softreset signal > + * @mode: drd static host/device config > + */ > +struct sti_dwc3_glue_platdata { > + phys_addr_t syscfg_base; > + phys_addr_t glue_base; > + phys_addr_t syscfg_offset; > + struct reset_ctl powerdown_ctl; > + struct reset_ctl softreset_ctl; > + enum usb_dr_mode mode; > +}; > + > +static int sti_dwc3_glue_drd_init(struct sti_dwc3_glue_platdata *plat) > +{ > + unsigned long val; > + > + val = readl(plat->syscfg_base + plat->syscfg_offset); > + > + val &= USB3_CONTROL_MASK; > + > + switch (plat->mode) { > + case USB_DR_MODE_PERIPHERAL: > + val &= ~(USB3_DELAY_VBUSVALID > + | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3) > + | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2 > + | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); > + > + val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID; > + break; > + > + case USB_DR_MODE_HOST: > + val &= ~(USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID > + | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3) > + | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2 > + | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); > + > + val |= USB3_DELAY_VBUSVALID; > + break; > + > + default: > + error("Unsupported mode of operation %d\n", plat->mode); > + return -EINVAL; > + } > + writel(val, plat->syscfg_base + plat->syscfg_offset); > + > + return 0; > +} > + > +static void sti_dwc3_glue_init(struct sti_dwc3_glue_platdata *plat) > +{ > + unsigned long reg; > + > + reg = readl(plat->glue_base + CLKRST_CTRL); > + > + reg |= AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION; > + reg &= ~SW_PIPEW_RESET_N; > + > + writel(reg, plat->glue_base + CLKRST_CTRL); > + > + /* configure mux for vbus, powerpresent and bvalid signals */ > + reg = readl(plat->glue_base + USB2_VBUS_MNGMNT_SEL1); > + > + reg |= SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) | > + SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) | > + SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG); > + > + writel(reg, plat->glue_base + USB2_VBUS_MNGMNT_SEL1); > + > + setbits_le32(plat->glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N); > +} > + > +static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev) > +{ > + struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev); > + struct udevice *syscon; > + struct regmap *regmap; > + int ret; > + u32 reg[4]; > + > + ret = fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), > + "reg", reg, ARRAY_SIZE(reg)); > + if (ret) { > + error("unable to find st,stih407-dwc3 reg property(%d)\n", ret); > + return ret; > + } > + > + plat->glue_base = reg[0]; > + plat->syscfg_offset = reg[2]; > + > + /* get corresponding syscon phandle */ > + ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "st,syscfg", > + &syscon); > + if (ret) { > + error("unable to find syscon device (%d)\n", ret); > + return ret; > + } > + > + /* get syscfg-reg base address */ > + regmap = syscon_get_regmap(syscon); > + if (!regmap) { > + error("unable to find regmap\n"); > + return -ENODEV; > + } > + plat->syscfg_base = regmap->base; > + > + /* get powerdown reset */ > + ret = reset_get_by_name(dev, "powerdown", &plat->powerdown_ctl); > + if (ret) { > + error("can't get powerdown reset for %s (%d)", dev->name, ret); > + return ret; > + } > + > + /* get softreset reset */ > + ret = reset_get_by_name(dev, "softreset", &plat->softreset_ctl); > + if (ret) > + error("can't get soft reset for %s (%d)", dev->name, ret); > + > + return ret; > +}; > + > +static int sti_dwc3_glue_bind(struct udevice *dev) > +{ > + struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev); > + int dwc3_node; > + > + /* check if one subnode is present */ > + dwc3_node = fdt_first_subnode(gd->fdt_blob, dev_of_offset(dev)); > + if (dwc3_node <= 0) { > + error("Can't find subnode for %s\n", dev->name); > + return -ENODEV; > + } > + > + /* check if the subnode compatible string is the dwc3 one*/ > + if (fdt_node_check_compatible(gd->fdt_blob, dwc3_node, > + "snps,dwc3") != 0) { > + error("Can't find dwc3 subnode for %s\n", dev->name); > + return -ENODEV; > + } > + > + /* retrieve the DWC3 dual role mode */ > + plat->mode = usb_get_dr_mode(dwc3_node); > + if (plat->mode == USB_DR_MODE_UNKNOWN) > + /* by default set dual role mode to HOST */ > + plat->mode = USB_DR_MODE_HOST; > + > + return dm_scan_fdt_dev(dev); > +} > + > +static int sti_dwc3_glue_probe(struct udevice *dev) > +{ > + struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev); > + int ret; > + > + /* deassert both powerdown and softreset */ > + ret = reset_deassert(&plat->powerdown_ctl); > + if (ret < 0) { > + error("DWC3 powerdown reset deassert failed: %d", ret); > + return ret; > + } > + > + ret = reset_deassert(&plat->softreset_ctl); > + if (ret < 0) { > + error("DWC3 soft reset deassert failed: %d", ret); > + goto err1; > + } > + > + ret = sti_dwc3_glue_drd_init(plat); > + if (ret) > + goto err2; > + > + sti_dwc3_glue_init(plat); > + > + return 0; > + > +err2: Invent some more descriptive failpath label names please > + ret = reset_assert(&plat->softreset_ctl); > + if (ret < 0) { > + error("DWC3 soft reset deassert failed: %d", ret); > + return ret; > + } > + > +err1: > + ret = reset_assert(&plat->powerdown_ctl); > + if (ret < 0) > + error("DWC3 powerdown reset deassert failed: %d", ret); > + > + return ret; > +} > + > +static int sti_dwc3_glue_remove(struct udevice *dev) > +{ > + struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev); > + int ret; > + > + /* assert both powerdown and softreset */ > + ret = reset_assert(&plat->powerdown_ctl); > + if (ret < 0) { > + error("DWC3 powerdown reset deassert failed: %d", ret); > + return ret; > + } > + > + ret = reset_assert(&plat->softreset_ctl); > + if (ret < 0) > + error("DWC3 soft reset deassert failed: %d", ret); > + > + return ret; > +} > + > +static const struct udevice_id sti_dwc3_glue_ids[] = { > + { .compatible = "st,stih407-dwc3" }, > + { } > +}; > + > +U_BOOT_DRIVER(dwc3_sti_glue) = { > + .name = "dwc3_sti_glue", > + .id = UCLASS_MISC, > + .of_match = sti_dwc3_glue_ids, > + .ofdata_to_platdata = sti_dwc3_glue_ofdata_to_platdata, > + .probe = sti_dwc3_glue_probe, > + .remove = sti_dwc3_glue_remove, > + .bind = sti_dwc3_glue_bind, > + .platdata_auto_alloc_size = sizeof(struct sti_dwc3_glue_platdata), > + .flags = DM_FLAG_ALLOC_PRIV_DMA, > +}; > diff --git a/include/dwc3-sti-glue.h b/include/dwc3-sti-glue.h > new file mode 100644 > index 0000000..2083427 > --- /dev/null > +++ b/include/dwc3-sti-glue.h > @@ -0,0 +1,43 @@ > +/* > + * Copyright (c) 2017 > + * Patrice Chotard <patrice.chot...@st.com> > + * > + * SPDX-License-Identifier: GPL-2.0+ > + */ > + > +#ifndef __DWC3_STI_UBOOT_H_ > +#define __DWC3_STI_UBOOT_H_ > + > +#include <linux/usb/otg.h> Does this have to be in a separate header file ? > +/* glue registers */ > +#define CLKRST_CTRL 0x00 > +#define AUX_CLK_EN BIT(0) > +#define SW_PIPEW_RESET_N BIT(4) > +#define EXT_CFG_RESET_N BIT(8) > + > +#define XHCI_REVISION BIT(12) > + > +#define USB2_VBUS_MNGMNT_SEL1 0x2C > +#define USB2_VBUS_UTMIOTG 0x1 > + > +#define SEL_OVERRIDE_VBUSVALID(n) ((n) << 0) > +#define SEL_OVERRIDE_POWERPRESENT(n) ((n) << 4) > +#define SEL_OVERRIDE_BVALID(n) ((n) << 8) > + > +/* Static DRD configuration */ > +#define USB3_CONTROL_MASK 0xf77 > + > +#define USB3_DEVICE_NOT_HOST BIT(0) > +#define USB3_FORCE_VBUSVALID BIT(1) > +#define USB3_DELAY_VBUSVALID BIT(2) > +#define USB3_SEL_FORCE_OPMODE BIT(4) > +#define USB3_FORCE_OPMODE(n) ((n) << 5) > +#define USB3_SEL_FORCE_DPPULLDOWN2 BIT(8) > +#define USB3_FORCE_DPPULLDOWN2 BIT(9) > +#define USB3_SEL_FORCE_DMPULLDOWN2 BIT(10) > +#define USB3_FORCE_DMPULLDOWN2 BIT(11) > + > +int sti_dwc3_init(enum usb_dr_mode mode); > + > +#endif /* __DWC3_STI_UBOOT_H_ */ > -- Best regards, Marek Vasut _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot