* [PATCH] clk: sunxi: Add an A31/A23/A33 legacy PRCM MFD driver
@ 2022-11-19 4:47 Samuel Holland
2023-01-04 17:33 ` Sean Anderson
0 siblings, 1 reply; 2+ messages in thread
From: Samuel Holland @ 2022-11-19 4:47 UTC (permalink / raw)
To: Andre Przywara, Jagan Teki, Lukasz Majewski, Sean Anderson
Cc: Samuel Holland, u-boot
When the CCU binding and driver for the PRCM were written, it seems the
intention was to convert the A31 and A23/A33 devicetrees to use them.
However, that never happened, so those SoCs still use the old binding,
with an MFD for the PRCM, and separate DT nodes for clocks and resets.
The specifier in the legacy clock/reset bindings is the register bit
offset, so the drivers are trivial. Only the outer PRCM node has a reg
property, so the clock/reset drivers use the parent device's MMIO base.
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
I didn't reuse the sunxi gate/reset ops, because the driver is actually
smaller without them. I tested this driver on an A33 tablet.
drivers/clk/sunxi/Kconfig | 13 +++-
drivers/clk/sunxi/Makefile | 1 +
drivers/clk/sunxi/clk_sun6i_prcm.c | 104 +++++++++++++++++++++++++++++
3 files changed, 116 insertions(+), 2 deletions(-)
create mode 100644 drivers/clk/sunxi/clk_sun6i_prcm.c
diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
index bf11fad6eef..759ef410b66 100644
--- a/drivers/clk/sunxi/Kconfig
+++ b/drivers/clk/sunxi/Kconfig
@@ -39,11 +39,20 @@ config CLK_SUN6I_A31
on Allwinner A31/A31s SoC.
config CLK_SUN6I_A31_R
- bool "Clock driver for Allwinner A31 generation PRCM"
+ bool "Clock driver for Allwinner A31 generation PRCM (CCU)"
default SUNXI_GEN_SUN6I
help
This enables common clock driver support for the PRCM
- in Allwinner A31/A31s/A23/A33/A83T/H3/A64/H5 SoCs.
+ in Allwinner A31/A31s/A23/A33/A83T/H3/A64/H5 SoCs using
+ the CCU binding.
+
+config CLK_SUN6I_PRCM
+ bool "Clock driver for Allwinner A31 generation PRCM (legacy)"
+ default MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
+ help
+ This enables common clock driver support for the PRCM
+ in Allwinner A31/A31s/A23/A33 SoCs using the legacy PRCM
+ MFD binding.
config CLK_SUN8I_A23
bool "Clock driver for Allwinner A23/A33"
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index 895da02ebea..3266409cc7a 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_CLK_SUN4I_A10) += clk_a10.o
obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o
obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o
obj-$(CONFIG_CLK_SUN6I_A31_R) += clk_a31_r.o
+obj-$(CONFIG_CLK_SUN6I_PRCM) += clk_sun6i_prcm.o
obj-$(CONFIG_CLK_SUN8I_A23) += clk_a23.o
obj-$(CONFIG_CLK_SUN8I_A83T) += clk_a83t.o
obj-$(CONFIG_CLK_SUN8I_R40) += clk_r40.o
diff --git a/drivers/clk/sunxi/clk_sun6i_prcm.c b/drivers/clk/sunxi/clk_sun6i_prcm.c
new file mode 100644
index 00000000000..488b47e77a7
--- /dev/null
+++ b/drivers/clk/sunxi/clk_sun6i_prcm.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
+ */
+
+#include <clk-uclass.h>
+#include <dm.h>
+#include <reset-uclass.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+struct sun6i_prcm_plat {
+ void *base;
+};
+
+static int sun6i_prcm_set_field(struct udevice *dev, uint reg,
+ u32 mask, bool set)
+{
+ struct sun6i_prcm_plat *plat = dev_get_plat(dev->parent);
+
+ clrsetbits_le32(plat->base + reg, mask, set ? mask : 0);
+
+ return 0;
+}
+
+static int sun6i_prcm_clk_enable(struct clk *clk)
+{
+ return sun6i_prcm_set_field(clk->dev, 0x28, BIT(clk->id), true);
+}
+
+static int sun6i_prcm_clk_disable(struct clk *clk)
+{
+ return sun6i_prcm_set_field(clk->dev, 0x28, BIT(clk->id), false);
+}
+
+static const struct clk_ops sun6i_prcm_clk_ops = {
+ .enable = sun6i_prcm_clk_enable,
+ .disable = sun6i_prcm_clk_disable,
+};
+
+static const struct udevice_id sun6i_prcm_clk_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-apb0-gates-clk" },
+ { .compatible = "allwinner,sun8i-a23-apb0-gates-clk" },
+ { }
+};
+
+U_BOOT_DRIVER(sun6i_prcm_clk) = {
+ .name = "sun6i_prcm_clk",
+ .id = UCLASS_CLK,
+ .of_match = sun6i_prcm_clk_ids,
+ .ops = &sun6i_prcm_clk_ops,
+};
+
+static int sun6i_prcm_reset_assert(struct reset_ctl *reset)
+{
+ return sun6i_prcm_set_field(reset->dev, 0xb0, BIT(reset->id), false);
+}
+
+static int sun6i_prcm_reset_deassert(struct reset_ctl *reset)
+{
+ return sun6i_prcm_set_field(reset->dev, 0xb0, BIT(reset->id), true);
+}
+
+static const struct reset_ops sun6i_prcm_reset_ops = {
+ .rst_assert = sun6i_prcm_reset_assert,
+ .rst_deassert = sun6i_prcm_reset_deassert,
+};
+
+static const struct udevice_id sun6i_prcm_reset_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-clock-reset" },
+ { }
+};
+
+U_BOOT_DRIVER(sun6i_prcm_reset) = {
+ .name = "sun6i_prcm_reset",
+ .id = UCLASS_RESET,
+ .of_match = sun6i_prcm_reset_ids,
+ .ops = &sun6i_prcm_reset_ops,
+};
+
+static int sun6i_prcm_of_to_plat(struct udevice *dev)
+{
+ struct sun6i_prcm_plat *plat = dev_get_plat(dev);
+
+ plat->base = dev_read_addr_ptr(dev);
+ if (!plat->base)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static const struct udevice_id sun6i_prcm_mfd_ids[] = {
+ { .compatible = "allwinner,sun6i-a31-prcm" },
+ { .compatible = "allwinner,sun8i-a23-prcm" },
+ { }
+};
+
+U_BOOT_DRIVER(sun6i_prcm_mfd) = {
+ .name = "sun6i_prcm_mfd",
+ .id = UCLASS_SIMPLE_BUS,
+ .of_match = sun6i_prcm_mfd_ids,
+ .of_to_plat = sun6i_prcm_of_to_plat,
+ .plat_auto = sizeof(struct sun6i_prcm_plat),
+};
--
2.37.4
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] clk: sunxi: Add an A31/A23/A33 legacy PRCM MFD driver
2022-11-19 4:47 [PATCH] clk: sunxi: Add an A31/A23/A33 legacy PRCM MFD driver Samuel Holland
@ 2023-01-04 17:33 ` Sean Anderson
0 siblings, 0 replies; 2+ messages in thread
From: Sean Anderson @ 2023-01-04 17:33 UTC (permalink / raw)
To: Samuel Holland, Andre Przywara, Jagan Teki, Lukasz Majewski; +Cc: u-boot
On 11/18/22 23:47, Samuel Holland wrote:
> When the CCU binding and driver for the PRCM were written, it seems the
> intention was to convert the A31 and A23/A33 devicetrees to use them.
> However, that never happened, so those SoCs still use the old binding,
> with an MFD for the PRCM, and separate DT nodes for clocks and resets.
>
> The specifier in the legacy clock/reset bindings is the register bit
> offset, so the drivers are trivial. Only the outer PRCM node has a reg
> property, so the clock/reset drivers use the parent device's MMIO base.
>
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
> I didn't reuse the sunxi gate/reset ops, because the driver is actually
> smaller without them. I tested this driver on an A33 tablet.
>
> drivers/clk/sunxi/Kconfig | 13 +++-
> drivers/clk/sunxi/Makefile | 1 +
> drivers/clk/sunxi/clk_sun6i_prcm.c | 104 +++++++++++++++++++++++++++++
> 3 files changed, 116 insertions(+), 2 deletions(-)
> create mode 100644 drivers/clk/sunxi/clk_sun6i_prcm.c
>
> diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig
> index bf11fad6eef..759ef410b66 100644
> --- a/drivers/clk/sunxi/Kconfig
> +++ b/drivers/clk/sunxi/Kconfig
> @@ -39,11 +39,20 @@ config CLK_SUN6I_A31
> on Allwinner A31/A31s SoC.
>
> config CLK_SUN6I_A31_R
> - bool "Clock driver for Allwinner A31 generation PRCM"
> + bool "Clock driver for Allwinner A31 generation PRCM (CCU)"
> default SUNXI_GEN_SUN6I
> help
> This enables common clock driver support for the PRCM
> - in Allwinner A31/A31s/A23/A33/A83T/H3/A64/H5 SoCs.
> + in Allwinner A31/A31s/A23/A33/A83T/H3/A64/H5 SoCs using
> + the CCU binding.
> +
> +config CLK_SUN6I_PRCM
> + bool "Clock driver for Allwinner A31 generation PRCM (legacy)"
> + default MACH_SUN6I || MACH_SUN8I_A23 || MACH_SUN8I_A33
> + help
> + This enables common clock driver support for the PRCM
> + in Allwinner A31/A31s/A23/A33 SoCs using the legacy PRCM
> + MFD binding.
>
> config CLK_SUN8I_A23
> bool "Clock driver for Allwinner A23/A33"
> diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
> index 895da02ebea..3266409cc7a 100644
> --- a/drivers/clk/sunxi/Makefile
> +++ b/drivers/clk/sunxi/Makefile
> @@ -13,6 +13,7 @@ obj-$(CONFIG_CLK_SUN4I_A10) += clk_a10.o
> obj-$(CONFIG_CLK_SUN5I_A10S) += clk_a10s.o
> obj-$(CONFIG_CLK_SUN6I_A31) += clk_a31.o
> obj-$(CONFIG_CLK_SUN6I_A31_R) += clk_a31_r.o
> +obj-$(CONFIG_CLK_SUN6I_PRCM) += clk_sun6i_prcm.o
> obj-$(CONFIG_CLK_SUN8I_A23) += clk_a23.o
> obj-$(CONFIG_CLK_SUN8I_A83T) += clk_a83t.o
> obj-$(CONFIG_CLK_SUN8I_R40) += clk_r40.o
> diff --git a/drivers/clk/sunxi/clk_sun6i_prcm.c b/drivers/clk/sunxi/clk_sun6i_prcm.c
> new file mode 100644
> index 00000000000..488b47e77a7
> --- /dev/null
> +++ b/drivers/clk/sunxi/clk_sun6i_prcm.c
> @@ -0,0 +1,104 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Copyright (C) 2022 Samuel Holland <samuel@sholland.org>
> + */
> +
> +#include <clk-uclass.h>
> +#include <dm.h>
> +#include <reset-uclass.h>
> +#include <asm/io.h>
> +#include <linux/bitops.h>
> +
> +struct sun6i_prcm_plat {
> + void *base;
> +};
> +
> +static int sun6i_prcm_set_field(struct udevice *dev, uint reg,
> + u32 mask, bool set)
> +{
> + struct sun6i_prcm_plat *plat = dev_get_plat(dev->parent);
> +
> + clrsetbits_le32(plat->base + reg, mask, set ? mask : 0);
> +
> + return 0;
> +}
> +
> +static int sun6i_prcm_clk_enable(struct clk *clk)
> +{
> + return sun6i_prcm_set_field(clk->dev, 0x28, BIT(clk->id), true);
> +}
> +
> +static int sun6i_prcm_clk_disable(struct clk *clk)
> +{
> + return sun6i_prcm_set_field(clk->dev, 0x28, BIT(clk->id), false);
> +}
> +
> +static const struct clk_ops sun6i_prcm_clk_ops = {
> + .enable = sun6i_prcm_clk_enable,
> + .disable = sun6i_prcm_clk_disable,
> +};
> +
> +static const struct udevice_id sun6i_prcm_clk_ids[] = {
> + { .compatible = "allwinner,sun6i-a31-apb0-gates-clk" },
> + { .compatible = "allwinner,sun8i-a23-apb0-gates-clk" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(sun6i_prcm_clk) = {
> + .name = "sun6i_prcm_clk",
> + .id = UCLASS_CLK,
> + .of_match = sun6i_prcm_clk_ids,
> + .ops = &sun6i_prcm_clk_ops,
> +};
> +
> +static int sun6i_prcm_reset_assert(struct reset_ctl *reset)
> +{
> + return sun6i_prcm_set_field(reset->dev, 0xb0, BIT(reset->id), false);
> +}
> +
> +static int sun6i_prcm_reset_deassert(struct reset_ctl *reset)
> +{
> + return sun6i_prcm_set_field(reset->dev, 0xb0, BIT(reset->id), true);
> +}
> +
> +static const struct reset_ops sun6i_prcm_reset_ops = {
> + .rst_assert = sun6i_prcm_reset_assert,
> + .rst_deassert = sun6i_prcm_reset_deassert,
> +};
> +
> +static const struct udevice_id sun6i_prcm_reset_ids[] = {
> + { .compatible = "allwinner,sun6i-a31-clock-reset" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(sun6i_prcm_reset) = {
> + .name = "sun6i_prcm_reset",
> + .id = UCLASS_RESET,
> + .of_match = sun6i_prcm_reset_ids,
> + .ops = &sun6i_prcm_reset_ops,
> +};
> +
> +static int sun6i_prcm_of_to_plat(struct udevice *dev)
> +{
> + struct sun6i_prcm_plat *plat = dev_get_plat(dev);
> +
> + plat->base = dev_read_addr_ptr(dev);
> + if (!plat->base)
> + return -ENOMEM;
> +
> + return 0;
> +}
> +
> +static const struct udevice_id sun6i_prcm_mfd_ids[] = {
> + { .compatible = "allwinner,sun6i-a31-prcm" },
> + { .compatible = "allwinner,sun8i-a23-prcm" },
> + { }
> +};
> +
> +U_BOOT_DRIVER(sun6i_prcm_mfd) = {
> + .name = "sun6i_prcm_mfd",
> + .id = UCLASS_SIMPLE_BUS,
> + .of_match = sun6i_prcm_mfd_ids,
> + .of_to_plat = sun6i_prcm_of_to_plat,
> + .plat_auto = sizeof(struct sun6i_prcm_plat),
> +};
Reviewed-by: Sean Anderson <seanga2@gmail.com>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2023-01-04 17:34 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-11-19 4:47 [PATCH] clk: sunxi: Add an A31/A23/A33 legacy PRCM MFD driver Samuel Holland
2023-01-04 17:33 ` Sean Anderson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox