From 7af26f3c11640c0ca3bd478e46454f4ec0cfc96a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 10 Sep 2024 18:32:43 +0200 Subject: [PATCH 01/10] reset: amlogic: convert driver to regmap To allow using the same driver for the main reset controller and the auxiliary ones embedded in the clock controllers, convert the the Amlogic reset driver to regmap. Reviewed-by: Neil Armstrong Signed-off-by: Jerome Brunet Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-1-60be62635d3e@baylibre.com Signed-off-by: Philipp Zabel --- drivers/reset/Kconfig | 1 + drivers/reset/reset-meson.c | 79 ++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 5484a65f66b95..c730ba6f678b0 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -157,6 +157,7 @@ config RESET_MESON tristate "Meson Reset Driver" depends on ARCH_MESON || COMPILE_TEST default ARCH_MESON + select REGMAP_MMIO help This enables the reset driver for Amlogic Meson SoCs. diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 1e9fca3e30e8e..9dd38cc209e27 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -11,36 +11,43 @@ #include #include #include +#include #include #include #include -#define BITS_PER_REG 32 - struct meson_reset_param { int reg_count; int level_offset; }; struct meson_reset { - void __iomem *reg_base; const struct meson_reset_param *param; struct reset_controller_dev rcdev; - spinlock_t lock; + struct regmap *map; }; +static void meson_reset_offset_and_bit(struct meson_reset *data, + unsigned long id, + unsigned int *offset, + unsigned int *bit) +{ + unsigned int stride = regmap_get_reg_stride(data->map); + + *offset = (id / (stride * BITS_PER_BYTE)) * stride; + *bit = id % (stride * BITS_PER_BYTE); +} + static int meson_reset_reset(struct reset_controller_dev *rcdev, - unsigned long id) + unsigned long id) { struct meson_reset *data = container_of(rcdev, struct meson_reset, rcdev); - unsigned int bank = id / BITS_PER_REG; - unsigned int offset = id % BITS_PER_REG; - void __iomem *reg_addr = data->reg_base + (bank << 2); + unsigned int offset, bit; - writel(BIT(offset), reg_addr); + meson_reset_offset_and_bit(data, id, &offset, &bit); - return 0; + return regmap_write(data->map, offset, BIT(bit)); } static int meson_reset_level(struct reset_controller_dev *rcdev, @@ -48,25 +55,13 @@ static int meson_reset_level(struct reset_controller_dev *rcdev, { struct meson_reset *data = container_of(rcdev, struct meson_reset, rcdev); - unsigned int bank = id / BITS_PER_REG; - unsigned int offset = id % BITS_PER_REG; - void __iomem *reg_addr; - unsigned long flags; - u32 reg; + unsigned int offset, bit; - reg_addr = data->reg_base + data->param->level_offset + (bank << 2); + meson_reset_offset_and_bit(data, id, &offset, &bit); + offset += data->param->level_offset; - spin_lock_irqsave(&data->lock, flags); - - reg = readl(reg_addr); - if (assert) - writel(reg & ~BIT(offset), reg_addr); - else - writel(reg | BIT(offset), reg_addr); - - spin_unlock_irqrestore(&data->lock, flags); - - return 0; + return regmap_update_bits(data->map, offset, + BIT(bit), assert ? 0 : BIT(bit)); } static int meson_reset_assert(struct reset_controller_dev *rcdev, @@ -119,30 +114,42 @@ static const struct of_device_id meson_reset_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, meson_reset_dt_ids); +static const struct regmap_config regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, +}; + static int meson_reset_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct meson_reset *data; + void __iomem *base; - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM; - data->reg_base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(data->reg_base)) - return PTR_ERR(data->reg_base); + base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(base)) + return PTR_ERR(base); - data->param = of_device_get_match_data(&pdev->dev); + data->param = of_device_get_match_data(dev); if (!data->param) return -ENODEV; - spin_lock_init(&data->lock); + data->map = devm_regmap_init_mmio(dev, base, ®map_config); + if (IS_ERR(data->map)) + return dev_err_probe(dev, PTR_ERR(data->map), + "can't init regmap mmio region\n"); data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = data->param->reg_count * BITS_PER_REG; + data->rcdev.nr_resets = data->param->reg_count * BITS_PER_BYTE + * regmap_config.reg_stride; data->rcdev.ops = &meson_reset_ops; - data->rcdev.of_node = pdev->dev.of_node; + data->rcdev.of_node = dev->of_node; - return devm_reset_controller_register(&pdev->dev, &data->rcdev); + return devm_reset_controller_register(dev, &data->rcdev); } static struct platform_driver meson_reset_driver = { From 58d1d138db3243f1b102c0ae2848738d443abf97 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 10 Sep 2024 18:32:44 +0200 Subject: [PATCH 02/10] reset: amlogic: use generic data matching function There is no need to use the DT specific function to get matching data, use the generic one instead Suggested-by: Stephen Boyd Reviewed-by: Neil Armstrong Signed-off-by: Jerome Brunet Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-2-60be62635d3e@baylibre.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 9dd38cc209e27..848c2d88503ef 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -134,7 +134,7 @@ static int meson_reset_probe(struct platform_device *pdev) if (IS_ERR(base)) return PTR_ERR(base); - data->param = of_device_get_match_data(dev); + data->param = device_get_match_data(dev); if (!data->param) return -ENODEV; From ee64998610329653d12866bedc941b6f045ee29f Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 10 Sep 2024 18:32:45 +0200 Subject: [PATCH 03/10] reset: amlogic: make parameters unsigned register count and offset cannot be negative. Use unsigned integer for this. Suggested-by: Stephen Boyd Reviewed-by: Neil Armstrong Signed-off-by: Jerome Brunet Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-3-60be62635d3e@baylibre.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 848c2d88503ef..50bd2241ef2fc 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -17,8 +17,8 @@ #include struct meson_reset_param { - int reg_count; - int level_offset; + unsigned int reg_count; + unsigned int level_offset; }; struct meson_reset { From 6b2d2e5c7a10015af554017d071e64818959be9a Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 10 Sep 2024 18:32:46 +0200 Subject: [PATCH 04/10] reset: amlogic: add driver parameters To allow using the same driver for the main reset controller and the auxiliary ones embedded in the clock controllers, allow to customise the reset offset, same as the level offset. Also add an option to make the level reset active low or high. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-4-60be62635d3e@baylibre.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 50bd2241ef2fc..6a90613c80956 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -18,7 +18,9 @@ struct meson_reset_param { unsigned int reg_count; + unsigned int reset_offset; unsigned int level_offset; + bool level_low_reset; }; struct meson_reset { @@ -46,6 +48,7 @@ static int meson_reset_reset(struct reset_controller_dev *rcdev, unsigned int offset, bit; meson_reset_offset_and_bit(data, id, &offset, &bit); + offset += data->param->reset_offset; return regmap_write(data->map, offset, BIT(bit)); } @@ -59,9 +62,10 @@ static int meson_reset_level(struct reset_controller_dev *rcdev, meson_reset_offset_and_bit(data, id, &offset, &bit); offset += data->param->level_offset; + assert ^= data->param->level_low_reset; return regmap_update_bits(data->map, offset, - BIT(bit), assert ? 0 : BIT(bit)); + BIT(bit), assert ? BIT(bit) : 0); } static int meson_reset_assert(struct reset_controller_dev *rcdev, @@ -84,22 +88,30 @@ static const struct reset_control_ops meson_reset_ops = { static const struct meson_reset_param meson8b_param = { .reg_count = 8, + .reset_offset = 0x0, .level_offset = 0x7c, + .level_low_reset = true, }; static const struct meson_reset_param meson_a1_param = { .reg_count = 3, + .reset_offset = 0x0, .level_offset = 0x40, + .level_low_reset = true, }; static const struct meson_reset_param meson_s4_param = { .reg_count = 6, + .reset_offset = 0x0, .level_offset = 0x40, + .level_low_reset = true, }; static const struct meson_reset_param t7_param = { .reg_count = 7, + .reset_offset = 0x0, .level_offset = 0x40, + .level_low_reset = true, }; static const struct of_device_id meson_reset_dt_ids[] = { From 83dde3e5df6a5be9631428acdc7bfbb10e8df07c Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 10 Sep 2024 18:32:47 +0200 Subject: [PATCH 05/10] reset: amlogic: use reset number instead of register count The reset driver from audio clock controller may register less reset than a register can hold. To avoid making any change while switching to auxiliary support, use the number of reset instead of the register count to define the bounds of the reset controller. Reviewed-by: Neil Armstrong Signed-off-by: Jerome Brunet Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-5-60be62635d3e@baylibre.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index 6a90613c80956..e31c1b7c9e4d7 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -17,7 +17,7 @@ #include struct meson_reset_param { - unsigned int reg_count; + unsigned int reset_num; unsigned int reset_offset; unsigned int level_offset; bool level_low_reset; @@ -87,28 +87,28 @@ static const struct reset_control_ops meson_reset_ops = { }; static const struct meson_reset_param meson8b_param = { - .reg_count = 8, + .reset_num = 256, .reset_offset = 0x0, .level_offset = 0x7c, .level_low_reset = true, }; static const struct meson_reset_param meson_a1_param = { - .reg_count = 3, + .reset_num = 96, .reset_offset = 0x0, .level_offset = 0x40, .level_low_reset = true, }; static const struct meson_reset_param meson_s4_param = { - .reg_count = 6, + .reset_num = 192, .reset_offset = 0x0, .level_offset = 0x40, .level_low_reset = true, }; static const struct meson_reset_param t7_param = { - .reg_count = 7, + .reset_num = 224, .reset_offset = 0x0, .level_offset = 0x40, .level_low_reset = true, @@ -156,8 +156,7 @@ static int meson_reset_probe(struct platform_device *pdev) "can't init regmap mmio region\n"); data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = data->param->reg_count * BITS_PER_BYTE - * regmap_config.reg_stride; + data->rcdev.nr_resets = data->param->reset_num; data->rcdev.ops = &meson_reset_ops; data->rcdev.of_node = dev->of_node; From d623ee26050f8e9a6d68ee3a1a97b30493cd2b1b Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 10 Sep 2024 18:32:48 +0200 Subject: [PATCH 06/10] reset: amlogic: add reset status support Add a callback to check the status of the level reset, as done in the reset driver of the audio clock controller. This is done keep the functionality when the audio reset controller get migrated to meson-reset. Reviewed-by: Neil Armstrong Signed-off-by: Jerome Brunet Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-6-60be62635d3e@baylibre.com Signed-off-by: Philipp Zabel --- drivers/reset/reset-meson.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/reset/reset-meson.c b/drivers/reset/reset-meson.c index e31c1b7c9e4d7..af690d3012ec1 100644 --- a/drivers/reset/reset-meson.c +++ b/drivers/reset/reset-meson.c @@ -68,6 +68,22 @@ static int meson_reset_level(struct reset_controller_dev *rcdev, BIT(bit), assert ? BIT(bit) : 0); } +static int meson_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct meson_reset *data = + container_of(rcdev, struct meson_reset, rcdev); + unsigned int val, offset, bit; + + meson_reset_offset_and_bit(data, id, &offset, &bit); + offset += data->param->level_offset; + + regmap_read(data->map, offset, &val); + val = !!(BIT(bit) & val); + + return val ^ data->param->level_low_reset; +} + static int meson_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) { @@ -84,6 +100,7 @@ static const struct reset_control_ops meson_reset_ops = { .reset = meson_reset_reset, .assert = meson_reset_assert, .deassert = meson_reset_deassert, + .status = meson_reset_status, }; static const struct meson_reset_param meson8b_param = { From 2c138ee3354f8088769d05701a2e16d1cb4cc22d Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 10 Sep 2024 18:32:49 +0200 Subject: [PATCH 07/10] reset: amlogic: move drivers to a dedicated directory The meson reset driver will be split in two part, one implemeting the ops, the other providing the platform driver support. This will be done to facilitate the addition of the auxiliary bus support. To avoid making a mess in drivers/reset/ while doing so, move the amlogic reset drivers to a dedicated directory. Reviewed-by: Neil Armstrong Signed-off-by: Jerome Brunet Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-7-60be62635d3e@baylibre.com Signed-off-by: Philipp Zabel --- drivers/reset/Kconfig | 16 +--------------- drivers/reset/Makefile | 3 +-- drivers/reset/amlogic/Kconfig | 14 ++++++++++++++ drivers/reset/amlogic/Makefile | 2 ++ .../reset/{ => amlogic}/reset-meson-audio-arb.c | 0 drivers/reset/{ => amlogic}/reset-meson.c | 0 6 files changed, 18 insertions(+), 17 deletions(-) create mode 100644 drivers/reset/amlogic/Kconfig create mode 100644 drivers/reset/amlogic/Makefile rename drivers/reset/{ => amlogic}/reset-meson-audio-arb.c (100%) rename drivers/reset/{ => amlogic}/reset-meson.c (100%) diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index c730ba6f678b0..d28c4401a3109 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -153,21 +153,6 @@ config RESET_MCHP_SPARX5 help This driver supports switch core reset for the Microchip Sparx5 SoC. -config RESET_MESON - tristate "Meson Reset Driver" - depends on ARCH_MESON || COMPILE_TEST - default ARCH_MESON - select REGMAP_MMIO - help - This enables the reset driver for Amlogic Meson SoCs. - -config RESET_MESON_AUDIO_ARB - tristate "Meson Audio Memory Arbiter Reset Driver" - depends on ARCH_MESON || COMPILE_TEST - help - This enables the reset driver for Audio Memory Arbiter of - Amlogic's A113 based SoCs - config RESET_NPCM bool "NPCM BMC Reset Driver" if COMPILE_TEST default ARCH_NPCM @@ -357,6 +342,7 @@ config RESET_ZYNQMP help This enables the reset controller driver for Xilinx ZynqMP SoCs. +source "drivers/reset/amlogic/Kconfig" source "drivers/reset/starfive/Kconfig" source "drivers/reset/sti/Kconfig" source "drivers/reset/hisilicon/Kconfig" diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index 4411a2a124d7d..677c4d1e26320 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 obj-y += core.o +obj-y += amlogic/ obj-y += hisilicon/ obj-y += starfive/ obj-y += sti/ @@ -21,8 +22,6 @@ obj-$(CONFIG_RESET_K210) += reset-k210.o obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o -obj-$(CONFIG_RESET_MESON) += reset-meson.o -obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o obj-$(CONFIG_RESET_NPCM) += reset-npcm.o obj-$(CONFIG_RESET_NUVOTON_MA35D1) += reset-ma35d1.o obj-$(CONFIG_RESET_PISTACHIO) += reset-pistachio.o diff --git a/drivers/reset/amlogic/Kconfig b/drivers/reset/amlogic/Kconfig new file mode 100644 index 0000000000000..532e6a4f78659 --- /dev/null +++ b/drivers/reset/amlogic/Kconfig @@ -0,0 +1,14 @@ +config RESET_MESON + tristate "Meson Reset Driver" + depends on ARCH_MESON || COMPILE_TEST + default ARCH_MESON + select REGMAP_MMIO + help + This enables the reset driver for Amlogic Meson SoCs. + +config RESET_MESON_AUDIO_ARB + tristate "Meson Audio Memory Arbiter Reset Driver" + depends on ARCH_MESON || COMPILE_TEST + help + This enables the reset driver for Audio Memory Arbiter of + Amlogic's A113 based SoCs diff --git a/drivers/reset/amlogic/Makefile b/drivers/reset/amlogic/Makefile new file mode 100644 index 0000000000000..55509fc785131 --- /dev/null +++ b/drivers/reset/amlogic/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_RESET_MESON) += reset-meson.o +obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o diff --git a/drivers/reset/reset-meson-audio-arb.c b/drivers/reset/amlogic/reset-meson-audio-arb.c similarity index 100% rename from drivers/reset/reset-meson-audio-arb.c rename to drivers/reset/amlogic/reset-meson-audio-arb.c diff --git a/drivers/reset/reset-meson.c b/drivers/reset/amlogic/reset-meson.c similarity index 100% rename from drivers/reset/reset-meson.c rename to drivers/reset/amlogic/reset-meson.c From c38ae95cd31c636ae21fff3e6a9250df680f0cdd Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 10 Sep 2024 18:32:50 +0200 Subject: [PATCH 08/10] reset: amlogic: split the device core and platform probe To prepare the addition of the auxiliary device support, split out the device coomon functions from the probe of the platform device. The device core function will be common to both the platform and auxiliary driver. Signed-off-by: Jerome Brunet Reviewed-by: Neil Armstrong Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-8-60be62635d3e@baylibre.com Signed-off-by: Philipp Zabel --- drivers/reset/amlogic/Kconfig | 7 +- drivers/reset/amlogic/Makefile | 1 + drivers/reset/amlogic/reset-meson-common.c | 121 ++++++++++++++++++++ drivers/reset/amlogic/reset-meson.c | 122 +++------------------ drivers/reset/amlogic/reset-meson.h | 24 ++++ 5 files changed, 167 insertions(+), 108 deletions(-) create mode 100644 drivers/reset/amlogic/reset-meson-common.c create mode 100644 drivers/reset/amlogic/reset-meson.h diff --git a/drivers/reset/amlogic/Kconfig b/drivers/reset/amlogic/Kconfig index 532e6a4f78659..1d77987088f43 100644 --- a/drivers/reset/amlogic/Kconfig +++ b/drivers/reset/amlogic/Kconfig @@ -1,10 +1,15 @@ +config RESET_MESON_COMMON + tristate + select REGMAP + config RESET_MESON tristate "Meson Reset Driver" depends on ARCH_MESON || COMPILE_TEST default ARCH_MESON select REGMAP_MMIO + select RESET_MESON_COMMON help - This enables the reset driver for Amlogic Meson SoCs. + This enables the reset driver for Amlogic SoCs. config RESET_MESON_AUDIO_ARB tristate "Meson Audio Memory Arbiter Reset Driver" diff --git a/drivers/reset/amlogic/Makefile b/drivers/reset/amlogic/Makefile index 55509fc785131..74aaa2fb5e13e 100644 --- a/drivers/reset/amlogic/Makefile +++ b/drivers/reset/amlogic/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_RESET_MESON) += reset-meson.o +obj-$(CONFIG_RESET_MESON_COMMON) += reset-meson-common.o obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o diff --git a/drivers/reset/amlogic/reset-meson-common.c b/drivers/reset/amlogic/reset-meson-common.c new file mode 100644 index 0000000000000..d57544801ae90 --- /dev/null +++ b/drivers/reset/amlogic/reset-meson-common.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Amlogic Meson Reset core functions + * + * Copyright (c) 2016-2024 BayLibre, SAS. + * Authors: Neil Armstrong + * Jerome Brunet + */ + +#include +#include +#include +#include + +#include "reset-meson.h" + +struct meson_reset { + const struct meson_reset_param *param; + struct reset_controller_dev rcdev; + struct regmap *map; +}; + +static void meson_reset_offset_and_bit(struct meson_reset *data, + unsigned long id, + unsigned int *offset, + unsigned int *bit) +{ + unsigned int stride = regmap_get_reg_stride(data->map); + + *offset = (id / (stride * BITS_PER_BYTE)) * stride; + *bit = id % (stride * BITS_PER_BYTE); +} + +static int meson_reset_reset(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct meson_reset *data = + container_of(rcdev, struct meson_reset, rcdev); + unsigned int offset, bit; + + meson_reset_offset_and_bit(data, id, &offset, &bit); + offset += data->param->reset_offset; + + return regmap_write(data->map, offset, BIT(bit)); +} + +static int meson_reset_level(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) +{ + struct meson_reset *data = + container_of(rcdev, struct meson_reset, rcdev); + unsigned int offset, bit; + + meson_reset_offset_and_bit(data, id, &offset, &bit); + offset += data->param->level_offset; + assert ^= data->param->level_low_reset; + + return regmap_update_bits(data->map, offset, + BIT(bit), assert ? BIT(bit) : 0); +} + +static int meson_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct meson_reset *data = + container_of(rcdev, struct meson_reset, rcdev); + unsigned int val, offset, bit; + + meson_reset_offset_and_bit(data, id, &offset, &bit); + offset += data->param->level_offset; + + regmap_read(data->map, offset, &val); + val = !!(BIT(bit) & val); + + return val ^ data->param->level_low_reset; +} + +static int meson_reset_assert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_reset_level(rcdev, id, true); +} + +static int meson_reset_deassert(struct reset_controller_dev *rcdev, + unsigned long id) +{ + return meson_reset_level(rcdev, id, false); +} + +static const struct reset_control_ops meson_reset_ops = { + .reset = meson_reset_reset, + .assert = meson_reset_assert, + .deassert = meson_reset_deassert, + .status = meson_reset_status, +}; + +int meson_reset_controller_register(struct device *dev, struct regmap *map, + const struct meson_reset_param *param) +{ + struct meson_reset *data; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->param = param; + data->map = map; + data->rcdev.owner = dev->driver->owner; + data->rcdev.nr_resets = param->reset_num; + data->rcdev.ops = &meson_reset_ops; + data->rcdev.of_node = dev->of_node; + + return devm_reset_controller_register(dev, &data->rcdev); +} +EXPORT_SYMBOL_NS_GPL(meson_reset_controller_register, MESON_RESET); + +MODULE_DESCRIPTION("Amlogic Meson Reset Core function"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(MESON_RESET); diff --git a/drivers/reset/amlogic/reset-meson.c b/drivers/reset/amlogic/reset-meson.c index af690d3012ec1..feb19bf6da77b 100644 --- a/drivers/reset/amlogic/reset-meson.c +++ b/drivers/reset/amlogic/reset-meson.c @@ -2,106 +2,20 @@ /* * Amlogic Meson Reset Controller driver * - * Copyright (c) 2016 BayLibre, SAS. - * Author: Neil Armstrong + * Copyright (c) 2016-2024 BayLibre, SAS. + * Authors: Neil Armstrong + * Jerome Brunet */ + #include -#include #include #include #include #include #include #include -#include -#include - -struct meson_reset_param { - unsigned int reset_num; - unsigned int reset_offset; - unsigned int level_offset; - bool level_low_reset; -}; - -struct meson_reset { - const struct meson_reset_param *param; - struct reset_controller_dev rcdev; - struct regmap *map; -}; - -static void meson_reset_offset_and_bit(struct meson_reset *data, - unsigned long id, - unsigned int *offset, - unsigned int *bit) -{ - unsigned int stride = regmap_get_reg_stride(data->map); - - *offset = (id / (stride * BITS_PER_BYTE)) * stride; - *bit = id % (stride * BITS_PER_BYTE); -} - -static int meson_reset_reset(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct meson_reset *data = - container_of(rcdev, struct meson_reset, rcdev); - unsigned int offset, bit; - - meson_reset_offset_and_bit(data, id, &offset, &bit); - offset += data->param->reset_offset; - - return regmap_write(data->map, offset, BIT(bit)); -} - -static int meson_reset_level(struct reset_controller_dev *rcdev, - unsigned long id, bool assert) -{ - struct meson_reset *data = - container_of(rcdev, struct meson_reset, rcdev); - unsigned int offset, bit; - - meson_reset_offset_and_bit(data, id, &offset, &bit); - offset += data->param->level_offset; - assert ^= data->param->level_low_reset; - return regmap_update_bits(data->map, offset, - BIT(bit), assert ? BIT(bit) : 0); -} - -static int meson_reset_status(struct reset_controller_dev *rcdev, - unsigned long id) -{ - struct meson_reset *data = - container_of(rcdev, struct meson_reset, rcdev); - unsigned int val, offset, bit; - - meson_reset_offset_and_bit(data, id, &offset, &bit); - offset += data->param->level_offset; - - regmap_read(data->map, offset, &val); - val = !!(BIT(bit) & val); - - return val ^ data->param->level_low_reset; -} - -static int meson_reset_assert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return meson_reset_level(rcdev, id, true); -} - -static int meson_reset_deassert(struct reset_controller_dev *rcdev, - unsigned long id) -{ - return meson_reset_level(rcdev, id, false); -} - -static const struct reset_control_ops meson_reset_ops = { - .reset = meson_reset_reset, - .assert = meson_reset_assert, - .deassert = meson_reset_deassert, - .status = meson_reset_status, -}; +#include "reset-meson.h" static const struct meson_reset_param meson8b_param = { .reset_num = 256, @@ -151,33 +65,25 @@ static const struct regmap_config regmap_config = { static int meson_reset_probe(struct platform_device *pdev) { + const struct meson_reset_param *param; struct device *dev = &pdev->dev; - struct meson_reset *data; + struct regmap *map; void __iomem *base; - data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); - data->param = device_get_match_data(dev); - if (!data->param) + param = device_get_match_data(dev); + if (!param) return -ENODEV; - data->map = devm_regmap_init_mmio(dev, base, ®map_config); - if (IS_ERR(data->map)) - return dev_err_probe(dev, PTR_ERR(data->map), + map = devm_regmap_init_mmio(dev, base, ®map_config); + if (IS_ERR(map)) + return dev_err_probe(dev, PTR_ERR(map), "can't init regmap mmio region\n"); - data->rcdev.owner = THIS_MODULE; - data->rcdev.nr_resets = data->param->reset_num; - data->rcdev.ops = &meson_reset_ops; - data->rcdev.of_node = dev->of_node; - - return devm_reset_controller_register(dev, &data->rcdev); + return meson_reset_controller_register(dev, map, param); } static struct platform_driver meson_reset_driver = { @@ -191,4 +97,6 @@ module_platform_driver(meson_reset_driver); MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver"); MODULE_AUTHOR("Neil Armstrong "); +MODULE_AUTHOR("Jerome Brunet "); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(MESON_RESET); diff --git a/drivers/reset/amlogic/reset-meson.h b/drivers/reset/amlogic/reset-meson.h new file mode 100644 index 0000000000000..4e1dbd7569c59 --- /dev/null +++ b/drivers/reset/amlogic/reset-meson.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (c) 2024 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#ifndef __MESON_RESET_H +#define __MESON_RESET_H + +#include +#include +#include + +struct meson_reset_param { + unsigned int reset_num; + unsigned int reset_offset; + unsigned int level_offset; + bool level_low_reset; +}; + +int meson_reset_controller_register(struct device *dev, struct regmap *map, + const struct meson_reset_param *param); + +#endif /* __MESON_RESET_H */ From fb4c31587adfa9cd50661a535bdbfcc4da57ee38 Mon Sep 17 00:00:00 2001 From: Jerome Brunet Date: Tue, 10 Sep 2024 18:32:51 +0200 Subject: [PATCH 09/10] reset: amlogic: add auxiliary reset driver support Add support for the reset controller present in the audio clock controller of the g12 and sm1 SoC families, using the auxiliary bus. This is expected to replace the driver currently present directly within the related clock driver. Signed-off-by: Jerome Brunet Reviewed-by: Philipp Zabel Link: https://lore.kernel.org/r/20240910-meson-rst-aux-v5-9-60be62635d3e@baylibre.com Signed-off-by: Philipp Zabel --- drivers/reset/amlogic/Kconfig | 8 ++ drivers/reset/amlogic/Makefile | 1 + drivers/reset/amlogic/reset-meson-aux.c | 136 +++++++++++++++++++++ drivers/reset/amlogic/reset-meson-common.c | 25 +++- drivers/reset/amlogic/reset-meson.c | 3 + drivers/reset/amlogic/reset-meson.h | 4 + include/soc/amlogic/reset-meson-aux.h | 23 ++++ 7 files changed, 198 insertions(+), 2 deletions(-) create mode 100644 drivers/reset/amlogic/reset-meson-aux.c create mode 100644 include/soc/amlogic/reset-meson-aux.h diff --git a/drivers/reset/amlogic/Kconfig b/drivers/reset/amlogic/Kconfig index 1d77987088f43..3bee9fd602694 100644 --- a/drivers/reset/amlogic/Kconfig +++ b/drivers/reset/amlogic/Kconfig @@ -11,6 +11,14 @@ config RESET_MESON help This enables the reset driver for Amlogic SoCs. +config RESET_MESON_AUX + tristate "Meson Reset Auxiliary Driver" + depends on ARCH_MESON || COMPILE_TEST + select AUXILIARY_BUS + select RESET_MESON_COMMON + help + This enables the reset auxiliary driver for Amlogic SoCs. + config RESET_MESON_AUDIO_ARB tristate "Meson Audio Memory Arbiter Reset Driver" depends on ARCH_MESON || COMPILE_TEST diff --git a/drivers/reset/amlogic/Makefile b/drivers/reset/amlogic/Makefile index 74aaa2fb5e13e..ca99a691282c2 100644 --- a/drivers/reset/amlogic/Makefile +++ b/drivers/reset/amlogic/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_RESET_MESON) += reset-meson.o +obj-$(CONFIG_RESET_MESON_AUX) += reset-meson-aux.o obj-$(CONFIG_RESET_MESON_COMMON) += reset-meson-common.o obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o diff --git a/drivers/reset/amlogic/reset-meson-aux.c b/drivers/reset/amlogic/reset-meson-aux.c new file mode 100644 index 0000000000000..dd8453001db9c --- /dev/null +++ b/drivers/reset/amlogic/reset-meson-aux.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Amlogic Meson Reset Auxiliary driver + * + * Copyright (c) 2024 BayLibre, SAS. + * Author: Jerome Brunet + */ + +#include +#include +#include +#include +#include +#include + +#include "reset-meson.h" +#include + +static DEFINE_IDA(meson_rst_aux_ida); + +struct meson_reset_adev { + struct auxiliary_device adev; + struct regmap *map; +}; + +#define to_meson_reset_adev(_adev) \ + container_of((_adev), struct meson_reset_adev, adev) + +static const struct meson_reset_param meson_g12a_audio_param = { + .reset_ops = &meson_reset_toggle_ops, + .reset_num = 26, + .level_offset = 0x24, +}; + +static const struct meson_reset_param meson_sm1_audio_param = { + .reset_ops = &meson_reset_toggle_ops, + .reset_num = 39, + .level_offset = 0x28, +}; + +static const struct auxiliary_device_id meson_reset_aux_ids[] = { + { + .name = "axg-audio-clkc.rst-g12a", + .driver_data = (kernel_ulong_t)&meson_g12a_audio_param, + }, { + .name = "axg-audio-clkc.rst-sm1", + .driver_data = (kernel_ulong_t)&meson_sm1_audio_param, + }, {} +}; +MODULE_DEVICE_TABLE(auxiliary, meson_reset_aux_ids); + +static int meson_reset_aux_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + const struct meson_reset_param *param = + (const struct meson_reset_param *)(id->driver_data); + struct meson_reset_adev *raux = + to_meson_reset_adev(adev); + + return meson_reset_controller_register(&adev->dev, raux->map, param); +} + +static struct auxiliary_driver meson_reset_aux_driver = { + .probe = meson_reset_aux_probe, + .id_table = meson_reset_aux_ids, +}; +module_auxiliary_driver(meson_reset_aux_driver); + +static void meson_rst_aux_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + struct meson_reset_adev *raux = + to_meson_reset_adev(adev); + + ida_free(&meson_rst_aux_ida, adev->id); + kfree(raux); +} + +static void meson_rst_aux_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); + auxiliary_device_uninit(adev); +} + +int devm_meson_rst_aux_register(struct device *dev, + struct regmap *map, + const char *adev_name) +{ + struct meson_reset_adev *raux; + struct auxiliary_device *adev; + int ret; + + raux = kzalloc(sizeof(*raux), GFP_KERNEL); + if (!raux) + return -ENOMEM; + + ret = ida_alloc(&meson_rst_aux_ida, GFP_KERNEL); + if (ret < 0) + goto raux_free; + + raux->map = map; + + adev = &raux->adev; + adev->id = ret; + adev->name = adev_name; + adev->dev.parent = dev; + adev->dev.release = meson_rst_aux_release; + device_set_of_node_from_dev(&adev->dev, dev); + + ret = auxiliary_device_init(adev); + if (ret) + goto ida_free; + + ret = __auxiliary_device_add(adev, dev->driver->name); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(dev, meson_rst_aux_unregister_adev, + adev); + +ida_free: + ida_free(&meson_rst_aux_ida, adev->id); +raux_free: + kfree(raux); + return ret; +} +EXPORT_SYMBOL_GPL(devm_meson_rst_aux_register); + +MODULE_DESCRIPTION("Amlogic Meson Reset Auxiliary driver"); +MODULE_AUTHOR("Jerome Brunet "); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_IMPORT_NS(MESON_RESET); diff --git a/drivers/reset/amlogic/reset-meson-common.c b/drivers/reset/amlogic/reset-meson-common.c index d57544801ae90..a7b1b250a64db 100644 --- a/drivers/reset/amlogic/reset-meson-common.c +++ b/drivers/reset/amlogic/reset-meson-common.c @@ -87,12 +87,33 @@ static int meson_reset_deassert(struct reset_controller_dev *rcdev, return meson_reset_level(rcdev, id, false); } -static const struct reset_control_ops meson_reset_ops = { +static int meson_reset_level_toggle(struct reset_controller_dev *rcdev, + unsigned long id) +{ + int ret; + + ret = meson_reset_assert(rcdev, id); + if (ret) + return ret; + + return meson_reset_deassert(rcdev, id); +} + +const struct reset_control_ops meson_reset_ops = { .reset = meson_reset_reset, .assert = meson_reset_assert, .deassert = meson_reset_deassert, .status = meson_reset_status, }; +EXPORT_SYMBOL_NS_GPL(meson_reset_ops, MESON_RESET); + +const struct reset_control_ops meson_reset_toggle_ops = { + .reset = meson_reset_level_toggle, + .assert = meson_reset_assert, + .deassert = meson_reset_deassert, + .status = meson_reset_status, +}; +EXPORT_SYMBOL_NS_GPL(meson_reset_toggle_ops, MESON_RESET); int meson_reset_controller_register(struct device *dev, struct regmap *map, const struct meson_reset_param *param) @@ -107,7 +128,7 @@ int meson_reset_controller_register(struct device *dev, struct regmap *map, data->map = map; data->rcdev.owner = dev->driver->owner; data->rcdev.nr_resets = param->reset_num; - data->rcdev.ops = &meson_reset_ops; + data->rcdev.ops = data->param->reset_ops; data->rcdev.of_node = dev->of_node; return devm_reset_controller_register(dev, &data->rcdev); diff --git a/drivers/reset/amlogic/reset-meson.c b/drivers/reset/amlogic/reset-meson.c index feb19bf6da77b..6ae4ed6b7f8ba 100644 --- a/drivers/reset/amlogic/reset-meson.c +++ b/drivers/reset/amlogic/reset-meson.c @@ -18,6 +18,7 @@ #include "reset-meson.h" static const struct meson_reset_param meson8b_param = { + .reset_ops = &meson_reset_ops, .reset_num = 256, .reset_offset = 0x0, .level_offset = 0x7c, @@ -25,6 +26,7 @@ static const struct meson_reset_param meson8b_param = { }; static const struct meson_reset_param meson_a1_param = { + .reset_ops = &meson_reset_ops, .reset_num = 96, .reset_offset = 0x0, .level_offset = 0x40, @@ -32,6 +34,7 @@ static const struct meson_reset_param meson_a1_param = { }; static const struct meson_reset_param meson_s4_param = { + .reset_ops = &meson_reset_ops, .reset_num = 192, .reset_offset = 0x0, .level_offset = 0x40, diff --git a/drivers/reset/amlogic/reset-meson.h b/drivers/reset/amlogic/reset-meson.h index 4e1dbd7569c59..2051e126dc3a2 100644 --- a/drivers/reset/amlogic/reset-meson.h +++ b/drivers/reset/amlogic/reset-meson.h @@ -12,6 +12,7 @@ #include struct meson_reset_param { + const struct reset_control_ops *reset_ops; unsigned int reset_num; unsigned int reset_offset; unsigned int level_offset; @@ -21,4 +22,7 @@ struct meson_reset_param { int meson_reset_controller_register(struct device *dev, struct regmap *map, const struct meson_reset_param *param); +extern const struct reset_control_ops meson_reset_ops; +extern const struct reset_control_ops meson_reset_toggle_ops; + #endif /* __MESON_RESET_H */ diff --git a/include/soc/amlogic/reset-meson-aux.h b/include/soc/amlogic/reset-meson-aux.h new file mode 100644 index 0000000000000..d8a15d48c9849 --- /dev/null +++ b/include/soc/amlogic/reset-meson-aux.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __SOC_RESET_MESON_AUX_H +#define __SOC_RESET_MESON_AUX_H + +#include + +struct device; +struct regmap; + +#if IS_ENABLED(CONFIG_RESET_MESON_AUX) +int devm_meson_rst_aux_register(struct device *dev, + struct regmap *map, + const char *adev_name); +#else +static inline int devm_meson_rst_aux_register(struct device *dev, + struct regmap *map, + const char *adev_name) +{ + return 0; +} +#endif + +#endif /* __SOC_RESET_MESON_AUX_H */ From 5f79c4b659b50e332ba31ed2c322376e38453bb0 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 30 Sep 2024 18:55:56 +0200 Subject: [PATCH 10/10] reset: amlogic: Fix small whitespace issue Fix a checkpatch --strict issue: CHECK: Alignment should match open parenthesis #48: FILE: drivers/reset/amlogic/reset-meson-common.c:48: +static int meson_reset_level(struct reset_controller_dev *rcdev, + unsigned long id, bool assert) Reviewed-by: Jerome Brunet Link: https://lore.kernel.org/r/20240930-reset-align-amlogic-v1-1-f64ed5c4efc1@pengutronix.de Signed-off-by: Philipp Zabel --- drivers/reset/amlogic/reset-meson-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/reset/amlogic/reset-meson-common.c b/drivers/reset/amlogic/reset-meson-common.c index a7b1b250a64db..38a767c06fc71 100644 --- a/drivers/reset/amlogic/reset-meson-common.c +++ b/drivers/reset/amlogic/reset-meson-common.c @@ -45,7 +45,7 @@ static int meson_reset_reset(struct reset_controller_dev *rcdev, } static int meson_reset_level(struct reset_controller_dev *rcdev, - unsigned long id, bool assert) + unsigned long id, bool assert) { struct meson_reset *data = container_of(rcdev, struct meson_reset, rcdev);