summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandy.hu <andy.hu@starfivetech.com>2023-08-30 13:16:40 +0300
committerandy.hu <andy.hu@starfivetech.com>2023-08-30 13:16:40 +0300
commiteec56304c34fabd95031f7524c51decf6dc82042 (patch)
tree818c61c372e9bf51a68b8c6175b18a4d7033d5d8
parent2a533dc9209ebe8a085c03020ae0cded0e098741 (diff)
parent37cf2331abec749f33deaefe30c31d266b62d076 (diff)
downloadu-boot-eec56304c34fabd95031f7524c51decf6dc82042.tar.xz
Merge branch 'CR_7199_add_usb_host_minda' into 'jh7110-master'
CR_7199 usb: cdns3: starfive: Add usb driver to support for JH7110 See merge request sdk/u-boot!66
-rw-r--r--arch/riscv/dts/jh7110.dtsi12
-rw-r--r--arch/riscv/dts/starfive_evb.dts15
-rw-r--r--drivers/usb/cdns3/cdns3-starfive.c232
3 files changed, 246 insertions, 13 deletions
diff --git a/arch/riscv/dts/jh7110.dtsi b/arch/riscv/dts/jh7110.dtsi
index e353aeb25b..1022a08db5 100644
--- a/arch/riscv/dts/jh7110.dtsi
+++ b/arch/riscv/dts/jh7110.dtsi
@@ -354,21 +354,25 @@
usbdrd30: usbdrd{
compatible = "starfive,jh7110-cdns3";
+ dma-coherent;
#address-cells = <2>;
#size-cells = <2>;
- clocks = <&clkgen JH7110_USB0_CLK_APP_125>,
+ reg = <0x0 0x10210000 0x0 0x1000>,
+ <0x0 0x10200000 0x0 0x1000>;
+ clocks = <&clkgen JH7110_USB_125M>,
+ <&clkgen JH7110_USB0_CLK_APP_125>,
<&clkgen JH7110_USB0_CLK_LPM>,
<&clkgen JH7110_USB0_CLK_STB>,
<&clkgen JH7110_USB0_CLK_USB_APB>,
<&clkgen JH7110_USB0_CLK_AXI>,
<&clkgen JH7110_USB0_CLK_UTMI_APB>;
- clock-names = "app","lpm","stb","apb","axi","utmi";
+ clock-names = "125m","app","lpm","stb","apb","axi","utmi";
resets = <&rstgen RSTN_U0_CDN_USB_PWRUP>,
<&rstgen RSTN_U0_CDN_USB_APB>,
<&rstgen RSTN_U0_CDN_USB_AXI>,
<&rstgen RSTN_U0_CDN_USB_UTMI_APB>;
reset-names = "pwrup","apb","axi","utmi";
- starfive,stg-syscon = <&stg_syscon 0x4>;
+ starfive,stg-syscon = <&stg_syscon 0x4 0xc4 0x148 0x1f4>;
starfive,sys-syscon = <&sys_syscon 0x18>;
status = "disabled";
@@ -378,7 +382,7 @@
<0x0 0x10110000 0x0 0x10000>,
<0x0 0x10120000 0x0 0x10000>;
reg-names = "otg", "xhci", "dev";
- interrupts = <108>, <109>, <110>;
+ interrupts = <100>, <108>, <110>;
interrupt-names = "host", "peripheral", "otg";
phy-names = "cdns3,usb3-phy", "cnds3,usb2-phy";
maximum-speed = "super-speed";
diff --git a/arch/riscv/dts/starfive_evb.dts b/arch/riscv/dts/starfive_evb.dts
index 19b8e5f1e0..0ce86ad8bd 100644
--- a/arch/riscv/dts/starfive_evb.dts
+++ b/arch/riscv/dts/starfive_evb.dts
@@ -297,6 +297,21 @@
};
&usbdrd30 {
+ clocks = <&clkgen JH7110_USB_125M>,
+ <&clkgen JH7110_USB0_CLK_APP_125>,
+ <&clkgen JH7110_USB0_CLK_LPM>,
+ <&clkgen JH7110_USB0_CLK_STB>,
+ <&clkgen JH7110_USB0_CLK_USB_APB>,
+ <&clkgen JH7110_USB0_CLK_AXI>,
+ <&clkgen JH7110_USB0_CLK_UTMI_APB>,
+ <&clkgen JH7110_PCIE0_CLK_APB>;
+ clock-names = "125m","app","lpm","stb","apb","axi","utmi", "phy";
+ resets = <&rstgen RSTN_U0_CDN_USB_PWRUP>,
+ <&rstgen RSTN_U0_CDN_USB_APB>,
+ <&rstgen RSTN_U0_CDN_USB_AXI>,
+ <&rstgen RSTN_U0_CDN_USB_UTMI_APB>,
+ <&rstgen RSTN_U0_PLDA_PCIE_APB>;
+ reset-names = "pwrup","apb","axi","utmi", "phy";
status = "okay";
};
diff --git a/drivers/usb/cdns3/cdns3-starfive.c b/drivers/usb/cdns3/cdns3-starfive.c
index d51bf30b67..a7682c2fbf 100644
--- a/drivers/usb/cdns3/cdns3-starfive.c
+++ b/drivers/usb/cdns3/cdns3-starfive.c
@@ -6,50 +6,263 @@
* Author: yanhong <yanhong.wang@starfivetech.com>
*/
+#include <asm/io.h>
#include <common.h>
#include <clk.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <linux/usb/otg.h>
#include <reset.h>
+#include <regmap.h>
+#include <syscon.h>
#include "core.h"
+#define USB_STRAP_HOST (2 << 0x10)
+#define USB_STRAP_DEVICE (4 << 0X10)
+#define USB_STRAP_MASK 0x70000
+
+#define USB_SUSPENDM_HOST (1 << 0x13)
+#define USB_SUSPENDM_DEVICE (0 << 0x13)
+#define USB_SUSPENDM_MASK 0x80000
+
+#define USB_SUSPENDM_BYPS_SHIFT 0x14
+#define USB_SUSPENDM_BYPS_MASK 0x100000
+#define USB_REFCLK_MODE_SHIFT 0x17
+#define USB_REFCLK_MODE_MASK 0x800000
+#define USB_PLL_EN_SHIFT 0x16
+#define USB_PLL_EN_MASK 0x400000
+#define USB_PDRSTN_SPLIT_SHIFT 0x11
+#define USB_PDRSTN_SPLIT_MASK 0x20000
+
+#define PCIE_CKREF_SRC_SHIFT 0x12
+#define PCIE_CKREF_SRC_MASK 0xC0000
+#define PCIE_CLK_SEL_SHIFT 0x14
+#define PCIE_CLK_SEL_MASK 0x300000
+#define PCIE_PHY_MODE_SHIFT 0x14
+#define PCIE_PHY_MODE_MASK 0x300000
+#define PCIE_USB3_BUS_WIDTH_SHIFT 0x2
+#define PCIE_USB3_BUS_WIDTH_MASK 0xC
+#define PCIE_USB3_RATE_SHIFT 0x5
+#define PCIE_USB3_RATE_MASK 0x60
+#define PCIE_USB3_RX_STANDBY_SHIFT 0x7
+#define PCIE_USB3_RX_STANDBY_MASK 0x80
+#define PCIE_USB3_PHY_ENABLE_SHIFT 0x4
+#define PCIE_USB3_PHY_ENABLE_MASK 0x10
+#define PCIE_USB3_PHY_PLL_CTL_OFF (0x1f * 4)
+
+#define USB_125M_CLK_RATE 125000000
+
+#define USB3_PHY_RES_INDEX 0
+#define USB2_PHY_RES_INDEX 1
+#define USB_LS_KEEPALIVE_OFF 0x4
+#define USB_LS_KEEPALIVE_ENABLE 4
+
struct cdns_starfive {
struct udevice *dev;
struct clk_bulk clks;
struct reset_ctl_bulk resets;
+ struct regmap *stg_map;
+ struct regmap *sys_map;
+ struct clk usb_125m_clk;
+ void __iomem *phy3_base;
+ void __iomem *phy2_base;
+ u32 sys_offset;
+ u32 stg_offset_4;
+ u32 stg_offset_196;
+ u32 stg_offset_328;
+ u32 stg_offset_500;
+ u32 usb2_only;
+ enum usb_dr_mode mode;
};
-static int cdns_starfive_probe(struct udevice *dev)
+static int cdns_mode_init(struct cdns_starfive *data)
+{
+ enum usb_dr_mode mode;
+
+ /* Init usb 2.0 utmi phy */
+ regmap_update_bits(data->stg_map, data->stg_offset_4,
+ USB_SUSPENDM_BYPS_MASK, BIT(USB_SUSPENDM_BYPS_SHIFT));
+ regmap_update_bits(data->stg_map, data->stg_offset_4,
+ USB_PLL_EN_MASK, BIT(USB_PLL_EN_SHIFT));
+ regmap_update_bits(data->stg_map, data->stg_offset_4,
+ USB_REFCLK_MODE_MASK, BIT(USB_REFCLK_MODE_SHIFT));
+
+ if (data->usb2_only) {
+ /* Disconnect usb 3.0 phy mode */
+ regmap_update_bits(data->sys_map, data->sys_offset,
+ USB_PDRSTN_SPLIT_MASK, BIT(USB_PDRSTN_SPLIT_SHIFT));
+ } else {
+ /* Config usb 3.0 pipe phy */
+ regmap_update_bits(data->stg_map, data->stg_offset_196,
+ PCIE_CKREF_SRC_MASK, (0<<PCIE_CKREF_SRC_SHIFT));
+ regmap_update_bits(data->stg_map, data->stg_offset_196,
+ PCIE_CLK_SEL_MASK, (0<<PCIE_CLK_SEL_SHIFT));
+ regmap_update_bits(data->stg_map, data->stg_offset_328,
+ PCIE_PHY_MODE_MASK, BIT(PCIE_PHY_MODE_SHIFT));
+ regmap_update_bits(data->stg_map, data->stg_offset_500,
+ PCIE_USB3_BUS_WIDTH_MASK, (0 << PCIE_USB3_BUS_WIDTH_SHIFT));
+ regmap_update_bits(data->stg_map, data->stg_offset_500,
+ PCIE_USB3_RATE_MASK, (0 << PCIE_USB3_RATE_SHIFT));
+ regmap_update_bits(data->stg_map, data->stg_offset_500,
+ PCIE_USB3_RX_STANDBY_MASK, (0 << PCIE_USB3_RX_STANDBY_SHIFT));
+ regmap_update_bits(data->stg_map, data->stg_offset_500,
+ PCIE_USB3_PHY_ENABLE_MASK, BIT(PCIE_USB3_PHY_ENABLE_SHIFT));
+
+ /* Connect usb 3.0 phy mode */
+ regmap_update_bits(data->sys_map, data->sys_offset,
+ USB_PDRSTN_SPLIT_MASK, (0 << USB_PDRSTN_SPLIT_SHIFT));
+ }
+
+ mode = usb_get_dr_mode(dev_read_first_subnode(data->dev));
+ data->mode = mode;
+
+ switch (mode) {
+ case USB_DR_MODE_HOST:
+ regmap_update_bits(data->stg_map,
+ data->stg_offset_4,
+ USB_STRAP_MASK,
+ USB_STRAP_HOST);
+ regmap_update_bits(data->stg_map,
+ data->stg_offset_4,
+ USB_SUSPENDM_MASK,
+ USB_SUSPENDM_HOST);
+ break;
+
+ case USB_DR_MODE_PERIPHERAL:
+ regmap_update_bits(data->stg_map, data->stg_offset_4,
+ USB_STRAP_MASK, USB_STRAP_DEVICE);
+ regmap_update_bits(data->stg_map, data->stg_offset_4,
+ USB_SUSPENDM_MASK, USB_SUSPENDM_DEVICE);
+ break;
+
+ case USB_DR_MODE_UNKNOWN:
+ case USB_DR_MODE_OTG:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int cdns_clk_rst_init(struct cdns_starfive *data)
{
- struct cdns_starfive *data = dev_get_plat(dev);
int ret;
- data->dev = dev;
+ ret = clk_get_by_name(data->dev, "125m", &data->usb_125m_clk);
+ if (ret)
+ goto exit;
- ret = clk_get_bulk(dev, &data->clks);
+ ret = clk_get_bulk(data->dev, &data->clks);
if (ret)
- goto err;
+ goto err_125m_clk;
- ret = reset_get_bulk(dev, &data->resets);
+ ret = reset_get_bulk(data->dev, &data->resets);
if (ret)
goto err_clk;
+ /* Needs to set the USB_125M clock explicitly,
+ * since it's divided from pll0 clock, and the pll0 clock
+ * changes per the cpu frequency.
+ */
+ ret = clk_set_rate(&data->usb_125m_clk, USB_125M_CLK_RATE);
+ if (!ret)
+ goto err_en_clk;
+
ret = clk_enable_bulk(&data->clks);
if (ret)
- goto err_reset;
+ goto err_en_clk;
ret = reset_deassert_bulk(&data->resets);
if (ret)
goto err_reset;
return 0;
+
err_reset:
+ clk_disable_bulk(&data->clks);
+err_en_clk:
reset_release_bulk(&data->resets);
err_clk:
clk_release_bulk(&data->clks);
-err:
+err_125m_clk:
+ clk_free(&data->usb_125m_clk);
+exit:
+ return ret;
+}
+
+static void cdns_starfive_set_phy(struct cdns_starfive *data)
+{
+ unsigned int val;
+ void __iomem *addr;
+
+ if (data->mode != USB_DR_MODE_PERIPHERAL) {
+ /* Enable the LS speed keep-alive signal */
+ addr = data->phy2_base + USB_LS_KEEPALIVE_OFF;
+ val = readl(addr);
+ val |= BIT(USB_LS_KEEPALIVE_ENABLE);
+ writel(val, addr);
+ }
+
+ if (!data->usb2_only) {
+ addr = data->phy3_base + PCIE_USB3_PHY_PLL_CTL_OFF;
+ /* Configuare spread-spectrum mode: down-spread-spectrum */
+ writel(BIT(4), addr);
+ }
+}
+
+static int cdns_starfive_probe(struct udevice *dev)
+{
+ struct cdns_starfive *data = dev_get_plat(dev);
+ struct ofnode_phandle_args args;
+ int ret;
+
+ data->dev = dev;
+ data->phy3_base = (void *)dev_read_addr_index(dev, USB3_PHY_RES_INDEX);
+ if (data->phy3_base == (void __iomem *)FDT_ADDR_T_NONE) {
+ dev_err(dev, "Missing phy 3.0 reg base\n");
+ return -EINVAL;
+ }
+
+ data->phy2_base = (void *)dev_read_addr_index(dev, USB2_PHY_RES_INDEX);
+ if (data->phy2_base == (void __iomem *)FDT_ADDR_T_NONE) {
+ dev_err(dev, "Missing phy 2.0 reg base");
+ return -EINVAL;
+ }
+
+ data->usb2_only = dev_read_bool(dev, "starfive,usb2-only");
+
+ ret = dev_read_phandle_with_args(dev, "starfive,stg-syscon", NULL, 4, 0, &args);
+ if (ret)
+ return ret;
+
+ data->stg_map = syscon_node_to_regmap(args.node);
+ if (IS_ERR(data->stg_map))
+ return PTR_ERR(data->stg_map);
+
+ data->stg_offset_4 = args.args[0];
+ data->stg_offset_196 = args.args[1];
+ data->stg_offset_328 = args.args[2];
+ data->stg_offset_500 = args.args[3];
+
+ ret = dev_read_phandle_with_args(dev, "starfive,sys-syscon", NULL, 1, 0, &args);
+ if (ret)
+ return ret;
+
+ data->sys_map = syscon_node_to_regmap(args.node);
+ if (IS_ERR(data->sys_map))
+ return PTR_ERR(data->sys_map);
+ data->sys_offset = args.args[0];
+
+ cdns_mode_init(data);
+
+ ret = cdns_clk_rst_init(data);
+ if (ret < 0) {
+ pr_err("Failed to init usb clk reset: %d\n", ret);
+ return ret;
+ }
+ cdns_starfive_set_phy(data);
+
return ret;
}
@@ -58,7 +271,8 @@ static int cdns_starfive_remove(struct udevice *dev)
struct cdns_starfive *data = dev_get_plat(dev);
clk_release_bulk(&data->clks);
-// reset_assert_bulk(&data->resets);
+ reset_assert_bulk(&data->resets);
+ clk_free(&data->usb_125m_clk);
return 0;
}