clk: renesas: rcar-gen3: Factor out CPG library
authorHai Pham <hai.pham.ud@renesas.com>
Thu, 26 Jan 2023 20:06:07 +0000 (21:06 +0100)
committerMarek Vasut <marek.vasut+renesas@gmail.com>
Thu, 2 Feb 2023 00:49:20 +0000 (01:49 +0100)
R-Car V3U has a CPG different enough to not be a generic Gen3 CPG but
similar enough to reuse code. Introduce a new CPG library, factor out
the SD clock and RPC clock handling and hook them to the generic Gen3
CPG driver so we have an equal state.

Based on Linux commit [1] and [2] by Wolfram Sang

[1] 8bb67d87346a ("clk: renesas: rcar-gen3: Factor out CPG library")
[2] 6f21d145b90f ("clk: renesas: cpg-lib: Move RPC clock registration to
the library")

Signed-off-by: Hai Pham <hai.pham.ud@renesas.com>
Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Marek: - Add rcar_clk_* prefix to all functions
       - Rebase on changes to
         clk: renesas: Introduce and use rcar_clk_get_rate64_div_table function
       - Use u32_encode_bits/GENMASK bitfield ops

drivers/clk/renesas/Kconfig
drivers/clk/renesas/Makefile
drivers/clk/renesas/clk-rcar-gen3.c
drivers/clk/renesas/rcar-cpg-lib.c [new file with mode: 0644]
drivers/clk/renesas/rcar-cpg-lib.h [new file with mode: 0644]

index a538e7e7aa050ba81ec81b98eba6560572ec9242..1686410d6d3f7feab4c5445205720f3471efbd85 100644 (file)
@@ -4,6 +4,9 @@ config CLK_RENESAS
        help
          Enable support for clock present on Renesas RCar SoCs.
 
+config CLK_RCAR_CPG_LIB
+       bool "CPG/MSSR library functions"
+
 config CLK_RCAR_GEN2
        bool "Renesas RCar Gen2 clock driver"
        def_bool y if RCAR_32
@@ -45,6 +48,7 @@ config CLK_RCAR_GEN3
        bool "Renesas RCar Gen3 clock driver"
        def_bool y if RCAR_GEN3
        depends on CLK_RENESAS
+       select CLK_RCAR_CPG_LIB
        help
          Enable this to support the clocks on Renesas RCar Gen3 SoC.
 
index df6bbc20bc377d35db07eed4c5c6898be9b88734..8f82a7aa3e042c7f1033b86657c9be2ecaaf961d 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_CLK_RENESAS) += renesas-cpg-mssr.o
+obj-$(CONFIG_CLK_RCAR_CPG_LIB) += rcar-cpg-lib.o
 obj-$(CONFIG_CLK_RCAR_GEN2) += clk-rcar-gen2.o
 obj-$(CONFIG_CLK_R8A774A1) += r8a774a1-cpg-mssr.o
 obj-$(CONFIG_CLK_R8A774B1) += r8a774b1-cpg-mssr.o
index f8a23623223507d0ce3ab6ccccf619cd31fe231f..d778db6569d564220c14bef045f32b7a1f3840e2 100644 (file)
 
 #include "renesas-cpg-mssr.h"
 #include "rcar-gen3-cpg.h"
+#include "rcar-cpg-lib.h"
 
 #define CPG_PLL0CR             0x00d8
 #define CPG_PLL2CR             0x002c
 #define CPG_PLL4CR             0x01f4
 
-#define SDnSRCFC_SHIFT         2
-#define STPnHCK_TABLE          (CPG_SDCKCR_STPnHCK >> SDnSRCFC_SHIFT)
-
-/* Non-constant mask variant of FIELD_GET/FIELD_PREP */
-#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
-
 static const struct clk_div_table cpg_rpcsrc_div_table[] = {
        { 2, 5 }, { 3, 6 }, { 0, 0 },
 };
 
