summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/.kunitconfig1
-rw-r--r--drivers/clk/Kconfig7
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-cdce925.c2
-rw-r--r--drivers/clk/clk-fractional-divider.c27
-rw-r--r--drivers/clk/clk-fractional-divider_test.c147
-rw-r--r--drivers/clk/clk-gate_test.c30
-rw-r--r--drivers/clk/clk-si514.c2
-rw-r--r--drivers/clk/clk-si5341.c2
-rw-r--r--drivers/clk/clk-si5351.c2
-rw-r--r--drivers/clk/clk-si544.c2
-rw-r--r--drivers/clk/clk-si570.c2
-rw-r--r--drivers/clk/clk-versaclock3.c8
-rw-r--r--drivers/clk/clk-versaclock5.c2
-rw-r--r--drivers/clk/clk-versaclock7.c2
-rw-r--r--drivers/clk/clk_test.c130
-rw-r--r--drivers/clk/renesas/Kconfig7
-rw-r--r--drivers/clk/renesas/Makefile1
-rw-r--r--drivers/clk/renesas/r8a7795-cpg-mssr.c4
-rw-r--r--drivers/clk/renesas/r9a06g032-clocks.c69
-rw-r--r--drivers/clk/renesas/r9a07g043-cpg.c19
-rw-r--r--drivers/clk/renesas/r9a07g044-cpg.c19
-rw-r--r--drivers/clk/renesas/r9a08g045-cpg.c248
-rw-r--r--drivers/clk/renesas/rcar-cpg-lib.c15
-rw-r--r--drivers/clk/renesas/rzg2l-cpg.c467
-rw-r--r--drivers/clk/renesas/rzg2l-cpg.h39
26 files changed, 1071 insertions, 184 deletions
diff --git a/drivers/clk/.kunitconfig b/drivers/clk/.kunitconfig
index 2fbeb71316f8..efa12ac2b3f2 100644
--- a/drivers/clk/.kunitconfig
+++ b/drivers/clk/.kunitconfig
@@ -2,4 +2,5 @@ CONFIG_KUNIT=y
CONFIG_COMMON_CLK=y
CONFIG_CLK_KUNIT_TEST=y
CONFIG_CLK_GATE_KUNIT_TEST=y
+CONFIG_CLK_FD_KUNIT_TEST=y
CONFIG_UML_PCI_OVER_VIRTIO=n
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3944f081ebad..c30d0d396f7a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -526,4 +526,11 @@ config CLK_GATE_KUNIT_TEST
help
Kunit test for the basic clk gate type.
+config CLK_FD_KUNIT_TEST
+ tristate "Basic fractional divider type Kunit test" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Kunit test for the clk-fractional-divider type.
+
endif
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 86e46adcb619..ed71f2e0ee36 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
+obj-$(CONFIG_CLK_FD_KUNIT_TEST) += clk-fractional-divider_test.o
obj-$(CONFIG_COMMON_CLK) += clk-gpio.o
ifeq ($(CONFIG_OF), y)
obj-$(CONFIG_COMMON_CLK) += clk-conf.o
diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c
index cdee4958f26d..5ffaf1255ff7 100644
--- a/drivers/clk/clk-cdce925.c
+++ b/drivers/clk/clk-cdce925.c
@@ -647,7 +647,7 @@ static int cdce925_probe(struct i2c_client *client)
.name = "configuration0",
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
};
dev_dbg(&client->dev, "%s\n", __func__);
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
index 479297763e70..5067e067e906 100644
--- a/drivers/clk/clk-fractional-divider.c
+++ b/drivers/clk/clk-fractional-divider.c
@@ -123,6 +123,7 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw,
unsigned long *m, unsigned long *n)
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
+ unsigned long max_m, max_n;
/*
* Get rate closer to *parent_rate to guarantee there is no overflow
@@ -138,10 +139,17 @@ void clk_fractional_divider_general_approximation(struct clk_hw *hw,
rate <<= scale - fd->nwidth;
}
- rational_best_approximation(rate, *parent_rate,
- GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
- m, n);
+ if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
+ max_m = 1 << fd->mwidth;
+ max_n = 1 << fd->nwidth;
+ } else {
+ max_m = GENMASK(fd->mwidth - 1, 0);
+ max_n = GENMASK(fd->nwidth - 1, 0);
+ }
+
+ rational_best_approximation(rate, *parent_rate, max_m, max_n, m, n);
}
+EXPORT_SYMBOL_GPL(clk_fractional_divider_general_approximation);
static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
@@ -169,13 +177,18 @@ static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
{
struct clk_fractional_divider *fd = to_clk_fd(hw);
unsigned long flags = 0;
- unsigned long m, n;
+ unsigned long m, n, max_m, max_n;
u32 mmask, nmask;
u32 val;
- rational_best_approximation(rate, parent_rate,
- GENMASK(fd->mwidth - 1, 0), GENMASK(fd->nwidth - 1, 0),
- &m, &n);
+ if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
+ max_m = 1 << fd->mwidth;
+ max_n = 1 << fd->nwidth;
+ } else {
+ max_m = GENMASK(fd->mwidth - 1, 0);
+ max_n = GENMASK(fd->nwidth - 1, 0);
+ }
+ rational_best_approximation(rate, parent_rate, max_m, max_n, &m, &n);
if (fd->flags & CLK_FRAC_DIVIDER_ZERO_BASED) {
m--;
diff --git a/drivers/clk/clk-fractional-divider_test.c b/drivers/clk/clk-fractional-divider_test.c
new file mode 100644
index 000000000000..929eec927548
--- /dev/null
+++ b/drivers/clk/clk-fractional-divider_test.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kunit test for clock fractional divider
+ */
+#include <linux/clk-provider.h>
+#include <kunit/test.h>
+
+#include "clk-fractional-divider.h"
+
+/*
+ * Test the maximum denominator case for fd clock without flags.
+ *
+ * Expect the highest possible denominator to be used in order to get as close as possible to the
+ * requested rate.
+ */
+static void clk_fd_test_approximation_max_denominator(struct kunit *test)
+{
+ struct clk_fractional_divider *fd;
+ unsigned long rate, parent_rate, parent_rate_before, m, n, max_n;
+
+ fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fd);
+
+ fd->mwidth = 3;
+ fd->nwidth = 3;
+ max_n = 7;
+
+ rate = 240000000;
+ parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */
+ parent_rate_before = parent_rate;
+
+ clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n);
+ KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before);
+
+ KUNIT_EXPECT_EQ(test, m, 1);
+ KUNIT_EXPECT_EQ(test, n, max_n);
+}
+
+/*
+ * Test the maximum numerator case for fd clock without flags.
+ *
+ * Expect the highest possible numerator to be used in order to get as close as possible to the
+ * requested rate.
+ */
+static void clk_fd_test_approximation_max_numerator(struct kunit *test)
+{
+ struct clk_fractional_divider *fd;
+ unsigned long rate, parent_rate, parent_rate_before, m, n, max_m;
+
+ fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fd);
+
+ fd->mwidth = 3;
+ max_m = 7;
+ fd->nwidth = 3;
+
+ rate = 240000000;
+ parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */
+ parent_rate_before = parent_rate;
+
+ clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n);
+ KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before);
+
+ KUNIT_EXPECT_EQ(test, m, max_m);
+ KUNIT_EXPECT_EQ(test, n, 1);
+}
+
+/*
+ * Test the maximum denominator case for zero based fd clock.
+ *
+ * Expect the highest possible denominator to be used in order to get as close as possible to the
+ * requested rate.
+ */
+static void clk_fd_test_approximation_max_denominator_zero_based(struct kunit *test)
+{
+ struct clk_fractional_divider *fd;
+ unsigned long rate, parent_rate, parent_rate_before, m, n, max_n;
+
+ fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fd);
+
+ fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
+ fd->mwidth = 3;
+ fd->nwidth = 3;
+ max_n = 8;
+
+ rate = 240000000;
+ parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */
+ parent_rate_before = parent_rate;
+
+ clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n);
+ KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before);
+
+ KUNIT_EXPECT_EQ(test, m, 1);
+ KUNIT_EXPECT_EQ(test, n, max_n);
+}
+
+/*
+ * Test the maximum numerator case for zero based fd clock.
+ *
+ * Expect the highest possible numerator to be used in order to get as close as possible to the
+ * requested rate.
+ */
+static void clk_fd_test_approximation_max_numerator_zero_based(struct kunit *test)
+{
+ struct clk_fractional_divider *fd;
+ unsigned long rate, parent_rate, parent_rate_before, m, n, max_m;
+
+ fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fd);
+
+ fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
+ fd->mwidth = 3;
+ max_m = 8;
+ fd->nwidth = 3;
+
+ rate = 240000000;
+ parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */
+ parent_rate_before = parent_rate;
+
+ clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n);
+ KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before);
+
+ KUNIT_EXPECT_EQ(test, m, max_m);
+ KUNIT_EXPECT_EQ(test, n, 1);
+}
+
+static struct kunit_case clk_fd_approximation_test_cases[] = {
+ KUNIT_CASE(clk_fd_test_approximation_max_denominator),
+ KUNIT_CASE(clk_fd_test_approximation_max_numerator),
+ KUNIT_CASE(clk_fd_test_approximation_max_denominator_zero_based),
+ KUNIT_CASE(clk_fd_test_approximation_max_numerator_zero_based),
+ {}
+};
+
+/*
+ * Test suite for clk_fractional_divider_general_approximation().
+ */
+static struct kunit_suite clk_fd_approximation_suite = {
+ .name = "clk-fd-approximation",
+ .test_cases = clk_fd_approximation_test_cases,
+};
+
+kunit_test_suites(
+ &clk_fd_approximation_suite
+);
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-gate_test.c b/drivers/clk/clk-gate_test.c
index e136aaad48bf..c96d93b19ddf 100644
--- a/drivers/clk/clk-gate_test.c
+++ b/drivers/clk/clk-gate_test.c
@@ -131,7 +131,7 @@ struct clk_gate_test_context {
void __iomem *fake_mem;
struct clk_hw *hw;
struct clk_hw *parent;
- u32 fake_reg; /* Keep at end, KASAN can detect out of bounds */
+ __le32 fake_reg; /* Keep at end, KASAN can detect out of bounds */
};
static struct clk_gate_test_context *clk_gate_test_alloc_ctx(struct kunit *test)
@@ -166,7 +166,7 @@ static void clk_gate_test_enable(struct kunit *test)
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
- KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
+ KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
@@ -183,10 +183,10 @@ static void clk_gate_test_disable(struct kunit *test)
u32 disable_val = 0;
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
- KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
+ KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
clk_disable_unprepare(clk);
- KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
+ KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg));
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
@@ -246,7 +246,7 @@ static void clk_gate_test_invert_enable(struct kunit *test)
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
- KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
+ KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
@@ -263,10 +263,10 @@ static void clk_gate_test_invert_disable(struct kunit *test)
u32 disable_val = BIT(15);
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
- KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
+ KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
clk_disable_unprepare(clk);
- KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
+ KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg));
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
@@ -290,7 +290,7 @@ static int clk_gate_test_invert_init(struct kunit *test)
2000000);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
- ctx->fake_reg = BIT(15); /* Default to off */
+ ctx->fake_reg = cpu_to_le32(BIT(15)); /* Default to off */
hw = clk_hw_register_gate_parent_hw(NULL, "test_gate", parent, 0,
ctx->fake_mem, 15,
CLK_GATE_SET_TO_DISABLE, NULL);
@@ -319,7 +319,7 @@ static void clk_gate_test_hiword_enable(struct kunit *test)
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
- KUNIT_EXPECT_EQ(test, enable_val, ctx->fake_reg);
+ KUNIT_EXPECT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(hw));
KUNIT_EXPECT_TRUE(test, clk_hw_is_prepared(hw));
KUNIT_EXPECT_TRUE(test, clk_hw_is_enabled(parent));
@@ -336,10 +336,10 @@ static void clk_gate_test_hiword_disable(struct kunit *test)
u32 disable_val = BIT(9 + 16);
KUNIT_ASSERT_EQ(test, clk_prepare_enable(clk), 0);
- KUNIT_ASSERT_EQ(test, enable_val, ctx->fake_reg);
+ KUNIT_ASSERT_EQ(test, enable_val, le32_to_cpu(ctx->fake_reg));
clk_disable_unprepare(clk);
- KUNIT_EXPECT_EQ(test, disable_val, ctx->fake_reg);
+ KUNIT_EXPECT_EQ(test, disable_val, le32_to_cpu(ctx->fake_reg));
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(hw));
KUNIT_EXPECT_FALSE(test, clk_hw_is_prepared(hw));
KUNIT_EXPECT_FALSE(test, clk_hw_is_enabled(parent));
@@ -387,7 +387,7 @@ static void clk_gate_test_is_enabled(struct kunit *test)
struct clk_gate_test_context *ctx;
ctx = clk_gate_test_alloc_ctx(test);
- ctx->fake_reg = BIT(7);
+ ctx->fake_reg = cpu_to_le32(BIT(7));
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
0, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
@@ -402,7 +402,7 @@ static void clk_gate_test_is_disabled(struct kunit *test)
struct clk_gate_test_context *ctx;
ctx = clk_gate_test_alloc_ctx(test);
- ctx->fake_reg = BIT(4);
+ ctx->fake_reg = cpu_to_le32(BIT(4));
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 7,
0, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
@@ -417,7 +417,7 @@ static void clk_gate_test_is_enabled_inverted(struct kunit *test)
struct clk_gate_test_context *ctx;
ctx = clk_gate_test_alloc_ctx(test);
- ctx->fake_reg = BIT(31);
+ ctx->fake_reg = cpu_to_le32(BIT(31));
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 2,
CLK_GATE_SET_TO_DISABLE, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
@@ -432,7 +432,7 @@ static void clk_gate_test_is_disabled_inverted(struct kunit *test)
struct clk_gate_test_context *ctx;
ctx = clk_gate_test_alloc_ctx(test);
- ctx->fake_reg = BIT(29);
+ ctx->fake_reg = cpu_to_le32(BIT(29));
hw = clk_hw_register_gate(NULL, "test_gate", NULL, 0, ctx->fake_mem, 29,
CLK_GATE_SET_TO_DISABLE, NULL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hw);
diff --git a/drivers/clk/clk-si514.c b/drivers/clk/clk-si514.c
index e8c18afac184..6ee148e5469d 100644
--- a/drivers/clk/clk-si514.c
+++ b/drivers/clk/clk-si514.c
@@ -321,7 +321,7 @@ static bool si514_regmap_is_writeable(struct device *dev, unsigned int reg)
static const struct regmap_config si514_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = SI514_REG_CONTROL,
.writeable_reg = si514_regmap_is_writeable,
.volatile_reg = si514_regmap_is_volatile,
diff --git a/drivers/clk/clk-si5341.c b/drivers/clk/clk-si5341.c
index 9599857842c7..845b451511d2 100644
--- a/drivers/clk/clk-si5341.c
+++ b/drivers/clk/clk-si5341.c
@@ -1260,7 +1260,7 @@ static int si5341_wait_device_ready(struct i2c_client *client)
static const struct regmap_config si5341_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.ranges = si5341_regmap_ranges,
.num_ranges = ARRAY_SIZE(si5341_regmap_ranges),
.max_register = SI5341_REGISTER_MAX,
diff --git a/drivers/clk/clk-si5351.c b/drivers/clk/clk-si5351.c
index 00fb9b09e030..cbf7cde01157 100644
--- a/drivers/clk/clk-si5351.c
+++ b/drivers/clk/clk-si5351.c
@@ -206,7 +206,7 @@ static bool si5351_regmap_is_writeable(struct device *dev, unsigned int reg)
static const struct regmap_config si5351_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = 187,
.writeable_reg = si5351_regmap_is_writeable,
.volatile_reg = si5351_regmap_is_volatile,
diff --git a/drivers/clk/clk-si544.c b/drivers/clk/clk-si544.c
index 22925968aa35..c4288cf83f9f 100644
--- a/drivers/clk/clk-si544.c
+++ b/drivers/clk/clk-si544.c
@@ -446,7 +446,7 @@ static bool si544_regmap_is_volatile(struct device *dev, unsigned int reg)
static const struct regmap_config si544_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = SI544_REG_PAGE_SELECT,
.volatile_reg = si544_regmap_is_volatile,
};
diff --git a/drivers/clk/clk-si570.c b/drivers/clk/clk-si570.c
index de0212fb5f87..262f582c9213 100644
--- a/drivers/clk/clk-si570.c
+++ b/drivers/clk/clk-si570.c
@@ -392,7 +392,7 @@ static bool si570_regmap_is_writeable(struct device *dev, unsigned int reg)
static const struct regmap_config si570_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = 137,
.writeable_reg = si570_regmap_is_writeable,
.volatile_reg = si570_regmap_is_volatile,
diff --git a/drivers/clk/clk-versaclock3.c b/drivers/clk/clk-versaclock3.c
index 3d7de355f8f6..00930d7bca77 100644
--- a/drivers/clk/clk-versaclock3.c
+++ b/drivers/clk/clk-versaclock3.c
@@ -585,17 +585,11 @@ static const struct clk_ops vc3_clk_mux_ops = {
.get_parent = vc3_clk_mux_get_parent,
};
-static bool vc3_regmap_is_writeable(struct device *dev, unsigned int reg)
-{
- return true;
-}
-
static const struct regmap_config vc3_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = 0x24,
- .writeable_reg = vc3_regmap_is_writeable,
};
static struct vc3_hw_data clk_div[5];
diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c
index 17cbb30d20ad..6d31cd54d7cf 100644
--- a/drivers/clk/clk-versaclock5.c
+++ b/drivers/clk/clk-versaclock5.c
@@ -217,7 +217,7 @@ static bool vc5_regmap_is_writeable(struct device *dev, unsigned int reg)
static const struct regmap_config vc5_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.max_register = 0x76,
.writeable_reg = vc5_regmap_is_writeable,
};
diff --git a/drivers/clk/clk-versaclock7.c b/drivers/clk/clk-versaclock7.c
index 9ab35c1af0ff..f323263e32c3 100644
--- a/drivers/clk/clk-versaclock7.c
+++ b/drivers/clk/clk-versaclock7.c
@@ -1275,7 +1275,7 @@ static const struct regmap_config vc7_regmap_config = {
.ranges = vc7_range_cfg,
.num_ranges = ARRAY_SIZE(vc7_range_cfg),
.volatile_reg = vc7_volatile_reg,
- .cache_type = REGCACHE_RBTREE,
+ .cache_type = REGCACHE_MAPLE,
.can_multi_write = true,
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index a154ec9d0111..39e2b5ff4f51 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -10,6 +10,8 @@
#include <kunit/test.h>
+static const struct clk_ops empty_clk_ops = { };
+
#define DUMMY_CLOCK_INIT_RATE (42 * 1000 * 1000)
#define DUMMY_CLOCK_RATE_1 (142 * 1000 * 1000)
#define DUMMY_CLOCK_RATE_2 (242 * 1000 * 1000)
@@ -2155,6 +2157,31 @@ static struct kunit_suite clk_range_minimize_test_suite = {
struct clk_leaf_mux_ctx {
struct clk_multiple_parent_ctx mux_ctx;
struct clk_hw hw;
+ struct clk_hw parent;
+ struct clk_rate_request *req;
+ int (*determine_rate_func)(struct clk_hw *hw, struct clk_rate_request *req);
+};
+
+static int clk_leaf_mux_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ struct clk_leaf_mux_ctx *ctx = container_of(hw, struct clk_leaf_mux_ctx, hw);
+ int ret;
+ struct clk_rate_request *parent_req = ctx->req;
+
+ clk_hw_forward_rate_request(hw, req, req->best_parent_hw, parent_req, req->rate);
+ ret = ctx->determine_rate_func(req->best_parent_hw, parent_req);
+ if (ret)
+ return ret;
+
+ req->rate = parent_req->rate;
+
+ return 0;
+}
+
+static const struct clk_ops clk_leaf_mux_set_rate_parent_ops = {
+ .determine_rate = clk_leaf_mux_determine_rate,
+ .set_parent = clk_dummy_single_set_parent,
+ .get_parent = clk_dummy_single_get_parent,
};
static int
@@ -2193,8 +2220,14 @@ clk_leaf_mux_set_rate_parent_test_init(struct kunit *test)
if (ret)
return ret;
- ctx->hw.init = CLK_HW_INIT_HW("test-clock", &ctx->mux_ctx.hw,
- &clk_dummy_single_parent_ops,
+ ctx->parent.init = CLK_HW_INIT_HW("test-parent", &ctx->mux_ctx.hw,
+ &empty_clk_ops, CLK_SET_RATE_PARENT);
+ ret = clk_hw_register(NULL, &ctx->parent);
+ if (ret)
+ return ret;
+
+ ctx->hw.init = CLK_HW_INIT_HW("test-clock", &ctx->parent,
+ &clk_leaf_mux_set_rate_parent_ops,
CLK_SET_RATE_PARENT);
ret = clk_hw_register(NULL, &ctx->hw);
if (ret)
@@ -2208,32 +2241,94 @@ static void clk_leaf_mux_set_rate_parent_test_exit(struct kunit *test)
struct clk_leaf_mux_ctx *ctx = test->priv;
clk_hw_unregister(&ctx->hw);
+ clk_hw_unregister(&ctx->parent);
clk_hw_unregister(&ctx->mux_ctx.hw);
clk_hw_unregister(&ctx->mux_ctx.parents_ctx[0].hw);
clk_hw_unregister(&ctx->mux_ctx.parents_ctx[1].hw);
}
+struct clk_leaf_mux_set_rate_parent_determine_rate_test_case {
+ const char *desc;
+ int (*determine_rate_func)(struct clk_hw *hw, struct clk_rate_request *req);
+};
+
+static void
+clk_leaf_mux_set_rate_parent_determine_rate_test_case_to_desc(
+ const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case *t, char *desc)
+{
+ strcpy(desc, t->desc);
+}
+
+static const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case
+clk_leaf_mux_set_rate_parent_determine_rate_test_cases[] = {
+ {
+ /*
+ * Test that __clk_determine_rate() on the parent that can't
+ * change rate doesn't return a clk_rate_request structure with
+ * the best_parent_hw pointer pointing to the parent.
+ */
+ .desc = "clk_leaf_mux_set_rate_parent__clk_determine_rate_proper_parent",
+ .determine_rate_func = __clk_determine_rate,
+ },
+ {
+ /*
+ * Test that __clk_mux_determine_rate() on the parent that
+ * can't change rate doesn't return a clk_rate_request
+ * structure with the best_parent_hw pointer pointing to
+ * the parent.
+ */
+ .desc = "clk_leaf_mux_set_rate_parent__clk_mux_determine_rate_proper_parent",
+ .determine_rate_func = __clk_mux_determine_rate,
+ },
+ {
+ /*
+ * Test that __clk_mux_determine_rate_closest() on the parent
+ * that can't change rate doesn't return a clk_rate_request
+ * structure with the best_parent_hw pointer pointing to
+ * the parent.
+ */
+ .desc = "clk_leaf_mux_set_rate_parent__clk_mux_determine_rate_closest_proper_parent",
+ .determine_rate_func = __clk_mux_determine_rate_closest,
+ },
+ {
+ /*
+ * Test that clk_hw_determine_rate_no_reparent() on the parent
+ * that can't change rate doesn't return a clk_rate_request
+ * structure with the best_parent_hw pointer pointing to
+ * the parent.
+ */
+ .desc = "clk_leaf_mux_set_rate_parent_clk_hw_determine_rate_no_reparent_proper_parent",
+ .determine_rate_func = clk_hw_determine_rate_no_reparent,
+ },
+};
+
+KUNIT_ARRAY_PARAM(clk_leaf_mux_set_rate_parent_determine_rate_test,
+ clk_leaf_mux_set_rate_parent_determine_rate_test_cases,
+ clk_leaf_mux_set_rate_parent_determine_rate_test_case_to_desc)
+
/*
- * Test that, for a clock that will forward any rate request to its
- * parent, the rate request structure returned by __clk_determine_rate
- * is sane and will be what we expect.
+ * Test that when a clk that can't change rate itself calls a function like
+ * __clk_determine_rate() on its parent it doesn't get back a clk_rate_request
+ * structure that has the best_parent_hw pointer point to the clk_hw passed
+ * into the determine rate function. See commit 262ca38f4b6e ("clk: Stop
+ * forwarding clk_rate_requests to the parent") for more background.
*/
-static void clk_leaf_mux_set_rate_parent_determine_rate(struct kunit *test)
+static void clk_leaf_mux_set_rate_parent_determine_rate_test(struct kunit *test)
{
struct clk_leaf_mux_ctx *ctx = test->priv;
struct clk_hw *hw = &ctx->hw;
struct clk *clk = clk_hw_get_clk(hw, NULL);
struct clk_rate_request req;
unsigned long rate;
- int ret;
+ const struct clk_leaf_mux_set_rate_parent_determine_rate_test_case *test_param;
+
+ test_param = test->param_value;
+ ctx->determine_rate_func = test_param->determine_rate_func;
+ ctx->req = &req;
rate = clk_get_rate(clk);
KUNIT_ASSERT_EQ(test, rate, DUMMY_CLOCK_RATE_1);
-
- clk_hw_init_rate_request(hw, &req, DUMMY_CLOCK_RATE_2);
-
- ret = __clk_determine_rate(hw, &req);
- KUNIT_ASSERT_EQ(test, ret, 0);
+ KUNIT_ASSERT_EQ(test, DUMMY_CLOCK_RATE_2, clk_round_rate(clk, DUMMY_CLOCK_RATE_2));
KUNIT_EXPECT_EQ(test, req.rate, DUMMY_CLOCK_RATE_2);
KUNIT_EXPECT_EQ(test, req.best_parent_rate, DUMMY_CLOCK_RATE_2);
@@ -2243,15 +2338,16 @@ static void clk_leaf_mux_set_rate_parent_determine_rate(struct kunit *test)
}
static struct kunit_case clk_leaf_mux_set_rate_parent_test_cases[] = {
- KUNIT_CASE(clk_leaf_mux_set_rate_parent_determine_rate),
+ KUNIT_CASE_PARAM(clk_leaf_mux_set_rate_parent_determine_rate_test,
+ clk_leaf_mux_set_rate_parent_determine_rate_test_gen_params),
{}
};
/*
- * Test suite for a clock whose parent is a mux with multiple parents.
- * The leaf clock has CLK_SET_RATE_PARENT, and will forward rate
- * requests to the mux, which will then select which parent is the best
- * fit for a given rate.
+ * Test suite for a clock whose parent is a pass-through clk whose parent is a
+ * mux with multiple parents. The leaf and pass-through clocks have the
+ * CLK_SET_RATE_PARENT flag, and will forward rate requests to the mux, which
+ * will then select which parent is the best fit for a given rate.
*
* These tests exercise the behaviour of muxes, and the proper selection
* of parents.
diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig
index 37632a0659d8..69396e197959 100644
--- a/drivers/clk/renesas/Kconfig
+++ b/drivers/clk/renesas/Kconfig
@@ -37,6 +37,7 @@ config CLK_RENESAS
select CLK_R9A07G043 if ARCH_R9A07G043
select CLK_R9A07G044 if ARCH_R9A07G044
select CLK_R9A07G054 if ARCH_R9A07G054
+ select CLK_R9A08G045 if ARCH_R9A08G045
select CLK_R9A09G011 if ARCH_R9A09G011
select CLK_SH73A0 if ARCH_SH73A0
@@ -179,6 +180,10 @@ config CLK_R9A07G054
bool "RZ/V2L clock support" if COMPILE_TEST
select CLK_RZG2L
+config CLK_R9A08G045
+ bool "RZ/G3S clock support" if COMPILE_TEST
+ select CLK_RZG2L
+
config CLK_R9A09G011
bool "RZ/V2M clock support" if COMPILE_TEST
select CLK_RZG2L
@@ -215,7 +220,7 @@ config CLK_RCAR_USB2_CLOCK_SEL
This is a driver for R-Car USB2 clock selector
config CLK_RZG2L
- bool "Renesas RZ/{G2L,G2UL,V2L} family clock support" if COMPILE_TEST
+ bool "Renesas RZ/{G2L,G2UL,G3S,V2L} family clock support" if COMPILE_TEST
select RESET_CONTROLLER
# Generic
diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile
index de907623fe3f..879a07d445f9 100644
--- a/drivers/clk/renesas/Makefile
+++ b/drivers/clk/renesas/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_CLK_R9A06G032) += r9a06g032-clocks.o
obj-$(CONFIG_CLK_R9A07G043) += r9a07g043-cpg.o
obj-$(CONFIG_CLK_R9A07G044) += r9a07g044-cpg.o
obj-$(CONFIG_CLK_R9A07G054) += r9a07g044-cpg.o
+obj-$(CONFIG_CLK_R9A08G045) += r9a08g045-cpg.o
obj-$(CONFIG_CLK_R9A09G011) += r9a09g011-cpg.o
obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o
diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c
index ad20b3301ef6..e47d9b1fcc0a 100644
--- a/drivers/clk/renesas/r8a7795-cpg-mssr.c
+++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c
@@ -51,7 +51,7 @@ enum clk_ids {
MOD_CLK_BASE
};
-static struct cpg_core_clk r8a7795_core_clks[] __initdata = {
+static const struct cpg_core_clk r8a7795_core_clks[] __initconst = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
DEF_INPUT("extalr", CLK_EXTALR),
@@ -128,7 +128,7 @@ static struct cpg_core_clk r8a7795_core_clks[] __initdata = {
DEF_BASE("r", R8A7795_CLK_R, CLK_TYPE_GEN3_R, CLK_RINT),
};
-static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = {
+static const struct mssr_mod_clk r8a7795_mod_clks[] __initconst = {
DEF_MOD("3dge", 112, R8A7795_CLK_ZG),
DEF_MOD("fdp1-1", 118, R8A7795_CLK_S0D1),
DEF_MOD("fdp1-0", 119, R8A7795_CLK_S0D1),
diff --git a/drivers/clk/renesas/r9a06g032-clocks.c b/drivers/clk/renesas/r9a06g032-clocks.c
index 55db63c7041a..c1348e2d450c 100644
--- a/drivers/clk/renesas/r9a06g032-clocks.c
+++ b/drivers/clk/renesas/r9a06g032-clocks.c
@@ -102,19 +102,22 @@ enum gate_type {
* @source: the ID+1 of the parent clock element.
* Root clock uses ID of ~0 (PARENT_ID);
* @gate: clock enable/disable
- * @div_min: smallest permitted clock divider
- * @div_max: largest permitted clock divider
- * @reg: clock divider register offset, in 32-bit words
- * @div_table: optional list of fixed clock divider values;
+ * @div: substructure for clock divider
+ * @div.min: smallest permitted clock divider
+ * @div.max: largest permitted clock divider
+ * @div.reg: clock divider register offset, in 32-bit words
+ * @div.table: optional list of fixed clock divider values;
* must be in ascending order, zero for unused
- * @div: divisor for fixed-factor clock
- * @mul: multiplier for fixed-factor clock
- * @group: UART group, 0=UART0/1/2, 1=UART3/4/5/6/7
- * @sel: select either g1/r1 or g2/r2 as clock source
- * @g1: 1st source gate (clock enable/disable)
- * @r1: 1st source reset (module reset)
- * @g2: 2nd source gate (clock enable/disable)
- * @r2: 2nd source reset (module reset)
+ * @ffc: substructure for fixed-factor clocks
+ * @ffc.div: divisor for fixed-factor clock
+ * @ffc.mul: multiplier for fixed-factor clock
+ * @dual: substructure for dual clock gates
+ * @dual.group: UART group, 0=UART0/1/2, 1=UART3/4/5/6/7
+ * @dual.sel: select either g1/r1 or g2/r2 as clock source
+ * @dual.g1: 1st source gate (clock enable/disable)
+ * @dual.r1: 1st source reset (module reset)
+ * @dual.g2: 2nd source gate (clock enable/disable)
+ * @dual.r2: 2nd source reset (module reset)
*
* Describes a single element in the clock tree hierarchy.
* As there are quite a large number of clock elements, this
@@ -131,13 +134,13 @@ struct r9a06g032_clkdesc {
struct r9a06g032_gate gate;
/* type = K_DIV */
struct {
- unsigned int div_min:10, div_max:10, reg:10;
- u16 div_table[4];
- };
+ unsigned int min:10, max:10, reg:10;
+ u16 table[4];
+ } div;
/* type = K_FFC */
struct {
u16 div, mul;
- };
+ } ffc;
/* type = K_DUALGATE */
struct {
uint16_t group:1;
@@ -178,26 +181,26 @@ struct r9a06g032_clkdesc {
.type = K_FFC, \
.index = R9A06G032_##_idx, \
.name = _n, \
- .div = _div, \
- .mul = _mul \
+ .ffc.div = _div, \
+ .ffc.mul = _mul \
}
#define D_FFC(_idx, _n, _src, _div) { \
.type = K_FFC, \
.index = R9A06G032_##_idx, \
.source = 1 + R9A06G032_##_src, \
.name = _n, \
- .div = _div, \
- .mul = 1 \
+ .ffc.div = _div, \
+ .ffc.mul = 1 \
}
#define D_DIV(_idx, _n, _src, _reg, _min, _max, ...) { \
.type = K_DIV, \
.index = R9A06G032_##_idx, \
.source = 1 + R9A06G032_##_src, \
.name = _n, \
- .reg = _reg, \
- .div_min = _min, \
- .div_max = _max, \
- .div_table = { __VA_ARGS__ } \
+ .div.reg = _reg, \
+ .div.min = _min, \
+ .div.max = _max, \
+ .div.table = { __VA_ARGS__ } \
}
#define D_UGATE(_idx, _n, _src, _g, _g1, _r1, _g2, _r2) { \
.type = K_DUALGATE, \
@@ -1063,14 +1066,14 @@ r9a06g032_register_div(struct r9a06g032_priv *clocks,
div->clocks = clocks;
div->index = desc->index;
- div->reg = desc->reg;
+ div->reg = desc->div.reg;
div->hw.init = &init;
- div->min = desc->div_min;
- div->max = desc->div_max;
+ div->min = desc->div.min;
+ div->max = desc->div.max;
/* populate (optional) divider table fixed values */
for (i = 0; i < ARRAY_SIZE(div->table) &&
- i < ARRAY_SIZE(desc->div_table) && desc->div_table[i]; i++) {
- div->table[div->table_size++] = desc->div_table[i];
+ i < ARRAY_SIZE(desc->div.table) && desc->div.table[i]; i++) {
+ div->table[div->table_size++] = desc->div.table[i];
}
clk = clk_register(NULL, &div->hw);
@@ -1269,11 +1272,10 @@ static void r9a06g032_clocks_del_clk_provider(void *data)
static void __init r9a06g032_init_h2mode(struct r9a06g032_priv *clocks)
{
- struct device_node *usbf_np = NULL;
+ struct device_node *usbf_np;
u32 usb;
- while ((usbf_np = of_find_compatible_node(usbf_np, NULL,
- "renesas,rzn1-usbf"))) {
+ for_each_compatible_node(usbf_np, NULL, "renesas,rzn1-usbf") {
if (of_device_is_available(usbf_np))
break;
}
@@ -1333,7 +1335,8 @@ static int __init r9a06g032_clocks_probe(struct platform_device *pdev)
case K_FFC:
clk = clk_register_fixed_factor(NULL, d->name,
parent_name, 0,
- d->mul, d->div);
+ d->ffc.mul,
+ d->ffc.div);
break;
case K_GATE:
clk = r9a06g032_register_gate(clocks, parent_name, d);
diff --git a/drivers/clk/renesas/r9a07g043-cpg.c b/drivers/clk/renesas/r9a07g043-cpg.c
index 1a7a6d60aca4..b70bb378ab46 100644
--- a/drivers/clk/renesas/r9a07g043-cpg.c
+++ b/drivers/clk/renesas/r9a07g043-cpg.c
@@ -14,6 +14,17 @@
#include "rzg2l-cpg.h"
+/* Specific registers. */
+#define CPG_PL2SDHI_DSEL (0x218)
+
+/* Clock select configuration. */
+#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2)
+#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2)
+
+/* Clock status configuration. */
+#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1)
+#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1)
+
enum clk_ids {
/* Core Clock Outputs exported to DT */
LAST_DT_CORE_CLK = R9A07G043_CLK_P0_DIV2,
@@ -78,6 +89,8 @@ static const char * const sel_pll3_3[] = { ".pll3_533", ".pll3_400" };
static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" };
static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" };
+static const u32 mtable_sdhi[] = { 1, 2, 3 };
+
static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = {
/* External Clock Inputs */
DEF_INPUT("extal", CLK_EXTAL),
@@ -123,8 +136,10 @@ static const struct cpg_core_clk r9a07g043_core_clks[] __initconst = {
DEF_MUX("HP", R9A07G043_CLK_HP, SEL_PLL6_2, sel_pll6_2),
DEF_FIXED("SPI0", R9A07G043_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2),
DEF_FIXED("SPI1", R9A07G043_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4),
- DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, sel_shdi),
- DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, sel_shdi),
+ DEF_SD_MUX("SD0", R9A07G043_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi,
+ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier),
+ DEF_SD_MUX("SD1", R9A07G043_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi,
+ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier),
DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G043_CLK_SD0, 1, 4),
DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G043_CLK_SD1, 1, 4),
};
diff --git a/drivers/clk/renesas/r9a07g044-cpg.c b/drivers/clk/renesas/r9a07g044-cpg.c
index c597414a94d8..1047278c9079 100644
--- a/drivers/clk/renesas/r9a07g044-cpg.c
+++ b/drivers/clk/renesas/r9a07g044-cpg.c
@@ -15,6 +15,17 @@
#include "rzg2l-cpg.h"
+/* Specific registers. */
+#define CPG_PL2SDHI_DSEL (0x218)
+
+/* Clock select configuration. */
+#define SEL_SDHI0 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 0, 2)
+#define SEL_SDHI1 SEL_PLL_PACK(CPG_PL2SDHI_DSEL, 4, 2)
+
+/* Clock status configuration. */
+#define SEL_SDHI0_STS SEL_PLL_PACK(CPG_CLKSTATUS, 28, 1)
+#define SEL_SDHI1_STS SEL_PLL_PACK(CPG_CLKSTATUS, 29, 1)
+
enum clk_ids {
/* Core Clock Outputs exported to DT */
LAST_DT_CORE_CLK = R9A07G054_CLK_DRP_A,
@@ -98,6 +109,8 @@ static const char * const sel_pll6_2[] = { ".pll6_250", ".pll5_250" };
static const char * const sel_shdi[] = { ".clk_533", ".clk_400", ".clk_266" };
static const char * const sel_gpu2[] = { ".pll6", ".pll3_div2_2" };
+static const u32 mtable_sdhi[] = { 1, 2, 3 };
+
static const struct {
struct cpg_core_clk common[56];
#ifdef CONFIG_CLK_R9A07G054
@@ -163,8 +176,10 @@ static const struct {
DEF_MUX("HP", R9A07G044_CLK_HP, SEL_PLL6_2, sel_pll6_2),
DEF_FIXED("SPI0", R9A07G044_CLK_SPI0, CLK_DIV_PLL3_C, 1, 2),
DEF_FIXED("SPI1", R9A07G044_CLK_SPI1, CLK_DIV_PLL3_C, 1, 4),
- DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, sel_shdi),
- DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, sel_shdi),
+ DEF_SD_MUX("SD0", R9A07G044_CLK_SD0, SEL_SDHI0, SEL_SDHI0_STS, sel_shdi,
+ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier),
+ DEF_SD_MUX("SD1", R9A07G044_CLK_SD1, SEL_SDHI1, SEL_SDHI0_STS, sel_shdi,
+ mtable_sdhi, 0, rzg2l_cpg_sd_clk_mux_notifier),
DEF_FIXED("SD0_DIV4", CLK_SD0_DIV4, R9A07G044_CLK_SD0, 1, 4),
DEF_FIXED("SD1_DIV4", CLK_SD1_DIV4, R9A07G044_CLK_SD1, 1, 4),
DEF_DIV("G", R9A07G044_CLK_G, CLK_SEL_GPU2, DIVGPU, dtable_1_8),
diff --git a/drivers/clk/renesas/r9a08g045-cpg.c b/drivers/clk/renesas/r9a08g045-cpg.c
new file mode 100644
index 000000000000..4394cb241d99
--- /dev/null
+++ b/drivers/clk/renesas/r9a08g045-cpg.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * RZ/G3S CPG driver
+ *
+ * Copyright (C) 2023 Renesas Electronics Corp.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+
+#include <dt-bindings/clock/r9a08g045-cpg.h>
+
+#include "rzg2l-cpg.h"
+
+/* RZ/G3S Specific registers. */
+#define G3S_CPG_PL2_DDIV (0x204)
+#define G3S_CPG_SDHI_DDIV (0x218)
+#define G3S_CPG_PLL_DSEL (0x240)
+#define G3S_CPG_SDHI_DSEL (0x244)
+#define G3S_CLKDIVSTATUS (0x280)
+#define G3S_CLKSELSTATUS (0x284)
+
+/* RZ/G3S Specific division configuration. */
+#define G3S_DIVPL2B DDIV_PACK(G3S_CPG_PL2_DDIV, 4, 3)
+#define G3S_DIV_SDHI0 DDIV_PACK(G3S_CPG_SDHI_DDIV, 0, 1)
+#define G3S_DIV_SDHI1 DDIV_PACK(G3S_CPG_SDHI_DDIV, 4, 1)
+#define G3S_DIV_SDHI2 DDIV_PACK(G3S_CPG_SDHI_DDIV, 8, 1)
+
+/* RZ/G3S Clock status configuration. */
+#define G3S_DIVPL1A_STS DDIV_PACK(G3S_CLKDIVSTATUS, 0, 1)
+#define G3S_DIVPL2B_STS DDIV_PACK(G3S_CLKDIVSTATUS, 5, 1)
+#define G3S_DIVPL3A_STS DDIV_PACK(G3S_CLKDIVSTATUS, 8, 1)
+#define G3S_DIVPL3B_STS DDIV_PACK(G3S_CLKDIVSTATUS, 9, 1)
+#define G3S_DIVPL3C_STS DDIV_PACK(G3S_CLKDIVSTATUS, 10, 1)
+#define G3S_DIV_SDHI0_STS DDIV_PACK(G3S_CLKDIVSTATUS, 24, 1)
+#define G3S_DIV_SDHI1_STS DDIV_PACK(G3S_CLKDIVSTATUS, 25, 1)
+#define G3S_DIV_SDHI2_STS DDIV_PACK(G3S_CLKDIVSTATUS, 26, 1)
+
+#define G3S_SEL_PLL4_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 6, 1)
+#define G3S_SEL_SDHI0_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 16, 1)
+#define G3S_SEL_SDHI1_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 17, 1)
+#define G3S_SEL_SDHI2_STS SEL_PLL_PACK(G3S_CLKSELSTATUS, 18, 1)
+
+/* RZ/G3S Specific clocks select. */
+#define G3S_SEL_PLL4 SEL_PLL_PACK(G3S_CPG_PLL_DSEL, 6, 1)
+#define G3S_SEL_SDHI0 SEL_PLL_PACK(G3S_CPG_SDHI_DSEL, 0, 2)
+#define G3S_SEL_SDHI1 SEL_PLL_PACK(G3S_CPG_SDHI_DSEL, 4, 2)
+#define G3S_SEL_SDHI2 SEL_PLL_PACK(G3S_CPG_SDHI_DSEL, 8, 2)
+
+/* PLL 1/4/6 configuration registers macro. */
+#define G3S_PLL146_CONF(clk1, clk2) ((clk1) << 22 | (clk2) << 12)
+
+#define DEF_G3S_MUX(_name, _id, _conf, _parent_names, _mux_flags, _clk_flags) \
+ DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = (_conf), \
+ .parent_names = (_parent_names), \
+ .num_parents = ARRAY_SIZE((_parent_names)), \
+ .mux_flags = CLK_MUX_HIWORD_MASK | (_mux_flags), \
+ .flag = (_clk_flags))
+
+enum clk_ids {
+ /* Core Clock Outputs exported to DT */
+ LAST_DT_CORE_CLK = R9A08G045_SWD,
+
+ /* External Input Clocks */
+ CLK_EXTAL,
+
+ /* Internal Core Clocks */
+ CLK_OSC_DIV1000,
+ CLK_PLL1,
+ CLK_PLL2,
+ CLK_PLL2_DIV2,
+ CLK_PLL2_DIV2_8,
+ CLK_PLL2_DIV6,
+ CLK_PLL3,
+ CLK_PLL3_DIV2,
+ CLK_PLL3_DIV2_4,
+ CLK_PLL3_DIV2_8,
+ CLK_PLL3_DIV6,
+ CLK_PLL4,
+ CLK_PLL6,
+ CLK_PLL6_DIV2,
+ CLK_SEL_SDHI0,
+ CLK_SEL_SDHI1,
+ CLK_SEL_SDHI2,
+ CLK_SEL_PLL4,
+ CLK_P1_DIV2,
+ CLK_P3_DIV2,
+ CLK_SD0_DIV4,
+ CLK_SD1_DIV4,
+ CLK_SD2_DIV4,
+
+ /* Module Clocks */
+ MOD_CLK_BASE,
+};
+
+/* Divider tables */
+static const struct clk_div_table dtable_1_2[] = {
+ { 0, 1 },
+ { 1, 2 },
+ { 0, 0 },
+};
+
+static const struct clk_div_table dtable_1_8[] = {
+ { 0, 1 },
+ { 1, 2 },
+ { 2, 4 },
+ { 3, 8 },
+ { 0, 0 },
+};
+
+static const struct clk_div_table dtable_1_32[] = {
+ { 0, 1 },
+ { 1, 2 },
+ { 2, 4 },
+ { 3, 8 },
+ { 4, 32 },
+ { 0, 0 },
+};
+
+/* Mux clock names tables. */
+static const char * const sel_sdhi[] = { ".pll2_div2", ".pll6", ".pll2_div6" };
+static const char * const sel_pll4[] = { ".osc_div1000", ".pll4" };
+
+/* Mux clock indices tables. */
+static const u32 mtable_sd[] = { 0, 2, 3 };
+static const u32 mtable_pll4[] = { 0, 1 };
+
+static const struct cpg_core_clk r9a08g045_core_clks[] __initconst = {
+ /* External Clock Inputs */
+ DEF_INPUT("extal", CLK_EXTAL),
+
+ /* Internal Core Clocks */
+ DEF_FIXED(".osc_div1000", CLK_OSC_DIV1000, CLK_EXTAL, 1, 1000),
+ DEF_G3S_PLL(".pll1", CLK_PLL1, CLK_EXTAL, G3S_PLL146_CONF(0x4, 0x8)),
+ DEF_FIXED(".pll2", CLK_PLL2, CLK_EXTAL, 200, 3),
+ DEF_FIXED(".pll3", CLK_PLL3, CLK_EXTAL, 200, 3),
+ DEF_FIXED(".pll4", CLK_PLL4, CLK_EXTAL, 100, 3),
+ DEF_FIXED(".pll6", CLK_PLL6, CLK_EXTAL, 125, 6),
+ DEF_FIXED(".pll2_div2", CLK_PLL2_DIV2, CLK_PLL2, 1, 2),
+ DEF_FIXED(".pll2_div2_8", CLK_PLL2_DIV2_8, CLK_PLL2_DIV2, 1, 8),
+ DEF_FIXED(".pll2_div6", CLK_PLL2_DIV6, CLK_PLL2, 1, 6),
+ DEF_FIXED(".pll3_div2", CLK_PLL3_DIV2, CLK_PLL3, 1, 2),
+ DEF_FIXED(".pll3_div2_4", CLK_PLL3_DIV2_4, CLK_PLL3_DIV2, 1, 4),
+ DEF_FIXED(".pll3_div2_8", CLK_PLL3_DIV2_8, CLK_PLL3_DIV2, 1, 8),
+ DEF_FIXED(".pll3_div6", CLK_PLL3_DIV6, CLK_PLL3, 1, 6),
+ DEF_FIXED(".pll6_div2", CLK_PLL6_DIV2, CLK_PLL6, 1, 2),
+ DEF_SD_MUX(".sel_sd0", CLK_SEL_SDHI0, G3S_SEL_SDHI0, G3S_SEL_SDHI0_STS, sel_sdhi,
+ mtable_sd, 0, NULL),
+ DEF_SD_MUX(".sel_sd1", CLK_SEL_SDHI1, G3S_SEL_SDHI1, G3S_SEL_SDHI1_STS, sel_sdhi,
+ mtable_sd, 0, NULL),
+ DEF_SD_MUX(".sel_sd2", CLK_SEL_SDHI2, G3S_SEL_SDHI2, G3S_SEL_SDHI2_STS, sel_sdhi,
+ mtable_sd, 0, NULL),
+ DEF_SD_MUX(".sel_pll4", CLK_SEL_PLL4, G3S_SEL_PLL4, G3S_SEL_PLL4_STS, sel_pll4,
+ mtable_pll4, CLK_SET_PARENT_GATE, NULL),
+
+ /* Core output clk */
+ DEF_G3S_DIV("I", R9A08G045_CLK_I, CLK_PLL1, DIVPL1A, G3S_DIVPL1A_STS, dtable_1_8,
+ 0, 0, 0, NULL),
+ DEF_G3S_DIV("P0", R9A08G045_CLK_P0, CLK_PLL2_DIV2_8, G3S_DIVPL2B, G3S_DIVPL2B_STS,
+ dtable_1_32, 0, 0, 0, NULL),
+ DEF_G3S_DIV("SD0", R9A08G045_CLK_SD0, CLK_SEL_SDHI0, G3S_DIV_SDHI0, G3S_DIV_SDHI0_STS,
+ dtable_1_2, 800000000UL, 500000000UL, CLK_SET_RATE_PARENT,
+ rzg3s_cpg_div_clk_notifier),
+ DEF_G3S_DIV("SD1", R9A08G045_CLK_SD1, CLK_SEL_SDHI1, G3S_DIV_SDHI1, G3S_DIV_SDHI1_STS,
+ dtable_1_2, 800000000UL, 500000000UL, CLK_SET_RATE_PARENT,
+ rzg3s_cpg_div_clk_notifier),
+ DEF_G3S_DIV("SD2", R9A08G045_CLK_SD2, CLK_SEL_SDHI2, G3S_DIV_SDHI2, G3S_DIV_SDHI2_STS,
+ dtable_1_2, 800000000UL, 500000000UL, CLK_SET_RATE_PARENT,
+ rzg3s_cpg_div_clk_notifier),
+ DEF_FIXED(".sd0_div4", CLK_SD0_DIV4, R9A08G045_CLK_SD0, 1, 4),
+ DEF_FIXED(".sd1_div4", CLK_SD1_DIV4, R9A08G045_CLK_SD1, 1, 4),
+ DEF_FIXED(".sd2_div4", CLK_SD2_DIV4, R9A08G045_CLK_SD2, 1, 4),
+ DEF_FIXED("M0", R9A08G045_CLK_M0, CLK_PLL3_DIV2_4, 1, 1),
+ DEF_G3S_DIV("P1", R9A08G045_CLK_P1, CLK_PLL3_DIV2_4, DIVPL3A, G3S_DIVPL3A_STS,
+ dtable_1_32, 0, 0, 0, NULL),
+ DEF_FIXED("P1_DIV2", CLK_P1_DIV2, R9A08G045_CLK_P1, 1, 2),
+ DEF_G3S_DIV("P2", R9A08G045_CLK_P2, CLK_PLL3_DIV2_8, DIVPL3B, G3S_DIVPL3B_STS,
+ dtable_1_32, 0, 0, 0, NULL),
+ DEF_G3S_DIV("P3", R9A08G045_CLK_P3, CLK_PLL3_DIV2_4, DIVPL3C, G3S_DIVPL3C_STS,
+ dtable_1_32, 0, 0, 0, NULL),
+ DEF_FIXED("P3_DIV2", CLK_P3_DIV2, R9A08G045_CLK_P3, 1, 2),
+ DEF_FIXED("S0", R9A08G045_CLK_S0, CLK_SEL_PLL4, 1, 2),
+ DEF_FIXED("OSC", R9A08G045_OSCCLK, CLK_EXTAL, 1, 1),
+ DEF_FIXED("OSC2", R9A08G045_OSCCLK2, CLK_EXTAL, 1, 3),
+};
+
+static const struct rzg2l_mod_clk r9a08g045_mod_clks[] = {
+ DEF_MOD("gic_gicclk", R9A08G045_GIC600_GICCLK, R9A08G045_CLK_P1, 0x514, 0),
+ DEF_MOD("ia55_clk", R9A08G045_IA55_CLK, R9A08G045_CLK_P1, 0x518, 1),
+ DEF_MOD("dmac_aclk", R9A08G045_DMAC_ACLK, R9A08G045_CLK_P3, 0x52c, 0),
+ DEF_MOD("sdhi0_imclk", R9A08G045_SDHI0_IMCLK, CLK_SD0_DIV4, 0x554, 0),
+ DEF_MOD("sdhi0_imclk2", R9A08G045_SDHI0_IMCLK2, CLK_SD0_DIV4, 0x554, 1),
+ DEF_MOD("sdhi0_clk_hs", R9A08G045_SDHI0_CLK_HS, R9A08G045_CLK_SD0, 0x554, 2),
+ DEF_MOD("sdhi0_aclk", R9A08G045_SDHI0_ACLK, R9A08G045_CLK_P1, 0x554, 3),
+ DEF_MOD("sdhi1_imclk", R9A08G045_SDHI1_IMCLK, CLK_SD1_DIV4, 0x554, 4),
+ DEF_MOD("sdhi1_imclk2", R9A08G045_SDHI1_IMCLK2, CLK_SD1_DIV4, 0x554, 5),
+ DEF_MOD("sdhi1_clk_hs", R9A08G045_SDHI1_CLK_HS, R9A08G045_CLK_SD1, 0x554, 6),
+ DEF_MOD("sdhi1_aclk", R9A08G045_SDHI1_ACLK, R9A08G045_CLK_P1, 0x554, 7),
+ DEF_MOD("sdhi2_imclk", R9A08G045_SDHI2_IMCLK, CLK_SD2_DIV4, 0x554, 8),
+ DEF_MOD("sdhi2_imclk2", R9A08G045_SDHI2_IMCLK2, CLK_SD2_DIV4, 0x554, 9),
+ DEF_MOD("sdhi2_clk_hs", R9A08G045_SDHI2_CLK_HS, R9A08G045_CLK_SD2, 0x554, 10),
+ DEF_MOD("sdhi2_aclk", R9A08G045_SDHI2_ACLK, R9A08G045_CLK_P1, 0x554, 11),
+ DEF_MOD("scif0_clk_pck", R9A08G045_SCIF0_CLK_PCK, R9A08G045_CLK_P0, 0x584, 0),
+ DEF_MOD("gpio_hclk", R9A08G045_GPIO_HCLK, R9A08G045_OSCCLK, 0x598, 0),
+};
+
+static const struct rzg2l_reset r9a08g045_resets[] = {
+ DEF_RST(R9A08G045_GIC600_GICRESET_N, 0x814, 0),
+ DEF_RST(R9A08G045_GIC600_DBG_GICRESET_N, 0x814, 1),
+ DEF_RST(R9A08G045_SDHI0_IXRST, 0x854, 0),
+ DEF_RST(R9A08G045_SDHI1_IXRST, 0x854, 1),
+ DEF_RST(R9A08G045_SDHI2_IXRST, 0x854, 2),
+ DEF_RST(R9A08G045_SCIF0_RST_SYSTEM_N, 0x884, 0),
+ DEF_RST(R9A08G045_GPIO_RSTN, 0x898, 0),
+ DEF_RST(R9A08G045_GPIO_PORT_RESETN, 0x898, 1),
+ DEF_RST(R9A08G045_GPIO_SPARE_RESETN, 0x898, 2),
+};
+
+static const unsigned int r9a08g045_crit_mod_clks[] __initconst = {
+ MOD_CLK_BASE + R9A08G045_GIC600_GICCLK,
+ MOD_CLK_BASE + R9A08G045_IA55_CLK,
+ MOD_CLK_BASE + R9A08G045_DMAC_ACLK,
+};
+
+const struct rzg2l_cpg_info r9a08g045_cpg_info = {
+ /* Core Clocks */
+ .core_clks = r9a08g045_core_clks,
+ .num_core_clks = ARRAY_SIZE(r9a08g045_core_clks),
+ .last_dt_core_clk = LAST_DT_CORE_CLK,
+ .num_total_core_clks = MOD_CLK_BASE,
+
+ /* Critical Module Clocks */
+ .crit_mod_clks = r9a08g045_crit_mod_clks,
+ .num_crit_mod_clks = ARRAY_SIZE(r9a08g045_crit_mod_clks),
+
+ /* Module Clocks */
+ .mod_clks = r9a08g045_mod_clks,
+ .num_mod_clks = ARRAY_SIZE(r9a08g045_mod_clks),
+ .num_hw_mod_clks = R9A08G045_VBAT_BCLK + 1,
+
+ /* Resets */
+ .resets = r9a08g045_resets,
+ .num_resets = R9A08G045_VBAT_BRESETN + 1, /* Last reset ID + 1 */
+
+ .has_clk_mon_regs = true,
+};
diff --git a/drivers/clk/renesas/rcar-cpg-lib.c b/drivers/clk/renesas/rcar-cpg-lib.c
index e2e0447de190..5a15f8788b92 100644
--- a/drivers/clk/renesas/rcar-cpg-lib.c
+++ b/drivers/clk/renesas/rcar-cpg-lib.c
@@ -70,8 +70,21 @@ void cpg_simple_notifier_register(struct raw_notifier_head *notifiers,
#define STPnHCK BIT(9 - SDnSRCFC_SHIFT)
static const struct clk_div_table cpg_sdh_div_table[] = {
+ /*
+ * These values are recommended by the datasheet. Because they come
+ * first, Linux will only use these.
+ */
{ 0, 1 }, { 1, 2 }, { STPnHCK | 2, 4 }, { STPnHCK | 3, 8 },
- { STPnHCK | 4, 16 }, { 0, 0 },
+ { STPnHCK | 4, 16 },
+ /*
+ * These values are not recommended because STPnHCK is wrong. But they
+ * have been seen because of broken firmware. So, we support reading
+ * them but Linux will sanitize them when initializing through
+ * recalc_rate.
+ */
+ { STPnHCK | 0, 1 }, { STPnHCK | 1, 2 }, { 2, 4 }, { 3, 8 }, { 4, 16 },
+ /* Sentinel */
+ { 0, 0 }
};
struct clk * __init cpg_sdh_clk_register(const char *name,
diff --git a/drivers/clk/renesas/rzg2l-cpg.c b/drivers/clk/renesas/rzg2l-cpg.c
index 47f488387f33..764bd72cf059 100644
--- a/drivers/clk/renesas/rzg2l-cpg.c
+++ b/drivers/clk/renesas/rzg2l-cpg.c
@@ -11,6 +11,7 @@
* Copyright (C) 2015 Renesas Electronics Corp.
*/
+#include <linux/bitfield.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/clk/renesas.h>
@@ -38,14 +39,18 @@
#define WARN_DEBUG(x) do { } while (0)
#endif
-#define DIV_RSMASK(v, s, m) ((v >> s) & m)
#define GET_SHIFT(val) ((val >> 12) & 0xff)
#define GET_WIDTH(val) ((val >> 8) & 0xf)
-#define KDIV(val) DIV_RSMASK(val, 16, 0xffff)
-#define MDIV(val) DIV_RSMASK(val, 6, 0x3ff)
-#define PDIV(val) DIV_RSMASK(val, 0, 0x3f)
-#define SDIV(val) DIV_RSMASK(val, 0, 0x7)
+#define KDIV(val) ((s16)FIELD_GET(GENMASK(31, 16), val))
+#define MDIV(val) FIELD_GET(GENMASK(15, 6), val)
+#define PDIV(val) FIELD_GET(GENMASK(5, 0), val)
+#define SDIV(val) FIELD_GET(GENMASK(2, 0), val)
+
+#define RZG3S_DIV_P GENMASK(28, 26)
+#define RZG3S_DIV_M GENMASK(25, 22)
+#define RZG3S_DIV_NI GENMASK(21, 13)
+#define RZG3S_DIV_NF GENMASK(12, 1)
#define CLK_ON_R(reg) (reg)
#define CLK_MON_R(reg) (0x180 + (reg))
@@ -56,15 +61,55 @@
#define GET_REG_SAMPLL_CLK1(val) ((val >> 22) & 0xfff)
#define GET_REG_SAMPLL_CLK2(val) ((val >> 12) & 0xfff)
+#define CPG_WEN_BIT BIT(16)
+
#define MAX_VCLK_FREQ (148500000)
-struct sd_hw_data {
+/**
+ * struct clk_hw_data - clock hardware data
+ * @hw: clock hw
+ * @conf: clock configuration (register offset, shift, width)
+ * @sconf: clock status configuration (register offset, shift, width)
+ * @priv: CPG private data structure
+ */
+struct clk_hw_data {
struct clk_hw hw;
u32 conf;
+ u32 sconf;
struct rzg2l_cpg_priv *priv;
};
-#define to_sd_hw_data(_hw) container_of(_hw, struct sd_hw_data, hw)
+#define to_clk_hw_data(_hw) container_of(_hw, struct clk_hw_data, hw)
+
+/**
+ * struct sd_mux_hw_data - SD MUX clock hardware data
+ * @hw_data: clock hw data
+ * @mtable: clock mux table
+ */
+struct sd_mux_hw_data {
+ struct clk_hw_data hw_data;
+ const u32 *mtable;
+};
+
+#define to_sd_mux_hw_data(_hw) container_of(_hw, struct sd_mux_hw_data, hw_data)
+
+/**
+ * struct div_hw_data - divider clock hardware data
+ * @hw_data: clock hw data
+ * @dtable: pointer to divider table
+ * @invalid_rate: invalid rate for divider
+ * @max_rate: maximum rate for divider
+ * @width: divider width
+ */
+struct div_hw_data {
+ struct clk_hw_data hw_data;
+ const struct clk_div_table *dtable;
+ unsigned long invalid_rate;
+ unsigned long max_rate;
+ u32 width;
+};
+
+#define to_div_hw_data(_hw) container_of(_hw, struct div_hw_data, hw_data)
struct rzg2l_pll5_param {
u32 pl5_fracin;
@@ -121,6 +166,241 @@ static void rzg2l_cpg_del_clk_provider(void *data)
of_clk_del_provider(data);
}
+/* Must be called in atomic context. */
+static int rzg2l_cpg_wait_clk_update_done(void __iomem *base, u32 conf)
+{
+ u32 bitmask = GENMASK(GET_WIDTH(conf) - 1, 0) << GET_SHIFT(conf);
+ u32 off = GET_REG_OFFSET(conf);
+ u32 val;
+
+ return readl_poll_timeout_atomic(base + off, val, !(val & bitmask), 10, 200);
+}
+
+int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct clk_notifier_data *cnd = data;
+ struct clk_hw *hw = __clk_get_hw(cnd->clk);
+ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
+ struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
+ u32 off = GET_REG_OFFSET(clk_hw_data->conf);
+ u32 shift = GET_SHIFT(clk_hw_data->conf);
+ const u32 clk_src_266 = 3;
+ unsigned long flags;
+ int ret;
+
+ if (event != PRE_RATE_CHANGE || (cnd->new_rate / MEGA == 266))
+ return NOTIFY_DONE;
+
+ spin_lock_irqsave(&priv->rmw_lock, flags);
+
+ /*
+ * As per the HW manual, we should not directly switch from 533 MHz to
+ * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz)
+ * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first,
+ * and then switch to the target setting (2’b01 (533 MHz) or 2’b10
+ * (400 MHz)).
+ * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock
+ * switching register is prohibited.
+ * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and
+ * the index to value mapping is done by adding 1 to the index.
+ */
+
+ writel((CPG_WEN_BIT | clk_src_266) << shift, priv->base + off);
+
+ /* Wait for the update done. */
+ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
+
+ spin_unlock_irqrestore(&priv->rmw_lock, flags);
+
+ if (ret)
+ dev_err(priv->dev, "failed to switch to safe clk source\n");
+
+ return notifier_from_errno(ret);
+}
+
+int rzg3s_cpg_div_clk_notifier(struct notifier_block *nb, unsigned long event,
+ void *data)
+{
+ struct clk_notifier_data *cnd = data;
+ struct clk_hw *hw = __clk_get_hw(cnd->clk);
+ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
+ struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
+ struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
+ u32 off = GET_REG_OFFSET(clk_hw_data->conf);
+ u32 shift = GET_SHIFT(clk_hw_data->conf);
+ unsigned long flags;
+ int ret = 0;
+ u32 val;
+
+ if (event != PRE_RATE_CHANGE || !div_hw_data->invalid_rate ||
+ div_hw_data->invalid_rate % cnd->new_rate)
+ return NOTIFY_DONE;
+
+ spin_lock_irqsave(&priv->rmw_lock, flags);
+
+ val = readl(priv->base + off);
+ val >>= shift;
+ val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0);
+
+ /*
+ * There are different constraints for the user of this notifiers as follows:
+ * 1/ SD div cannot be 1 (val == 0) if parent rate is 800MHz
+ * 2/ OCTA / SPI div cannot be 1 (val == 0) if parent rate is 400MHz
+ * As SD can have only one parent having 800MHz and OCTA div can have
+ * only one parent having 400MHz we took into account the parent rate
+ * at the beginning of function (by checking invalid_rate % new_rate).
+ * Now it is time to check the hardware divider and update it accordingly.
+ */
+ if (!val) {
+ writel((CPG_WEN_BIT | 1) << shift, priv->base + off);
+ /* Wait for the update done. */
+ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
+ }
+
+ spin_unlock_irqrestore(&priv->rmw_lock, flags);
+
+ if (ret)
+ dev_err(priv->dev, "Failed to downgrade the div\n");
+
+ return notifier_from_errno(ret);
+}
+
+static int rzg2l_register_notifier(struct clk_hw *hw, const struct cpg_core_clk *core,
+ struct rzg2l_cpg_priv *priv)
+{
+ struct notifier_block *nb;
+
+ if (!core->notifier)
+ return 0;
+
+ nb = devm_kzalloc(priv->dev, sizeof(*nb), GFP_KERNEL);
+ if (!nb)
+ return -ENOMEM;
+
+ nb->notifier_call = core->notifier;
+
+ return clk_notifier_register(hw->clk, nb);
+}
+
+static unsigned long rzg3s_div_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
+ struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
+ struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
+ u32 val;
+
+ val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf));
+ val >>= GET_SHIFT(clk_hw_data->conf);
+ val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0);
+
+ return divider_recalc_rate(hw, parent_rate, val, div_hw_data->dtable,
+ CLK_DIVIDER_ROUND_CLOSEST, div_hw_data->width);
+}
+
+static int rzg3s_div_clk_determine_rate(struct clk_hw *hw, struct clk_rate_request *req)
+{
+ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
+ struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
+
+ if (div_hw_data->max_rate && req->rate > div_hw_data->max_rate)
+ req->rate = div_hw_data->max_rate;
+
+ return divider_determine_rate(hw, req, div_hw_data->dtable, div_hw_data->width,
+ CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+static int rzg3s_div_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
+ struct div_hw_data *div_hw_data = to_div_hw_data(clk_hw_data);
+ struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
+ u32 off = GET_REG_OFFSET(clk_hw_data->conf);
+ u32 shift = GET_SHIFT(clk_hw_data->conf);
+ unsigned long flags;
+ u32 val;
+ int ret;
+
+ val = divider_get_val(rate, parent_rate, div_hw_data->dtable, div_hw_data->width,
+ CLK_DIVIDER_ROUND_CLOSEST);
+
+ spin_lock_irqsave(&priv->rmw_lock, flags);
+ writel((CPG_WEN_BIT | val) << shift, priv->base + off);
+ /* Wait for the update done. */
+ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
+ spin_unlock_irqrestore(&priv->rmw_lock, flags);
+
+ return ret;
+}
+
+static const struct clk_ops rzg3s_div_clk_ops = {
+ .recalc_rate = rzg3s_div_clk_recalc_rate,
+ .determine_rate = rzg3s_div_clk_determine_rate,
+ .set_rate = rzg3s_div_clk_set_rate,
+};
+
+static struct clk * __init
+rzg3s_cpg_div_clk_register(const struct cpg_core_clk *core, struct clk **clks,
+ void __iomem *base, struct rzg2l_cpg_priv *priv)
+{
+ struct div_hw_data *div_hw_data;
+ struct clk_init_data init = {};
+ const struct clk_div_table *clkt;
+ struct clk_hw *clk_hw;
+ const struct clk *parent;
+ const char *parent_name;
+ u32 max = 0;
+ int ret;
+
+ parent = clks[core->parent & 0xffff];
+ if (IS_ERR(parent))
+ return ERR_CAST(parent);
+
+ parent_name = __clk_get_name(parent);
+
+ div_hw_data = devm_kzalloc(priv->dev, sizeof(*div_hw_data), GFP_KERNEL);
+ if (!div_hw_data)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = core->name;
+ init.flags = core->flag;
+ init.ops = &rzg3s_div_clk_ops;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ /* Get the maximum divider to retrieve div width. */
+ for (clkt = core->dtable; clkt->div; clkt++) {
+ if (max < clkt->div)
+ max = clkt->div;
+ }
+
+ div_hw_data->hw_data.priv = priv;
+ div_hw_data->hw_data.conf = core->conf;
+ div_hw_data->hw_data.sconf = core->sconf;
+ div_hw_data->dtable = core->dtable;
+ div_hw_data->invalid_rate = core->invalid_rate;
+ div_hw_data->max_rate = core->max_rate;
+ div_hw_data->width = fls(max) - 1;
+
+ clk_hw = &div_hw_data->hw_data.hw;
+ clk_hw->init = &init;
+
+ ret = devm_clk_hw_register(priv->dev, clk_hw);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = rzg2l_register_notifier(clk_hw, core, priv);
+ if (ret) {
+ dev_err(priv->dev, "Failed to register notifier for %s\n",
+ core->name);
+ return ERR_PTR(ret);
+ }
+
+ return clk_hw->clk;
+}
+
static struct clk * __init
rzg2l_cpg_div_clk_register(const struct cpg_core_clk *core,
struct clk **clks,
@@ -183,63 +463,44 @@ rzg2l_cpg_mux_clk_register(const struct cpg_core_clk *core,
static int rzg2l_cpg_sd_clk_mux_set_parent(struct clk_hw *hw, u8 index)
{
- struct sd_hw_data *hwdata = to_sd_hw_data(hw);
- struct rzg2l_cpg_priv *priv = hwdata->priv;
- u32 off = GET_REG_OFFSET(hwdata->conf);
- u32 shift = GET_SHIFT(hwdata->conf);
- const u32 clk_src_266 = 2;
- u32 bitmask;
+ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
+ struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data);
+ struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
+ u32 off = GET_REG_OFFSET(clk_hw_data->conf);
+ u32 shift = GET_SHIFT(clk_hw_data->conf);
+ unsigned long flags;
+ u32 val;
+ int ret;
- /*
- * As per the HW manual, we should not directly switch from 533 MHz to
- * 400 MHz and vice versa. To change the setting from 2’b01 (533 MHz)
- * to 2’b10 (400 MHz) or vice versa, Switch to 2’b11 (266 MHz) first,
- * and then switch to the target setting (2’b01 (533 MHz) or 2’b10
- * (400 MHz)).
- * Setting a value of '0' to the SEL_SDHI0_SET or SEL_SDHI1_SET clock
- * switching register is prohibited.
- * The clock mux has 3 input clocks(533 MHz, 400 MHz, and 266 MHz), and
- * the index to value mapping is done by adding 1 to the index.
- */
- bitmask = (GENMASK(GET_WIDTH(hwdata->conf) - 1, 0) << shift) << 16;
- if (index != clk_src_266) {
- u32 msk, val;
- int ret;
+ val = clk_mux_index_to_val(sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, index);
- writel(bitmask | ((clk_src_266 + 1) << shift), priv->base + off);
+ spin_lock_irqsave(&priv->rmw_lock, flags);
- msk = off ? CPG_CLKSTATUS_SELSDHI1_STS : CPG_CLKSTATUS_SELSDHI0_STS;
+ writel((CPG_WEN_BIT | val) << shift, priv->base + off);
- ret = readl_poll_timeout(priv->base + CPG_CLKSTATUS, val,
- !(val & msk), 100,
- CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US);
- if (ret) {
- dev_err(priv->dev, "failed to switch clk source\n");
- return ret;
- }
- }
+ /* Wait for the update done. */
+ ret = rzg2l_cpg_wait_clk_update_done(priv->base, clk_hw_data->sconf);
- writel(bitmask | ((index + 1) << shift), priv->base + off);
+ spin_unlock_irqrestore(&priv->rmw_lock, flags);
- return 0;
+ if (ret)
+ dev_err(priv->dev, "Failed to switch parent\n");
+
+ return ret;
}
static u8 rzg2l_cpg_sd_clk_mux_get_parent(struct clk_hw *hw)
{
- struct sd_hw_data *hwdata = to_sd_hw_data(hw);
- struct rzg2l_cpg_priv *priv = hwdata->priv;
- u32 val = readl(priv->base + GET_REG_OFFSET(hwdata->conf));
-
- val >>= GET_SHIFT(hwdata->conf);
- val &= GENMASK(GET_WIDTH(hwdata->conf) - 1, 0);
- if (val) {
- val--;
- } else {
- /* Prohibited clk source, change it to 533 MHz(reset value) */
- rzg2l_cpg_sd_clk_mux_set_parent(hw, 0);
- }
+ struct clk_hw_data *clk_hw_data = to_clk_hw_data(hw);
+ struct sd_mux_hw_data *sd_mux_hw_data = to_sd_mux_hw_data(clk_hw_data);
+ struct rzg2l_cpg_priv *priv = clk_hw_data->priv;
+ u32 val;
+
+ val = readl(priv->base + GET_REG_OFFSET(clk_hw_data->conf));
+ val >>= GET_SHIFT(clk_hw_data->conf);
+ val &= GENMASK(GET_WIDTH(clk_hw_data->conf) - 1, 0);
- return val;
+ return clk_mux_val_to_index(hw, sd_mux_hw_data->mtable, CLK_MUX_ROUND_CLOSEST, val);
}
static const struct clk_ops rzg2l_cpg_sd_clk_mux_ops = {
@@ -253,31 +514,40 @@ rzg2l_cpg_sd_mux_clk_register(const struct cpg_core_clk *core,
void __iomem *base,
struct rzg2l_cpg_priv *priv)
{
- struct sd_hw_data *clk_hw_data;
+ struct sd_mux_hw_data *sd_mux_hw_data;
struct clk_init_data init;
struct clk_hw *clk_hw;
int ret;
- clk_hw_data = devm_kzalloc(priv->dev, sizeof(*clk_hw_data), GFP_KERNEL);
- if (!clk_hw_data)
+ sd_mux_hw_data = devm_kzalloc(priv->dev, sizeof(*sd_mux_hw_data), GFP_KERNEL);
+ if (!sd_mux_hw_data)
return ERR_PTR(-ENOMEM);
- clk_hw_data->priv = priv;
- clk_hw_data->conf = core->conf;
+ sd_mux_hw_data->hw_data.priv = priv;
+ sd_mux_hw_data->hw_data.conf = core->conf;
+ sd_mux_hw_data->hw_data.sconf = core->sconf;
+ sd_mux_hw_data->mtable = core->mtable;
- init.name = GET_SHIFT(core->conf) ? "sd1" : "sd0";
+ init.name = core->name;
init.ops = &rzg2l_cpg_sd_clk_mux_ops;
- init.flags = 0;
+ init.flags = core->flag;
init.num_parents = core->num_parents;
init.parent_names = core->parent_names;
- clk_hw = &clk_hw_data->hw;
+ clk_hw = &sd_mux_hw_data->hw_data.hw;
clk_hw->init = &init;
ret = devm_clk_hw_register(priv->dev, clk_hw);
if (ret)
return ERR_PTR(ret);
+ ret = rzg2l_register_notifier(clk_hw, core, priv);
+ if (ret) {
+ dev_err(priv->dev, "Failed to register notifier for %s\n",
+ core->name);
+ return ERR_PTR(ret);
+ }
+
return clk_hw->clk;
}
@@ -695,29 +965,61 @@ static unsigned long rzg2l_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
struct pll_clk *pll_clk = to_pll(hw);
struct rzg2l_cpg_priv *priv = pll_clk->priv;
unsigned int val1, val2;
- unsigned int mult = 1;
- unsigned int div = 1;
+ u64 rate;
if (pll_clk->type != CLK_TYPE_SAM_PLL)
return parent_rate;
val1 = readl(priv->base + GET_REG_SAMPLL_CLK1(pll_clk->conf));
val2 = readl(priv->base + GET_REG_SAMPLL_CLK2(pll_clk->conf));
- mult = MDIV(val1) + KDIV(val1) / 65536;
- div = PDIV(val1) << SDIV(val2);
- return DIV_ROUND_CLOSEST_ULL((u64)parent_rate * mult, div);
+ rate = mul_u64_u32_shr(parent_rate, (MDIV(val1) << 16) + KDIV(val1),
+ 16 + SDIV(val2));
+
+ return DIV_ROUND_CLOSEST_ULL(rate, PDIV(val1));
}
static const struct clk_ops rzg2l_cpg_pll_ops = {
.recalc_rate = rzg2l_cpg_pll_clk_recalc_rate,
};
+static unsigned long rzg3s_cpg_pll_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct pll_clk *pll_clk = to_pll(hw);
+ struct rzg2l_cpg_priv *priv = pll_clk->priv;
+ u32 nir, nfr, mr, pr, val;
+ u64 rate;
+
+ if (pll_clk->type != CLK_TYPE_G3S_PLL)
+ return parent_rate;
+
+ val = readl(priv->base + GET_REG_SAMPLL_CLK1(pll_clk->conf));
+
+ pr = 1 << FIELD_GET(RZG3S_DIV_P, val);
+ /* Hardware interprets values higher than 8 as p = 16. */
+ if (pr > 8)
+ pr = 16;
+
+ mr = FIELD_GET(RZG3S_DIV_M, val) + 1;
+ nir = FIELD_GET(RZG3S_DIV_NI, val) + 1;
+ nfr = FIELD_GET(RZG3S_DIV_NF, val);
+
+ rate = mul_u64_u32_shr(parent_rate, 4096 * nir + nfr, 12);
+
+ return DIV_ROUND_CLOSEST_ULL(rate, (mr * pr));
+}
+
+static const struct clk_ops rzg3s_cpg_pll_ops = {
+ .recalc_rate = rzg3s_cpg_pll_clk_recalc_rate,
+};
+
static struct clk * __init
rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core,
struct clk **clks,
void __iomem *base,
- struct rzg2l_cpg_priv *priv)
+ struct rzg2l_cpg_priv *priv,
+ const struct clk_ops *ops)
{
struct device *dev = priv->dev;
const struct clk *parent;
@@ -735,7 +1037,7 @@ rzg2l_cpg_pll_clk_register(const struct cpg_core_clk *core,
parent_name = __clk_get_name(parent);
init.name = core->name;
- init.ops = &rzg2l_cpg_pll_ops;
+ init.ops = ops;
init.flags = 0;
init.parent_names = &parent_name;
init.num_parents = 1;
@@ -830,8 +1132,12 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core,
core->mult, div);
break;
case CLK_TYPE_SAM_PLL:
- clk = rzg2l_cpg_pll_clk_register(core, priv->clks,
- priv->base, priv);
+ clk = rzg2l_cpg_pll_clk_register(core, priv->clks, priv->base, priv,
+ &rzg2l_cpg_pll_ops);
+ break;
+ case CLK_TYPE_G3S_PLL:
+ clk = rzg2l_cpg_pll_clk_register(core, priv->clks, priv->base, priv,
+ &rzg3s_cpg_pll_ops);
break;
case CLK_TYPE_SIPLL5:
clk = rzg2l_cpg_sipll5_register(core, priv->clks, priv);
@@ -840,6 +1146,9 @@ rzg2l_cpg_register_core_clk(const struct cpg_core_clk *core,
clk = rzg2l_cpg_div_clk_register(core, priv->clks,
priv->base, priv);
break;
+ case CLK_TYPE_G3S_DIV:
+ clk = rzg3s_cpg_div_clk_register(core, priv->clks, priv->base, priv);
+ break;
case CLK_TYPE_MUX:
clk = rzg2l_cpg_mux_clk_register(core, priv->base, priv);
break;
@@ -895,7 +1204,6 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable)
struct rzg2l_cpg_priv *priv = clock->priv;
unsigned int reg = clock->off;
struct device *dev = priv->dev;
- unsigned long flags;
u32 bitmask = BIT(clock->bit);
u32 value;
int error;
@@ -905,17 +1213,14 @@ static int rzg2l_mod_clock_endisable(struct clk_hw *hw, bool enable)
return 0;
}
- dev_dbg(dev, "CLK_ON %u/%pC %s\n", CLK_ON_R(reg), hw->clk,
+ dev_dbg(dev, "CLK_ON 0x%x/%pC %s\n", CLK_ON_R(reg), hw->clk,
enable ? "ON" : "OFF");
- spin_lock_irqsave(&priv->rmw_lock, flags);
+ value = bitmask << 16;
if (enable)
- value = (bitmask << 16) | bitmask;
- else
- value = bitmask << 16;
- writel(value, priv->base + CLK_ON_R(reg));
+ value |= bitmask;
- spin_unlock_irqrestore(&priv->rmw_lock, flags);
+ writel(value, priv->base + CLK_ON_R(reg));
if (!enable)
return 0;
@@ -1401,6 +1706,12 @@ static const struct of_device_id rzg2l_cpg_match[] = {
.data = &r9a07g054_cpg_info,
},
#endif
+#ifdef CONFIG_CLK_R9A08G045
+ {
+ .compatible = "renesas,r9a08g045-cpg",
+ .data = &r9a08g045_cpg_info,
+ },
+#endif
#ifdef CONFIG_CLK_R9A09G011
{
.compatible = "renesas,r9a09g011-cpg",
diff --git a/drivers/clk/renesas/rzg2l-cpg.h b/drivers/clk/renesas/rzg2l-cpg.h
index 6cee9e56acc7..6e38c8fc888c 100644
--- a/drivers/clk/renesas/rzg2l-cpg.h
+++ b/drivers/clk/renesas/rzg2l-cpg.h
@@ -9,6 +9,8 @@
#ifndef __RENESAS_RZG2L_CPG_H__
#define __RENESAS_RZG2L_CPG_H__
+#include <linux/notifier.h>
+
#define CPG_SIPLL5_STBY (0x140)
#define CPG_SIPLL5_CLK1 (0x144)
#define CPG_SIPLL5_CLK3 (0x14C)
@@ -19,7 +21,6 @@
#define CPG_PL2_DDIV (0x204)
#define CPG_PL3A_DDIV (0x208)
#define CPG_PL6_DDIV (0x210)
-#define CPG_PL2SDHI_DSEL (0x218)
#define CPG_CLKSTATUS (0x280)
#define CPG_PL3_SSEL (0x408)
#define CPG_PL6_SSEL (0x414)
@@ -43,8 +44,6 @@
#define CPG_CLKSTATUS_SELSDHI0_STS BIT(28)
#define CPG_CLKSTATUS_SELSDHI1_STS BIT(29)
-#define CPG_SDHI_CLK_SWITCH_STATUS_TIMEOUT_US 20000
-
/* n = 0/1/2 for PLL1/4/6 */
#define CPG_SAMPLL_CLK1(n) (0x04 + (16 * n))
#define CPG_SAMPLL_CLK2(n) (0x08 + (16 * n))
@@ -69,9 +68,6 @@
#define SEL_PLL6_2 SEL_PLL_PACK(CPG_PL6_ETH_SSEL, 0, 1)
#define SEL_GPU2 SEL_PLL_PACK(CPG_PL6_SSEL, 12, 1)
-#define SEL_SDHI0 DDIV_PACK(CPG_PL2SDHI_DSEL, 0, 2)
-#define SEL_SDHI1 DDIV_PACK(CPG_PL2SDHI_DSEL, 4, 2)
-
#define EXTAL_FREQ_IN_MEGA_HZ (24)
/**
@@ -90,10 +86,15 @@ struct cpg_core_clk {
unsigned int mult;
unsigned int type;
unsigned int conf;
+ unsigned int sconf;
const struct clk_div_table *dtable;
+ const u32 *mtable;
+ const unsigned long invalid_rate;
+ const unsigned long max_rate;
const char * const *parent_names;
- int flag;
- int mux_flags;
+ notifier_fn_t notifier;
+ u32 flag;
+ u32 mux_flags;
int num_parents;
};
@@ -102,9 +103,11 @@ enum clk_types {
CLK_TYPE_IN, /* External Clock Input */
CLK_TYPE_FF, /* Fixed Factor Clock */
CLK_TYPE_SAM_PLL,
+ CLK_TYPE_G3S_PLL,
/* Clock with divider */
CLK_TYPE_DIV,
+ CLK_TYPE_G3S_DIV,
/* Clock with clock source selector */
CLK_TYPE_MUX,
@@ -129,6 +132,8 @@ enum clk_types {
DEF_TYPE(_name, _id, _type, .parent = _parent)
#define DEF_SAMPLL(_name, _id, _parent, _conf) \
DEF_TYPE(_name, _id, CLK_TYPE_SAM_PLL, .parent = _parent, .conf = _conf)
+#define DEF_G3S_PLL(_name, _id, _parent, _conf) \
+ DEF_TYPE(_name, _id, CLK_TYPE_G3S_PLL, .parent = _parent, .conf = _conf)
#define DEF_INPUT(_name, _id) \
DEF_TYPE(_name, _id, CLK_TYPE_IN)
#define DEF_FIXED(_name, _id, _parent, _mult, _div) \
@@ -141,6 +146,13 @@ enum clk_types {
DEF_TYPE(_name, _id, CLK_TYPE_DIV, .conf = _conf, \
.parent = _parent, .dtable = _dtable, \
.flag = CLK_DIVIDER_READ_ONLY)
+#define DEF_G3S_DIV(_name, _id, _parent, _conf, _sconf, _dtable, _invalid_rate, \
+ _max_rate, _clk_flags, _notif) \
+ DEF_TYPE(_name, _id, CLK_TYPE_G3S_DIV, .conf = _conf, .sconf = _sconf, \
+ .parent = _parent, .dtable = _dtable, \
+ .invalid_rate = _invalid_rate, \
+ .max_rate = _max_rate, .flag = (_clk_flags), \
+ .notifier = _notif)
#define DEF_MUX(_name, _id, _conf, _parent_names) \
DEF_TYPE(_name, _id, CLK_TYPE_MUX, .conf = _conf, \
.parent_names = _parent_names, \
@@ -151,10 +163,11 @@ enum clk_types {
.parent_names = _parent_names, \
.num_parents = ARRAY_SIZE(_parent_names), \
.mux_flags = CLK_MUX_READ_ONLY)
-#define DEF_SD_MUX(_name, _id, _conf, _parent_names) \
- DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, \
+#define DEF_SD_MUX(_name, _id, _conf, _sconf, _parent_names, _mtable, _clk_flags, _notifier) \
+ DEF_TYPE(_name, _id, CLK_TYPE_SD_MUX, .conf = _conf, .sconf = _sconf, \
.parent_names = _parent_names, \
- .num_parents = ARRAY_SIZE(_parent_names))
+ .num_parents = ARRAY_SIZE(_parent_names), \
+ .mtable = _mtable, .flag = _clk_flags, .notifier = _notifier)
#define DEF_PLL5_FOUTPOSTDIV(_name, _id, _parent) \
DEF_TYPE(_name, _id, CLK_TYPE_SIPLL5, .parent = _parent)
#define DEF_PLL5_4_MUX(_name, _id, _conf, _parent_names) \
@@ -271,6 +284,10 @@ struct rzg2l_cpg_info {
extern const struct rzg2l_cpg_info r9a07g043_cpg_info;
extern const struct rzg2l_cpg_info r9a07g044_cpg_info;
extern const struct rzg2l_cpg_info r9a07g054_cpg_info;
+extern const struct rzg2l_cpg_info r9a08g045_cpg_info;
extern const struct rzg2l_cpg_info r9a09g011_cpg_info;
+int rzg2l_cpg_sd_clk_mux_notifier(struct notifier_block *nb, unsigned long event, void *data);
+int rzg3s_cpg_div_clk_notifier(struct notifier_block *nb, unsigned long event, void *data);
+
#endif