Renesas RZ/G2L USB support, remaining RAVB ethernet fix and KSZ9031 LED
errata fix.
This commit is contained in:
Tom Rini 2025-03-20 08:07:56 -06:00
commit 069da0cf25
13 changed files with 482 additions and 39 deletions

View file

@ -26,6 +26,7 @@ CONFIG_CMD_GPIO=y
CONFIG_CMD_I2C=y CONFIG_CMD_I2C=y
CONFIG_CMD_MMC=y CONFIG_CMD_MMC=y
CONFIG_CMD_PART=y CONFIG_CMD_PART=y
CONFIG_CMD_USB=y
CONFIG_CMD_PMIC=y CONFIG_CMD_PMIC=y
CONFIG_CMD_EXT2=y CONFIG_CMD_EXT2=y
CONFIG_CMD_EXT4=y CONFIG_CMD_EXT4=y
@ -54,5 +55,12 @@ CONFIG_PMIC_RAA215300=y
CONFIG_DM_REGULATOR=y CONFIG_DM_REGULATOR=y
CONFIG_DM_REGULATOR_FIXED=y CONFIG_DM_REGULATOR_FIXED=y
CONFIG_DM_REGULATOR_GPIO=y CONFIG_DM_REGULATOR_GPIO=y
CONFIG_RESET_RZG2L_USBPHY_CTRL=y
CONFIG_SYSRESET=y CONFIG_SYSRESET=y
CONFIG_SYSRESET_RAA215300=y CONFIG_SYSRESET_RAA215300=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_GENERIC=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_GENERIC=y
CONFIG_USB_STORAGE=y

View file

