[PATCH v4 2/2] arm: rk3399: usb2phy: phy-rockchip-inno-usb2.c: Implement operations for the 480MHz usb2phy clock in rk3399.
Xavier Drudis Ferran
xdrudis at tinet.cat
Fri Dec 9 16:47:19 CET 2022
This clock has no users but appears in a phandle list used by
ehci-generic.c to bulk enable it. The phandle list comes from linux,
where it is needed for suspend/resume to work [1].
My tests give the same results with or without this patch, but Marek
Vasut found it weird to declare an empty clk_ops[2].
So I adapted the code from linux 6.1-rc8 so that it hopefully works
if it ever has some user. For now, without real users, it seems to
at least not give any errors.
Links: [1] https://lkml.kernel.org/lkml/1731551.Q6cHK6n5ZM@phil/T/
[2] https://patchwork.ozlabs.org/project/uboot/patch/Y5IWpjYLB4aXMy9o@localhost/#3018135
Cc: Simon Glass <sjg at chromium.org>
Cc: Philipp Tomsich <philipp.tomsich at vrull.eu>
Cc: Kever Yang <kever.yang at rock-chips.com>
Cc: Lukasz Majewski <lukma at denx.de>
Cc: Sean Anderson <seanga2 at gmail.com>
Cc: Marek Vasut <marex at denx.de>
Signed-off-by: Xavier Drudis Ferran <xdrudis at tinet.cat>
---
drivers/phy/rockchip/phy-rockchip-inno-usb2.c | 79 ++++++++++++++++++-
1 file changed, 77 insertions(+), 2 deletions(-)
diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
index cfbdc7d87e..766dde11a6 100644
--- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
+++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c
@@ -55,6 +55,7 @@ struct rockchip_usb2phy_port_cfg {
struct rockchip_usb2phy_cfg {
unsigned int reg;
+ struct usb2phy_reg clkout_ctl;
const struct rockchip_usb2phy_port_cfg port_cfgs[USB2PHY_NUM_PORTS];
};
@@ -76,6 +77,18 @@ static inline int property_enable(void *reg_base,
return writel(val, reg_base + reg->offset);
}
+static inline bool property_enabled(void *reg_base,
+ const struct usb2phy_reg *reg)
+{
+ unsigned int tmp, orig;
+ unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
+
+ orig = readl(reg_base + reg->offset);
+
+ tmp = (orig & mask) >> reg->bitstart;
+ return tmp != reg->disable;
+}
+
static const
struct rockchip_usb2phy_port_cfg *us2phy_get_port(struct phy *phy)
{
@@ -168,7 +181,64 @@ static struct phy_ops rockchip_usb2phy_ops = {
.of_xlate = rockchip_usb2phy_of_xlate,
};
+/**
+ * round_rate() - Adjust a rate to the exact rate a clock can provide.
+ * @clk: The clock to manipulate.
+ * @rate: Desidered clock rate in Hz.
+ *
+ * Return: rounded rate in Hz, or -ve error code.
+ */
+ulong rockchip_usb2phy_clk_round_rate(struct clk *clk, ulong rate)
+{
+ return 480000000;
+}
+
+/**
+ * enable() - Enable a clock.
+ * @clk: The clock to manipulate.
+ *
+ * Return: zero on success, or -ve error code.
+ */
+int rockchip_usb2phy_clk_enable(struct clk *clk)
+{
+ struct udevice *parent = dev_get_parent(clk->dev);
+ struct rockchip_usb2phy *priv = dev_get_priv(parent);
+ const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg;
+ int ret;
+
+ /* turn on 480m clk output if it is off */
+ if (!property_enabled(priv->reg_base, &phy_cfg->clkout_ctl)) {
+ ret = property_enable(priv->reg_base, &phy_cfg->clkout_ctl, true);
+ if (ret)
+ return ret;
+
+ /* waiting for the clk become stable */
+ usleep_range(1200, 1300);
+ }
+
+ return 0;
+}
+
+/**
+ * disable() - Disable a clock.
+ * @clk: The clock to manipulate.
+ *
+ * Return: zero on success, or -ve error code.
+ */
+int rockchip_usb2phy_clk_disable(struct clk *clk)
+{
+ struct udevice *parent = dev_get_parent(clk->dev);
+ struct rockchip_usb2phy *priv = dev_get_priv(parent);
+ const struct rockchip_usb2phy_cfg *phy_cfg = priv->phy_cfg;
+
+ /* turn off 480m clk output */
+ return property_enable(priv->reg_base, &phy_cfg->clkout_ctl, false);
+}
+
static struct clk_ops rockchip_usb2phy_clk_ops = {
+ .enable = rockchip_usb2phy_clk_enable,
+ .disable = rockchip_usb2phy_clk_disable,
+ .round_rate = rockchip_usb2phy_clk_round_rate
};
static int rockchip_usb2phy_probe(struct udevice *dev)
@@ -245,8 +315,11 @@ static int rockchip_usb2phy_bind(struct udevice *dev)
if (!ret) {
node = dev_ofnode(dev);
- name = ofnode_get_name(node);
- dev_dbg(dev, "clk for node %s\n", name);
+ name = "clk_usbphy_480m";
+ dev_read_string_index(dev, "clock-output-names", 0, &name);
+
+ dev_dbg(dev, "clk %s for node %s\n", name, ofnode_get_name(node));
+
ret = device_bind_driver_to_node(dev, "rockchip_usb2phy_clock",
name, node, &usb2phy_dev);
if (ret) {
@@ -261,6 +334,7 @@ static int rockchip_usb2phy_bind(struct udevice *dev)
static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
{
.reg = 0xe450,
+ .clkout_ctl = { 0xe450, 4, 4, 1, 0 },
.port_cfgs = {
[USB2PHY_PORT_OTG] = {
.phy_sus = { 0xe454, 1, 0, 2, 1 },
@@ -282,6 +356,7 @@ static const struct rockchip_usb2phy_cfg rk3399_usb2phy_cfgs[] = {
},
{
.reg = 0xe460,
+ .clkout_ctl = { 0xe460, 4, 4, 1, 0 },
.port_cfgs = {
[USB2PHY_PORT_OTG] = {
.phy_sus = { 0xe464, 1, 0, 2, 1 },
--
2.20.1
More information about the U-Boot
mailing list