From bd970cfc7a821e9cb2cbd1bdce8acaafa4043869 Mon Sep 17 00:00:00 2001 From: Manivannan Sadhasivam Date: Wed, 12 Jun 2019 12:00:56 +0530 Subject: temp --- arch/arm64/boot/dts/actions/s900-bubblegum-96.dts | 8 + arch/arm64/boot/dts/actions/s900.dtsi | 48 +- drivers/soc/actions/owl-sps.c | 2 + drivers/usb/dwc3/Kconfig | 9 + drivers/usb/dwc3/Makefile | 1 + drivers/usb/dwc3/dwc3-of-simple.c | 12 +- drivers/usb/dwc3/dwc3-owl.c | 634 ++++++++++++++++++++++ drivers/usb/phy/Kconfig | 12 + drivers/usb/phy/Makefile | 2 + drivers/usb/phy/phy-owl-usb.h | 48 ++ drivers/usb/phy/phy-owl-usb2.c | 266 +++++++++ drivers/usb/phy/phy-owl-usb3.c | 183 +++++++ 12 files changed, 1223 insertions(+), 2 deletions(-) create mode 100644 drivers/usb/dwc3/dwc3-owl.c create mode 100644 drivers/usb/phy/phy-owl-usb.h create mode 100644 drivers/usb/phy/phy-owl-usb2.c create mode 100644 drivers/usb/phy/phy-owl-usb3.c diff --git a/arch/arm64/boot/dts/actions/s900-bubblegum-96.dts b/arch/arm64/boot/dts/actions/s900-bubblegum-96.dts index 3b596d72de25..dee55f8f6b39 100644 --- a/arch/arm64/boot/dts/actions/s900-bubblegum-96.dts +++ b/arch/arm64/boot/dts/actions/s900-bubblegum-96.dts @@ -300,3 +300,11 @@ &uart5 { status = "okay"; }; + +&usbdrd3_0 { + status = "okay"; +}; + +&usbdrd_dwc3_0 { + status = "okay"; +}; diff --git a/arch/arm64/boot/dts/actions/s900.dtsi b/arch/arm64/boot/dts/actions/s900.dtsi index eb35cf78ab73..4dbc5717934c 100644 --- a/arch/arm64/boot/dts/actions/s900.dtsi +++ b/arch/arm64/boot/dts/actions/s900.dtsi @@ -6,6 +6,7 @@ #include #include #include +#include #include / { @@ -176,7 +177,7 @@ }; sps: power-controller@e012e000 { - compatible = "actions,s900-sps"; + compatible = "actions,s900-sps", "simple-pm-bus"; reg = <0x0 0xe012e000 0x0 0x2000>; #power-domain-cells = <1>; }; @@ -329,5 +330,50 @@ dma-names = "mmc"; status = "disabled"; }; + + usbdrd3_0: usb@e0400000 { + compatible = "actions,s900-dwc3"; + reg = <0x0 0xe040cd00 0x0 0x0c>; + clocks = <&cmu CLK_USB3_480MPLL0>, + <&cmu CLK_USB3_480MPHY0>, + <&cmu CLK_USB3_5GPHY>, + <&cmu CLK_USB3_CCE>, + <&cmu CLK_USB3_MAC>; + clock-names = "usb3_480mpll0", "usb3_480mphy0", + "usb3_5gphy", "usb3_cce", + "usb3_mac"; + resets = <&cmu RESET_USB3>; + reset-names = "usb3"; + power-domains = <&sps S900_PD_USB3>; + #address-cells = <2>; + #size-cells = <2>; + ranges; + status = "disabled"; + + usbdrd_dwc3_0: dwc3 { + compatible = "snps,dwc3"; + reg = <0x0 0xe0400000 0x0 0xcd00>; + interrupts = ; +// phys = <&usb2_phy>, <&usb3_phy>; + usb-phy = <&usb2_phy>, <&usb3_phy>; +// phy-names = "usb2-phy", "usb3-phy"; +// phy_type = "utmi_wide"; + dr_mode = "host"; + power-domains = <&sps S900_PD_USB3>; + snps,dis_u3_susphy_quirk; + snps,dis_u2_susphy_quirk; + status = "disabled"; + }; + }; + + usb2_phy: usb2phy@0xe040cd0c { + compatible = "actions,s900-usb2phy"; + reg = <0 0xe040cd0c 0 0x4>; + }; + + usb3_phy: usb3phy@0xe040cf00 { + compatible = "actions,s900-usb3phy"; + reg = <0 0xe040cf00 0 0x100>; + }; }; }; diff --git a/drivers/soc/actions/owl-sps.c b/drivers/soc/actions/owl-sps.c index 73a9e0bb7e8e..205d5adfb584 100644 --- a/drivers/soc/actions/owl-sps.c +++ b/drivers/soc/actions/owl-sps.c @@ -51,6 +51,7 @@ static int owl_sps_set_power(struct owl_sps_domain *pd, bool enable) ack_mask = BIT(pd->info->ack_bit); pwr_mask = BIT(pd->info->pwr_bit); + pr_info("%s power on", pd->info->name); return owl_sps_set_pg(pd->sps->base, pwr_mask, ack_mask, enable); } @@ -89,6 +90,7 @@ static int owl_sps_init_domain(struct owl_sps *sps, int index) pd->genpd.flags = pd->info->genpd_flags; pm_genpd_init(&pd->genpd, NULL, false); + owl_sps_set_power(pd, true); sps->genpd_data.domains[index] = &pd->genpd; return 0; diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 4a62045cc812..53b429e0f5cf 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -137,4 +137,13 @@ config USB_DWC3_QCOM for peripheral mode support. Say 'Y' or 'M' if you have one such device. +config USB_DWC3_OWL + tristate "STMicroelectronics Platforms" + depends on (ARCH_ACTIONS || COMPILE_TEST) && OF + default USB_DWC3 + help + STMicroelectronics SoCs with one DesignWare Core USB3 IP + inside (i.e. STiH407). + Say 'Y' or 'M' if you have one such device. + endif diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index ae86da0dc5bd..7e170df2b885 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile @@ -51,3 +51,4 @@ obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o +obj-$(CONFIG_USB_DWC3_OWL) += dwc3-owl.o diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index bdac3e7d7b18..c7e7eed4b704 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -40,6 +40,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) int ret; bool shared_resets = false; + pr_info("%s: %d", __func__, __LINE__); simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL); if (!simple) return -ENOMEM; @@ -51,8 +52,10 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) * Some controllers need to toggle the usb3-otg reset before trying to * initialize the PHY, otherwise the PHY times out. */ - if (of_device_is_compatible(np, "rockchip,rk3399-dwc3")) + if (of_device_is_compatible(np, "rockchip,rk3399-dwc3")) { simple->need_reset = true; + simple->pulse_resets = true; + } if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") || of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) { @@ -87,6 +90,11 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) if (ret) goto err_resetc_assert; + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + pr_info("%s: %d", __func__, __LINE__); ret = of_platform_populate(np, NULL, NULL, dev); if (ret) goto err_clk_put; @@ -95,6 +103,7 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_runtime_get_sync(dev); + pr_info("DWC3 probed!!!"); return 0; err_clk_put: @@ -183,6 +192,7 @@ static const struct of_device_id of_dwc3_simple_match[] = { { .compatible = "amlogic,meson-axg-dwc3" }, { .compatible = "amlogic,meson-gxl-dwc3" }, { .compatible = "allwinner,sun50i-h6-dwc3" }, + { .compatible = "actions,owl-dwc3" }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, of_dwc3_simple_match); diff --git a/drivers/usb/dwc3/dwc3-owl.c b/drivers/usb/dwc3/dwc3-owl.c new file mode 100644 index 000000000000..85f4c646b070 --- /dev/null +++ b/drivers/usb/dwc3/dwc3-owl.c @@ -0,0 +1,634 @@ +/** + * Actions OWL SoCs dwc3 driver + * + * Copyright (c) 2015 Actions Semiconductor Co., ltd. + * tangshaoqing + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "core.h" + +#ifdef DEBUG_S700_CLK +void dwc3_owl_printk_power_usage_count(void); +void dwc3_owl_printk_clk_reg(void); + +#define PWR_USB3 (1<<10) +#define ACK_USB3 (1<<10) + +#define SPS_PG_BASE 0xE01B0100 +#define SPS_PG_CTL (SPS_PG_BASE+0x0000) +#define SPS_PG_ACK (SPS_PG_BASE+0x0018) + +#define USB3_CONTROLLER_CLOCK_ENABLE (1 << 25) +#define USB3_MOD_RST (1 << 25) + +#define CMU_BASE 0xE0168000 +#define CMU_DEVCLKEN0 (CMU_BASE+0x00a0) +#define CMU_DEVRST0 (CMU_BASE+0x00A8) +#define CMU_USBPLL (CMU_BASE+0x00b0) + +#define PLL_LDO_EN (1<<31) +#define SOFT_VBUS_VALUE (1<<7) +#define SOFT_VBUS_EN (1<<6) +#endif + +#ifdef DEBUG_S900_CLK +void dwc3_owl_printk_power_usage_count(void); +void dwc3_owl_printk_clk_reg(void); + +#define USB3_MOD_RST (1 << 14) + +#define PWR_USB3 (1<<8) +#define ACK_USB3 (1<<8) +#define USB3_AVDD_EN (1<<17) + +#define ASSIST_PLL_EN (1<<0) +#define USB3_MAC_DIV(n) ((n)<<12) +#define USB3_MAC_DIV_MASK (3<<12) + +#define SPS_PG_BASE 0xE012e000 +#define SPS_PG_CTL (SPS_PG_BASE+0x0000) +#define SPS_PG_ACK (SPS_PG_BASE+0x0004) +#define SPS_LDO_CTL (SPS_PG_BASE+0x0014) + +#define CMU_BASE 0xE0160000 +#define CMU_USBPLL (CMU_BASE+0x0080) +#define CMU_ASSISTPLL (CMU_BASE+0x0084) +#define CMU_DEVRST1 (CMU_BASE+0x00AC) +#endif + +#ifdef FPGA_VERIFY +#define S700_SOFTVBUS (1<<7) +#define S700_SOFTVBUSEN (1<<6) +#define S700_TIMER_BASE 0xE024C000 +#define S700_USB3_ECS (S700_TIMER_BASE+0x0090) + +#define S900_SOFTVBUS (1<<25) +#define S900_SOFTVBUSEN (1<<24) +#define S900_TIMER_BASE 0xE0228000 +#define S900_USB3_ECS (S900_TIMER_BASE+0x0090) +#endif + +struct dwc3_owl_regs { +#ifdef DEBUG_S700_CLK + void __iomem *sps_pg_ctl; + void __iomem *sps_pg_ack; + + void __iomem *usbpll; + void __iomem *cmu_devclken0; + void __iomem *devrst; +#endif + +#ifdef DEBUG_S900_CLK + void __iomem *sps_pg_ctl; + void __iomem *sps_pg_ack; + void __iomem *sps_ldo_ctl; + + void __iomem *usbpll; + void __iomem *cmu_assistpll; + void __iomem *devrst; +#endif + +#ifdef FPGA_VERIFY + void __iomem *usbecs; +#endif +}; + + +#define USB3_BACKDOOR 0x0 + +enum { + DWC3_S700 = 0, + DWC3_S900 = 0x100 +}; + +struct dwc3_owl_data { + int ic_type; +}; + +struct dwc3_owl { + struct platform_device *dwc3; + struct device *dev; + + struct dwc3_owl_data *data; + + struct clk * clk_usb3_480mpll0; + struct clk * clk_usb3_480mphy0; + struct clk * clk_usb3_5gphy; + struct clk * clk_usb3_cce; + + struct clk * clk_usb3_mac; + + struct dwc3_owl_regs regs; + + void __iomem *base; +}; + +struct dwc3_owl *_dwc3_owl = 0; + + +#ifdef FPGA_VERIFY +static void dwc3_owl_set_softvbus_for_fpga_verify(struct dwc3_owl *owl) +{ + u32 reg; + + reg = readl(owl->regs.usbecs); + + if (owl->data->ic_type == DWC3_S700) + reg |= (S700_SOFTVBUS | S700_SOFTVBUSEN); + else if (owl->data->ic_type == DWC3_S900) + reg |= (S900_SOFTVBUS | S900_SOFTVBUSEN); + + writel(reg, owl->regs.usbecs); +} +#endif + +static void dwc3_owl_clk_init(struct dwc3_owl *owl) +{ + struct device *dev = owl->dev; + + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + clk_prepare_enable(owl->clk_usb3_480mpll0); + clk_prepare_enable(owl->clk_usb3_480mphy0); + clk_prepare_enable(owl->clk_usb3_5gphy); + clk_prepare_enable(owl->clk_usb3_cce); + + clk_prepare_enable(owl->clk_usb3_mac); + + pr_info("USB3 MAC clk req: %ld", clk_round_rate(owl->clk_usb3_mac, (500000000/4))); + if (owl->data->ic_type == DWC3_S900) + clk_set_rate(owl->clk_usb3_mac, clk_round_rate(owl->clk_usb3_mac, (500000000/4))); + + pr_info("USB3 MAC clk req: %ld", clk_get_rate(owl->clk_usb3_mac)); + if (owl->data->ic_type == DWC3_S700) { + int val; + val = readl(owl->base + USB3_BACKDOOR); + val |= (0x1<<27); + writel(val, owl->base + USB3_BACKDOOR); + } + +#ifdef FPGA_VERIFY + dwc3_owl_set_softvbus_for_fpga_verify(owl); +#endif +} + +static void dwc3_owl_clk_exit(struct dwc3_owl *owl) +{ + struct device *dev = owl->dev; + + clk_disable_unprepare(owl->clk_usb3_mac); + + clk_disable_unprepare(owl->clk_usb3_cce); + clk_disable_unprepare(owl->clk_usb3_5gphy); + clk_disable_unprepare(owl->clk_usb3_480mphy0); + clk_disable_unprepare(owl->clk_usb3_480mpll0); + + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); +} + +void dwc3_owl_clock_init(void) +{ + if (_dwc3_owl) + dwc3_owl_clk_init(_dwc3_owl); +} +EXPORT_SYMBOL_GPL(dwc3_owl_clock_init); + +void dwc3_owl_clock_exit(void) +{ + if (_dwc3_owl) + dwc3_owl_clk_exit(_dwc3_owl); +} +EXPORT_SYMBOL_GPL(dwc3_owl_clock_exit); + +void dwc3_actions_clock_init(void) +{ + dwc3_owl_clock_init(); +} +EXPORT_SYMBOL_GPL(dwc3_actions_clock_init); + +void dwc3_actions_clock_exit(void) +{ + dwc3_owl_clock_exit(); +} +EXPORT_SYMBOL_GPL(dwc3_actions_clock_exit); + + + +static int __dwc3_owl_suspend(struct dwc3_owl *owl) +{ + printk("%s\n", __func__); + + clk_disable_unprepare(owl->clk_usb3_mac); + + clk_disable_unprepare(owl->clk_usb3_cce); + clk_disable_unprepare(owl->clk_usb3_5gphy); + clk_disable_unprepare(owl->clk_usb3_480mphy0); + clk_disable_unprepare(owl->clk_usb3_480mpll0); + + return 0; +} + +static int __dwc3_owl_resume(struct dwc3_owl *owl) +{ + struct device *dev = owl->dev; + + printk("%s\n", __func__); + + clk_prepare_enable(owl->clk_usb3_480mpll0); + clk_prepare_enable(owl->clk_usb3_480mphy0); + clk_prepare_enable(owl->clk_usb3_5gphy); + clk_prepare_enable(owl->clk_usb3_cce); + + clk_prepare_enable(owl->clk_usb3_mac); + clk_set_rate(owl->clk_usb3_mac, clk_round_rate(owl->clk_usb3_mac, (500000000/4)) ); + + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + return 0; +} + + +void dwc3_owl_plug_suspend(void) +{ + if (_dwc3_owl) + __dwc3_owl_suspend(_dwc3_owl); + +} +EXPORT_SYMBOL_GPL(dwc3_owl_plug_suspend); + +void dwc3_owl_plug_resume(void) +{ + if (_dwc3_owl) + __dwc3_owl_resume(_dwc3_owl); +} +EXPORT_SYMBOL_GPL(dwc3_owl_plug_resume); + + +#ifdef DEBUG_S700_CLK +static int dwc3_owl_debug_regs_remap(struct dwc3_owl *owl) +{ + struct device *dev = owl->dev; + + owl->regs.sps_pg_ctl = devm_ioremap_nocache(dev, SPS_PG_CTL, 4); + owl->regs.sps_pg_ack = devm_ioremap_nocache(dev, SPS_PG_ACK, 4); + + owl->regs.usbpll = devm_ioremap_nocache(dev, CMU_USBPLL, 4); + owl->regs.cmu_devclken0 = devm_ioremap_nocache(dev, CMU_DEVCLKEN0, 4); + owl->regs.devrst = devm_ioremap_nocache(dev, CMU_DEVRST0, 4); + + if ((!owl->regs.sps_pg_ctl) || (!owl->regs.sps_pg_ack) + || (!owl->regs.usbpll) || (!owl->regs.cmu_devclken0) || (!owl->regs.devrst)) { + dev_err(dev, "%s %d ioremap failed\n", __func__, __LINE__); + return -ENOMEM; + } + + return 0; +} + +void dwc3_owl_printk_power_usage_count(void) +{ + struct device *dev; + + if (!_dwc3_owl) + return; + + dev = _dwc3_owl->dev; + + printk("dwc3 owl dev: disable_depth=%d usage_count=%d\n", + dev->power.disable_depth, dev->power.usage_count.counter); +} +EXPORT_SYMBOL_GPL(dwc3_owl_printk_power_usage_count); + +void dwc3_owl_printk_clk_reg(void) +{ + struct dwc3_owl *owl = _dwc3_owl; + + if (!owl) + return; + + printk("owl->regs.sps_pg_ctl:0x%x\n", readl(owl->regs.sps_pg_ctl)); + printk("owl->regs.sps_pg_ack:0x%x\n", readl(owl->regs.sps_pg_ack)); + + printk("owl->regs.usbpll:0x%x\n", readl(owl->regs.usbpll)); + printk("owl->regs.cmu_devclken0:0x%x\n", readl(owl->regs.cmu_devclken0)); + printk("owl->regs.devrst:0x%x\n", readl(owl->regs.devrst)); +} +EXPORT_SYMBOL_GPL(dwc3_owl_printk_clk_reg); +#endif + + +#ifdef DEBUG_S900_CLK +static int dwc3_owl_debug_regs_remap(struct dwc3_owl *owl) +{ + struct device *dev = owl->dev; + + owl->regs.sps_pg_ctl = devm_ioremap_nocache(dev, SPS_PG_CTL, 4); + owl->regs.sps_pg_ack = devm_ioremap_nocache(dev, SPS_PG_ACK, 4); + owl->regs.sps_ldo_ctl = devm_ioremap_nocache(dev, SPS_LDO_CTL, 4); + + owl->regs.usbpll = devm_ioremap_nocache(dev, CMU_USBPLL, 4); + owl->regs.cmu_assistpll = devm_ioremap_nocache(dev, CMU_ASSISTPLL, 4); + owl->regs.devrst = devm_ioremap_nocache(dev, CMU_DEVRST1, 4); + + if ((!owl->regs.sps_pg_ctl) || (!owl->regs.sps_pg_ack) || (!owl->regs.sps_ldo_ctl) + || (!owl->regs.usbpll) || (!owl->regs.cmu_assistpll) || (!owl->regs.devrst)) { + dev_err(dev, "%s %d ioremap failed\n", __func__, __LINE__); + return -ENOMEM; + } + + return 0; +} + +void dwc3_owl_printk_power_usage_count(void) +{ + struct device *dev; + + if (!_dwc3_owl) + return; + + dev = _dwc3_owl->dev; + + printk("dwc3 owl dev: disable_depth=%d usage_count=%d\n", + dev->power.disable_depth, dev->power.usage_count.counter); +} +EXPORT_SYMBOL_GPL(dwc3_owl_printk_power_usage_count); + +void dwc3_owl_printk_clk_reg(void) +{ + struct dwc3_owl *owl = _dwc3_owl; + + if (!owl) + return; + + printk("owl->regs.sps_pg_ctl:0x%x\n", readl(owl->regs.sps_pg_ctl)); + printk("owl->regs.sps_pg_ack:0x%x\n", readl(owl->regs.sps_pg_ack)); + printk("owl->regs.sps_ldo_ctl:0x%x\n", readl(owl->regs.sps_ldo_ctl)); + + printk("owl->regs.usbpll:0x%x\n", readl(owl->regs.usbpll)); + printk("owl->regs.cmu_assistpll:0x%x\n", readl(owl->regs.cmu_assistpll)); + printk("owl->regs.devrst:0x%x\n", readl(owl->regs.devrst)); +} +EXPORT_SYMBOL_GPL(dwc3_owl_printk_clk_reg); +#endif + + + + +static const struct of_device_id owl_dwc3_match[]; +static u64 dwc3_dma_mask = DMA_BIT_MASK(32); +static int dwc3_owl_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(owl_dwc3_match, &pdev->dev); + struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; + struct dwc3_owl *owl; + struct resource *res; + void __iomem *base; + int ret = -ENOMEM; + + + if (!node) { + dev_err(dev, "device node not found\n"); + return -EINVAL; + } + + if (!of_id) { + dev_err(dev, "no compatible OF match\n"); + return -EINVAL; + } + + dev->dma_mask = &dwc3_dma_mask; + dev->coherent_dma_mask = DMA_BIT_MASK(32); + + owl = devm_kzalloc(dev,sizeof(*owl), GFP_KERNEL); + if (!owl) { + dev_err(dev, "not enough memory\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, owl); + owl->dwc3 = pdev; + owl->dev = &pdev->dev; + owl->data = (struct dwc3_owl_data *)of_id->data; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing memory base resource\n"); + return -EINVAL; + } + + res = devm_request_mem_region(dev, res->start,resource_size(res), + dev_name(dev)); + if (!res) { + dev_err(dev, "can't request mem region\n"); + return -ENOMEM; + } + + base = devm_ioremap_nocache(dev, res->start, resource_size(res)); + if (!base) { + dev_err(dev, "ioremap failed\n"); + return -ENOMEM; + } + + owl->base = base; + +#ifdef FPGA_VERIFY + if (owl->data->ic_type == DWC3_S700) + owl->regs.usbecs = devm_ioremap_nocache(dev, S700_USB3_ECS, 4); + else if (owl->data->ic_type == DWC3_S900) + owl->regs.usbecs = devm_ioremap_nocache(dev, S900_USB3_ECS, 4); + + if (!owl->regs.usbecs) { + dev_err(dev, "ioremap failed\n"); + return -ENOMEM; + } +#endif + +#if defined(DEBUG_S700_CLK) || defined(DEBUG_S900_CLK) + if (dwc3_owl_debug_regs_remap(owl)) + return -ENOMEM; +#endif + + //"usb3_480mpll0", "usb3_480mphy0", "usb3_5gphy", "usb3_cce", "usb3_mac"; + owl->clk_usb3_480mpll0 = devm_clk_get(dev, "usb3_480mpll0"); + if (IS_ERR(owl->clk_usb3_480mpll0)) { + dev_err(&pdev->dev, "unable to get clk_usb3_480mpll0\n"); + return -EINVAL; + } + + owl->clk_usb3_480mphy0 = devm_clk_get(dev, "usb3_480mphy0"); + if (IS_ERR(owl->clk_usb3_480mphy0)) { + dev_err(&pdev->dev, "unable to get usb3_480mphy0\n"); + return -EINVAL; + } + + owl->clk_usb3_5gphy = devm_clk_get(dev, "usb3_5gphy"); + if (IS_ERR(owl->clk_usb3_5gphy)) { + dev_err(&pdev->dev, "unable to get usb3_5gphy\n"); + return -EINVAL; + } + + owl->clk_usb3_cce = devm_clk_get(dev, "usb3_cce"); + if (IS_ERR(owl->clk_usb3_cce)) { + dev_err(&pdev->dev, "unable to get usb3_cce\n"); + return -EINVAL; + } + + owl->clk_usb3_mac = devm_clk_get(dev, "usb3_mac"); + if (IS_ERR(owl->clk_usb3_mac)) { + dev_err(&pdev->dev, "unable to get usb3_mac\n"); + return -EINVAL; + } + + dwc3_owl_clk_init(owl); + + ret = of_platform_populate(node, NULL, NULL, dev); + if (ret) { + dev_err(&pdev->dev, "failed to create dwc3 core\n"); + goto err; + } + + _dwc3_owl = owl; + + printk("%s %d success\n", __FUNCTION__, __LINE__); + + return 0; + +err: + dwc3_owl_clk_exit(owl); + + return ret; +} + + +static int dwc3_owl_remove_core(struct device *dev, void *c) +{ + struct platform_device *pdev = to_platform_device(dev); + + platform_device_unregister(pdev); + + return 0; +} + +static int dwc3_owl_remove(struct platform_device *pdev) +{ + struct dwc3_owl *owl = platform_get_drvdata(pdev); + + _dwc3_owl = 0; + + dwc3_owl_clk_exit(owl); + device_for_each_child(&pdev->dev, NULL, dwc3_owl_remove_core); + + return 0; +} + + +#ifdef CONFIG_PM_SLEEP +static int dwc3_owl_suspend(struct device *dev) +{ + printk("%s\n", __func__); + + return 0; +} + +static int dwc3_owl_resume(struct device *dev) +{ + printk("%s\n", __func__); + + return 0; +} + +static const struct dev_pm_ops dwc3_owl_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(dwc3_owl_suspend, dwc3_owl_resume) +}; + +#define DEV_PM_OPS (&dwc3_owl_dev_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + + +#ifdef CONFIG_OF +static struct dwc3_owl_data dwc3_owl_s700_data = { + .ic_type = DWC3_S700, +}; + +static struct dwc3_owl_data dwc3_owl_s900_data = { + .ic_type = DWC3_S900, +}; + +static const struct of_device_id owl_dwc3_match[] = { + { .compatible = "actions,s700-dwc3", .data = &dwc3_owl_s700_data,}, + { .compatible = "actions,s900-dwc3", .data = &dwc3_owl_s900_data,}, + {}, +}; +MODULE_DEVICE_TABLE(of, owl_dwc3_match); +#endif + + +static struct platform_driver dwc3_owl_driver = { + .probe = dwc3_owl_probe, + .remove = dwc3_owl_remove, + .driver = { + .name = "owl-dwc3", + .of_match_table = of_match_ptr(owl_dwc3_match), + .pm = DEV_PM_OPS, + }, +}; + +module_platform_driver(dwc3_owl_driver); + +#if 0 +static int __init dwc3_owl_init(void) +{ + printk("%s %d %s %s\n", __FUNCTION__, __LINE__, __DATE__, __TIME__); + return platform_driver_register(&dwc3_owl_driver); +} +module_init(dwc3_owl_init); + +static void __exit dwc3_owl_exit(void) +{ + platform_driver_unregister(&dwc3_owl_driver); +} +module_exit(dwc3_owl_exit); +#endif + +MODULE_ALIAS("platform:owl-dwc3"); +MODULE_AUTHOR("tangshaoqing "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("DesignWare USB3 actions Glue Layer"); diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 24b4f091acb8..00f96f86011d 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -160,6 +160,18 @@ config USB_MXS_PHY MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x. +config OWL_USB2PHY + tristate "ACTIONS OWL USB2 PHY Driver" + help + Enable this to support the USB2 PHY that is part of SOC. This + driver takes care of all the PHY functionality. + +config OWL_USB3PHY + tristate "ACTIONS OWL USB3 PHY Driver" + help + Enable this to support the USB3 PHY that is part of SOC. This + driver takes care of all the PHY functionality. + config USB_TEGRA_PHY tristate "NVIDIA Tegra USB PHY Driver" depends on ARCH_TEGRA diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index df1d99010079..401718750c2b 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -24,3 +24,5 @@ obj-$(CONFIG_USB_MXS_PHY) += phy-mxs-usb.o obj-$(CONFIG_USB_ULPI) += phy-ulpi.o obj-$(CONFIG_USB_ULPI_VIEWPORT) += phy-ulpi-viewport.o obj-$(CONFIG_KEYSTONE_USB_PHY) += phy-keystone.o +obj-$(CONFIG_OWL_USB2PHY) += phy-owl-usb2.o +obj-$(CONFIG_OWL_USB3PHY) += phy-owl-usb3.o diff --git a/drivers/usb/phy/phy-owl-usb.h b/drivers/usb/phy/phy-owl-usb.h new file mode 100644 index 000000000000..a72b2920b27b --- /dev/null +++ b/drivers/usb/phy/phy-owl-usb.h @@ -0,0 +1,48 @@ +/* + * Actions OWL SoCs phy driver + * + * Copyright (c) 2015 Actions Semiconductor Co., ltd. + * tangshaoqing + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#ifndef __PHY_OWL_USB_H +#define __PHY_OWL_USB_H + + +#include + +enum { + PHY_S700 = 0, + PHY_S900 = 0x100 +}; + +struct phy_owl_data { + int ic_type; +}; + + +struct owl_usbphy { + struct usb_phy phy; + struct device *dev; + struct phy_owl_data *data; + void __iomem *regs; +}; + +#define phy_to_sphy(x) container_of((x), struct owl_usbphy, phy) + + +#endif /* __PHY_OWL_USB_H */ + diff --git a/drivers/usb/phy/phy-owl-usb2.c b/drivers/usb/phy/phy-owl-usb2.c new file mode 100644 index 000000000000..51abc89f5387 --- /dev/null +++ b/drivers/usb/phy/phy-owl-usb2.c @@ -0,0 +1,266 @@ +/* + * Actions OWL SoCs phy driver + * + * Copyright (c) 2015 Actions Semiconductor Co., ltd. + * tangshaoqing + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-owl-usb.h" + +struct owl_usbphy *usb2_sphy; + +static void setphy(struct owl_usbphy *sphy, unsigned char reg_add, unsigned char value) +{ + void __iomem *usb3_usb_vcon = sphy->regs; + volatile unsigned char addr_low; + volatile unsigned char addr_high; + volatile unsigned int vstate; + + addr_low = reg_add & 0x0f; + addr_high = (reg_add >> 4) & 0x0f; + + vstate = value; + vstate = vstate << 8; + + addr_low |= 0x10; + writel(vstate | addr_low, usb3_usb_vcon); + mb(); + + addr_low &= 0x0f; + writel(vstate | addr_low, usb3_usb_vcon); + mb(); + + addr_low |= 0x10; + writel(vstate | addr_low, usb3_usb_vcon); + mb(); + + addr_high |= 0x10; + writel(vstate | addr_high, usb3_usb_vcon); + mb(); + + addr_high &= 0x0f; + writel(vstate | addr_high, usb3_usb_vcon); + mb(); + + addr_high |= 0x10; + writel(vstate | addr_high, usb3_usb_vcon); + mb(); + return; +} + + +#define SET_PHY_FROM_CONFIG_FILE +#undef SET_PHY_FROM_CONFIG_FILE + +#ifdef SET_PHY_FROM_CONFIG_FILE +void phy_debug_setphy(unsigned char reg_add, unsigned char value) +{ + if (usb2_sphy) + setphy(usb2_sphy, reg_add, value); +} + +extern int set_phy_from_config_file(char *file_path); +static void dwc3_phy_setup_from_config_file(int is_device_mode) +{ + if (is_device_mode) + set_phy_from_config_file("/misc/modules/phy_config_dwc3"); + else + set_phy_from_config_file("/misc/modules/phy_config_xhci"); + + udelay(100); + + return; +} +#endif + + +static int s900_usb2phy_param_setup(struct owl_usbphy *sphy, int is_device_mode) +{ +#ifdef SET_PHY_FROM_CONFIG_FILE + dwc3_phy_setup_from_config_file(is_device_mode); + return 0; +#endif + + if (is_device_mode) { + printk("%s device mode\n", __FUNCTION__); + + setphy(sphy, 0xe7, 0x1b); + setphy(sphy, 0xe7,0x1f); + + udelay(10); + + setphy(sphy, 0xe2,0x48); + /* setphy(sphy, 0xe5, 0x00); */ + setphy(sphy, 0xe0, 0xa3); + setphy(sphy, 0x87, 0x1f); + } else { + printk("%s host mode\n", __FUNCTION__); + + setphy(sphy, 0xe7, 0x1b); + setphy(sphy, 0xe7, 0x1f); + + udelay(10); + + setphy(sphy, 0xe2,0x46); + /* setphy(sphy, 0xe5, 0x00); */ + setphy(sphy, 0xe0, 0xa3); + setphy(sphy, 0x87, 0x1f); + } + + return 0; +} + +int owl_dwc3_usb2phy_param_setup(int is_device_mode) +{ + int ret = 0; + + if (!usb2_sphy) + return 0; + + if (usb2_sphy->data->ic_type == PHY_S900) + ret = s900_usb2phy_param_setup(usb2_sphy, is_device_mode); + + return ret; +} +EXPORT_SYMBOL_GPL(owl_dwc3_usb2phy_param_setup); + + +static int owl_usb2phy_init(struct usb_phy *phy) +{ + return 0; +} + +static void owl_usb2phy_shutdown(struct usb_phy *phy) +{ +} + +static const struct of_device_id owl_usbphy_dt_match[]; +static int owl_usb2phy_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(owl_usbphy_dt_match, &pdev->dev); + struct owl_usbphy *sphy; + struct device *dev = &pdev->dev; + struct resource *phy_mem; + void __iomem *phy_base; + int ret = 0; + + printk("%s %d\n", __func__, __LINE__); + + if (!of_id) { + dev_err(dev, "no compatible OF match\n"); + return -EINVAL; + } + + phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phy_base = devm_ioremap_nocache(dev, phy_mem->start, resource_size(phy_mem)); + if (!phy_base) { + dev_err(dev, "ioremap failed\n"); + return -ENOMEM; + } + + sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL); + if (!sphy) + return -ENOMEM; + + + sphy->dev = dev; + sphy->data = (struct phy_owl_data *)of_id->data; + + sphy->regs = phy_base; + sphy->phy.dev = sphy->dev; + sphy->phy.label = "owl-usb2phy"; + sphy->phy.init = owl_usb2phy_init; + sphy->phy.shutdown = owl_usb2phy_shutdown; + + + platform_set_drvdata(pdev, sphy); + + ATOMIC_INIT_NOTIFIER_HEAD(&sphy->phy.notifier); + + + ret = usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2); + if(ret) { + return ret; + } + + usb2_sphy = sphy; + + return ret; + +} + +static int owl_usb2phy_remove(struct platform_device *pdev) +{ + struct owl_usbphy *sphy = platform_get_drvdata(pdev); + + usb2_sphy = 0; + usb_remove_phy(&sphy->phy); + + return 0; +} + + +#ifdef CONFIG_OF +static struct phy_owl_data phy_owl_s700_data = { + .ic_type = PHY_S700, +}; + +static struct phy_owl_data phy_owl_s900_data = { + .ic_type = PHY_S900, +}; + +static const struct of_device_id owl_usbphy_dt_match[] = { + { + .compatible = "actions,s700-usb2phy", + .data = &phy_owl_s700_data, + }, + { + .compatible = "actions,s900-usb2phy", + .data = &phy_owl_s900_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, owl_usbphy_dt_match); +#endif + + +static struct platform_driver owl_usb2phy_driver = { + .probe = owl_usb2phy_probe, + .remove = owl_usb2phy_remove, + .driver = { + .name = "owl-usb2phy", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(owl_usbphy_dt_match), + }, +}; + +module_platform_driver(owl_usb2phy_driver); + +MODULE_DESCRIPTION("Actions owl USB 2.0 phy controller"); +MODULE_AUTHOR("tangshaoqing "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:owl-usb2phy"); diff --git a/drivers/usb/phy/phy-owl-usb3.c b/drivers/usb/phy/phy-owl-usb3.c new file mode 100644 index 000000000000..5256ecc2d665 --- /dev/null +++ b/drivers/usb/phy/phy-owl-usb3.c @@ -0,0 +1,183 @@ +/* + * Actions OWL SoCs phy driver + * + * Copyright (c) 2015 Actions Semiconductor Co., ltd. + * tangshaoqing + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License v2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "phy-owl-usb.h" + + + +static inline u8 owl_phy_readb(void __iomem *base, u32 offset) +{ + return readb(base + offset); +} + +static inline void owl_phy_writeb(void __iomem *base, u32 offset, u8 value) +{ + writeb(value, base + offset); +} + + + +#define USB3_TX_DATA_PATH_CTRL (0X5D) +#define USB3_RX_DATA_PATH_CTRL1 (0X87) + +static int s900_usb3phy_init(struct usb_phy *phy) +{ + struct owl_usbphy *sphy = phy_to_sphy(phy); + void __iomem *base = sphy->regs; + u8 reg; + u32 offset; + + + /* IO_OR_U8(USB3_TX_DATA_PATH_CTRL, 0x02); */ + offset = USB3_TX_DATA_PATH_CTRL; + reg = owl_phy_readb(base, offset); + reg |= 0x02; + owl_phy_writeb(base, offset, reg); + printk("%s 0x%x:0x%x\n",__FUNCTION__, offset, owl_phy_readb(base, offset)); + + /* IO_OR_U8(USB3_RX_DATA_PATH_CTRL1, 0x20); */ + offset = USB3_RX_DATA_PATH_CTRL1; + reg = owl_phy_readb(base, offset); + reg |= 0x20; + owl_phy_writeb(base, offset, reg); + printk("%s 0x%x:0x%x\n",__FUNCTION__, offset, owl_phy_readb(base, offset)); + + return 0; +} + +static int owl_usb3phy_init(struct usb_phy *phy) +{ + struct owl_usbphy *sphy = phy_to_sphy(phy); + + if (sphy->data->ic_type == PHY_S900) + s900_usb3phy_init(phy); + + return 0; +} + +static void owl_usb3phy_shutdown(struct usb_phy *phy) +{ +} + +static const struct of_device_id owl_usbphy_dt_match[]; +static int owl_usb3phy_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(owl_usbphy_dt_match, &pdev->dev); + struct owl_usbphy *sphy; + struct device *dev = &pdev->dev; + struct resource *phy_mem; + void __iomem *phy_base; + + if (!of_id) { + dev_err(dev, "no compatible OF match\n"); + return -EINVAL; + } + + phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phy_base = devm_ioremap_nocache(dev, phy_mem->start, resource_size(phy_mem)); + if (!phy_base) { + dev_err(dev, "ioremap failed\n"); + return -ENOMEM; + } + + sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL); + if (!sphy) + return -ENOMEM; + + + sphy->dev = dev; + sphy->data = (struct phy_owl_data *)of_id->data; + + + sphy->regs = phy_base; + sphy->phy.dev = sphy->dev; + sphy->phy.label = "owl-usb3phy"; + sphy->phy.init = owl_usb3phy_init; + sphy->phy.shutdown = owl_usb3phy_shutdown; + + + platform_set_drvdata(pdev, sphy); + + printk("%s %d\n", __func__, __LINE__); + + return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB3); +} + +static int owl_usb3phy_remove(struct platform_device *pdev) +{ + struct owl_usbphy *sphy = platform_get_drvdata(pdev); + + usb_remove_phy(&sphy->phy); + + return 0; +} + + +#ifdef CONFIG_OF +static struct phy_owl_data phy_owl_s700_data = { + .ic_type = PHY_S700, +}; + +static struct phy_owl_data phy_owl_s900_data = { + .ic_type = PHY_S900, +}; + +static const struct of_device_id owl_usbphy_dt_match[] = { + { + .compatible = "actions,s700-usb3phy", + .data = &phy_owl_s700_data, + }, + { + .compatible = "actions,s900-usb3phy", + .data = &phy_owl_s900_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, owl_usbphy_dt_match); +#endif + + +static struct platform_driver owl_usb3phy_driver = { + .probe = owl_usb3phy_probe, + .remove = owl_usb3phy_remove, + .driver = { + .name = "owl-usb3phy", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(owl_usbphy_dt_match), + }, +}; + +module_platform_driver(owl_usb3phy_driver); + +MODULE_DESCRIPTION("Actions owl USB 3.0 phy controller"); +MODULE_AUTHOR("tangshaoqing "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:owl-usb3phy"); -- cgit v1.2.1