@ -389,10 +389,126 @@ U_BOOT_PHY_DRIVER(ksz9031) = {
#define KSZ9131RN_DLL_ENABLE_DELAY 0 #define KSZ9131RN_DLL_ENABLE_DELAY 0
#define KSZ9131RN_DLL_DISABLE_DELAY BIT(12) #define KSZ9131RN_DLL_DISABLE_DELAY BIT(12)
#define KSZ9131RN_COMMON_CTRL 0
#define KSZ9131RN_COMMON_CTRL_INDIVIDUAL_LED_MODE BIT(4)
#define KSZ9131RN_LED_ERRATA_REG 0x1e
#define KSZ9131RN_LED_ERRATA_BIT BIT(9)
#define KSZ9131RN_CONTROL_PAD_SKEW 4
#define KSZ9131RN_RX_DATA_PAD_SKEW 5
#define KSZ9131RN_TX_DATA_PAD_SKEW 6
#define KSZ9131RN_CLK_PAD_SKEW 8
#define KSZ9131RN_SKEW_5BIT_MAX 2400
#define KSZ9131RN_SKEW_4BIT_MAX 800
#define KSZ9131RN_OFFSET 700
#define KSZ9131RN_STEP 100
static int ksz9131_of_load_skew_values(struct phy_device *phydev,
ofnode of_node,
u16 reg, size_t field_sz,
const char *field[], u8 numfields)
{
int val[4] = {-(1 + KSZ9131RN_OFFSET), -(2 + KSZ9131RN_OFFSET),
-(3 + KSZ9131RN_OFFSET), -(4 + KSZ9131RN_OFFSET)};
int skewval, skewmax = 0;
int matches = 0;
u16 maxval;
u16 newval;
u16 mask;
int i;
/* psec properties in dts should mean x pico seconds */
if (field_sz == 5)
skewmax = KSZ9131RN_SKEW_5BIT_MAX;
else
skewmax = KSZ9131RN_SKEW_4BIT_MAX;
for (i = 0; i < numfields; i++)
if (!ofnode_read_s32(of_node, field[i], &skewval)) {
if (skewval < -KSZ9131RN_OFFSET)
skewval = -KSZ9131RN_OFFSET;
else if (skewval > skewmax)
skewval = skewmax;
val[i] = skewval + KSZ9131RN_OFFSET;
matches++;
}
if (!matches)
return 0;
if (matches < numfields)
newval = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, reg);
else
newval = 0;
maxval = (field_sz == 4) ? 0xf : 0x1f;
for (i = 0; i < numfields; i++)
if (val[i] != -(i + 1 + KSZ9131RN_OFFSET)) {
mask = 0xffff;
mask ^= maxval << (field_sz * i);
newval = (newval & mask) |
(((val[i] / KSZ9131RN_STEP) & maxval)
<< (field_sz * i));
}
return phy_write_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG, reg, newval);
}
static int ksz9131_of_load_all_skew_values(struct phy_device *phydev)
{
const char *control_skews[2] = { "txen-skew-psec", "rxdv-skew-psec" };
const char *clk_skews[2] = { "rxc-skew-psec", "txc-skew-psec" };
const char *rx_data_skews[4] = {
"rxd0-skew-psec", "rxd1-skew-psec",
"rxd2-skew-psec", "rxd3-skew-psec"
};
const char *tx_data_skews[4] = {
"txd0-skew-psec", "txd1-skew-psec",
"txd2-skew-psec", "txd3-skew-psec"
};
struct ofnode_phandle_args phandle_args;
int ret;
/*
* Silently ignore failure here as the device tree is not required to
* contain a phy node.
*/
if (dev_read_phandle_with_args(phydev->dev, "phy-handle", NULL, 0, 0,
&phandle_args))
return 0;
if (!ofnode_valid(phandle_args.node))
return 0;
ret = ksz9131_of_load_skew_values(phydev, phandle_args.node,
KSZ9131RN_CLK_PAD_SKEW, 5,
clk_skews, 2);
if (ret < 0)
return ret;
ret = ksz9131_of_load_skew_values(phydev, phandle_args.node,
KSZ9131RN_CONTROL_PAD_SKEW, 4,
control_skews, 2);
if (ret < 0)
return ret;
ret = ksz9131_of_load_skew_values(phydev, phandle_args.node,
KSZ9131RN_RX_DATA_PAD_SKEW, 4,
rx_data_skews, 4);
if (ret < 0)
return ret;
return ksz9131_of_load_skew_values(phydev, phandle_args.node,
KSZ9131RN_TX_DATA_PAD_SKEW, 4,
tx_data_skews, 4);
}
static int ksz9131_config_rgmii_delay(struct phy_device *phydev) static int ksz9131_config_rgmii_delay(struct phy_device *phydev)
{ {
struct phy_driver *drv = phydev->drv; u16 rxcdll_val, txcdll_val;
u16 rxcdll_val, txcdll_val, val;
int ret; int ret;
switch (phydev->interface) { switch (phydev->interface) {
@ -416,24 +532,37 @@ static int ksz9131_config_rgmii_delay(struct phy_device *phydev)
return 0; return 0;
} }
val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG, ret = phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL); KSZ9131RN_RXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
val &= ~KSZ9131RN_DLL_CTRL_BYPASS; rxcdll_val);
val |= rxcdll_val; if (ret < 0)
ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_RXC_DLL_CTRL, val);
if (ret)
return ret; return ret;
val = drv->readext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG, return phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_TXC_DLL_CTRL); KSZ9131RN_TXC_DLL_CTRL, KSZ9131RN_DLL_CTRL_BYPASS,
txcdll_val);
}
val &= ~KSZ9131RN_DLL_CTRL_BYPASS; /* Silicon Errata DS80000693B
val |= txcdll_val; *
ret = drv->writeext(phydev, 0, KSZ9131RN_MMD_COMMON_CTRL_REG, * When LEDs are configured in Individual Mode, LED1 is ON in a no-link
KSZ9131RN_TXC_DLL_CTRL, val); * condition. Workaround is to set register 0x1e, bit 9, this way LED1 behaves
* according to the datasheet (off if there is no link).
*/
static int ksz9131_led_errata(struct phy_device *phydev)
{
int reg;
return ret; reg = phy_read_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
KSZ9131RN_COMMON_CTRL);
if (reg < 0)
return reg;
if (!(reg & KSZ9131RN_COMMON_CTRL_INDIVIDUAL_LED_MODE))
return 0;
return phy_set_bits(phydev, MDIO_DEVAD_NONE, KSZ9131RN_LED_ERRATA_REG,
KSZ9131RN_LED_ERRATA_BIT);
} }
static int ksz9131_config(struct phy_device *phydev) static int ksz9131_config(struct phy_device *phydev)
@ -446,6 +575,14 @@ static int ksz9131_config(struct phy_device *phydev)
return ret; return ret;
} }
ret = ksz9131_of_load_all_skew_values(phydev);
if (ret < 0)
return ret;
ret = ksz9131_led_errata(phydev);
if (ret < 0)
return ret;
/* add an option to disable the gigabit feature of this PHY */ /* add an option to disable the gigabit feature of this PHY */
if (env_get("disable_giga")) { if (env_get("disable_giga")) {
unsigned features; unsigned features;

View file

@ -592,7 +592,7 @@ static int ravb_probe(struct udevice *dev)
ret = clk_get_bulk(dev, &eth->clks); ret = clk_get_bulk(dev, &eth->clks);
if (ret < 0) if (ret < 0)
goto err_mdio_alloc; goto err_clk_get;
mdiodev = mdio_alloc(); mdiodev = mdio_alloc();
if (!mdiodev) { if (!mdiodev) {
@ -614,23 +614,25 @@ static int ravb_probe(struct udevice *dev)
/* Bring up PHY */ /* Bring up PHY */
ret = clk_enable_bulk(&eth->clks); ret = clk_enable_bulk(&eth->clks);
if (ret) if (ret)
goto err_mdio_register; goto err_clk_enable;
ret = ravb_reset(dev); ret = ravb_reset(dev);
if (ret) if (ret)
goto err_mdio_reset; goto err_clk_enable;
ret = ravb_phy_config(dev); ret = ravb_phy_config(dev);
if (ret) if (ret)
goto err_mdio_reset; goto err_clk_enable;
return 0; return 0;
err_mdio_reset: err_clk_enable:
clk_release_bulk(&eth->clks); mdio_unregister(mdiodev);
err_mdio_register: err_mdio_register:
mdio_free(mdiodev); mdio_free(mdiodev);
err_mdio_alloc: err_mdio_alloc:
clk_release_bulk(&eth->clks);
err_clk_get:
unmap_physmem(eth->iobase, MAP_NOCACHE); unmap_physmem(eth->iobase, MAP_NOCACHE);
return ret; return ret;
} }

View file

@ -163,8 +163,8 @@ config PHY_RCAR_GEN2
config PHY_RCAR_GEN3 config PHY_RCAR_GEN3
tristate "Renesas R-Car Gen3 USB PHY" tristate "Renesas R-Car Gen3 USB PHY"
depends on PHY && RCAR_GEN3 && CLK && DM_REGULATOR depends on PHY && CLK && DM_REGULATOR && (RCAR_GEN3 || RZG2L)
default y if RCAR_GEN3 default y if (RCAR_GEN3 || RZG2L)
help help
Support for the Renesas R-Car Gen3 USB PHY. This driver operates the Support for the Renesas R-Car Gen3 USB PHY. This driver operates the
PHY connected to EHCI USB module and controls USB OTG operation. PHY connected to EHCI USB module and controls USB OTG operation.

View file

@ -55,6 +55,7 @@
/* VBCTRL */ /* VBCTRL */
#define USB2_VBCTRL_DRVVBUSSEL BIT(8) #define USB2_VBCTRL_DRVVBUSSEL BIT(8)
#define USB2_VBCTRL_VBOUT BIT(0)
/* LINECTRL1 */ /* LINECTRL1 */
#define USB2_LINECTRL1_DPRPD_EN BIT(19) #define USB2_LINECTRL1_DPRPD_EN BIT(19)
@ -68,6 +69,13 @@
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
#define USB2_ADPCTRL_DRVVBUS BIT(4) #define USB2_ADPCTRL_DRVVBUS BIT(4)
/* RZ/G2L specific */
#define USB2_OBINT_IDCHG_EN BIT(0)
#define USB2_LINECTRL1_USB2_IDMON BIT(0)
/* Device flags */
#define RCAR_GEN3_PHY_NO_ADPCTRL BIT(0)
struct rcar_gen3_phy { struct rcar_gen3_phy {
fdt_addr_t regs; fdt_addr_t regs;
struct clk clk; struct clk clk;
@ -122,15 +130,50 @@ static int rcar_gen3_phy_phy_power_off(struct phy *phy)
return regulator_set_enable(priv->vbus_supply, false); return regulator_set_enable(priv->vbus_supply, false);
} }
static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode, static bool rcar_gen3_phy_check_id(struct phy *phy)
int submode)
{ {
const u32 adpdevmask = USB2_ADPCTRL_IDDIG | USB2_ADPCTRL_OTGSESSVLD; const u32 adpdevmask = USB2_ADPCTRL_IDDIG | USB2_ADPCTRL_OTGSESSVLD;
struct rcar_gen3_phy *priv = dev_get_priv(phy->dev); struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
u32 adpctrl; ulong flags = dev_get_driver_data(phy->dev);
u32 val;
if (flags & RCAR_GEN3_PHY_NO_ADPCTRL) {
val = readl(priv->regs + USB2_LINECTRL1);
return !!(val & USB2_LINECTRL1_USB2_IDMON);
}
val = readl(priv->regs + USB2_ADPCTRL);
return (val & adpdevmask) == adpdevmask;
}
static void rcar_gen3_phy_set_vbus(struct phy *phy, bool enable)
{
struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
ulong flags = dev_get_driver_data(phy->dev);
u32 bits = USB2_ADPCTRL_DRVVBUS;
u64 reg = USB2_ADPCTRL;
if (flags & RCAR_GEN3_PHY_NO_ADPCTRL) {
bits = USB2_VBCTRL_VBOUT;
reg = USB2_VBCTRL;
}
if (enable)
setbits_le32(priv->regs + reg, bits);
else
clrbits_le32(priv->regs + reg, bits);
}
static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
int submode)
{
struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
ulong flags = dev_get_driver_data(phy->dev);
if (mode == PHY_MODE_USB_OTG) { if (mode == PHY_MODE_USB_OTG) {
if (submode) { if (submode) {
u32 obint_enable_bits;
/* OTG submode is used as initialization indicator */ /* OTG submode is used as initialization indicator */
writel(USB2_INT_ENABLE_UCOM_INTEN | writel(USB2_INT_ENABLE_UCOM_INTEN |
USB2_INT_ENABLE_USBH_INTB_EN | USB2_INT_ENABLE_USBH_INTB_EN |
@ -138,13 +181,16 @@ static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
priv->regs + USB2_INT_ENABLE); priv->regs + USB2_INT_ENABLE);
setbits_le32(priv->regs + USB2_VBCTRL, setbits_le32(priv->regs + USB2_VBCTRL,
USB2_VBCTRL_DRVVBUSSEL); USB2_VBCTRL_DRVVBUSSEL);
writel(USB2_OBINT_SESSVLDCHG | USB2_OBINT_IDDIGCHG, if (flags & RCAR_GEN3_PHY_NO_ADPCTRL) {
priv->regs + USB2_OBINTSTA); obint_enable_bits = USB2_OBINT_IDCHG_EN;
setbits_le32(priv->regs + USB2_OBINTEN, } else {
USB2_OBINT_SESSVLDCHG | obint_enable_bits = USB2_OBINT_SESSVLDCHG |
USB2_OBINT_IDDIGCHG); USB2_OBINT_IDDIGCHG;
setbits_le32(priv->regs + USB2_ADPCTRL, setbits_le32(priv->regs + USB2_ADPCTRL,
USB2_ADPCTRL_IDPULLUP); USB2_ADPCTRL_IDPULLUP);
}
writel(obint_enable_bits, priv->regs + USB2_OBINTSTA);
setbits_le32(priv->regs + USB2_OBINTEN, obint_enable_bits);
clrsetbits_le32(priv->regs + USB2_LINECTRL1, clrsetbits_le32(priv->regs + USB2_LINECTRL1,
USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DP_RPD |
USB2_LINECTRL1_DM_RPD | USB2_LINECTRL1_DM_RPD |
@ -154,8 +200,7 @@ static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
USB2_LINECTRL1_DMRPD_EN); USB2_LINECTRL1_DMRPD_EN);
} }
adpctrl = readl(priv->regs + USB2_ADPCTRL); if (rcar_gen3_phy_check_id(phy))
if ((adpctrl & adpdevmask) == adpdevmask)
mode = PHY_MODE_USB_DEVICE; mode = PHY_MODE_USB_DEVICE;
else else
mode = PHY_MODE_USB_HOST; mode = PHY_MODE_USB_HOST;
@ -165,13 +210,13 @@ static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
clrbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI); clrbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI);
setbits_le32(priv->regs + USB2_LINECTRL1, setbits_le32(priv->regs + USB2_LINECTRL1,
USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD);
setbits_le32(priv->regs + USB2_ADPCTRL, USB2_ADPCTRL_DRVVBUS); rcar_gen3_phy_set_vbus(phy, true);
} else if (mode == PHY_MODE_USB_DEVICE) { } else if (mode == PHY_MODE_USB_DEVICE) {
setbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI); setbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI);
clrsetbits_le32(priv->regs + USB2_LINECTRL1, clrsetbits_le32(priv->regs + USB2_LINECTRL1,
USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD, USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD,
USB2_LINECTRL1_DM_RPD); USB2_LINECTRL1_DM_RPD);
clrbits_le32(priv->regs + USB2_ADPCTRL, USB2_ADPCTRL_DRVVBUS); rcar_gen3_phy_set_vbus(phy, false);
} else { } else {
dev_err(phy->dev, "Unknown mode %d\n", mode); dev_err(phy->dev, "Unknown mode %d\n", mode);
return -EINVAL; return -EINVAL;
@ -226,7 +271,13 @@ static int rcar_gen3_phy_remove(struct udevice *dev)
} }
static const struct udevice_id rcar_gen3_phy_of_match[] = { static const struct udevice_id rcar_gen3_phy_of_match[] = {
{ .compatible = "renesas,rcar-gen3-usb2-phy", }, {
.compatible = "renesas,rcar-gen3-usb2-phy",
},
{
.compatible = "renesas,rzg2l-usb2-phy",
.data = RCAR_GEN3_PHY_NO_ADPCTRL,
},
{ }, { },
}; };

