.sel_shift = CLK_SPI5_PLL_SEL_SHIFT, },
};
-static inline u32 extract_bits(u32 val, unsigned width, unsigned shift)
-{
- return (val >> shift) & ((1 << width) - 1);
-}
-
static ulong rk3399_spi_get_clk(struct rk3399_cru *cru, ulong clk_id)
{
const struct spi_clkreg *spiclk = NULL;
}
val = readl(&cru->clksel_con[spiclk->reg]);
- div = extract_bits(val, CLK_SPI_PLL_DIV_CON_WIDTH, spiclk->div_shift);
+ div = bitfield_extract(val, spiclk->div_shift,
+ CLK_SPI_PLL_DIV_CON_WIDTH);
return DIV_TO_RATE(GPLL_HZ, div);
}
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)
switch (clk->id) {
case 0 ... 63:
return 0;
+
+ case ACLK_PERIHP:
+ case HCLK_PERIHP:
+ case PCLK_PERIHP:
+ return 0;
+
+ case ACLK_PERILP0:
+ case HCLK_PERILP0:
+ case PCLK_PERILP0:
+ return 0;
+
+ case ACLK_CCI:
+ return 0;
+
+ case HCLK_PERILP1:
+ case PCLK_PERILP1:
+ return 0;
+
case HCLK_SDMMC:
case SCLK_SDMMC:
case SCLK_EMMC:
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:
return ret;
}
+static int __maybe_unused 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 __maybe_unused 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) {
static struct clk_ops rk3399_clk_ops = {
.get_rate = rk3399_clk_get_rate,
.set_rate = rk3399_clk_set_rate,
+#if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
+ .set_parent = rk3399_clk_set_parent,
+#endif
.enable = rk3399_clk_enable,
};
sys_child->priv = priv;
}
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+ ret = offsetof(struct rk3399_cru, softrst_con[0]);
+ ret = rockchip_reset_bind(dev, ret, 21);
+ if (ret)
+ debug("Warning: software reset driver bind faile\n");
+#endif
+
return 0;
}
return 0;
}
+static int rk3399_pmuclk_bind(struct udevice *dev)
+{
+#if CONFIG_IS_ENABLED(CONFIG_RESET_ROCKCHIP)
+ int ret;
+
+ ret = offsetof(struct rk3399_pmucru, pmucru_softrst_con[0]);
+ ret = rockchip_reset_bind(dev, ret, 2);
+ if (ret)
+ debug("Warning: software reset driver bind faile\n");
+#endif
+ return 0;
+}
+
static const struct udevice_id rk3399_pmuclk_ids[] = {
{ .compatible = "rockchip,rk3399-pmucru" },
{ }
.ofdata_to_platdata = rk3399_pmuclk_ofdata_to_platdata,
.ops = &rk3399_pmuclk_ops,
.probe = rk3399_pmuclk_probe,
+ .bind = rk3399_pmuclk_bind,
#if CONFIG_IS_ENABLED(OF_PLATDATA)
.platdata_auto_alloc_size = sizeof(struct rk3399_pmuclk_plat),
#endif