From: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> On the Renesas RZ/G3S SoC, the USB PHY block has an input signal called PWRRDY. This signal is managed by the system controller and must be de-asserted after powering on the area where USB PHY resides and asserted before powering it off. On power-on the USB PWRRDY signal need to be de-asserted before enabling clock and switching the module to normal state (though MSTOP support). The power-on configuration sequence must be: 1/ PWRRDY=0 2/ CLK_ON=1 3/ MSTOP=0 On power-off the configuration sequence should be: 1/ MSTOP=1 2/ CLK_ON=0 3/ PWRRDY=1 The CLK_ON and MSTOP functionalities are controlled by clock drivers. After long discussions with the internal HW team, it has been confirmed that the HW connection b/w USB PHY block, the USB channels, the system controller, clock, MSTOP, PWRRDY signal is as follows: ┌──────────────────────────────┐ │ │◄── CPG_CLKON_USB.CLK0_ON │ USB CH0 │ ┌──────────────────────────┐ │┌───────────────────────────┐ │◄── CPG_CLKON_USB.CLK2_ON │ ┌────────┐ ││host controller registers │ │ │ │ │ ││function controller registers│ │ │ PHY0 │◄──┤└───────────────────────────┘ │ │ USB PHY │ │ └────────────▲─────────────────┘ │ └────────┘ │ │ │ CPG_BUS_PERI_COM_MSTOP.MSTOP{6, 5}_ON │┌──────────────┐ ┌────────┐ ││USHPHY control│ │ │ ││ registers │ │ PHY1 │ ┌──────────────────────────────┐ │└──────────────┘ │ │◄──┤ USB CH1 │ │ └────────┘ │┌───────────────────────────┐ │◄── CPG_CLKON_USB.CLK1_ON └─▲───────▲─────────▲──────┘ ││ host controller registers │ │ │ │ │ │└───────────────────────────┘ │ │ │ │ └────────────▲─────────────────┘ │ │ │ │ │ │ │ CPG_BUS_PERI_COM_MSTOP.MSTOP7_ON │PWRRDY │ │ │ │ CPG_CLK_ON_USB.CLK3_ON │ │ │ CPG_BUS_PERI_COM_MSTOP.MSTOP4_ON │ ┌────┐ │SYSC│ └────┘ where: - CPG_CLKON_USB.CLK.CLKX_ON is the register bit controlling the clock X of different USB blocks, X in {0, 1, 2, 3} - CPG_BUS_PERI_COM_MSTOP.MSTOPX_ON is the register bit controlling the MSTOP of different USB blocks, X in {4, 5, 6, 7} - USB PHY is the USB PHY block exposing 2 ports, port0 and port1, used by the USB CH0, USB CH1 - SYSC is the system controller block controlling the PWRRDY signal - USB CHx are individual USB block with host and function capabilities (USB CH0 have both host and function capabilities, USB CH1 has only host capabilities) The USBPHY control registers are controlled though the reset-rzg2l-usbphy-ctrl driver. The USB PHY ports are controlled by phy_rcar_gen3_usb2 (drivers/phy/renesas/phy-rcar-gen3-usb2.c file). The USB PHY ports requests resets from the reset-rzg2l-usbphy-ctrl driver. The connection b/w the system controller and the USB PHY drivers is implemented through the renesas,sysc-signals device tree property. This property specifies the register offset and the bitmask required to control the signal. The system controller exports the syscon regmap, and the read/write access to the memory area of the PWRRDY signal is reference-counted, as the same system controller signal is provided to the PHY driver and the reset-rzg2l-usbphy-ctrl. This approach was chosen to avoid any violation of the configuration sequence b/w PWRRDY, CLK_ON and MSTOP bits specified above. Add support for PWRRDY in reset-rzg2l-usbphy-ctrl driver. Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> --- Changes in v3: - none; this patch is new drivers/reset/reset-rzg2l-usbphy-ctrl.c | 42 +++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/reset/reset-rzg2l-usbphy-ctrl.c b/drivers/reset/reset-rzg2l-usbphy-ctrl.c index 8a7f167e405e..016aae883b2e 100644 --- a/drivers/reset/reset-rzg2l-usbphy-ctrl.c +++ b/drivers/reset/reset-rzg2l-usbphy-ctrl.c @@ -13,6 +13,7 @@ #include <linux/regmap.h> #include <linux/reset.h> #include <linux/reset-controller.h> +#include <linux/soc/renesas/rz-sysc.h> #define RESET 0x000 #define VBENCTL 0x03c @@ -35,6 +36,7 @@ struct rzg2l_usbphy_ctrl_priv { struct reset_control *rstc; void __iomem *base; struct platform_device *vdev; + struct rz_sysc_signal_map *pwrrdy; spinlock_t lock; }; @@ -91,6 +93,8 @@ static int rzg2l_usbphy_ctrl_status(struct reset_controller_dev *rcdev, return !!(readl(priv->base + RESET) & port_mask); } +#define RZG2L_USBPHY_CTRL_PWRRDY 1 + static const struct of_device_id rzg2l_usbphy_ctrl_match_table[] = { { .compatible = "renesas,rzg2l-usbphy-ctrl" }, { /* Sentinel */ } @@ -110,6 +114,40 @@ static const struct regmap_config rzg2l_usb_regconf = { .max_register = 1, }; +static void rzg2l_usbphy_ctrl_set_pwrrdy(struct rzg2l_usbphy_ctrl_priv *priv, + bool power_on) +{ + struct rz_sysc_signal_map *pwrrdy = priv->pwrrdy; + + regmap_update_bits(pwrrdy->regmap, pwrrdy->offset, pwrrdy->mask, !power_on); +} + +static void rzg2l_usbphy_ctrl_pwrrdy_off(void *data) +{ + rzg2l_usbphy_ctrl_set_pwrrdy(data, false); +} + +static int rzg2l_usbphy_ctrl_pwrrdy_init(struct device *dev, + struct rzg2l_usbphy_ctrl_priv *priv) +{ + struct rz_sysc_signal_map *pwrrdy; + const int *data; + + data = device_get_match_data(dev); + if (data != (int *)RZG2L_USBPHY_CTRL_PWRRDY) + return 0; + + pwrrdy = rz_sysc_get_signal_map(dev); + if (IS_ERR(pwrrdy)) + return PTR_ERR(pwrrdy); + + priv->pwrrdy = pwrrdy; + + rzg2l_usbphy_ctrl_set_pwrrdy(priv, true); + + return devm_add_action_or_reset(dev, rzg2l_usbphy_ctrl_pwrrdy_off, priv); +} + static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -132,6 +170,10 @@ static int rzg2l_usbphy_ctrl_probe(struct platform_device *pdev) if (IS_ERR(regmap)) return PTR_ERR(regmap); + error = rzg2l_usbphy_ctrl_pwrrdy_init(dev, priv); + if (error) + return error; + priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(priv->rstc)) return dev_err_probe(dev, PTR_ERR(priv->rstc), -- 2.43.0