View file

@ -478,3 +478,11 @@ config DM_REGULATOR_TPS65219
features for REGULATOR TPS65219 and the family of TPS65219 PMICs. features for REGULATOR TPS65219 and the family of TPS65219 PMICs.
TPS65219 series of PMICs have 3 single phase BUCKs & 4 LDOs. TPS65219 series of PMICs have 3 single phase BUCKs & 4 LDOs.
The driver implements get/set api for value and enable. The driver implements get/set api for value and enable.
config REGULATOR_RZG2L_USBPHY
bool "Enable driver for RZ/G2L USB PHY VBUS supply"
depends on DM_REGULATOR
help
Enable this option to support controlling the VBUS supply in
the USB PHY peripheral of the Renesas RZ/G2L SoC. This option
is required in order to use the USB OTG port.

View file

@ -42,3 +42,4 @@ obj-$(CONFIG_DM_REGULATOR_TPS65941) += tps65941_regulator.o
obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o obj-$(CONFIG_DM_REGULATOR_SCMI) += scmi_regulator.o
obj-$(CONFIG_$(XPL_)DM_REGULATOR_ANATOP) += anatop_regulator.o obj-$(CONFIG_$(XPL_)DM_REGULATOR_ANATOP) += anatop_regulator.o
obj-$(CONFIG_DM_REGULATOR_TPS65219) += tps65219_regulator.o obj-$(CONFIG_DM_REGULATOR_TPS65219) += tps65219_regulator.o
obj-$(CONFIG_REGULATOR_RZG2L_USBPHY) += rzg2l-usbphy-regulator.o

