Merge branch 'next' of git://source.denx.de/u-boot-usb into next

- Add USB support on Starfive JH7110
This commit is contained in:
Tom Rini 2025-03-17 10:18:59 -06:00
commit 6a5917fba1
15 changed files with 665 additions and 0 deletions

View file

@ -63,6 +63,11 @@ enum gpio_state {
GPIO_DIN_MASK << GPIO_SHIFT(gpi), \ GPIO_DIN_MASK << GPIO_SHIFT(gpi), \
((gpio + 2) & GPIO_DIN_MASK) << GPIO_SHIFT(gpi)) ((gpio + 2) & GPIO_DIN_MASK) << GPIO_SHIFT(gpi))
#define SYS_IOMUX_DIN_DISABLED(gpi)\
clrsetbits_le32(JH7110_SYS_IOMUX + GPIO_DIN + GPIO_OFFSET(gpi), \
GPIO_DIN_MASK << GPIO_SHIFT(gpi), \
((0x1) & GPIO_DIN_MASK) << GPIO_SHIFT(gpi))
#define SYS_IOMUX_SET_DS(gpio, ds) \ #define SYS_IOMUX_SET_DS(gpio, ds) \
clrsetbits_le32(JH7110_SYS_IOMUX + GPIO_CONFIG + gpio * 4, \ clrsetbits_le32(JH7110_SYS_IOMUX + GPIO_CONFIG + gpio * 4, \
GPIO_DS_MASK, (ds) << GPIO_DS_SHIFT) GPIO_DS_MASK, (ds) << GPIO_DS_SHIFT)

View file

