summaryrefslogtreecommitdiff
path: root/drivers
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 /drivers
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
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/cdns3/cdns3-starfive.c232
1 files changed, 223 insertions, 9 deletions
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;
}