View file

@ -0,0 +1,42 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2024 Renesas Electronics Corporation
*/
#include <asm/io.h>
#include <dm.h>
#include <power/regulator.h>
#include <renesas/rzg2l-usbphy.h>
#define VBENCTL 0x03c
#define VBENCTL_VBUS_SEL BIT(0)
static int rzg2l_usbphy_regulator_set_enable(struct udevice *dev, bool enable)
{
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(dev->parent);
if (enable)
clrbits_le32(priv->regs + VBENCTL, VBENCTL_VBUS_SEL);
else
setbits_le32(priv->regs + VBENCTL, VBENCTL_VBUS_SEL);
return 0;
}
static int rzg2l_usbphy_regulator_get_enable(struct udevice *dev)
{
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(dev->parent);
return !!readl(priv->regs + VBENCTL) & VBENCTL_VBUS_SEL;
}
static const struct dm_regulator_ops rzg2l_usbphy_regulator_ops = {
.get_enable = rzg2l_usbphy_regulator_get_enable,
.set_enable = rzg2l_usbphy_regulator_set_enable,
};
U_BOOT_DRIVER(rzg2l_usbphy_regulator) = {
.name = "rzg2l_usbphy_regulator",
.id = UCLASS_REGULATOR,
.ops = &rzg2l_usbphy_regulator_ops,
};