@ -103,6 +103,9 @@ void board_init_f(ulong dummy)
JH7110_CLK_CPU_ROOT_MASK, JH7110_CLK_CPU_ROOT_MASK,
BIT(JH7110_CLK_CPU_ROOT_SHIFT)); BIT(JH7110_CLK_CPU_ROOT_SHIFT));
/* Set USB overcurrent overflow pin disable */
SYS_IOMUX_DIN_DISABLED(2);
ret = spl_board_init_f(); ret = spl_board_init_f();
if (ret) { if (ret) {
debug("spl_board_init_f init failed: %d\n", ret); debug("spl_board_init_f init failed: %d\n", ret);

View file

@ -72,6 +72,7 @@ CONFIG_SYS_EEPROM_SIZE=512
CONFIG_SYS_EEPROM_PAGE_WRITE_BITS=4 CONFIG_SYS_EEPROM_PAGE_WRITE_BITS=4
CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS=5 CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS=5
CONFIG_CMD_MEMINFO=y CONFIG_CMD_MEMINFO=y
# CONFIG_CMD_BIND is not set
CONFIG_CMD_I2C=y CONFIG_CMD_I2C=y
CONFIG_CMD_PCI=y CONFIG_CMD_PCI=y
CONFIG_CMD_USB=y CONFIG_CMD_USB=y
@ -118,6 +119,9 @@ CONFIG_NVME_PCI=y
CONFIG_DM_PCI_COMPAT=y CONFIG_DM_PCI_COMPAT=y
CONFIG_PCI_REGION_MULTI_ENTRY=y CONFIG_PCI_REGION_MULTI_ENTRY=y
CONFIG_PCIE_STARFIVE_JH7110=y CONFIG_PCIE_STARFIVE_JH7110=y
CONFIG_PHY=y
CONFIG_PHY_STARFIVE_JH7110_PCIE=y
CONFIG_PHY_STARFIVE_JH7110_USB2=y
CONFIG_PINCTRL=y CONFIG_PINCTRL=y
CONFIG_PINCONF=y CONFIG_PINCONF=y
CONFIG_SPL_PINCTRL=y CONFIG_SPL_PINCTRL=y
@ -133,13 +137,19 @@ CONFIG_CADENCE_QSPI=y
CONFIG_SYSRESET=y CONFIG_SYSRESET=y
CONFIG_TIMER_EARLY=y CONFIG_TIMER_EARLY=y
CONFIG_USB=y CONFIG_USB=y
CONFIG_DM_USB_GADGET=y
CONFIG_USB_XHCI_HCD=y CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_PCI=y CONFIG_USB_XHCI_PCI=y
CONFIG_USB_EHCI_HCD=y CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_PCI=y CONFIG_USB_EHCI_PCI=y
CONFIG_USB_OHCI_HCD=y CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_PCI=y CONFIG_USB_OHCI_PCI=y
CONFIG_USB_CDNS3=y
CONFIG_USB_CDNS3_GADGET=y
CONFIG_USB_CDNS3_HOST=y
# CONFIG_USB_CDNS3_TI is not set
CONFIG_USB_KEYBOARD=y CONFIG_USB_KEYBOARD=y
CONFIG_USB_GADGET=y
# CONFIG_WATCHDOG is not set # CONFIG_WATCHDOG is not set
# CONFIG_WATCHDOG_AUTOSTART is not set # CONFIG_WATCHDOG_AUTOSTART is not set
CONFIG_WDT=y CONFIG_WDT=y

View file

@ -309,5 +309,6 @@ source "drivers/phy/cadence/Kconfig"
source "drivers/phy/ti/Kconfig" source "drivers/phy/ti/Kconfig"
source "drivers/phy/qcom/Kconfig" source "drivers/phy/qcom/Kconfig"
source "drivers/phy/renesas/Kconfig" source "drivers/phy/renesas/Kconfig"
source "drivers/phy/starfive/Kconfig"
endmenu endmenu

View file

@ -44,3 +44,4 @@ obj-y += cadence/
obj-y += ti/ obj-y += ti/
obj-y += qcom/ obj-y += qcom/
obj-y += renesas/ obj-y += renesas/
obj-y += starfive/

View file

@ -0,0 +1,21 @@
#
# PHY drivers for Starfive platforms
#
menu "Starfive PHY driver"
config PHY_STARFIVE_JH7110_PCIE
bool "Starfive JH7110 PCIe 2.0 PHY driver"
depends on PHY
help
Enable this to support the Starfive JH7110 PCIE 2.0/USB 3.0 PHY.
Generic PHY driver JH7110 USB 3.0/ PCIe 2.0.
config PHY_STARFIVE_JH7110_USB2
bool "Starfive JH7110 USB 2.0 PHY driver"
depends on PHY
help
Enable this to support the Starfive JH7110 USB 2.0 PHY.
Generic PHY driver JH7110 USB 2.0.
endmenu

View file

@ -0,0 +1,7 @@
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2023 Starfive
#
obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o
obj-$(CONFIG_PHY_STARFIVE_JH7110_USB2) += phy-jh7110-usb2.o

View file

@ -0,0 +1,239 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* StarFive JH7110 PCIe 2.0 PHY driver
*
* Copyright (C) 2024 StarFive Technology Co., Ltd.
* Author: Minda Chen <minda.chen@starfivetech.com>
*/
#include <asm/io.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <errno.h>
#include <generic-phy.h>
#include <regmap.h>
#include <soc.h>
#include <syscon.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include "phy-jh7110-usb-syscon.h"
#define PCIE_KVCO_LEVEL_OFF 0x28
#define PCIE_USB3_PHY_PLL_CTL_OFF 0x7c
#define PCIE_USB3_PHY_SS_MODE BIT(4)
#define PCIE_KVCO_TUNE_SIGNAL_OFF 0x80
#define PHY_KVCO_FINE_TUNE_LEVEL 0x91
#define PHY_KVCO_FINE_TUNE_SIGNALS 0xc
#define PCIE_USB3_PHY_MODE 0x1
#define PCIE_BUS_WIDTH 0x2
#define PCIE_USB3_PHY_ENABLE 0x1
#define PCIE_USB3_PHY_SPLIT 0x1
struct jh7110_pcie_phy {
struct phy *phy;
struct regmap *stg_syscon;
struct regmap *sys_syscon;
void __iomem *regs;
struct regmap_field *phy_mode;
struct regmap_field *bus_width;
struct regmap_field *usb3_phy_en;
struct regmap_field *usb_split;
enum phy_mode mode;
};
static int phy_pcie_mode_set(struct jh7110_pcie_phy *data, bool usb_mode)
{
unsigned int phy_mode, width, usb3_phy, ss_mode, split;
/* default is PCIe mode */
if (!data->stg_syscon || !data->sys_syscon) {
if (usb_mode) {
dev_err(data->phy->dev, "doesn't support USB3 mode\n");
return -EINVAL;
}
return 0;
}
if (usb_mode) {
phy_mode = PCIE_USB3_PHY_MODE;
width = 0;
usb3_phy = PCIE_USB3_PHY_ENABLE;
ss_mode = PCIE_USB3_PHY_SS_MODE;
split = 0;
} else {
phy_mode = 0;
width = PCIE_BUS_WIDTH;
usb3_phy = 0;
ss_mode = 0;
split = PCIE_USB3_PHY_SPLIT;
}
regmap_field_write(data->phy_mode, phy_mode);
regmap_field_write(data->bus_width, width);
regmap_field_write(data->usb3_phy_en, usb3_phy);
clrsetbits_le32(data->regs + PCIE_USB3_PHY_PLL_CTL_OFF,
PCIE_USB3_PHY_SS_MODE, ss_mode);
regmap_field_write(data->usb_split, split);
return 0;
}
static void phy_kvco_gain_set(struct jh7110_pcie_phy *phy)
{
/* PCIe Multi-PHY PLL KVCO Gain fine tune settings: */
writel(PHY_KVCO_FINE_TUNE_LEVEL, phy->regs + PCIE_KVCO_LEVEL_OFF);
writel(PHY_KVCO_FINE_TUNE_SIGNALS, phy->regs + PCIE_KVCO_TUNE_SIGNAL_OFF);
}
static int jh7110_pcie_phy_set_mode(struct phy *phy,
enum phy_mode mode, int submode)
{
struct udevice *dev = phy->dev;
struct jh7110_pcie_phy *pcie_phy = dev_get_priv(dev);
int ret;
if (mode == pcie_phy->mode)
return 0;
switch (mode) {
case PHY_MODE_USB_HOST:
case PHY_MODE_USB_DEVICE:
case PHY_MODE_USB_OTG:
ret = phy_pcie_mode_set(pcie_phy, 1);
if (ret)
return ret;
break;
case PHY_MODE_PCIE:
phy_pcie_mode_set(pcie_phy, 0);
break;
default:
return -EINVAL;
}
dev_dbg(phy->dev, "Changing PHY mode to %d\n", mode);
pcie_phy->mode = mode;
return 0;
}
static const struct phy_ops jh7110_pcie_phy_ops = {
.set_mode = jh7110_pcie_phy_set_mode,
};
static int phy_stg_regfield_init(struct udevice *dev, int mode, int usb3)
{
struct jh7110_pcie_phy *phy = dev_get_priv(dev);
struct reg_field phy_mode = REG_FIELD(mode, 20, 21);
struct reg_field bus_width = REG_FIELD(usb3, 2, 3);
struct reg_field usb3_phy_en = REG_FIELD(usb3, 4, 4);
phy->phy_mode = devm_regmap_field_alloc(dev, phy->stg_syscon, phy_mode);
if (IS_ERR(phy->phy_mode)) {
dev_err(dev, "PHY mode reg field init failed\n");
return PTR_ERR(phy->phy_mode);
}
phy->bus_width = devm_regmap_field_alloc(dev, phy->stg_syscon, bus_width);
if (IS_ERR(phy->bus_width)) {
dev_err(dev, "PHY bus width reg field init failed\n");
return PTR_ERR(phy->bus_width);
}
phy->usb3_phy_en = devm_regmap_field_alloc(dev, phy->stg_syscon, usb3_phy_en);
if (IS_ERR(phy->usb3_phy_en)) {
dev_err(dev, "USB3 PHY enable field init failed\n");
return PTR_ERR(phy->bus_width);
}
return 0;
}
static int phy_sys_regfield_init(struct udevice *dev, int split)
{
struct jh7110_pcie_phy *phy = dev_get_priv(dev);
struct reg_field usb_split = REG_FIELD(split, USB_PDRSTN_SPLIT_BIT, USB_PDRSTN_SPLIT_BIT);
phy->usb_split = devm_regmap_field_alloc(dev, phy->sys_syscon, usb_split);
if (IS_ERR(phy->usb_split)) {
dev_err(dev, "USB split field init failed\n");
return PTR_ERR(phy->usb_split);
}
return 0;
}
static int starfive_pcie_phy_get_syscon(struct udevice *dev)
{
struct jh7110_pcie_phy *phy = dev_get_priv(dev);
struct ofnode_phandle_args sys_phandle, stg_phandle;
int ret;
/* get corresponding syscon phandle */
ret = dev_read_phandle_with_args(dev, "starfive,sys-syscon", NULL, 1, 0,
&sys_phandle);
if (ret < 0) {
dev_err(dev, "Can't get sys cfg phandle: %d\n", ret);
return ret;
}
ret = dev_read_phandle_with_args(dev, "starfive,stg-syscon", NULL, 2, 0,
&stg_phandle);
if (ret < 0) {
dev_err(dev, "Can't get stg cfg phandle: %d\n", ret);
return ret;
}
phy->sys_syscon = syscon_node_to_regmap(sys_phandle.node);
/* get syscon register offset */
if (!IS_ERR(phy->sys_syscon)) {
ret = phy_sys_regfield_init(dev, SYSCON_USB_PDRSTN_REG_OFFSET);
if (ret)
return ret;
} else {
phy->sys_syscon = NULL;
}
phy->stg_syscon = syscon_node_to_regmap(stg_phandle.node);
if (!IS_ERR(phy->stg_syscon))
return phy_stg_regfield_init(dev, stg_phandle.args[0],
stg_phandle.args[1]);
else
phy->stg_syscon = NULL;
return 0;
}
int jh7110_pcie_phy_probe(struct udevice *dev)
{
struct jh7110_pcie_phy *phy = dev_get_priv(dev);
int rc;
phy->regs = dev_read_addr_ptr(dev);
if (!phy->regs)
return -EINVAL;
rc = starfive_pcie_phy_get_syscon(dev);
if (rc)
return rc;
phy_kvco_gain_set(phy);
return 0;
}
static const struct udevice_id jh7110_pcie_phy[] = {
{ .compatible = "starfive,jh7110-pcie-phy"},
{},
};
U_BOOT_DRIVER(jh7110_pcie_phy) = {
.name = "jh7110_pcie_phy",
.id = UCLASS_PHY,
.of_match = jh7110_pcie_phy,
.probe = jh7110_pcie_phy_probe,
.ops = &jh7110_pcie_phy_ops,
.priv_auto = sizeof(struct jh7110_pcie_phy),
};

View file

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef PHY_JH7110_USB_SYSCON_H_
#define PHY_JH7110_USB_SYSCON_H_
#define SYSCON_USB_PDRSTN_REG_OFFSET 0x18
#define USB_PDRSTN_SPLIT_BIT 17
#endif

View file

@ -0,0 +1,162 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* StarFive JH7110 USB 2.0 PHY driver
*
* Copyright (C) 2024 StarFive Technology Co., Ltd.
* Author: Minda Chen <minda.chen@starfivetech.com>
*/
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <errno.h>
#include <generic-phy.h>
#include <regmap.h>
#include <soc.h>
#include <syscon.h>
#include <linux/bitops.h>
#include <linux/err.h>
#include "phy-jh7110-usb-syscon.h"
#define USB_LS_KEEPALIVE_OFF 0x4
#define USB_LS_KEEPALIVE_ENABLE BIT(4)
#define USB_PHY_CLK_RATE 125000000
struct jh7110_usb2_phy {
struct phy *phy;
struct regmap *sys_syscon;
void __iomem *regs;
struct clk *usb_125m_clk;
struct clk *app_125m;
struct regmap_field *usb_split;
enum phy_mode mode;
};
static void usb2_set_ls_keepalive(struct jh7110_usb2_phy *phy, bool set)
{
/* Host mode enable the LS speed keep-alive signal */
clrsetbits_le32(phy->regs + USB_LS_KEEPALIVE_OFF,
USB_LS_KEEPALIVE_ENABLE,
set ? USB_LS_KEEPALIVE_ENABLE : 0);
}
static int usb2_phy_set_mode(struct phy *phy,
enum phy_mode mode, int submode)
{
struct udevice *dev = phy->dev;
struct jh7110_usb2_phy *usb2_phy = dev_get_priv(dev);
if (mode == usb2_phy->mode)
return 0;
switch (mode) {
case PHY_MODE_USB_HOST:
case PHY_MODE_USB_DEVICE:
case PHY_MODE_USB_OTG:
dev_dbg(dev, "Changing PHY to %d\n", mode);
usb2_phy->mode = mode;
usb2_set_ls_keepalive(usb2_phy, (mode != PHY_MODE_USB_DEVICE));
break;
default:
return -EINVAL;
}
/* set default split usb 2.0 only mode */
regmap_field_write(usb2_phy->usb_split, true);
return 0;
}
static int jh7110_usb2_phy_init(struct phy *phy)
{
struct udevice *dev = phy->dev;
struct jh7110_usb2_phy *usb2_phy = dev_get_priv(dev);
int ret;
ret = clk_set_rate(usb2_phy->usb_125m_clk, USB_PHY_CLK_RATE);
if (ret < 0) {
dev_err(dev, "Failed to set 125m clock\n");
return ret;
}
return clk_prepare_enable(usb2_phy->app_125m);
}
static int jh7110_usb2_phy_exit(struct phy *phy)
{
struct udevice *dev = phy->dev;
struct jh7110_usb2_phy *usb2_phy = dev_get_priv(dev);
clk_disable_unprepare(usb2_phy->app_125m);
return 0;
}
struct phy_ops jh7110_usb2_phy_ops = {
.init = jh7110_usb2_phy_init,
.exit = jh7110_usb2_phy_exit,
.set_mode = usb2_phy_set_mode,
};
int jh7110_usb2_phy_probe(struct udevice *dev)
{
struct jh7110_usb2_phy *phy = dev_get_priv(dev);
ofnode node;
struct reg_field usb_split;
int ret;
phy->regs = dev_read_addr_ptr(dev);
if (!phy->regs)
return -EINVAL;
node = ofnode_by_compatible(ofnode_null(), "starfive,jh7110-sys-syscon");
if (!ofnode_valid(node)) {
dev_err(dev, "Can't get syscon dev node\n");
return -ENODEV;
}
phy->sys_syscon = syscon_node_to_regmap(node);
if (IS_ERR(phy->sys_syscon)) {
dev_err(dev, "Can't get syscon regmap: %d\n", ret);
return PTR_ERR(phy->sys_syscon);
}
usb_split.reg = SYSCON_USB_PDRSTN_REG_OFFSET;
usb_split.lsb = USB_PDRSTN_SPLIT_BIT;
usb_split.msb = USB_PDRSTN_SPLIT_BIT;
phy->usb_split = devm_regmap_field_alloc(dev, phy->sys_syscon, usb_split);
if (IS_ERR(phy->usb_split)) {
dev_err(dev, "USB split field init failed\n");
return PTR_ERR(phy->usb_split);
}
phy->usb_125m_clk = devm_clk_get(dev, "125m");
if (IS_ERR(phy->usb_125m_clk)) {
dev_err(dev, "Failed to get 125m clock\n");
return PTR_ERR(phy->usb_125m_clk);
}
phy->app_125m = devm_clk_get(dev, "app_125m");
if (IS_ERR(phy->app_125m)) {
dev_err(dev, "Failed to get app 125m clock\n");
return PTR_ERR(phy->app_125m);
}
return 0;
}
static const struct udevice_id jh7110_usb2_phy[] = {
{ .compatible = "starfive,jh7110-usb-phy"},
{},
};
U_BOOT_DRIVER(jh7110_usb2_phy) = {
.name = "jh7110_usb2_phy",
.id = UCLASS_PHY,
.of_match = jh7110_usb2_phy,
.probe = jh7110_usb2_phy_probe,
.ops = &jh7110_usb2_phy_ops,
.priv_auto = sizeof(struct jh7110_usb2_phy),
};

View file

@ -49,6 +49,13 @@ config SPL_USB_CDNS3_HOST
Host controller is compliant with XHCI so it will use Host controller is compliant with XHCI so it will use
standard XHCI driver. standard XHCI driver.
config USB_CDNS3_STARFIVE
tristate "Cadence USB3 support on Starfive platforms"
default y if STARFIVE_JH7110
help
Say 'Y' here if you are building for Starfive platforms
that contain Cadence USB3 controller core. E.g.: JH7110.
config USB_CDNS3_TI config USB_CDNS3_TI
tristate "Cadence USB3 support on TI platforms" tristate "Cadence USB3 support on TI platforms"
default USB_CDNS3 default USB_CDNS3

View file

@ -8,4 +8,5 @@ cdns3-$(CONFIG_$(XPL_)USB_CDNS3_GADGET) += gadget.o ep0.o
cdns3-$(CONFIG_$(XPL_)USB_CDNS3_HOST) += host.o cdns3-$(CONFIG_$(XPL_)USB_CDNS3_HOST) += host.o
obj-$(CONFIG_USB_CDNS3_STARFIVE) += cdns3-starfive.o
obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o obj-$(CONFIG_USB_CDNS3_TI) += cdns3-ti.o

View file

@ -0,0 +1,182 @@
// SPDX-License-Identifier: GPL-2.0
/*
* cdns3-starfive.c - StarFive specific Glue layer for Cadence USB Controller
*
* Copyright (C) 2024 StarFive Technology Co., Ltd.
*
* Author: Minda Chen <minda.chen@starfivetech.com>
*/
#include <asm/io.h>
#include <clk.h>
#include <dm.h>
#include <dm/device_compat.h>
#include <linux/bitops.h>
#include <linux/usb/otg.h>
#include <malloc.h>
#include <reset.h>
#include <regmap.h>
#include <syscon.h>
#include "core.h"
#define USB_STRAP_HOST BIT(17)
#define USB_STRAP_DEVICE BIT(18)
#define USB_STRAP_MASK GENMASK(18, 16)
#define USB_SUSPENDM_HOST BIT(19)
#define USB_SUSPENDM_MASK BIT(19)
#define USB_MISC_CFG_MASK GENMASK(23, 20)
#define USB_SUSPENDM_BYPS BIT(20)
#define USB_PLL_EN BIT(22)
#define USB_REFCLK_MODE BIT(23)
struct cdns_starfive {
struct udevice *dev;
struct regmap *stg_syscon;
struct reset_ctl_bulk resets;
struct clk_bulk clks;
u32 stg_usb_mode;
enum usb_dr_mode mode;
};
static void cdns_mode_init(struct cdns_starfive *data, enum usb_dr_mode mode)
{
unsigned int strap, suspendm;
regmap_update_bits(data->stg_syscon, data->stg_usb_mode,
USB_MISC_CFG_MASK,
USB_SUSPENDM_BYPS | USB_PLL_EN | USB_REFCLK_MODE);
switch (mode) {
case USB_DR_MODE_HOST:
strap = USB_STRAP_HOST;
suspendm = USB_SUSPENDM_HOST;
break;
case USB_DR_MODE_PERIPHERAL:
strap = USB_STRAP_DEVICE;
suspendm = 0;
break;
default:
return;
}
regmap_update_bits(data->stg_syscon, data->stg_usb_mode,
USB_SUSPENDM_MASK | USB_STRAP_MASK,
strap | suspendm);
}
static void cdns_clk_rst_deinit(struct cdns_starfive *data)
{
reset_assert_bulk(&data->resets);
clk_disable_bulk(&data->clks);
}
static int cdns_clk_rst_init(struct cdns_starfive *data)
{
int ret;
ret = clk_get_bulk(data->dev, &data->clks);
if (ret)
return ret;
ret = reset_get_bulk(data->dev, &data->resets);
if (ret)
goto err_clk;
ret = clk_enable_bulk(&data->clks);
if (ret) {
dev_err(data->dev, "clk enable failed: %d\n", ret);
goto err_en_clk;
}
ret = reset_deassert_bulk(&data->resets);
if (ret) {
dev_err(data->dev, "reset deassert failed: %d\n", 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);
return ret;
}
static int cdns_starfive_get_syscon(struct cdns_starfive *data)
{
struct ofnode_phandle_args phandle;
int ret;
ret = dev_read_phandle_with_args(data->dev, "starfive,stg-syscon", NULL, 1, 0,
&phandle);
if (ret < 0) {
dev_err(data->dev, "Can't get stg cfg phandle: %d\n", ret);
return ret;
}
data->stg_syscon = syscon_node_to_regmap(phandle.node);
if (IS_ERR(data->stg_syscon)) {
dev_err(data->dev, "fail to get regmap: %d\n", (int)PTR_ERR(data->stg_syscon));
return PTR_ERR(data->stg_syscon);
}
data->stg_usb_mode = phandle.args[0];
return 0;
}
static int cdns_starfive_probe(struct udevice *dev)
{
struct cdns_starfive *data = dev_get_plat(dev);
enum usb_dr_mode dr_mode;
int ret;
data->dev = dev;
ret = cdns_starfive_get_syscon(data);
if (ret)
return ret;
dr_mode = usb_get_dr_mode(dev_ofnode(dev));
data->mode = dr_mode;
ret = cdns_clk_rst_init(data);
if (ret) {
dev_err(data->dev, "clk reset failed: %d\n", ret);
return ret;
}
cdns_mode_init(data, dr_mode);
return 0;
}
static int cdns_starfive_remove(struct udevice *dev)
{
struct cdns_starfive *data = dev_get_plat(dev);
cdns_clk_rst_deinit(data);
return 0;
}
static const struct udevice_id cdns_starfive_of_match[] = {
{ .compatible = "starfive,jh7110-usb", },
{},
};
U_BOOT_DRIVER(cdns_starfive) = {
.name = "cdns-starfive",
.id = UCLASS_NOP,
.of_match = cdns_starfive_of_match,
.bind = cdns3_bind,
.probe = cdns_starfive_probe,
.remove = cdns_starfive_remove,
.plat_auto = sizeof(struct cdns_starfive),
.flags = DM_FLAG_OS_PREPARE,
};

View file

@ -410,6 +410,9 @@ int cdns3_bind(struct udevice *parent)
name = ofnode_get_name(node); name = ofnode_get_name(node);
dr_mode = usb_get_dr_mode(node); dr_mode = usb_get_dr_mode(node);
if (dr_mode == USB_DR_MODE_UNKNOWN)
dr_mode = usb_get_dr_mode(dev_ofnode(parent));
switch (dr_mode) { switch (dr_mode) {
#if defined(CONFIG_SPL_USB_HOST) || \ #if defined(CONFIG_SPL_USB_HOST) || \
(!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST)) (!defined(CONFIG_XPL_BUILD) && defined(CONFIG_USB_HOST))

View file

@ -217,15 +217,19 @@ static int cdns3_init_otg_mode(struct cdns3 *cdns)
int cdns3_drd_update_mode(struct cdns3 *cdns) int cdns3_drd_update_mode(struct cdns3 *cdns)
{ {
int ret = 0; int ret = 0;
int mode;
switch (cdns->dr_mode) { switch (cdns->dr_mode) {
case USB_DR_MODE_PERIPHERAL: case USB_DR_MODE_PERIPHERAL:
mode = PHY_MODE_USB_DEVICE;
ret = cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL); ret = cdns3_set_mode(cdns, USB_DR_MODE_PERIPHERAL);
break; break;
case USB_DR_MODE_HOST: case USB_DR_MODE_HOST:
mode = PHY_MODE_USB_HOST;
ret = cdns3_set_mode(cdns, USB_DR_MODE_HOST); ret = cdns3_set_mode(cdns, USB_DR_MODE_HOST);
break; break;
case USB_DR_MODE_OTG: case USB_DR_MODE_OTG:
mode = PHY_MODE_USB_OTG;
ret = cdns3_init_otg_mode(cdns); ret = cdns3_init_otg_mode(cdns);
break; break;
default: default:
@ -234,6 +238,16 @@ int cdns3_drd_update_mode(struct cdns3 *cdns)
return -EINVAL; return -EINVAL;
} }
ret = generic_phy_set_mode(&cdns->usb2_phy, mode, 0);
if (ret) {
dev_err(cdns->dev, "Set usb 2.0 PHY mode failed %d\n", ret);
return ret;
}
ret = generic_phy_set_mode(&cdns->usb3_phy, mode, 0);
if (ret)
dev_err(cdns->dev, "Set usb 3.0 PHY mode failed %d\n", ret);
return ret; return ret;
} }