-static const struct clk_div_table cpg_rpc_div_table[] = {
-       { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 },
-};
-
-static const struct clk_div_table cpg_sdh_div_table[] = {
-       { 0, 1 }, { 1, 2 }, { STPnHCK_TABLE | 2, 4 }, { STPnHCK_TABLE | 3, 8 },
-       { STPnHCK_TABLE | 4, 16 }, { 0, 0 },
-};
-
-static const struct clk_div_table cpg_sd_div_table[] = {
-       { 0, 2 }, { 1, 4 }, { 0, 0 },
-};
-
 static const struct clk_div_table r8a77970_cpg_sd0h_div_table[] = {
        {  0,  2 }, {  1,  3 }, {  2,  4 }, {  3,  6 },
        {  4,  8 }, {  5, 12 }, {  6, 16 }, {  7, 18 },
@@ -69,48 +51,6 @@ static const struct clk_div_table r8a77970_cpg_sd0_div_table[] = {
        {  0,  0 },
 };
 
-static unsigned int rcar_clk_get_table_div(const struct clk_div_table *table,
-                                          const u32 value)
-{
-       const struct clk_div_table *clkt;
-
-       for (clkt = table; clkt->div; clkt++)
-               if (clkt->val == value)
-                       return clkt->div;
-       return 0;
-}
-
-static int rcar_clk_get_table_val(const struct clk_div_table *table,
-                                 unsigned int div)
-{
-       const struct clk_div_table *clkt;
-
-       for (clkt = table; clkt->div; clkt++)
-               if (clkt->div == div)
-                       return clkt->val;
-       return -EINVAL;
-}
-
-static __always_inline s64
-rcar_clk_get_rate64_div_table(unsigned int parent, u64 parent_rate,
-                             void __iomem *reg, const u32 mask,
-                             const struct clk_div_table *table, char *name)
-{
-       u32 value, div;
-       u64 rate;
-
-       value = field_get(mask, readl(reg));
-       div = rcar_clk_get_table_div(table, value);
-       if (!div)
-               return -EINVAL;
-
-       rate = parent_rate / div;
-       debug("%s[%i] %s clk: parent=%i div=%u => rate=%llu\n",
-             __func__, __LINE__, name, parent, div, rate);
-
-       return rate;
-}
-
 static int gen3_clk_get_parent(struct gen3_clk_priv *priv, struct clk *clk,
                               struct cpg_mssr_info *info, struct clk *parent)
 {
@@ -156,7 +96,6 @@ static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate)
        const struct cpg_core_clk *core;
        struct clk parent, grandparent;
        int ret;
-       u32 value = 0, div = 0;
 
        /*
         * The clk may be either CPG_MOD or core clock, in case this is MOD
@@ -191,45 +130,23 @@ static int gen3_clk_setup_sdif_div(struct clk *clk, ulong rate)
        case CLK_TYPE_GEN3_SDH:
                fallthrough;
        case CLK_TYPE_GEN4_SDH:
-               div = DIV_ROUND_CLOSEST(gen3_clk_get_rate64(&grandparent), rate);
-               value = rcar_clk_get_table_val(cpg_sdh_div_table, div);
-               if (value < 0)
-                       return value;
-
-               clrsetbits_le32(priv->base + core->offset,
-                               GENMASK(9, 2), value << 2);
-
-               debug("%s[%i] SDH clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n",
-                     __func__, __LINE__, core->parent, core->offset, div, rate, value);
-               break;
+               return rcar_clk_set_rate64_sdh(core->parent,
+                                              gen3_clk_get_rate64(&grandparent),
+                                              rate, priv->base + core->offset);
 
        case CLK_TYPE_GEN3_SD:
                fallthrough;
        case CLK_TYPE_GEN4_SD:
-               div = DIV_ROUND_CLOSEST(gen3_clk_get_rate64(&grandparent), rate);
-               value = rcar_clk_get_table_val(cpg_sd_div_table, div);
-               if (value < 0)
-                       return value;
-
-               clrsetbits_le32(priv->base + core->offset,
-                               GENMASK(1, 0), value);
-
-               debug("%s[%i] SD clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n",
-                     __func__, __LINE__, core->parent, core->offset, div, rate, value);
-               break;
+               return rcar_clk_set_rate64_sd(core->parent,
+                                             gen3_clk_get_rate64(&grandparent),
+                                             rate, priv->base + core->offset);
 
        case CLK_TYPE_R8A77970_SD0:
-               div = gen3_clk_get_rate64(&grandparent) / rate;
-               value = rcar_clk_get_table_val(cpg_sd_div_table, div);
-               if (!value)
-                       return -EINVAL;
-
-               clrsetbits_le32(priv->base + core->offset,
-                               GENMASK(7, 4), value << 4);
-
-               debug("%s[%i] SD clk: parent=%i offset=%x div=%u rate=%lu => val=%u\n",
-                     __func__, __LINE__, core->parent, core->offset, div, rate, value);
-               break;
+               return rcar_clk_set_rate64_div_table(core->parent,
+                                                    gen3_clk_get_rate64(&grandparent),
+                                                    rate, priv->base + core->offset,
+                                                    CPG_SDCKCR_SD0FC_MASK,
+                                                    r8a77970_cpg_sd0_div_table, "SD");
        }
 
        return 0;
@@ -371,17 +288,9 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
        case CLK_TYPE_GEN3_SDH: /* Fixed factor 1:1 */
                fallthrough;
        case CLK_TYPE_GEN4_SDH: /* Fixed factor 1:1 */
-               /*
-                * This takes STPnHCK and STPnCK bits into consideration
-                * in the table look up too, hence the inobvious GENMASK
-                * below. Bits [7:5] always read zero, so this is OKish.
-                */
-               return rcar_clk_get_rate64_div_table(core->parent,
-                                                    gen3_clk_get_rate64(&parent),
-                                                    priv->base + core->offset,
-                                                    CPG_SDCKCR_SRCFC_MASK |
-                                                    GENMASK(9, 5),
-                                                    cpg_sdh_div_table, "SDH");
+               return rcar_clk_get_rate64_sdh(core->parent,
+                                              gen3_clk_get_rate64(&parent),
+                                              priv->base + core->offset);
 
        case CLK_TYPE_R8A77970_SD0H:
                return rcar_clk_get_rate64_div_table(core->parent,
@@ -393,11 +302,9 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
        case CLK_TYPE_GEN3_SD:
                fallthrough;
        case CLK_TYPE_GEN4_SD:
-               return rcar_clk_get_rate64_div_table(core->parent,
-                                                    gen3_clk_get_rate64(&parent),
-                                                    priv->base + core->offset,
-                                                    CPG_SDCKCR_FC_MASK,
-                                                    cpg_sd_div_table, "SD");
+               return rcar_clk_get_rate64_sd(core->parent,
+                                             gen3_clk_get_rate64(&parent),
+                                             priv->base + core->offset);
 
        case CLK_TYPE_R8A77970_SD0:
                return rcar_clk_get_rate64_div_table(core->parent,
@@ -446,20 +353,14 @@ static u64 gen3_clk_get_rate64(struct clk *clk)
 
        case CLK_TYPE_GEN3_RPC:
        case CLK_TYPE_GEN4_RPC:
-               return rcar_clk_get_rate64_div_table(core->parent,
-                                                    gen3_clk_get_rate64(&parent),
-                                                    priv->base + CPG_RPCCKCR,
-                                                    CPG_RPCCKCR_DIV_PRE_MASK,
-                                                    cpg_rpc_div_table, "RPC");
+               return rcar_clk_get_rate64_rpc(core->parent,
+                                              gen3_clk_get_rate64(&parent),
+                                              priv->base + CPG_RPCCKCR);
 
        case CLK_TYPE_GEN3_RPCD2:
        case CLK_TYPE_GEN4_RPCD2:
-               rate = gen3_clk_get_rate64(&parent) / 2;
-
-               debug("%s[%i] RPCD2 clk: parent=%i => rate=%llu\n",
-                     __func__, __LINE__, core->parent, rate);
-
-               return rate;
+               return rcar_clk_get_rate64_rpcd2(core->parent,
+                                                gen3_clk_get_rate64(&parent));
 
        }
 
diff --git a/drivers/clk/renesas/rcar-cpg-lib.c b/drivers/clk/renesas/rcar-cpg-lib.c
new file mode 100644 (file)
index 0000000..a2fca66
--- /dev/null
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Renesas RCar Gen3 CPG MSSR driver
+ *
+ * Copyright (C) 2017 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on the following driver from Linux kernel:
+ * r8a7796 Clock Pulse Generator / Module Standby and Software Reset
+ *
+ * Copyright (C) 2016 Glider bvba
+ */
+
+#include <common.h>
+#include <clk-uclass.h>
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <wait_bit.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+
+#include <dt-bindings/clock/renesas-cpg-mssr.h>
+
+#include "renesas-cpg-mssr.h"
+#include "rcar-gen3-cpg.h"
+#include "rcar-cpg-lib.h"
+
+#define SDnSRCFC_SHIFT         2
+#define STPnHCK_TABLE          (CPG_SDCKCR_STPnHCK >> SDnSRCFC_SHIFT)
+
+/* Non-constant mask variant of FIELD_GET/FIELD_PREP */
+#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
+#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))
+
+static const struct clk_div_table cpg_sdh_div_table[] = {
+       { 0, 1 }, { 1, 2 }, { STPnHCK_TABLE | 2, 4 }, { STPnHCK_TABLE | 3, 8 },
+       { STPnHCK_TABLE | 4, 16 }, { 0, 0 },
+};
+
+static const struct clk_div_table cpg_sd_div_table[] = {
+       { 0, 2 }, { 1, 4 }, { 0, 0 },
+};
+
+static const struct clk_div_table cpg_rpc_div_table[] = {
+       { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 },
+};
+
+static unsigned int rcar_clk_get_table_div(const struct clk_div_table *table,
+                                          const u32 value)
+{
+       const struct clk_div_table *clkt;
+
+       for (clkt = table; clkt->div; clkt++)
+               if (clkt->val == value)
+                       return clkt->div;
+       return 0;
+}
+
+static int rcar_clk_get_table_val(const struct clk_div_table *table,
+                                 unsigned int div)
+{
+       const struct clk_div_table *clkt;
+
+       for (clkt = table; clkt->div; clkt++)
+               if (clkt->div == div)
+                       return clkt->val;
+       return -EINVAL;
+}
+
+s64 rcar_clk_get_rate64_div_table(unsigned int parent, u64 parent_rate,
+                                 void __iomem *reg, const u32 mask,
+                                 const struct clk_div_table *table, char *name)
+{
+       u32 value, div;
+       u64 rate;
+
+       value = field_get(mask, readl(reg));
+       div = rcar_clk_get_table_div(table, value);
+       if (!div)
+               return -EINVAL;
+
+       rate = parent_rate / div;
+       debug("%s[%i] %s clk: parent=%i div=%u => rate=%llu\n",
+             __func__, __LINE__, name, parent, div, rate);
+
+       return rate;
+}
+
+int rcar_clk_set_rate64_div_table(unsigned int parent, u64 parent_rate, ulong rate,
+                                 void __iomem *reg, const u32 mask,
+                                 const struct clk_div_table *table, char *name)
+{
+       u32 value = 0, div = 0;
+
+       div = DIV_ROUND_CLOSEST(parent_rate, rate);
+       value = rcar_clk_get_table_val(table, div);
+       if (value < 0)
+               return value;
+
+       clrsetbits_le32(reg, mask, field_prep(mask, value));
+
+       debug("%s[%i] %s clk: parent=%i div=%u rate=%lu => val=%u\n",
+             __func__, __LINE__, name, parent, div, rate, value);
+
+       return 0;
+}
+
+s64 rcar_clk_get_rate64_rpc(unsigned int parent, u64 parent_rate, void __iomem *reg)
+{
+       return rcar_clk_get_rate64_div_table(parent, parent_rate, reg,
+                                            CPG_RPCCKCR_DIV_PRE_MASK,
+                                            cpg_rpc_div_table, "RPC");
+}
+
+u64 rcar_clk_get_rate64_rpcd2(unsigned int parent, u64 parent_rate)
+{
+       u64 rate = 0;
+
+       rate = parent_rate / 2;
+       debug("%s[%i] RPCD2 clk: parent=%i => rate=%llu\n",
+             __func__, __LINE__, parent, rate);
+
+       return rate;
+}
+
+s64 rcar_clk_get_rate64_sdh(unsigned int parent, u64 parent_rate, void __iomem *reg)
+{
+       /*
+        * This takes STPnHCK and STPnCK bits into consideration
+        * in the table look up too, hence the inobvious GENMASK
+        * below. Bits [7:5] always read zero, so this is OKish.
+        */
+       return rcar_clk_get_rate64_div_table(parent, parent_rate, reg,
+                                            CPG_SDCKCR_SRCFC_MASK |
+                                            GENMASK(9, 5),
+                                            cpg_sdh_div_table, "SDH");
+}
+
+s64 rcar_clk_get_rate64_sd(unsigned int parent, u64 parent_rate, void __iomem *reg)
+{
+       return rcar_clk_get_rate64_div_table(parent, parent_rate, reg,
+                                            CPG_SDCKCR_FC_MASK,
+                                            cpg_sd_div_table, "SD");
+}
+
+int rcar_clk_set_rate64_sdh(unsigned int parent, u64 parent_rate, ulong rate,
+                           void __iomem *reg)
+{
+       /*
+        * This takes STPnHCK and STPnCK bits into consideration
+        * in the table look up too, hence the inobvious GENMASK
+        * below. Bits [7:5] always read zero, so this is OKish.
+        */
+       return rcar_clk_set_rate64_div_table(parent, parent_rate, rate, reg,
+                                            CPG_SDCKCR_SRCFC_MASK |
+                                            GENMASK(9, 5),
+                                            cpg_sdh_div_table, "SDH");
+}
+
+int rcar_clk_set_rate64_sd(unsigned int parent, u64 parent_rate, ulong rate,
+                          void __iomem *reg)
+{
+       return rcar_clk_set_rate64_div_table(parent, parent_rate, rate, reg,
+                                            CPG_SDCKCR_FC_MASK,
+                                            cpg_sd_div_table, "SD");
+}
diff --git a/drivers/clk/renesas/rcar-cpg-lib.h b/drivers/clk/renesas/rcar-cpg-lib.h
new file mode 100644 (file)
index 0000000..09b3e50
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * R-Car Gen3 Clock Pulse Generator Library
+ *
+ * Copyright (C) 2015-2018 Glider bvba
+ * Copyright (C) 2019 Renesas Electronics Corp.
+ *
+ * Based on clk-rcar-gen3.c
+ *
+ * Copyright (C) 2015 Renesas Electronics Corp.
+ */
+
+#ifndef __CLK_RENESAS_RCAR_CPG_LIB_H__
+#define __CLK_RENESAS_RCAR_CPG_LIB_H__
+
+s64 rcar_clk_get_rate64_div_table(unsigned int parent, u64 parent_rate,
+                                 void __iomem *reg, const u32 mask,
+                                 const struct clk_div_table *table, char *name);
+
+int rcar_clk_set_rate64_div_table(unsigned int parent, u64 parent_rate, ulong rate,
+                                 void __iomem *reg, const u32 mask,
+                                 const struct clk_div_table *table, char *name);
+
+s64 rcar_clk_get_rate64_sdh(unsigned int parent, u64 parent_rate, void __iomem *reg);
+s64 rcar_clk_get_rate64_sd(unsigned int parent, u64 parent_rate, void __iomem *reg);
+s64 rcar_clk_get_rate64_rpc(unsigned int parent, u64 parent_rate, void __iomem *reg);
+u64 rcar_clk_get_rate64_rpcd2(unsigned int parent, u64 parent_rate);
+int rcar_clk_set_rate64_sdh(unsigned int parent, u64 parent_rate, ulong rate,
+                           void __iomem *reg);
+int rcar_clk_set_rate64_sd(unsigned int parent, u64 parent_rate, ulong rate,
+                          void __iomem *reg);
+
+#endif