View file

@ -235,4 +235,14 @@ config RESET_AT91
This enables the Reset Controller driver support for Microchip/Atmel This enables the Reset Controller driver support for Microchip/Atmel
SoCs. Mainly used to expose assert/deassert methods to other drivers SoCs. Mainly used to expose assert/deassert methods to other drivers
that require it. that require it.
config RESET_RZG2L_USBPHY_CTRL
bool "Enable support for Renesas RZ/G2L USB 2.0 PHY control"
depends on DM_RESET
select REGULATOR_RZG2L_USBPHY
help
Enable support for controlling USB 2.0 PHY resets on the Renesas
RZ/G2L SoC. This is required for USB 2.0 functionality to work on this
SoC.
endmenu endmenu

View file

@ -33,3 +33,4 @@ obj-$(CONFIG_RESET_ZYNQMP) += reset-zynqmp.o
obj-$(CONFIG_RESET_DRA7) += reset-dra7.o obj-$(CONFIG_RESET_DRA7) += reset-dra7.o
obj-$(CONFIG_RESET_AT91) += reset-at91.o obj-$(CONFIG_RESET_AT91) += reset-at91.o
obj-$(CONFIG_$(PHASE_)RESET_JH7110) += reset-jh7110.o obj-$(CONFIG_$(PHASE_)RESET_JH7110) += reset-jh7110.o
obj-$(CONFIG_RESET_RZG2L_USBPHY_CTRL) += reset-rzg2l-usbphy-ctrl.o

