aboutsummaryrefslogtreecommitdiff
path: root/drivers/clk
diff options
context:
space:
mode:
authorPhilipp Tomsich2018-01-08 13:11:01 +0100
committerPhilipp Tomsich2018-01-28 17:12:36 +0100
commita45f17e8b9f91628936349ef40a06d10dc9c08ae (patch)
treefaeaa41207f5caf4c7e4ce9fe69c75f0df5a2456 /drivers/clk
parent95f9a7e5957093612b1e8447ac5460a6adcea3ba (diff)
rockchip: clk: rk3399: implement set_parent() operation
This implements the (newly added) set_parent() operation for the RK3399 with a focus on allowing the RGMII clock parent to be configured via the assigned-clock-parents property of the GMAC node. This implementation supports only the GMAC (in fact only the RGMII clock parent) and allows to set this clock's parent either to the internal SCLK_GMAC or to an external clock input (identifiable by it providing a 'clock-output-name' of "gmac_clkin"). Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com> Tested-by: David Wu <david.wu@rock-chips.com> Series-changes: 2 - Fixed David's email address.
Diffstat (limited to 'drivers/clk')
-rw-r--r--drivers/clk/rockchip/clk_rk3399.c74
1 files changed, 72 insertions, 2 deletions
diff --git a/drivers/clk/rockchip/clk_rk3399.c b/drivers/clk/rockchip/clk_rk3399.c
index 2f4c4e343cf..e791936dbb1 100644
--- a/drivers/clk/rockchip/clk_rk3399.c
+++ b/drivers/clk/rockchip/clk_rk3399.c
@@ -742,6 +742,30 @@ static ulong rk3399_mmc_set_clk(struct rk3399_cru *cru,
return rk3399_mmc_get_clk(cru, clk_id);
}
+static ulong rk3399_gmac_set_clk(struct rk3399_cru *cru, ulong rate)
+{
+ ulong ret;
+
+ /*
+ * The RGMII CLK can be derived either from an external "clkin"
+ * or can be generated from internally by a divider from SCLK_MAC.
+ */
+ if (readl(&cru->clksel_con[19]) & BIT(4)) {
+ /* An external clock will always generate the right rate... */
+ ret = rate;
+ } else {
+ /*
+ * No platform uses an internal clock to date.
+ * Implement this once it becomes necessary and print an error
+ * if someone tries to use it (while it remains unimplemented).
+ */
+ pr_err("%s: internal clock is UNIMPLEMENTED\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
#define PMUSGRF_DDR_RGN_CON16 0xff330040
static ulong rk3399_ddr_set_clk(struct rk3399_cru *cru,
ulong set_rate)
@@ -865,8 +889,7 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
ret = rk3399_mmc_set_clk(priv->cru, clk->id, rate);
break;
case SCLK_MAC:
- /* nothing to do, as this is an external clock */
- ret = rate;
+ ret = rk3399_gmac_set_clk(priv->cru, rate);
break;
case SCLK_I2C1:
case SCLK_I2C2:
@@ -902,6 +925,52 @@ static ulong rk3399_clk_set_rate(struct clk *clk, ulong rate)
return ret;
}
+static int rk3399_gmac_set_parent(struct clk *clk, struct clk *parent)
+{
+ struct rk3399_clk_priv *priv = dev_get_priv(clk->dev);
+ const char *clock_output_name;
+ int ret;
+
+ /*
+ * If the requested parent is in the same clock-controller and
+ * the id is SCLK_MAC ("clk_gmac"), switch to the internal clock.
+ */
+ if ((parent->dev == clk->dev) && (parent->id == SCLK_MAC)) {
+ debug("%s: switching RGMII to SCLK_MAC\n", __func__);
+ rk_clrreg(&priv->cru->clksel_con[19], BIT(4));
+ return 0;
+ }
+
+ /*
+ * Otherwise, we need to check the clock-output-names of the
+ * requested parent to see if the requested id is "clkin_gmac".
+ */
+ ret = dev_read_string_index(parent->dev, "clock-output-names",
+ parent->id, &clock_output_name);
+ if (ret < 0)
+ return -ENODATA;
+
+ /* If this is "clkin_gmac", switch to the external clock input */
+ if (!strcmp(clock_output_name, "clkin_gmac")) {
+ debug("%s: switching RGMII to CLKIN\n", __func__);
+ rk_setreg(&priv->cru->clksel_con[19], BIT(4));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int rk3399_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ switch (clk->id) {
+ case SCLK_RMII_SRC:
+ return rk3399_gmac_set_parent(clk, parent);
+ }
+
+ debug("%s: unsupported clk %ld\n", __func__, clk->id);
+ return -ENOENT;
+}
+
static int rk3399_clk_enable(struct clk *clk)
{
switch (clk->id) {
@@ -919,6 +988,7 @@ static int rk3399_clk_enable(struct clk *clk)
static struct clk_ops rk3399_clk_ops = {
.get_rate = rk3399_clk_get_rate,
.set_rate = rk3399_clk_set_rate,
+ .set_parent = rk3399_clk_set_parent,
.enable = rk3399_clk_enable,
};