From 22d5e1fae2a1f70e84a63341cda47fa91b0853ea Mon Sep 17 00:00:00 2001 From: Yanhong Wang Date: Fri, 19 May 2023 17:06:09 +0800 Subject: usb: cdns3: starfive: Add usb driver to support for JH7110 Add usb driver to support for jh7110. Signed-off-by: Yanhong Wang Signed-off-by: Minda Chen --- drivers/usb/cdns3/cdns3-starfive.c | 232 +++++++++++++++++++++++++++++++++++-- 1 file changed, 223 insertions(+), 9 deletions(-) (limited to 'drivers') 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 */ +#include #include #include #include #include #include #include +#include +#include #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<stg_map, data->stg_offset_196, + PCIE_CLK_SEL_MASK, (0<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; } -- cgit v1.2.3