View file

@ -0,0 +1,142 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2024 Renesas Electronics Corporation
*/
#include <asm/io.h>
#include <dm.h>
#include <dm/device-internal.h>
#include <dm/device_compat.h>
#include <dm/lists.h>
#include <renesas/rzg2l-usbphy.h>
#include <reset-uclass.h>
#include <reset.h>
#define RESET 0x000
#define RESET_SEL_PLLRESET BIT(12)
#define RESET_PLLRESET BIT(8)
#define RESET_SEL_P2RESET BIT(5)
#define RESET_SEL_P1RESET BIT(4)
#define RESET_PHYRST_2 BIT(1)
#define RESET_PHYRST_1 BIT(0)
#define PHY_RESET_MASK (RESET_PHYRST_1 | RESET_PHYRST_2)
#define NUM_PORTS 2
static int rzg2l_usbphy_ctrl_assert(struct reset_ctl *reset_ctl)
{
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(reset_ctl->dev);
u32 val;
val = readl(priv->regs + RESET);
val |= reset_ctl->id ? RESET_PHYRST_2 : RESET_PHYRST_1;
/* If both ports are in reset, we can also place the PLL into reset. */
if ((val & PHY_RESET_MASK) == PHY_RESET_MASK)
val |= RESET_PLLRESET;
writel(val, priv->regs + RESET);
return 0;
}
static int rzg2l_usbphy_ctrl_deassert(struct reset_ctl *reset_ctl)
{
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(reset_ctl->dev);
u32 val = reset_ctl->id ? RESET_PHYRST_2 : RESET_PHYRST_1;
/* If either port is out of reset, the PLL must also be out of reset. */
val |= RESET_PLLRESET;
clrbits_le32(priv->regs + RESET, val);
return 0;
}
static int rzg2l_usbphy_ctrl_of_xlate(struct reset_ctl *reset_ctl,
struct ofnode_phandle_args *args)
{
if (args->args[0] >= NUM_PORTS)
return -EINVAL;
reset_ctl->id = args->args[0];
return 0;
}
struct reset_ops rzg2l_usbphy_ctrl_ops = {
.rst_assert = rzg2l_usbphy_ctrl_assert,
.rst_deassert = rzg2l_usbphy_ctrl_deassert,
.of_xlate = rzg2l_usbphy_ctrl_of_xlate,
};
static int rzg2l_usbphy_ctrl_probe(struct udevice *dev)
{
struct rzg2l_usbphy_ctrl_priv *priv = dev_get_priv(dev);
struct reset_ctl rst;
int ret;
priv->regs = dev_read_addr(dev);
ret = reset_get_by_index(dev, 0, &rst);
if (ret < 0) {
dev_err(dev, "failed to get reset line: %d\n", ret);
return ret;
}
ret = reset_deassert(&rst);
if (ret < 0) {
dev_err(dev, "failed to de-assert reset line: %d\n", ret);
return ret;
}
/* put pll and phy into reset state */
setbits_le32(priv->regs + RESET,
RESET_SEL_PLLRESET | RESET_PLLRESET |
RESET_SEL_P1RESET | RESET_PHYRST_1 |
RESET_SEL_P2RESET | RESET_PHYRST_2);
return 0;
}
static const struct udevice_id rzg2l_usbphy_ctrl_ids[] = {
{ .compatible = "renesas,rzg2l-usbphy-ctrl", },
{ /* sentinel */ }
};
static int rzg2l_usbphy_ctrl_bind(struct udevice *dev)
{
struct driver *drv;
ofnode node;
int ret;
node = ofnode_find_subnode(dev_ofnode(dev), "regulator-vbus");
if (!ofnode_valid(node)) {
dev_err(dev, "Failed to find vbus regulator devicetree node\n");
return -ENOENT;
}
drv = lists_driver_lookup_name("rzg2l_usbphy_regulator");
if (!drv) {
dev_err(dev, "Failed to find vbus regulator driver\n");
return -ENOENT;
}
ret = device_bind(dev, drv, dev->name, NULL, node, NULL);
if (ret) {
dev_err(dev, "Failed to bind vbus regulator: %d\n", ret);
return ret;
}
return 0;
}
U_BOOT_DRIVER(rzg2l_usbphy_ctrl) = {
.name = "rzg2l_usbphy_ctrl",
.id = UCLASS_RESET,
.of_match = rzg2l_usbphy_ctrl_ids,
.bind = rzg2l_usbphy_ctrl_bind,
.probe = rzg2l_usbphy_ctrl_probe,
.ops = &rzg2l_usbphy_ctrl_ops,
.priv_auto = sizeof(struct rzg2l_usbphy_ctrl_priv),
};

View file

@ -333,6 +333,30 @@ int gen10g_startup(struct phy_device *phydev);
int gen10g_shutdown(struct phy_device *phydev); int gen10g_shutdown(struct phy_device *phydev);
int gen10g_discover_mmds(struct phy_device *phydev); int gen10g_discover_mmds(struct phy_device *phydev);
/**
* phy_set_bits - Convenience function for setting bits in a PHY register
* @phydev: the phy_device struct
* @devad: The MMD to read from
* @regnum: register number to write
* @val: bits to set
*/
static inline int phy_set_bits(struct phy_device *phydev, int devad, u32 regnum, u16 val)
{
return phy_modify(phydev, devad, regnum, 0, val);
}
/**
* phy_clear_bits - Convenience function for clearing bits in a PHY register
* @phydev: the phy_device struct
* @devad: The MMD to write to
* @regnum: register number to write
* @val: bits to clear
*/
static inline int phy_clear_bits(struct phy_device *phydev, int devad, u32 regnum, u16 val)
{
return phy_modify(phydev, devad, regnum, val, 0);
}
/** /**
* U_BOOT_PHY_DRIVER() - Declare a new U-Boot driver * U_BOOT_PHY_DRIVER() - Declare a new U-Boot driver
* @__name: name of the driver * @__name: name of the driver

View file

@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* RZ/G2L USB PHY common definitions
*
* Copyright (C) 2021-2023 Renesas Electronics Corp.
*/
#ifndef RENESAS_RZG2L_USBPHY_H
#define RENESAS_RZG2L_USBPHY_H
#include <fdtdec.h>
struct rzg2l_usbphy_ctrl_priv {
fdt_addr_t regs;
};
#endif /* RENESAS_RZG2L_USBPHY_H */