* Re: [PATCH v6 2/3] soc/sophgo: add top sysctrl layout file for CV18XX/SG200X
From: Vinod Koul @ 2024-04-07 11:23 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen Wang,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Jisheng Zhang, Liu Gui,
Jingbao Qiu, dlan, dmaengine, devicetree, linux-kernel,
linux-riscv
In-Reply-To: <IA1PR20MB49532FB358A842A2ACC5E878BB3A2@IA1PR20MB4953.namprd20.prod.outlook.com>
On 29-03-24, 10:04, Inochi Amaoto wrote:
> The "top" system controller of CV18XX/SG200X exposes control
> register access for various devices. Add soc header file to
> describe it.
>
> Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
> ---
> include/soc/sophgo/cv1800-sysctl.h | 30 ++++++++++++++++++++++++++++++
> 1 file changed, 30 insertions(+)
> create mode 100644 include/soc/sophgo/cv1800-sysctl.h
>
> diff --git a/include/soc/sophgo/cv1800-sysctl.h b/include/soc/sophgo/cv1800-sysctl.h
> new file mode 100644
> index 000000000000..b9396d33e240
> --- /dev/null
> +++ b/include/soc/sophgo/cv1800-sysctl.h
> @@ -0,0 +1,30 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
> + */
> +
> +#ifndef CV1800_SYSCTL_H
> +#define CV1800_SYSCTL_H
> +
> +/*
> + * SOPHGO CV1800/SG2000 SoC top system controller registers offsets.
> + */
> +
> +#define CV1800_CONF_INFO 0x004
> +#define CV1800_SYS_CTRL_REG 0x008
> +#define CV1800_USB_PHY_CTRL_REG 0x048
> +#define CV1800_SDMA_DMA_CHANNEL_REMAP0 0x154
> +#define CV1800_SDMA_DMA_CHANNEL_REMAP1 0x158
> +#define CV1800_TOP_TIMER_CLK_SEL 0x1a0
> +#define CV1800_TOP_WDT_CTRL 0x1a8
> +#define CV1800_DDR_AXI_URGENT_OW 0x1b8
> +#define CV1800_DDR_AXI_URGENT 0x1bc
> +#define CV1800_DDR_AXI_QOS_0 0x1d8
> +#define CV1800_DDR_AXI_QOS_1 0x1dc
> +#define CV1800_SD_PWRSW_CTRL 0x1f4
> +#define CV1800_SD_PWRSW_TIME 0x1f8
> +#define CV1800_DDR_AXI_QOS_OW 0x23c
> +#define CV1800_SD_CTRL_OPT 0x294
> +#define CV1800_SDMA_DMA_INT_MUX 0x298
Why are these register defines in soc, all the dma registers should
belong to dma driver and other IPs, why do you need a common header??
--
~Vinod
^ permalink raw reply
* Re: [PATCH v6 3/3] dmaengine: add driver for Sophgo CV18XX/SG200X dmamux
From: Vinod Koul @ 2024-04-07 11:29 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen Wang,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Jisheng Zhang, Liu Gui,
Jingbao Qiu, dlan, dmaengine, devicetree, linux-kernel,
linux-riscv
In-Reply-To: <IA1PR20MB4953AE1184DD09F9203C665CBB3A2@IA1PR20MB4953.namprd20.prod.outlook.com>
On 29-03-24, 10:04, Inochi Amaoto wrote:
> Sophgo CV18XX/SG200X use DW AXI CORE with a multiplexer for remapping
> its request lines. The multiplexer supports at most 8 request lines.
>
> Add driver for Sophgo CV18XX/SG200X DMA multiplexer.
>
> Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
> ---
> drivers/dma/Kconfig | 9 ++
> drivers/dma/Makefile | 1 +
> drivers/dma/cv1800-dmamux.c | 267 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 277 insertions(+)
> create mode 100644 drivers/dma/cv1800-dmamux.c
>
> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> index 002a5ec80620..cb31520b9f86 100644
> --- a/drivers/dma/Kconfig
> +++ b/drivers/dma/Kconfig
> @@ -546,6 +546,15 @@ config PLX_DMA
> These are exposed via extra functions on the switch's
> upstream port. Each function exposes one DMA channel.
>
> +config SOPHGO_CV1800_DMAMUX
> + tristate "Sophgo CV1800/SG2000 series SoC DMA multiplexer support"
> + depends on MFD_SYSCON
> + depends on ARCH_SOPHGO
> + help
> + Support for the DMA multiplexer on Sophgo CV1800/SG2000
> + series SoCs.
> + Say Y here if your board have this soc.
> +
> config STE_DMA40
> bool "ST-Ericsson DMA40 support"
> depends on ARCH_U8500
> diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> index dfd40d14e408..7465f249ee47 100644
> --- a/drivers/dma/Makefile
> +++ b/drivers/dma/Makefile
> @@ -67,6 +67,7 @@ obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
> obj-$(CONFIG_PXA_DMA) += pxa_dma.o
> obj-$(CONFIG_RENESAS_DMA) += sh/
> obj-$(CONFIG_SF_PDMA) += sf-pdma/
> +obj-$(CONFIG_SOPHGO_CV1800_DMAMUX) += cv1800-dmamux.o
> obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
> obj-$(CONFIG_STM32_DMA) += stm32-dma.o
> obj-$(CONFIG_STM32_DMAMUX) += stm32-dmamux.o
> diff --git a/drivers/dma/cv1800-dmamux.c b/drivers/dma/cv1800-dmamux.c
> new file mode 100644
> index 000000000000..709414898b67
> --- /dev/null
> +++ b/drivers/dma/cv1800-dmamux.c
> @@ -0,0 +1,267 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
2024
> + */
> +
> +#include <linux/bitops.h>
> +#include <linux/module.h>
> +#include <linux/of_dma.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/llist.h>
> +#include <linux/regmap.h>
> +#include <linux/spinlock.h>
> +#include <linux/mfd/syscon.h>
> +
> +#include <soc/sophgo/cv1800-sysctl.h>
> +
> +#define DMAMUX_NCELLS 2
> +#define MAX_DMA_MAPPING_ID 42
> +#define MAX_DMA_CPU_ID 2
> +#define MAX_DMA_CH_ID 7
> +
> +#define DMAMUX_INTMUX_REGISTER_LEN 4
> +#define DMAMUX_NR_CH_PER_REGISTER 4
> +#define DMAMUX_BIT_PER_CH 8
> +#define DMAMUX_CH_MASk GENMASK(5, 0)
> +#define DMAMUX_INT_BIT_PER_CPU 10
> +#define DMAMUX_CH_UPDATE_BIT BIT(31)
> +
> +#define DMAMUX_CH_REGPOS(chid) \
> + ((chid) / DMAMUX_NR_CH_PER_REGISTER)
> +#define DMAMUX_CH_REGOFF(chid) \
> + ((chid) % DMAMUX_NR_CH_PER_REGISTER)
> +#define DMAMUX_CH_REG(chid) \
> + ((DMAMUX_CH_REGPOS(chid) * sizeof(u32)) + \
> + CV1800_SDMA_DMA_CHANNEL_REMAP0)
> +#define DMAMUX_CH_SET(chid, val) \
> + (((val) << (DMAMUX_CH_REGOFF(chid) * DMAMUX_BIT_PER_CH)) | \
> + DMAMUX_CH_UPDATE_BIT)
> +#define DMAMUX_CH_MASK(chid) \
> + DMAMUX_CH_SET(chid, DMAMUX_CH_MASk)
> +
> +#define DMAMUX_INT_BIT(chid, cpuid) \
> + BIT((cpuid) * DMAMUX_INT_BIT_PER_CPU + (chid))
> +#define DMAMUX_INTEN_BIT(cpuid) \
> + DMAMUX_INT_BIT(8, cpuid)
> +#define DMAMUX_INT_CH_BIT(chid, cpuid) \
> + (DMAMUX_INT_BIT(chid, cpuid) | DMAMUX_INTEN_BIT(cpuid))
> +#define DMAMUX_INT_MASK(chid) \
> + (DMAMUX_INT_BIT(chid, 0) | \
> + DMAMUX_INT_BIT(chid, 1) | \
> + DMAMUX_INT_BIT(chid, 2))
> +#define DMAMUX_INT_CH_MASK(chid, cpuid) \
> + (DMAMUX_INT_MASK(chid) | DMAMUX_INTEN_BIT(cpuid))
> +
> +struct cv1800_dmamux_data {
> + struct dma_router dmarouter;
> + struct regmap *regmap;
> + spinlock_t lock;
> + struct llist_head free_maps;
> + struct llist_head reserve_maps;
> + DECLARE_BITMAP(mapped_peripherals, MAX_DMA_MAPPING_ID);
> +};
> +
> +struct cv1800_dmamux_map {
> + struct llist_node node;
> + unsigned int channel;
> + unsigned int peripheral;
> + unsigned int cpu;
> +};
> +
> +static void cv1800_dmamux_free(struct device *dev, void *route_data)
> +{
> + struct cv1800_dmamux_data *dmamux = dev_get_drvdata(dev);
> + struct cv1800_dmamux_map *map = route_data;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&dmamux->lock, flags);
> +
> + regmap_update_bits(dmamux->regmap,
> + DMAMUX_CH_REG(map->channel),
> + DMAMUX_CH_MASK(map->channel),
> + DMAMUX_CH_UPDATE_BIT);
> +
> + regmap_update_bits(dmamux->regmap, CV1800_SDMA_DMA_INT_MUX,
> + DMAMUX_INT_CH_MASK(map->channel, map->cpu),
> + DMAMUX_INTEN_BIT(map->cpu));
> +
> + spin_unlock_irqrestore(&dmamux->lock, flags);
> +
> + dev_info(dev, "free channel %u for req %u (cpu %u)\n",
> + map->channel, map->peripheral, map->cpu);
debug at most please
> +}
> +
> +static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec,
> + struct of_dma *ofdma)
> +{
> + struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
> + struct cv1800_dmamux_data *dmamux = platform_get_drvdata(pdev);
> + struct cv1800_dmamux_map *map;
> + struct llist_node *node;
> + unsigned long flags;
> + unsigned int chid, devid, cpuid;
> + int ret;
> +
> + if (dma_spec->args_count != DMAMUX_NCELLS) {
> + dev_err(&pdev->dev, "invalid number of dma mux args\n");
> + return ERR_PTR(-EINVAL);
> + }
> +
> + devid = dma_spec->args[0];
> + cpuid = dma_spec->args[1];
> + dma_spec->args_count = 1;
> +
> + if (devid > MAX_DMA_MAPPING_ID) {
> + dev_err(&pdev->dev, "invalid device id: %u\n", devid);
> + return ERR_PTR(-EINVAL);
> + }
> +
> + if (cpuid > MAX_DMA_CPU_ID) {
> + dev_err(&pdev->dev, "invalid cpu id: %u\n", cpuid);
> + return ERR_PTR(-EINVAL);
> + }
> +
> + dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
> + if (!dma_spec->np) {
> + dev_err(&pdev->dev, "can't get dma master\n");
> + return ERR_PTR(-EINVAL);
> + }
> +
> + spin_lock_irqsave(&dmamux->lock, flags);
> +
> + if (test_bit(devid, dmamux->mapped_peripherals)) {
> + llist_for_each_entry(map, dmamux->reserve_maps.first, node) {
> + if (map->peripheral == devid && map->cpu == cpuid)
> + goto found;
> + }
> +
> + ret = -EINVAL;
> + goto failed;
> + } else {
> + node = llist_del_first(&dmamux->free_maps);
> + if (!node) {
> + ret = -ENODEV;
> + goto failed;
> + }
> +
> + map = llist_entry(node, struct cv1800_dmamux_map, node);
> + llist_add(&map->node, &dmamux->reserve_maps);
> + set_bit(devid, dmamux->mapped_peripherals);
> + }
> +
> +found:
> + chid = map->channel;
> + map->peripheral = devid;
> + map->cpu = cpuid;
> +
> + regmap_set_bits(dmamux->regmap,
> + DMAMUX_CH_REG(chid),
> + DMAMUX_CH_SET(chid, devid));
> +
> + regmap_update_bits(dmamux->regmap, CV1800_SDMA_DMA_INT_MUX,
> + DMAMUX_INT_CH_MASK(chid, cpuid),
> + DMAMUX_INT_CH_BIT(chid, cpuid));
> +
> + spin_unlock_irqrestore(&dmamux->lock, flags);
> +
> + dma_spec->args[0] = chid;
> +
> + dev_info(&pdev->dev, "register channel %u for req %u (cpu %u)\n",
> + chid, devid, cpuid);
Here as well
> +
> + return map;
> +
> +failed:
> + spin_unlock_irqrestore(&dmamux->lock, flags);
> + of_node_put(dma_spec->np);
> + dev_err(&pdev->dev, "errno %d\n", ret);
> + return ERR_PTR(ret);
> +
> +}
> +
> +static int cv1800_dmamux_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *mux_node = dev->of_node;
> + struct cv1800_dmamux_data *data;
> + struct cv1800_dmamux_map *tmp;
> + struct device *parent = dev->parent;
> + struct device_node *dma_master;
> + struct regmap *regmap = NULL;
> + unsigned int i;
> +
> + if (!parent)
> + return -ENODEV;
> +
> + regmap = device_node_to_regmap(parent->of_node);
> + if (IS_ERR(regmap))
> + return PTR_ERR(regmap);
> +
> + dma_master = of_parse_phandle(mux_node, "dma-masters", 0);
> + if (!dma_master) {
> + dev_err(dev, "invalid dma-requests property\n");
> + return -ENODEV;
> + }
> + of_node_put(dma_master);
why do this if you dont need it??
> +
> + data = devm_kmalloc(dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + spin_lock_init(&data->lock);
> + init_llist_head(&data->free_maps);
> +
> + for (i = 0; i <= MAX_DMA_CH_ID; i++) {
> + tmp = devm_kmalloc(dev, sizeof(*tmp), GFP_KERNEL);
> + if (!tmp) {
> + /* It is OK for not allocating all channel */
> + dev_warn(dev, "can not allocate channel %u\n", i);
> + continue;
> + }
> +
> + init_llist_node(&tmp->node);
> + tmp->channel = i;
> + llist_add(&tmp->node, &data->free_maps);
> + }
> +
> + /* if no channel is allocated, the probe must fail */
> + if (llist_empty(&data->free_maps))
> + return -ENOMEM;
> +
> + data->regmap = regmap;
> + data->dmarouter.dev = dev;
> + data->dmarouter.route_free = cv1800_dmamux_free;
> +
> + platform_set_drvdata(pdev, data);
> +
> + return of_dma_router_register(mux_node,
> + cv1800_dmamux_route_allocate,
> + &data->dmarouter);
> +}
> +
> +static void cv1800_dmamux_remove(struct platform_device *pdev)
> +{
> + of_dma_controller_free(pdev->dev.of_node);
> +}
> +
> +static const struct of_device_id cv1800_dmamux_ids[] = {
> + { .compatible = "sophgo,cv1800-dmamux", },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, cv1800_dmamux_ids);
> +
> +static struct platform_driver cv1800_dmamux_driver = {
> + .driver = {
> + .name = "cv1800-dmamux",
> + .of_match_table = cv1800_dmamux_ids,
> + },
> + .probe = cv1800_dmamux_probe,
> + .remove_new = cv1800_dmamux_remove,
> +};
> +module_platform_driver(cv1800_dmamux_driver);
> +
> +MODULE_AUTHOR("Inochi Amaoto <inochiama@outlook.com>");
> +MODULE_DESCRIPTION("Sophgo CV1800/SG2000 Series Soc DMAMUX driver");
> +MODULE_LICENSE("GPL");
> --
> 2.44.0
--
~Vinod
^ permalink raw reply
* Re: [PATCH v6 2/3] soc/sophgo: add top sysctrl layout file for CV18XX/SG200X
From: Inochi Amaoto @ 2024-04-07 11:36 UTC (permalink / raw)
To: Vinod Koul, Inochi Amaoto
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen Wang,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Jisheng Zhang, Liu Gui,
Jingbao Qiu, dlan, dmaengine, devicetree, linux-kernel,
linux-riscv
In-Reply-To: <ZhKCHlAYxnhhcKnt@matsya>
On Sun, Apr 07, 2024 at 04:53:10PM +0530, Vinod Koul wrote:
> On 29-03-24, 10:04, Inochi Amaoto wrote:
> > The "top" system controller of CV18XX/SG200X exposes control
> > register access for various devices. Add soc header file to
> > describe it.
> >
> > Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
> > ---
> > include/soc/sophgo/cv1800-sysctl.h | 30 ++++++++++++++++++++++++++++++
> > 1 file changed, 30 insertions(+)
> > create mode 100644 include/soc/sophgo/cv1800-sysctl.h
> >
> > diff --git a/include/soc/sophgo/cv1800-sysctl.h b/include/soc/sophgo/cv1800-sysctl.h
> > new file mode 100644
> > index 000000000000..b9396d33e240
> > --- /dev/null
> > +++ b/include/soc/sophgo/cv1800-sysctl.h
> > @@ -0,0 +1,30 @@
> > +/* SPDX-License-Identifier: GPL-2.0-or-later */
> > +/*
> > + * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
> > + */
> > +
> > +#ifndef CV1800_SYSCTL_H
> > +#define CV1800_SYSCTL_H
> > +
> > +/*
> > + * SOPHGO CV1800/SG2000 SoC top system controller registers offsets.
> > + */
> > +
> > +#define CV1800_CONF_INFO 0x004
> > +#define CV1800_SYS_CTRL_REG 0x008
> > +#define CV1800_USB_PHY_CTRL_REG 0x048
> > +#define CV1800_SDMA_DMA_CHANNEL_REMAP0 0x154
> > +#define CV1800_SDMA_DMA_CHANNEL_REMAP1 0x158
> > +#define CV1800_TOP_TIMER_CLK_SEL 0x1a0
> > +#define CV1800_TOP_WDT_CTRL 0x1a8
> > +#define CV1800_DDR_AXI_URGENT_OW 0x1b8
> > +#define CV1800_DDR_AXI_URGENT 0x1bc
> > +#define CV1800_DDR_AXI_QOS_0 0x1d8
> > +#define CV1800_DDR_AXI_QOS_1 0x1dc
> > +#define CV1800_SD_PWRSW_CTRL 0x1f4
> > +#define CV1800_SD_PWRSW_TIME 0x1f8
> > +#define CV1800_DDR_AXI_QOS_OW 0x23c
> > +#define CV1800_SD_CTRL_OPT 0x294
> > +#define CV1800_SDMA_DMA_INT_MUX 0x298
>
> Why are these register defines in soc, all the dma registers should
> belong to dma driver and other IPs, why do you need a common header??
>
> --
> ~Vinod
This multiplexer is not a standalone device, instead, it is a
subdevice of the syscon. Although it is better to add this
header to the syscon series, the dma multiplexer driver itself
depends this header. So I add the header to this series.
Regards,
Inochi
^ permalink raw reply
* Re: [PATCH v6 3/3] dmaengine: add driver for Sophgo CV18XX/SG200X dmamux
From: Inochi Amaoto @ 2024-04-07 11:57 UTC (permalink / raw)
To: Vinod Koul, Inochi Amaoto
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen Wang,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Jisheng Zhang, Liu Gui,
Jingbao Qiu, dlan, dmaengine, devicetree, linux-kernel,
linux-riscv
In-Reply-To: <ZhKDo0GCpvffUcd8@matsya>
On Sun, Apr 07, 2024 at 04:59:39PM +0530, Vinod Koul wrote:
> On 29-03-24, 10:04, Inochi Amaoto wrote:
> > Sophgo CV18XX/SG200X use DW AXI CORE with a multiplexer for remapping
> > its request lines. The multiplexer supports at most 8 request lines.
> >
> > Add driver for Sophgo CV18XX/SG200X DMA multiplexer.
> >
> > Signed-off-by: Inochi Amaoto <inochiama@outlook.com>
> > ---
> > drivers/dma/Kconfig | 9 ++
> > drivers/dma/Makefile | 1 +
> > drivers/dma/cv1800-dmamux.c | 267 ++++++++++++++++++++++++++++++++++++
> > 3 files changed, 277 insertions(+)
> > create mode 100644 drivers/dma/cv1800-dmamux.c
> >
> > diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> > index 002a5ec80620..cb31520b9f86 100644
> > --- a/drivers/dma/Kconfig
> > +++ b/drivers/dma/Kconfig
> > @@ -546,6 +546,15 @@ config PLX_DMA
> > These are exposed via extra functions on the switch's
> > upstream port. Each function exposes one DMA channel.
> >
> > +config SOPHGO_CV1800_DMAMUX
> > + tristate "Sophgo CV1800/SG2000 series SoC DMA multiplexer support"
> > + depends on MFD_SYSCON
> > + depends on ARCH_SOPHGO
> > + help
> > + Support for the DMA multiplexer on Sophgo CV1800/SG2000
> > + series SoCs.
> > + Say Y here if your board have this soc.
> > +
> > config STE_DMA40
> > bool "ST-Ericsson DMA40 support"
> > depends on ARCH_U8500
> > diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> > index dfd40d14e408..7465f249ee47 100644
> > --- a/drivers/dma/Makefile
> > +++ b/drivers/dma/Makefile
> > @@ -67,6 +67,7 @@ obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/
> > obj-$(CONFIG_PXA_DMA) += pxa_dma.o
> > obj-$(CONFIG_RENESAS_DMA) += sh/
> > obj-$(CONFIG_SF_PDMA) += sf-pdma/
> > +obj-$(CONFIG_SOPHGO_CV1800_DMAMUX) += cv1800-dmamux.o
> > obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
> > obj-$(CONFIG_STM32_DMA) += stm32-dma.o
> > obj-$(CONFIG_STM32_DMAMUX) += stm32-dmamux.o
> > diff --git a/drivers/dma/cv1800-dmamux.c b/drivers/dma/cv1800-dmamux.c
> > new file mode 100644
> > index 000000000000..709414898b67
> > --- /dev/null
> > +++ b/drivers/dma/cv1800-dmamux.c
> > @@ -0,0 +1,267 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2023 Inochi Amaoto <inochiama@outlook.com>
>
> 2024
>
> > + */
> > +
> > +#include <linux/bitops.h>
> > +#include <linux/module.h>
> > +#include <linux/of_dma.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_platform.h>
> > +#include <linux/platform_device.h>
> > +#include <linux/llist.h>
> > +#include <linux/regmap.h>
> > +#include <linux/spinlock.h>
> > +#include <linux/mfd/syscon.h>
> > +
> > +#include <soc/sophgo/cv1800-sysctl.h>
> > +
> > +#define DMAMUX_NCELLS 2
> > +#define MAX_DMA_MAPPING_ID 42
> > +#define MAX_DMA_CPU_ID 2
> > +#define MAX_DMA_CH_ID 7
> > +
> > +#define DMAMUX_INTMUX_REGISTER_LEN 4
> > +#define DMAMUX_NR_CH_PER_REGISTER 4
> > +#define DMAMUX_BIT_PER_CH 8
> > +#define DMAMUX_CH_MASk GENMASK(5, 0)
> > +#define DMAMUX_INT_BIT_PER_CPU 10
> > +#define DMAMUX_CH_UPDATE_BIT BIT(31)
> > +
> > +#define DMAMUX_CH_REGPOS(chid) \
> > + ((chid) / DMAMUX_NR_CH_PER_REGISTER)
> > +#define DMAMUX_CH_REGOFF(chid) \
> > + ((chid) % DMAMUX_NR_CH_PER_REGISTER)
> > +#define DMAMUX_CH_REG(chid) \
> > + ((DMAMUX_CH_REGPOS(chid) * sizeof(u32)) + \
> > + CV1800_SDMA_DMA_CHANNEL_REMAP0)
> > +#define DMAMUX_CH_SET(chid, val) \
> > + (((val) << (DMAMUX_CH_REGOFF(chid) * DMAMUX_BIT_PER_CH)) | \
> > + DMAMUX_CH_UPDATE_BIT)
> > +#define DMAMUX_CH_MASK(chid) \
> > + DMAMUX_CH_SET(chid, DMAMUX_CH_MASk)
> > +
> > +#define DMAMUX_INT_BIT(chid, cpuid) \
> > + BIT((cpuid) * DMAMUX_INT_BIT_PER_CPU + (chid))
> > +#define DMAMUX_INTEN_BIT(cpuid) \
> > + DMAMUX_INT_BIT(8, cpuid)
> > +#define DMAMUX_INT_CH_BIT(chid, cpuid) \
> > + (DMAMUX_INT_BIT(chid, cpuid) | DMAMUX_INTEN_BIT(cpuid))
> > +#define DMAMUX_INT_MASK(chid) \
> > + (DMAMUX_INT_BIT(chid, 0) | \
> > + DMAMUX_INT_BIT(chid, 1) | \
> > + DMAMUX_INT_BIT(chid, 2))
> > +#define DMAMUX_INT_CH_MASK(chid, cpuid) \
> > + (DMAMUX_INT_MASK(chid) | DMAMUX_INTEN_BIT(cpuid))
> > +
> > +struct cv1800_dmamux_data {
> > + struct dma_router dmarouter;
> > + struct regmap *regmap;
> > + spinlock_t lock;
> > + struct llist_head free_maps;
> > + struct llist_head reserve_maps;
> > + DECLARE_BITMAP(mapped_peripherals, MAX_DMA_MAPPING_ID);
> > +};
> > +
> > +struct cv1800_dmamux_map {
> > + struct llist_node node;
> > + unsigned int channel;
> > + unsigned int peripheral;
> > + unsigned int cpu;
> > +};
> > +
> > +static void cv1800_dmamux_free(struct device *dev, void *route_data)
> > +{
> > + struct cv1800_dmamux_data *dmamux = dev_get_drvdata(dev);
> > + struct cv1800_dmamux_map *map = route_data;
> > + unsigned long flags;
> > +
> > + spin_lock_irqsave(&dmamux->lock, flags);
> > +
> > + regmap_update_bits(dmamux->regmap,
> > + DMAMUX_CH_REG(map->channel),
> > + DMAMUX_CH_MASK(map->channel),
> > + DMAMUX_CH_UPDATE_BIT);
> > +
> > + regmap_update_bits(dmamux->regmap, CV1800_SDMA_DMA_INT_MUX,
> > + DMAMUX_INT_CH_MASK(map->channel, map->cpu),
> > + DMAMUX_INTEN_BIT(map->cpu));
> > +
> > + spin_unlock_irqrestore(&dmamux->lock, flags);
> > +
> > + dev_info(dev, "free channel %u for req %u (cpu %u)\n",
> > + map->channel, map->peripheral, map->cpu);
>
> debug at most please
>
> > +}
> > +
> > +static void *cv1800_dmamux_route_allocate(struct of_phandle_args *dma_spec,
> > + struct of_dma *ofdma)
> > +{
> > + struct platform_device *pdev = of_find_device_by_node(ofdma->of_node);
> > + struct cv1800_dmamux_data *dmamux = platform_get_drvdata(pdev);
> > + struct cv1800_dmamux_map *map;
> > + struct llist_node *node;
> > + unsigned long flags;
> > + unsigned int chid, devid, cpuid;
> > + int ret;
> > +
> > + if (dma_spec->args_count != DMAMUX_NCELLS) {
> > + dev_err(&pdev->dev, "invalid number of dma mux args\n");
> > + return ERR_PTR(-EINVAL);
> > + }
> > +
> > + devid = dma_spec->args[0];
> > + cpuid = dma_spec->args[1];
> > + dma_spec->args_count = 1;
> > +
> > + if (devid > MAX_DMA_MAPPING_ID) {
> > + dev_err(&pdev->dev, "invalid device id: %u\n", devid);
> > + return ERR_PTR(-EINVAL);
> > + }
> > +
> > + if (cpuid > MAX_DMA_CPU_ID) {
> > + dev_err(&pdev->dev, "invalid cpu id: %u\n", cpuid);
> > + return ERR_PTR(-EINVAL);
> > + }
> > +
> > + dma_spec->np = of_parse_phandle(ofdma->of_node, "dma-masters", 0);
> > + if (!dma_spec->np) {
> > + dev_err(&pdev->dev, "can't get dma master\n");
> > + return ERR_PTR(-EINVAL);
> > + }
> > +
> > + spin_lock_irqsave(&dmamux->lock, flags);
> > +
> > + if (test_bit(devid, dmamux->mapped_peripherals)) {
> > + llist_for_each_entry(map, dmamux->reserve_maps.first, node) {
> > + if (map->peripheral == devid && map->cpu == cpuid)
> > + goto found;
> > + }
> > +
> > + ret = -EINVAL;
> > + goto failed;
> > + } else {
> > + node = llist_del_first(&dmamux->free_maps);
> > + if (!node) {
> > + ret = -ENODEV;
> > + goto failed;
> > + }
> > +
> > + map = llist_entry(node, struct cv1800_dmamux_map, node);
> > + llist_add(&map->node, &dmamux->reserve_maps);
> > + set_bit(devid, dmamux->mapped_peripherals);
> > + }
> > +
> > +found:
> > + chid = map->channel;
> > + map->peripheral = devid;
> > + map->cpu = cpuid;
> > +
> > + regmap_set_bits(dmamux->regmap,
> > + DMAMUX_CH_REG(chid),
> > + DMAMUX_CH_SET(chid, devid));
> > +
> > + regmap_update_bits(dmamux->regmap, CV1800_SDMA_DMA_INT_MUX,
> > + DMAMUX_INT_CH_MASK(chid, cpuid),
> > + DMAMUX_INT_CH_BIT(chid, cpuid));
> > +
> > + spin_unlock_irqrestore(&dmamux->lock, flags);
> > +
> > + dma_spec->args[0] = chid;
> > +
> > + dev_info(&pdev->dev, "register channel %u for req %u (cpu %u)\n",
> > + chid, devid, cpuid);
>
> Here as well
>
> > +
> > + return map;
> > +
> > +failed:
> > + spin_unlock_irqrestore(&dmamux->lock, flags);
> > + of_node_put(dma_spec->np);
> > + dev_err(&pdev->dev, "errno %d\n", ret);
> > + return ERR_PTR(ret);
> > +
> > +}
> > +
> > +static int cv1800_dmamux_probe(struct platform_device *pdev)
> > +{
> > + struct device *dev = &pdev->dev;
> > + struct device_node *mux_node = dev->of_node;
> > + struct cv1800_dmamux_data *data;
> > + struct cv1800_dmamux_map *tmp;
> > + struct device *parent = dev->parent;
> > + struct device_node *dma_master;
> > + struct regmap *regmap = NULL;
> > + unsigned int i;
> > +
> > + if (!parent)
> > + return -ENODEV;
> > +
> > + regmap = device_node_to_regmap(parent->of_node);
> > + if (IS_ERR(regmap))
> > + return PTR_ERR(regmap);
> > +
> > + dma_master = of_parse_phandle(mux_node, "dma-masters", 0);
> > + if (!dma_master) {
> > + dev_err(dev, "invalid dma-requests property\n");
> > + return -ENODEV;
> > + }
> > + of_node_put(dma_master);
>
> why do this if you dont need it??
>
This is a pre check. It will issue an error if no valid dma-master.
The dma-master is used in the route callback. Is it better to just
leave this check in the callback?
> > +
> > + data = devm_kmalloc(dev, sizeof(*data), GFP_KERNEL);
> > + if (!data)
> > + return -ENOMEM;
> > +
> > + spin_lock_init(&data->lock);
> > + init_llist_head(&data->free_maps);
> > +
> > + for (i = 0; i <= MAX_DMA_CH_ID; i++) {
> > + tmp = devm_kmalloc(dev, sizeof(*tmp), GFP_KERNEL);
> > + if (!tmp) {
> > + /* It is OK for not allocating all channel */
> > + dev_warn(dev, "can not allocate channel %u\n", i);
> > + continue;
> > + }
> > +
> > + init_llist_node(&tmp->node);
> > + tmp->channel = i;
> > + llist_add(&tmp->node, &data->free_maps);
> > + }
> > +
> > + /* if no channel is allocated, the probe must fail */
> > + if (llist_empty(&data->free_maps))
> > + return -ENOMEM;
> > +
> > + data->regmap = regmap;
> > + data->dmarouter.dev = dev;
> > + data->dmarouter.route_free = cv1800_dmamux_free;
> > +
> > + platform_set_drvdata(pdev, data);
> > +
> > + return of_dma_router_register(mux_node,
> > + cv1800_dmamux_route_allocate,
> > + &data->dmarouter);
> > +}
> > +
> > +static void cv1800_dmamux_remove(struct platform_device *pdev)
> > +{
> > + of_dma_controller_free(pdev->dev.of_node);
> > +}
> > +
> > +static const struct of_device_id cv1800_dmamux_ids[] = {
> > + { .compatible = "sophgo,cv1800-dmamux", },
> > + { }
> > +};
> > +MODULE_DEVICE_TABLE(of, cv1800_dmamux_ids);
> > +
> > +static struct platform_driver cv1800_dmamux_driver = {
> > + .driver = {
> > + .name = "cv1800-dmamux",
> > + .of_match_table = cv1800_dmamux_ids,
> > + },
> > + .probe = cv1800_dmamux_probe,
> > + .remove_new = cv1800_dmamux_remove,
> > +};
> > +module_platform_driver(cv1800_dmamux_driver);
> > +
> > +MODULE_AUTHOR("Inochi Amaoto <inochiama@outlook.com>");
> > +MODULE_DESCRIPTION("Sophgo CV1800/SG2000 Series Soc DMAMUX driver");
> > +MODULE_LICENSE("GPL");
> > --
> > 2.44.0
>
> --
> ~Vinod
^ permalink raw reply
* RE: [PATCH 1/5] dt-bindings: firmware: add i.MX SCMI Extension protocol
From: Peng Fan @ 2024-04-07 12:35 UTC (permalink / raw)
To: Rob Herring, Peng Fan (OSS)
Cc: Krzysztof Kozlowski, Conor Dooley, Sudeep Holla, Cristian Marussi,
Shawn Guo, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
dl-linux-imx, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org,
linux-arm-kernel@lists.infradead.org
In-Reply-To: <20240212150919.GA322668-robh@kernel.org>
Hi Rob,
Sorry for late reply.
> Subject: Re: [PATCH 1/5] dt-bindings: firmware: add i.MX SCMI Extension
> protocol
>
> On Fri, Feb 02, 2024 at 02:34:39PM +0800, Peng Fan (OSS) wrote:
> > From: Peng Fan <peng.fan@nxp.com>
> >
> > Add i.MX SCMI Extension protocol BBM and MISC binding.
>
> No idea what BBM and MISC are.
The Battery Backup (BB) Domain contains the Battery Backed
Security Module (BBSM) and the Battery Backed Non-Secure Module
(BBNSM).
BBNSM:
The BBNSM is the interface to a non-interruptable power supply
(backup battery) and serves as the non-volatile logic and storage
for the chip. When the chip is powered off, the BBNSM will maintain
PMIC logic while connected to a backup supply.
Main features: RTC, PMIC Control, ONOFF Control BBSM serves as
nonvolatile security logic and storage for ELE Main features:
Monotonic counter, Secure RTC, Zeroizable Master Key, Security
Violation and Tamper Detection
MISC: it is i.MX SCMI extension protocol, including BLK CTRL
settings, board level GPIO expander settings.
>
> >
> > Signed-off-by: Peng Fan <peng.fan@nxp.com>
> > ---
> > .../devicetree/bindings/firmware/nxp,scmi.yaml | 64
> ++++++++++++++++++++++
> > 1 file changed, 64 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/firmware/nxp,scmi.yaml
> > b/Documentation/devicetree/bindings/firmware/nxp,scmi.yaml
> > new file mode 100644
> > index 000000000000..00d6361bbbea
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/firmware/nxp,scmi.yaml
> > @@ -0,0 +1,64 @@
> > +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) # Copyright 2024
> > +NXP %YAML 1.2
> > +---
> > +$id:
> > +https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi
> >
> +cetree.org%2Fschemas%2Ffirmware%2Fnxp%2Cscmi.yaml%23&data=05%7
> C02%7Cp
> >
> +eng.fan%40nxp.com%7C625d14c7c4f14d16289908dc2bdc9967%7C686ea1
> d3bc2b4c
> >
> +6fa92cd99c5c301635%7C0%7C0%7C638433473675932860%7CUnknown%
> 7CTWFpbGZsb
> >
> +3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn
> 0%3D
> >
> +%7C0%7C%7C%7C&sdata=dP0%2FgyCwmWtSW9BNYWZQtunpgayjCl2AkSkj
> ZIZjn9o%3D&
> > +reserved=0
> > +$schema:
> > +https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fdevi
> > +cetree.org%2Fmeta-
> schemas%2Fcore.yaml%23&data=05%7C02%7Cpeng.fan%40nx
> >
> +p.com%7C625d14c7c4f14d16289908dc2bdc9967%7C686ea1d3bc2b4c6fa9
> 2cd99c5c
> >
> +301635%7C0%7C0%7C638433473675946764%7CUnknown%7CTWFpbGZs
> b3d8eyJWIjoiM
> >
> +C4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7
> C%7C%7
> >
> +C&sdata=efmqKP8%2FyS4YoDLCb%2Fmxx72D7ZW2KxiEDhgnWdEUT1s%3D
> &reserved=0
> > +
> > +title: i.MX System Control and Management Interface (SCMI) Protocol
> > +Extension
> > +
> > +maintainers:
> > + - Peng Fan <peng.fan@nxp.com>
> > +
> > +allOf:
> > + - $ref: arm,scmi.yaml#
> > +
> > +properties:
> > + protocol@11:
>
> Wrong unit-address?
Yeah. Fixed.
>
> > + $ref: 'arm,scmi.yaml#/$defs/protocol-node'
> > + unevaluatedProperties: false
>
> Description of what this protocol is needed.
Added.
>
> > +
> > + properties:
> > + reg:
> > + const: 0x81
> > +
> > + protocol@13:
> > + $ref: 'arm,scmi.yaml#/$defs/protocol-node'
> > + unevaluatedProperties: false
> > +
> > + properties:
> > + reg:
> > + const: 0x84
> > +
> > + wakeup-sources:
>
> Is this somehow generic?
I think it yes, but if you disagree, please suggest.
>
> > + description: each entry consists of 2 integers and represents
> > + the source and edge
>
> What does 'edge' mean in this context?
Electric signal edge.
>
> > + items:
> > + items:
> > + - description: the wakeup source
> > + - description: the wakeup edge
>
> Constraints?
Will add in V3.
minItems: 1
maxItems: 32
>
> > + $ref: /schemas/types.yaml#/definitions/uint32-matrix
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > + - |
> > + firmware {
> > + scmi {
>
>
> Need a compatible here so this actually gets tested.
Fixed.
>
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + protocol@81 {
> > + reg = <0x81>;
> > + };
> > +
> > + protocol@84 {
> > + reg = <0x84>;
> > + wakeup-sources = <6 1
> > + 7 1
> > + 8 1
> > + 9 1
> > + 10 1>;
>
> <> around each entry. e.g. "<6 1>"
Fix in V3.
Thanks,
Peng.
>
> > + };
> > + };
> > + };
> > +...
> >
> > --
> > 2.37.1
> >
^ permalink raw reply
* Re: [PATCH 2/3] dt-bindings: PCI: mediatek,mt7621: add missing child node reg
From: Sergio Paracuellos @ 2024-04-07 12:36 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Hector Martin,
Sven Peter, Alyssa Rosenzweig, Ray Jui, Scott Branden,
Broadcom internal kernel review list, Jim Quinlan,
Nicolas Saenz Julienne, Florian Fainelli, Will Deacon,
Linus Walleij, Srikanth Thokala, Ryder Lee, Jianjun Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Daire McNamara,
Bjorn Andersson, Konrad Dybcio, Marek Vasut, Yoshihiro Shimoda,
Shawn Lin, Heiko Stuebner, Jingoo Han, Gustavo Pimentel,
Manivannan Sadhasivam, Bharat Kumar Gogada, Michal Simek,
Geert Uytterhoeven, Magnus Damm, Neil Armstrong, Mark Kettenis,
Tom Joseph, Ahmad Zainie, Jiaxun Yang, Kishon Vijay Abraham I,
Thippeswamy Havalige, linux-pci, devicetree, linux-kernel, asahi,
linux-arm-kernel, linux-rpi-kernel, linux-mediatek, linux-arm-msm,
linux-renesas-soc, linux-rockchip
In-Reply-To: <20240407102000.37213-2-krzysztof.kozlowski@linaro.org>
On Sun, Apr 7, 2024 at 12:20 PM Krzysztof Kozlowski
<krzysztof.kozlowski@linaro.org> wrote:
>
> MT7621 PCI host bridge has children which apparently are also PCI host
> bridges, at least that's what the binding suggest. The children have
> "reg" property, but do not explicitly define it. Instead they rely on
> pci-bus.yaml schema, but that one has "reg" without any constraints.
>
> Define the "reg" for the children, so the binding will be more specific
> and later will allow dropping reference to deprecated pci-bus.yaml
> schema.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> ---
> .../devicetree/bindings/pci/mediatek,mt7621-pcie.yaml | 3 +++
> 1 file changed, 3 insertions(+)
Acked-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
Thanks,
Sergio Paracuellos
^ permalink raw reply
* Re: [PATCH 3/3] dt-bindings: PCI: host-bridges: switch from deprecated pci-bus.yaml
From: Sergio Paracuellos @ 2024-04-07 12:38 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Bjorn Helgaas, Lorenzo Pieralisi, Krzysztof Wilczyński,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Hector Martin,
Sven Peter, Alyssa Rosenzweig, Ray Jui, Scott Branden,
Broadcom internal kernel review list, Jim Quinlan,
Nicolas Saenz Julienne, Florian Fainelli, Will Deacon,
Linus Walleij, Srikanth Thokala, Ryder Lee, Jianjun Wang,
Matthias Brugger, AngeloGioacchino Del Regno, Daire McNamara,
Bjorn Andersson, Konrad Dybcio, Marek Vasut, Yoshihiro Shimoda,
Shawn Lin, Heiko Stuebner, Jingoo Han, Gustavo Pimentel,
Manivannan Sadhasivam, Bharat Kumar Gogada, Michal Simek,
Geert Uytterhoeven, Magnus Damm, Neil Armstrong, Mark Kettenis,
Tom Joseph, Ahmad Zainie, Jiaxun Yang, Kishon Vijay Abraham I,
Thippeswamy Havalige, linux-pci, devicetree, linux-kernel, asahi,
linux-arm-kernel, linux-rpi-kernel, linux-mediatek, linux-arm-msm,
linux-renesas-soc, linux-rockchip
In-Reply-To: <20240407102000.37213-3-krzysztof.kozlowski@linaro.org>
On Sun, Apr 7, 2024 at 12:20 PM Krzysztof Kozlowski
<krzysztof.kozlowski@linaro.org> wrote:
>
> dtschema package with core schemas deprecated pci-bus.yaml schema in
> favor of pci-host-bridge.yaml. Update all bindings to use the latter
> one.
>
> The difference between pci-bus.yaml and pci-host-bridge.yaml is only in
> lack of "reg" property defined by the latter, which should not have any
> effect here, because all these bindings define the "reg".
>
> The change is therefore quite trivial, except mediatek,mt7621-pcie.yaml
> binding which have children nodes being also host bridges, apparently.
>
> Signed-off-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
> ---
> .../devicetree/bindings/pci/mediatek,mt7621-pcie.yaml | 4 ++--
Acked-by: Sergio Paracuellos <sergio.paracuellos@gmail.com>
Thanks,
Sergio Paracuellos
^ permalink raw reply
* Re: [PATCH] dt-bindings: dma: snps,dma-spear1340: Fix data{-,_}width schema
From: Vinod Koul @ 2024-04-07 13:04 UTC (permalink / raw)
To: Rob Herring
Cc: Viresh Kumar, Andy Shevchenko, Krzysztof Kozlowski, Conor Dooley,
dmaengine, devicetree, linux-kernel
In-Reply-To: <20240311222522.1939951-1-robh@kernel.org>
On 11-03-24, 16:25, Rob Herring wrote:
> 'data-width' and 'data_width' properties are defined as arrays, but the
> schema is defined as a matrix. That works currently since everything gets
> decoded in to matrices, but that is internal to dtschema and could change.
This fails to apply on dmaengine/next.
Can you please rebase?
>
> Signed-off-by: Rob Herring <robh@kernel.org>
> ---
> .../bindings/dma/snps,dma-spear1340.yaml | 38 +++++++++----------
> 1 file changed, 17 insertions(+), 21 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml b/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml
> index 5da8291a7de0..7b0ff4afcaa1 100644
> --- a/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml
> +++ b/Documentation/devicetree/bindings/dma/snps,dma-spear1340.yaml
> @@ -93,10 +93,9 @@ properties:
> data-width:
> $ref: /schemas/types.yaml#/definitions/uint32-array
> description: Data bus width per each DMA master in bytes.
> + maxItems: 4
> items:
> - maxItems: 4
> - items:
> - enum: [4, 8, 16, 32]
> + enum: [4, 8, 16, 32]
>
> data_width:
> $ref: /schemas/types.yaml#/definitions/uint32-array
> @@ -106,28 +105,26 @@ properties:
> deprecated. It' usage is discouraged in favor of data-width one. Moreover
> the property incorrectly permits to define data-bus width of 8 and 16
> bits, which is impossible in accordance with DW DMAC IP-core data book.
> + maxItems: 4
> items:
> - maxItems: 4
> - items:
> - enum:
> - - 0 # 8 bits
> - - 1 # 16 bits
> - - 2 # 32 bits
> - - 3 # 64 bits
> - - 4 # 128 bits
> - - 5 # 256 bits
> - default: 0
> + enum:
> + - 0 # 8 bits
> + - 1 # 16 bits
> + - 2 # 32 bits
> + - 3 # 64 bits
> + - 4 # 128 bits
> + - 5 # 256 bits
> + default: 0
>
> multi-block:
> $ref: /schemas/types.yaml#/definitions/uint32-array
> description: |
> LLP-based multi-block transfer supported by hardware per
> each DMA channel.
> + maxItems: 8
> items:
> - maxItems: 8
> - items:
> - enum: [0, 1]
> - default: 1
> + enum: [0, 1]
> + default: 1
>
> snps,max-burst-len:
> $ref: /schemas/types.yaml#/definitions/uint32-array
> @@ -138,11 +135,10 @@ properties:
> will be from 1 to max-burst-len words. It's an array property with one
> cell per channel in the units determined by the value set in the
> CTLx.SRC_TR_WIDTH/CTLx.DST_TR_WIDTH fields (data width).
> + maxItems: 8
> items:
> - maxItems: 8
> - items:
> - enum: [4, 8, 16, 32, 64, 128, 256]
> - default: 256
> + enum: [4, 8, 16, 32, 64, 128, 256]
> + default: 256
>
> snps,dma-protection-control:
> $ref: /schemas/types.yaml#/definitions/uint32
> --
> 2.43.0
--
~Vinod
^ permalink raw reply
* Re: [PATCH] dt-bindings: dma: snps,dma-spear1340: Fix data{-,_}width schema
From: Vinod Koul @ 2024-04-07 13:05 UTC (permalink / raw)
To: Rob Herring
Cc: Viresh Kumar, Andy Shevchenko, Krzysztof Kozlowski, Conor Dooley,
dmaengine, devicetree, linux-kernel
In-Reply-To: <ZhKZwp4n7RYlprP-@matsya>
On 07-04-24, 18:34, Vinod Koul wrote:
> On 11-03-24, 16:25, Rob Herring wrote:
> > 'data-width' and 'data_width' properties are defined as arrays, but the
> > schema is defined as a matrix. That works currently since everything gets
> > decoded in to matrices, but that is internal to dtschema and could change.
>
> This fails to apply on dmaengine/next.
>
> Can you please rebase?
Never mind, the v2 worked just fine
--
~Vinod
^ permalink raw reply
* RE: [PATCH v3] clk: starfive: pll: Fix lower rate of CPUfreq by setting PLL0 rate to 1.5GHz
From: Xingyu Wu @ 2024-04-07 13:14 UTC (permalink / raw)
To: Samuel Holland
Cc: Paul Walmsley, Palmer Dabbelt, Albert Ou, Hal Feng,
linux-kernel@vger.kernel.org, linux-clk@vger.kernel.org,
linux-riscv@lists.infradead.org, devicetree@vger.kernel.org,
Krzysztof Kozlowski, Michael Turquette, Stephen Boyd,
Conor Dooley, Emil Renner Berthing, Rob Herring,
Krzysztof Kozlowski
In-Reply-To: <74d6213f-51de-4d48-a7fb-844d6bb57fa7@sifive.com>
On 2024-04-05 5:28 AM, Samuel Holland wrote:
>
> Hi Xingyu,
>
> On 2024-04-03 2:44 AM, Xingyu Wu wrote:
> > On 03/04/2024 15:24, Krzysztof Kozlowski wrote:
> >>
> >> On 03/04/2024 09:19, Xingyu Wu wrote:
> >>> On 03/04/2024 0:18, Krzysztof Kozlowski wrote:
> >>>>
> >>>> On 02/04/2024 11:09, Xingyu Wu wrote:
> >>>>> CPUfreq supports 4 cpu frequency loads on 375/500/750/1500MHz.
> >>>>> But now PLL0 rate is 1GHz and the cpu frequency loads become
> >>>>> 333/500/500/1000MHz in fact.
> >>>>>
> >>>>> So PLL0 rate should be default set to 1.5GHz. But setting the
> >>>>> PLL0 rate need certain steps:
> >>>>>
> >>>>> 1. Change the parent of cpu_root clock to OSC clock.
> >>>>> 2. Change the divider of cpu_core if PLL0 rate is higher than
> >>>>> 1.25GHz before CPUfreq boot.
> >>>>> 3. Change the parent of cpu_root clock back to PLL0 clock.
> >>>>>
> >>>>> Reviewed-by: Hal Feng <hal.feng@starfivetech.com>
> >>>>> Fixes: e2c510d6d630 ("riscv: dts: starfive: Add cpu scaling for
> >>>>> JH7110
> >>>>> SoC")
> >>>>> Signed-off-by: Xingyu Wu <xingyu.wu@starfivetech.com>
> >>>>> ---
> >>>>>
> >>>>> Hi Stephen and Emil,
> >>>>>
> >>>>> This patch fixes the issue about lower rate of CPUfreq[1] by
> >>>>> setting
> >>>>> PLL0 rate to 1.5GHz.
> >>>>>
> >>>>> In order not to affect the cpu operation, setting the PLL0 rate
> >>>>> need certain steps. The cpu_root's parent clock should be changed first.
> >>>>> And the divider of the cpu_core clock should be set to 2 so they
> >>>>> won't crash when setting 1.5GHz without voltage regulation. Due to
> >>>>> PLL driver boot earlier than SYSCRG driver, cpu_core and cpu_root
> >>>>> clocks are using by ioremap().
> >>>>>
> >>>>> [1]: https://github.com/starfive-tech/VisionFive2/issues/55
> >>>>>
> >>>>> Previous patch link:
> >>>>> v2:
> >>>>> https://lore.kernel.org/all/20230821152915.208366-1-xingyu.wu@star
> >>>>> fi
> >>>>> ve
> >>>>> tech.com/
> >>>>> v1:
> >>>>> https://lore.kernel.org/all/20230811033631.160912-1-xingyu.wu@star
> >>>>> fi
> >>>>> ve
> >>>>> tech.com/
> >>>>>
> >>>>> Thanks,
> >>>>> Xingyu Wu
> >>>>> ---
> >>>>> .../jh7110-starfive-visionfive-2.dtsi | 5 +
> >>>>> .../clk/starfive/clk-starfive-jh7110-pll.c | 102 ++++++++++++++++++
> >>>>
> >>>> Please do not mix DTS and driver code. That's not really portable.
> >>>> DTS is being exported and used in other projects.
> >>>
> >>> OK, I will submit that in two patches.
> >>>
> >>>>
> >>>> ...
> >>>>
> >>>>>
> >>>>> @@ -458,6 +535,8 @@ static int jh7110_pll_probe(struct
> >>>>> platform_device
> >>>> *pdev)
> >>>>> struct jh7110_pll_priv *priv;
> >>>>> unsigned int idx;
> >>>>> int ret;
> >>>>> + struct device_node *np;
> >>>>> + struct resource res;
> >>>>>
> >>>>> priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
> >>>>> if (!priv)
> >>>>> @@ -489,6 +568,29 @@ static int jh7110_pll_probe(struct
> >>>>> platform_device
> >>>> *pdev)
> >>>>> return ret;
> >>>>> }
> >>>>>
> >>>>> + priv->is_first_set = true;
> >>>>> + np = of_find_compatible_node(NULL, NULL,
> >>>>> +"starfive,jh7110-syscrg");
> >>>>
> >>>> Your drivers should not do it. It's fragile, hides true link/dependency.
> >>>> Please use phandles.
> >>>>
> >>>>
> >>>>> + if (!np) {
> >>>>> + ret = PTR_ERR(np);
> >>>>> + dev_err(priv->dev, "failed to get syscrg node\n");
> >>>>> + goto np_put;
> >>>>> + }
> >>>>> +
> >>>>> + ret = of_address_to_resource(np, 0, &res);
> >>>>> + if (ret) {
> >>>>> + dev_err(priv->dev, "failed to get syscrg resource\n");
> >>>>> + goto np_put;
> >>>>> + }
> >>>>> +
> >>>>> + priv->syscrg_base = ioremap(res.start, resource_size(&res));
> >>>>> + if (!priv->syscrg_base)
> >>>>> + ret = -ENOMEM;
> >>>>
> >>>> Why are you mapping other device's IO? How are you going to ensure
> >>>> synced access to registers?
> >>>
> >>> Because setting PLL0 rate need specific steps and use the clocks of SYSCRG.
> >>
> >> That's not a reason to map other device's IO. That could be a reason
> >> for having syscon or some other sort of relationship, like clock or reset.
> >>
> >>> But SYSCRG driver also need PLL clock to be clock source when adding
> >>> clock providers. I tried to add SYSCRG clocks in 'clocks' property
> >>> in DT and use
> >>> clk_get() to get the clocks. But it could not run and crash. So I
> >>> use
> >>> ioremap() instead.
> >>
> >> So instead of properly model the relationship, you entangle the
> >> drivers even more.
> >>
> >> Please come with a proper design for this. I have no clue about your
> >> hardware, but that looks like you are asynchronously configuring the
> >> same hardware in two different places.
> >>
> >> Sorry, that's poor code.
> >>
> >> Best regards,
> >> Krzysztof
> >
> > Hi Krzysztof,
> >
> > If I use the old patch[1] like v2 and set the PLL0 default rate in the
> > SYSCRG driver, will it be better?
> >
> > [1]:
> > https://lore.kernel.org/all/20230821152915.208366-1-xingyu.wu@starfive
> > tech.com/
>
> Both reparenting cpu_root and enforcing the maximum cpu_core frequency can
> be accomplished with clk notifiers. See for example ccu_mux_notifier_register()
> in drivers/clk/sunxi-ng/ccu_mux.c.
>
This seems like a good idea. I'll try it.
Thanks,
Xingyu Wu
^ permalink raw reply
* Re: [PATCH v9 2/6] PCI: qcom: Add ICC bandwidth vote for CPU to PCIe path
From: Manivannan Sadhasivam @ 2024-04-07 14:39 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lorenzo Pieralisi, Krzysztof Wilczyński,
Bjorn Helgaas, johan+linaro, bmasney, djakov, linux-arm-msm,
devicetree, linux-kernel, linux-pci, vireshk, quic_vbadigan,
quic_skananth, quic_nitegupt, quic_parass, krzysztof.kozlowski,
Bryan O'Donoghue
In-Reply-To: <20240407-opp_support-v9-2-496184dc45d7@quicinc.com>
On Sun, Apr 07, 2024 at 10:07:35AM +0530, Krishna chaitanya chundru wrote:
> To access PCIe registers, PCIe BAR space, config space the CPU-PCIe
Please specify whether you are referencing PCIe host controller or endpoint
device or both.
> ICC (interconnect consumers) path should be voted otherwise it may
ICC is just 'Interconnect' unless I misunderstood.
> lead to NoC (Network on chip) timeout. We are surviving because of
> other driver vote for this path.
>
s/vote/voting
> As there is less access on this path compared to PCIe to mem path
> add minimum vote i.e 1KBps bandwidth always which is recommended
> by HW team.
>
'which is sufficient enough to keep the path active.'
> When suspending, disable this path after register space access
> is done.
>
> Reviewed-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> drivers/pci/controller/dwc/pcie-qcom.c | 38 ++++++++++++++++++++++++++++++----
> 1 file changed, 34 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index 14772edcf0d3..b4893214b2d3 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -245,6 +245,7 @@ struct qcom_pcie {
> struct phy *phy;
> struct gpio_desc *reset;
> struct icc_path *icc_mem;
> + struct icc_path *icc_cpu;
> const struct qcom_pcie_cfg *cfg;
> struct dentry *debugfs;
> bool suspended;
> @@ -1409,6 +1410,9 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
> if (IS_ERR(pcie->icc_mem))
> return PTR_ERR(pcie->icc_mem);
>
> + pcie->icc_cpu = devm_of_icc_get(pci->dev, "cpu-pcie");
> + if (IS_ERR(pcie->icc_cpu))
> + return PTR_ERR(pcie->icc_cpu);
> /*
> * Some Qualcomm platforms require interconnect bandwidth constraints
> * to be set before enabling interconnect clocks.
> @@ -1418,7 +1422,19 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
> */
> ret = icc_set_bw(pcie->icc_mem, 0, QCOM_PCIE_LINK_SPEED_TO_BW(1));
> if (ret) {
> - dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
> + dev_err(pci->dev, "failed to set interconnect bandwidth for PCIe-MEM: %d\n",
> + ret);
> + return ret;
> + }
> +
> + /*
> + * Since the CPU-PCIe path is only used for activities like register
Again, differentiate PCIe controller and endpoint device access.
> + * access, Config/BAR space access, HW team has recommended to use a
> + * minimal bandwidth of 1KBps just to keep the link active.
> + */
> + ret = icc_set_bw(pcie->icc_cpu, 0, kBps_to_icc(1));
> + if (ret) {
> + dev_err(pci->dev, "failed to set interconnect bandwidth for CPU-PCIe: %d\n",
> ret);
> return ret;
> }
> @@ -1448,7 +1464,7 @@ static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
>
> ret = icc_set_bw(pcie->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed));
> if (ret) {
> - dev_err(pci->dev, "failed to set interconnect bandwidth: %d\n",
> + dev_err(pci->dev, "failed to set interconnect bandwidth for PCIe-MEM: %d\n",
> ret);
> }
> }
> @@ -1610,7 +1626,7 @@ static int qcom_pcie_suspend_noirq(struct device *dev)
> */
> ret = icc_set_bw(pcie->icc_mem, 0, kBps_to_icc(1));
> if (ret) {
> - dev_err(dev, "Failed to set interconnect bandwidth: %d\n", ret);
> + dev_err(dev, "Failed to set interconnect bandwidth for PCIe-MEM: %d\n", ret);
> return ret;
> }
>
> @@ -1634,7 +1650,15 @@ static int qcom_pcie_suspend_noirq(struct device *dev)
> pcie->suspended = true;
> }
>
> - return 0;
> + /*
> + * Remove the vote for CPU-PCIe path now, since at this point onwards,
> + * no register access will be done.
> + */
Are you sure? Didn't we see late access to DBI registers on sc7280?
> + ret = icc_disable(pcie->icc_cpu);
> + if (ret)
> + dev_err(dev, "failed to disable icc path of CPU-PCIe: %d\n", ret);
s/failed to disable icc path/Failed to disable Interconnect path between CPU-PCIe
> +
> + return ret;
> }
>
> static int qcom_pcie_resume_noirq(struct device *dev)
> @@ -1642,6 +1666,12 @@ static int qcom_pcie_resume_noirq(struct device *dev)
> struct qcom_pcie *pcie = dev_get_drvdata(dev);
> int ret;
>
> + ret = icc_enable(pcie->icc_cpu);
> + if (ret) {
> + dev_err(dev, "failed to enable icc path of CPU-PCIe: %d\n", ret);
Same as above.
- Mani
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v9 3/6] dt-bindings: pci: qcom: Add opp table
From: Manivannan Sadhasivam @ 2024-04-07 14:42 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lorenzo Pieralisi, Krzysztof Wilczyński,
Bjorn Helgaas, johan+linaro, bmasney, djakov, linux-arm-msm,
devicetree, linux-kernel, linux-pci, vireshk, quic_vbadigan,
quic_skananth, quic_nitegupt, quic_parass, krzysztof.kozlowski
In-Reply-To: <20240407-opp_support-v9-3-496184dc45d7@quicinc.com>
On Sun, Apr 07, 2024 at 10:07:36AM +0530, Krishna chaitanya chundru wrote:
s/opp/OPP
> PCIe needs to choose the appropriate performance state of RPMH power
s/RPMH/RPMh
> domain based upon the PCIe gen speed.
>
s/upon/on
> Adding the Operating Performance Points table allows to adjust power
> domain performance state and icc peak bw, depending on the PCIe gen
s/icc/ICC
s/PCIe gen speed/PCIe data rate
> speed and width.
>
s/width/link width
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
With above changes,
Reviewed-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
- Mani
> ---
> Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml
> index 1496d6993ab4..d8c0afaa4b19 100644
> --- a/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml
> +++ b/Documentation/devicetree/bindings/pci/qcom,pcie-sm8450.yaml
> @@ -69,6 +69,10 @@ properties:
> - const: msi6
> - const: msi7
>
> + operating-points-v2: true
> + opp-table:
> + type: object
> +
> resets:
> maxItems: 1
>
>
> --
> 2.42.0
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v9 4/6] arm64: dts: qcom: sm8450: Add opp table support to PCIe
From: Manivannan Sadhasivam @ 2024-04-07 14:45 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lorenzo Pieralisi, Krzysztof Wilczyński,
Bjorn Helgaas, johan+linaro, bmasney, djakov, linux-arm-msm,
devicetree, linux-kernel, linux-pci, vireshk, quic_vbadigan,
quic_skananth, quic_nitegupt, quic_parass, krzysztof.kozlowski
In-Reply-To: <20240407-opp_support-v9-4-496184dc45d7@quicinc.com>
On Sun, Apr 07, 2024 at 10:07:37AM +0530, Krishna chaitanya chundru wrote:
> PCIe needs to choose the appropriate performance state of RPMH power
> domain and interconnect bandwidth based up on the PCIe gen speed.
>
> Add the OPP table support to specify RPMH performance states and
> interconnect peak bandwidth.
>
Same comment as the bindings patch.
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> arch/arm64/boot/dts/qcom/sm8450.dtsi | 77 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 77 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/qcom/sm8450.dtsi b/arch/arm64/boot/dts/qcom/sm8450.dtsi
> index 615296e13c43..881e5339cfff 100644
> --- a/arch/arm64/boot/dts/qcom/sm8450.dtsi
> +++ b/arch/arm64/boot/dts/qcom/sm8450.dtsi
> @@ -1855,7 +1855,35 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
> pinctrl-names = "default";
> pinctrl-0 = <&pcie0_default_state>;
>
> + operating-points-v2 = <&pcie0_opp_table>;
> +
> status = "disabled";
> +
> + pcie0_opp_table: opp-table {
> + compatible = "operating-points-v2";
> +
> + /* GEN 1x1 */
s/GEN 1x1/Gen 1 x1
Same for all comments
- Mani
> + opp-2500000 {
> + opp-hz = /bits/ 64 <2500000>;
> + required-opps = <&rpmhpd_opp_low_svs>;
> + opp-peak-kBps = <250000 1>;
> + };
> +
> + /* GEN 2x1 */
> + opp-5000000 {
> + opp-hz = /bits/ 64 <5000000>;
> + required-opps = <&rpmhpd_opp_low_svs>;
> + opp-peak-kBps = <500000 1>;
> + };
> +
> + /* GEN 3x1 */
> + opp-8000000 {
> + opp-hz = /bits/ 64 <8000000>;
> + required-opps = <&rpmhpd_opp_nom>;
> + opp-peak-kBps = <984500 1>;
> + };
> + };
> +
> };
>
> pcie0_phy: phy@1c06000 {
> @@ -1982,7 +2010,56 @@ &mc_virt SLAVE_EBI1 QCOM_ICC_TAG_ALWAYS>,
> pinctrl-names = "default";
> pinctrl-0 = <&pcie1_default_state>;
>
> + operating-points-v2 = <&pcie1_opp_table>;
> +
> status = "disabled";
> +
> + pcie1_opp_table: opp-table {
> + compatible = "operating-points-v2";
> +
> + /* GEN 1x1 */
> + opp-2500000 {
> + opp-hz = /bits/ 64 <2500000>;
> + required-opps = <&rpmhpd_opp_low_svs>;
> + opp-peak-kBps = <250000 1>;
> + };
> +
> + /* GEN 1x2 GEN 2x1 */
> + opp-5000000 {
> + opp-hz = /bits/ 64 <5000000>;
> + required-opps = <&rpmhpd_opp_low_svs>;
> + opp-peak-kBps = <500000 1>;
> + };
> +
> + /* GEN 2x2 */
> + opp-10000000 {
> + opp-hz = /bits/ 64 <10000000>;
> + required-opps = <&rpmhpd_opp_low_svs>;
> + opp-peak-kBps = <1000000 1>;
> + };
> +
> + /* GEN 3x1 */
> + opp-8000000 {
> + opp-hz = /bits/ 64 <8000000>;
> + required-opps = <&rpmhpd_opp_nom>;
> + opp-peak-kBps = <984500 1>;
> + };
> +
> + /* GEN 3x2 GEN 4x1 */
> + opp-16000000 {
> + opp-hz = /bits/ 64 <16000000>;
> + required-opps = <&rpmhpd_opp_nom>;
> + opp-peak-kBps = <1969000 1>;
> + };
> +
> + /* GEN 4x2 */
> + opp-32000000 {
> + opp-hz = /bits/ 64 <32000000>;
> + required-opps = <&rpmhpd_opp_nom>;
> + opp-peak-kBps = <3938000 1>;
> + };
> + };
> +
> };
>
> pcie1_phy: phy@1c0e000 {
>
> --
> 2.42.0
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v9 6/6] PCI: qcom: Add OPP support to scale performance state of power domain
From: Manivannan Sadhasivam @ 2024-04-07 15:00 UTC (permalink / raw)
To: Krishna chaitanya chundru
Cc: Bjorn Andersson, Konrad Dybcio, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Lorenzo Pieralisi, Krzysztof Wilczyński,
Bjorn Helgaas, johan+linaro, bmasney, djakov, linux-arm-msm,
devicetree, linux-kernel, linux-pci, vireshk, quic_vbadigan,
quic_skananth, quic_nitegupt, quic_parass, krzysztof.kozlowski
In-Reply-To: <20240407-opp_support-v9-6-496184dc45d7@quicinc.com>
On Sun, Apr 07, 2024 at 10:07:39AM +0530, Krishna chaitanya chundru wrote:
> QCOM Resource Power Manager-hardened (RPMh) is a hardware block which
> maintains hardware state of a regulator by performing max aggregation of
> the requests made by all of the clients.
>
> PCIe controller can operate on different RPMh performance state of power
> domain based on the speed of the link. And this performance state varies
> from target to target, like some controllers support GEN3 in NOM (Nominal)
> voltage corner, while some other supports GEN3 in low SVS (static voltage
> scaling).
>
> The SoC can be more power efficient if we scale the performance state
> based on the aggregate PCIe link bandwidth.
>
> Add Operating Performance Points (OPP) support to vote for RPMh state based
> on the aggregate link bandwidth.
>
> OPP can handle ICC bw voting also, so move ICC bw voting through OPP
> framework if OPP entries are present.
>
> Different link configurations may share the same aggregate bandwidth,
> e.g., a 2.5 GT/s x2 link and a 5.0 GT/s x1 link have the same bandwidth
> and share the same OPP entry.
>
This info should be part of the dts change.
> As we are moving ICC voting as part of OPP, don't initialize ICC if OPP
> is supported.
>
> Before PCIe link is initialized vote for highest OPP in the OPP table,
> so that we are voting for maximum voltage corner for the link to come up
> in maximum supported speed.
>
> Signed-off-by: Krishna chaitanya chundru <quic_krichai@quicinc.com>
> ---
> drivers/pci/controller/dwc/pcie-qcom.c | 72 +++++++++++++++++++++++++++-------
> 1 file changed, 58 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-qcom.c b/drivers/pci/controller/dwc/pcie-qcom.c
> index b4893214b2d3..4ad5ef3bf8fc 100644
> --- a/drivers/pci/controller/dwc/pcie-qcom.c
> +++ b/drivers/pci/controller/dwc/pcie-qcom.c
> @@ -22,6 +22,7 @@
> #include <linux/of.h>
> #include <linux/of_gpio.h>
> #include <linux/pci.h>
> +#include <linux/pm_opp.h>
> #include <linux/pm_runtime.h>
> #include <linux/platform_device.h>
> #include <linux/phy/pcie.h>
> @@ -1442,15 +1443,13 @@ static int qcom_pcie_icc_init(struct qcom_pcie *pcie)
> return 0;
> }
>
> -static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
> +static void qcom_pcie_icc_opp_update(struct qcom_pcie *pcie)
> {
> struct dw_pcie *pci = pcie->pci;
> - u32 offset, status;
> + u32 offset, status, freq;
> + struct dev_pm_opp *opp;
> int speed, width;
> - int ret;
> -
> - if (!pcie->icc_mem)
> - return;
> + int ret, mbps;
>
> offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP);
> status = readw(pci->dbi_base + offset + PCI_EXP_LNKSTA);
> @@ -1462,10 +1461,26 @@ static void qcom_pcie_icc_update(struct qcom_pcie *pcie)
> speed = FIELD_GET(PCI_EXP_LNKSTA_CLS, status);
> width = FIELD_GET(PCI_EXP_LNKSTA_NLW, status);
>
> - ret = icc_set_bw(pcie->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed));
> - if (ret) {
> - dev_err(pci->dev, "failed to set interconnect bandwidth for PCIe-MEM: %d\n",
> - ret);
> + if (pcie->icc_mem) {
> + ret = icc_set_bw(pcie->icc_mem, 0, width * QCOM_PCIE_LINK_SPEED_TO_BW(speed));
> + if (ret) {
> + dev_err(pci->dev, "failed to set interconnect bandwidth for PCIe-MEM: %d\n",
s/failed/Failed
> + ret);
> + }
> + } else {
> + mbps = pcie_link_speed_to_mbps(pcie_link_speed[speed]);
> + if (mbps < 0)
> + return;
> +
> + freq = mbps * 1000;
> + opp = dev_pm_opp_find_freq_exact(pci->dev, freq * width, true);
As per the API documentation, dev_pm_opp_put() should be called for both success
and failure case.
> + if (!IS_ERR(opp)) {
So what is the action if OPP is not found for the freq?
> + ret = dev_pm_opp_set_opp(pci->dev, opp);
> + if (ret)
> + dev_err(pci->dev, "Failed to set opp: freq %ld ret %d\n",
'Failed to set OPP for freq (%ld): %d'
> + dev_pm_opp_get_freq(opp), ret);
> + dev_pm_opp_put(opp);
> + }
> }
> }
>
> @@ -1509,8 +1524,10 @@ static void qcom_pcie_init_debugfs(struct qcom_pcie *pcie)
> static int qcom_pcie_probe(struct platform_device *pdev)
> {
> const struct qcom_pcie_cfg *pcie_cfg;
> + unsigned long max_freq = INT_MAX;
> struct device *dev = &pdev->dev;
> struct qcom_pcie *pcie;
> + struct dev_pm_opp *opp;
> struct dw_pcie_rp *pp;
> struct resource *res;
> struct dw_pcie *pci;
> @@ -1577,9 +1594,33 @@ static int qcom_pcie_probe(struct platform_device *pdev)
> goto err_pm_runtime_put;
> }
>
> - ret = qcom_pcie_icc_init(pcie);
> - if (ret)
> + /* OPP table is optional */
> + ret = devm_pm_opp_of_add_table(dev);
> + if (ret && ret != -ENODEV) {
> + dev_err_probe(dev, ret, "Failed to add OPP table\n");
> goto err_pm_runtime_put;
> + }
> +
> + /*
> + * Use highest OPP here if the OPP table is present. At the end of
I believe I asked you to add the information justifying why the highest OPP
should be used.
> + * the probe(), OPP will be updated using qcom_pcie_icc_opp_update().
> + */
> + if (!ret) {
> + opp = dev_pm_opp_find_freq_floor(dev, &max_freq);
Same comment as dev_pm_opp_find_freq_exact().
> + if (!IS_ERR(opp)) {
> + ret = dev_pm_opp_set_opp(dev, opp);
> + if (ret)
> + dev_err_probe(pci->dev, ret,
> + "Failed to set OPP: freq %ld\n",
Same comment as above.
> + dev_pm_opp_get_freq(opp));
> + dev_pm_opp_put(opp);
So you want to continue even in the case of failure?
- Mani
> + }
> + } else {
> + /* Skip ICC init if OPP is supported as it is handled by OPP */
> + ret = qcom_pcie_icc_init(pcie);
> + if (ret)
> + goto err_pm_runtime_put;
> + }
>
> ret = pcie->cfg->ops->get_resources(pcie);
> if (ret)
> @@ -1599,7 +1640,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
> goto err_phy_exit;
> }
>
> - qcom_pcie_icc_update(pcie);
> + qcom_pcie_icc_opp_update(pcie);
>
> if (pcie->mhi)
> qcom_pcie_init_debugfs(pcie);
> @@ -1658,6 +1699,9 @@ static int qcom_pcie_suspend_noirq(struct device *dev)
> if (ret)
> dev_err(dev, "failed to disable icc path of CPU-PCIe: %d\n", ret);
>
> + if (!pcie->icc_mem)
> + dev_pm_opp_set_opp(pcie->pci->dev, NULL);
> +
> return ret;
> }
>
> @@ -1680,7 +1724,7 @@ static int qcom_pcie_resume_noirq(struct device *dev)
> pcie->suspended = false;
> }
>
> - qcom_pcie_icc_update(pcie);
> + qcom_pcie_icc_opp_update(pcie);
>
> return 0;
> }
>
> --
> 2.42.0
>
--
மணிவண்ணன் சதாசிவம்
^ permalink raw reply
* Re: [PATCH v2 1/6] dt-bindings: firmware: arm,scmi: set additionalProperties to true
From: Krzysztof Kozlowski @ 2024-04-07 16:15 UTC (permalink / raw)
To: Peng Fan, Peng Fan (OSS), Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Shawn Guo, Sascha Hauer, Pengutronix Kernel Team,
Fabio Estevam, Sudeep Holla, Cristian Marussi
Cc: devicetree@vger.kernel.org, imx@lists.linux.dev,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org
In-Reply-To: <DU0PR04MB9417C5B9BDD9E0B47E7494C088012@DU0PR04MB9417.eurprd04.prod.outlook.com>
On 07/04/2024 12:04, Peng Fan wrote:
>> Subject: Re: [PATCH v2 1/6] dt-bindings: firmware: arm,scmi: set
>> additionalProperties to true
>>
>> On 07/04/2024 02:37, Peng Fan wrote:
>>>> Subject: Re: [PATCH v2 1/6] dt-bindings: firmware: arm,scmi: set
>>>> additionalProperties to true
>>>>
>>>> On 05/04/2024 14:39, Peng Fan (OSS) wrote:
>>>>> From: Peng Fan <peng.fan@nxp.com>
>>>>>
>>>>> When adding vendor extension protocols, there is dt-schema warning:
>>>>> "
>>>>> imx,scmi.example.dtb: scmi: 'protocol@81', 'protocol@84' do not
>>>>> match any of the regexes: 'pinctrl-[0-9]+'
>>>>> "
>>>>>
>>>>> Set additionalProperties to true to address the issue.
>>>>
>>>> I do not see anything addressed here, except making the binding
>>>> accepting anything anywhere...
>>>
>>> I not wanna add vendor protocols in arm,scmi.yaml, so will introduce a
>>> new yaml imx.scmi.yaml which add i.MX SCMI protocol extension.
>>>
>>> With additionalProperties set to false, I not know how, please suggest.
>>
>> First of all, you cannot affect negatively existing devices (their
>> bindings) and your patch does exactly that. This should make you thing what
>> is the correct approach...
>>
>> Rob gave you the comment about missing compatible - you still did not
>> address that.
>
> I added the compatible in patch 2/6 in the examples "compatible = "arm,scmi";"
So you claim that your vendor extensions are the same or fully
compatible with arm,scmi and you add nothing... Are your
extensions/protocol valid for arm,scmi? If yes, why is this in separate
binding. If no, why you use someone else's compatible?
Maybe your binding is correct, feel free to convince me (and read first
writing bindings).
Best regards,
Krzysztof
^ permalink raw reply
* [PATCH v9 0/7] spmi: pmic-arb: Add support for multiple buses
From: Abel Vesa @ 2024-04-07 16:23 UTC (permalink / raw)
To: Stephen Boyd, Matthias Brugger, Bjorn Andersson, Konrad Dybcio,
Dmitry Baryshkov, Neil Armstrong, AngeloGioacchino Del Regno,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Srini Kandagatla, Johan Hovold, David Collins, linux-kernel,
linux-arm-kernel, linux-arm-msm, linux-mediatek, devicetree,
Abel Vesa, Krzysztof Kozlowski
This patchset prepares for and adds support for 2 buses, which is supported
in HW starting with version 7. Until now, none of the currently
supported platforms in upstream have used the second bus. The X1E80100
platform, on the other hand, needs the second bus for the USB2.0 to work
as there are 3 SMB2360 PMICs which provide eUSB2 repeaters and they are
all found on the second bus.
Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
---
Changes in v9:
- Use the proper number of buses on deregister, like David suggested
- Moved the lock from the arbiter to the bus, like David suggested
- Fixed type in schema file, pointed out by David
- Added Neil's R-b tag to patches #3, #6 and #7
- Link to v8: https://lore.kernel.org/r/20240402-spmi-multi-master-support-v8-0-ce6f2d14a058@linaro.org
Changes in v8:
- Added Neil's R-b tag to the 3rd patch
- Fixed compile warnings already existent by adding another patch
- Fixed compile warning about get_core_resources, reported by Neil
- Dropped and moved the spurious core removal changes, as suggested by Neil
- Link to v7: https://lore.kernel.org/r/20240329-spmi-multi-master-support-v7-0-7b902824246c@linaro.org
Changes in v7:
- This time really collected Krzysztof's R-b tags
- Added Neil's R-b tag to the 4th patch
- Split the multi bus patch into two separate patches, one for adding
the bus object and one for the secondary bus, as per Neil's suggestion
- Fixed regression for single bus platforms triggered by casting to
pmic_arb instead of bus in pmic_arb_non_data_cmd_v1
- Fixed bus object allocation by using ctrl drvdata instead
- Prefixed the spmi node property in x1e80100 schema with '^'
- Fixed struct and function documentation warnings reported by Neil
Changes in v6 (resend):
- Collected Krzysztof's R-b tags
- Link to v6: https://lore.kernel.org/r/20240222-spmi-multi-master-support-v6-0-bc34ea9561da@linaro.org
Changes in v6:
- Changed the compatible to platform specific (X1E80100) along with the
schema. Fixed the spmi buses unit addresses and added the empty ranges
property. Added missing properties to the spmi buses and the
"unevaluatedProperties: false".
- Deprecated the "qcom,bus-id" in the legacy schema.
- Changed the driver to check for legacy compatible first
- Link to v5: https://lore.kernel.org/r/20240221-spmi-multi-master-support-v5-0-3255ca413a0b@linaro.org
Changes in v5:
- Dropped the RFC as there aren't any concerns about the approach anymore
- Dropped the unused dev and res variables from pmic_arb_get_obsrvr_chnls_v2
- Link to v4: https://lore.kernel.org/r/20240220-spmi-multi-master-support-v4-0-dc813c878ba8@linaro.org
Changes in v4:
- Fixed comment above pmic_arb_init_apid_v7 by dropping the extra "bus" word
- Swicthed to devm_platform_ioremap_resource_byname for obsrvr and chnls.
The core remains with platform_get_resource_byname as we need the core size.
- Dropped comment from probe related to the need of platform_get_resource_byname
as it not true anymore.
- Dropped the qcom,bus-id optional property.
- Link to v3: https://lore.kernel.org/r/20240214-spmi-multi-master-support-v3-0-0bae0ef04faf@linaro.org
Changes in v3:
- Split the change into 3 separate patches. First 2 patches are moving
apid init and core resources into version specific ops. Third one is
adding the support for 2 buses and dedicated compatible.
- Added separate bindings patch
- Link to v2: https://lore.kernel.org/r/20240213-spmi-multi-master-support-v2-1-b3b102326906@linaro.org
Changes in v2:
- Reworked it so that it registers a spmi controller for each bus
rather than relying on the generic framework to pass on the bus
(master) id.
- Link to v1: https://lore.kernel.org/r/20240207-spmi-multi-master-support-v1-0-ce57f301c7fd@linaro.org
---
Abel Vesa (7):
dt-bindings: spmi: Add X1E80100 SPMI PMIC ARB schema
dt-bindings: spmi: Deprecate qcom,bus-id
spmi: pmic-arb: Fix some compile warnings about members not being described
spmi: pmic-arb: Make the APID init a version operation
spmi: pmic-arb: Make core resources acquiring a version operation
spmi: pmic-arb: Register controller for bus instead of arbiter
spmi: pmic-arb: Add multi bus support
.../bindings/spmi/qcom,spmi-pmic-arb.yaml | 1 +
.../bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml | 136 +++
drivers/spmi/spmi-pmic-arb.c | 964 +++++++++++++--------
3 files changed, 728 insertions(+), 373 deletions(-)
---
base-commit: 8568bb2ccc278f344e6ac44af6ed010a90aa88dc
change-id: 20240207-spmi-multi-master-support-832a704b779b
Best regards,
--
Abel Vesa <abel.vesa@linaro.org>
^ permalink raw reply
* [PATCH v9 1/7] dt-bindings: spmi: Add X1E80100 SPMI PMIC ARB schema
From: Abel Vesa @ 2024-04-07 16:23 UTC (permalink / raw)
To: Stephen Boyd, Matthias Brugger, Bjorn Andersson, Konrad Dybcio,
Dmitry Baryshkov, Neil Armstrong, AngeloGioacchino Del Regno,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Srini Kandagatla, Johan Hovold, David Collins, linux-kernel,
linux-arm-kernel, linux-arm-msm, linux-mediatek, devicetree,
Abel Vesa, Krzysztof Kozlowski
In-Reply-To: <20240407-spmi-multi-master-support-v9-0-fa151c1391f3@linaro.org>
Add dedicated schema for X1E80100 PMIC ARB (v7) as it allows multiple
buses by declaring them as child nodes.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
---
.../bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml | 136 +++++++++++++++++++++
1 file changed, 136 insertions(+)
diff --git a/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml
new file mode 100644
index 000000000000..a28b70fb330a
--- /dev/null
+++ b/Documentation/devicetree/bindings/spmi/qcom,x1e80100-spmi-pmic-arb.yaml
@@ -0,0 +1,136 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/spmi/qcom,x1e80100-spmi-pmic-arb.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Qualcomm X1E80100 SPMI Controller (PMIC Arbiter v7)
+
+maintainers:
+ - Stephen Boyd <sboyd@kernel.org>
+
+description: |
+ The X1E80100 SPMI PMIC Arbiter implements HW version 7 and it's an SPMI
+ controller with wrapping arbitration logic to allow for multiple on-chip
+ devices to control up to 2 SPMI separate buses.
+
+ The PMIC Arbiter can also act as an interrupt controller, providing interrupts
+ to slave devices.
+
+properties:
+ compatible:
+ const: qcom,x1e80100-spmi-pmic-arb
+
+ reg:
+ items:
+ - description: core registers
+ - description: tx-channel per virtual slave registers
+ - description: rx-channel (called observer) per virtual slave registers
+
+ reg-names:
+ items:
+ - const: core
+ - const: chnls
+ - const: obsrvr
+
+ ranges: true
+
+ '#address-cells':
+ const: 2
+
+ '#size-cells':
+ const: 2
+
+ qcom,ee:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 5
+ description: >
+ indicates the active Execution Environment identifier
+
+ qcom,channel:
+ $ref: /schemas/types.yaml#/definitions/uint32
+ minimum: 0
+ maximum: 5
+ description: >
+ which of the PMIC Arb provided channels to use for accesses
+
+patternProperties:
+ "^spmi@[a-f0-9]+$":
+ type: object
+ $ref: /schemas/spmi/spmi.yaml
+ unevaluatedProperties: false
+
+ properties:
+ reg:
+ items:
+ - description: configuration registers
+ - description: interrupt controller registers
+
+ reg-names:
+ items:
+ - const: cnfg
+ - const: intr
+
+ interrupts:
+ maxItems: 1
+
+ interrupt-names:
+ const: periph_irq
+
+ interrupt-controller: true
+
+ '#interrupt-cells':
+ const: 4
+ description: |
+ cell 1: slave ID for the requested interrupt (0-15)
+ cell 2: peripheral ID for requested interrupt (0-255)
+ cell 3: the requested peripheral interrupt (0-7)
+ cell 4: interrupt flags indicating level-sense information,
+ as defined in dt-bindings/interrupt-controller/irq.h
+
+required:
+ - compatible
+ - reg-names
+ - qcom,ee
+ - qcom,channel
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ spmi: arbiter@c400000 {
+ compatible = "qcom,x1e80100-spmi-pmic-arb";
+ reg = <0 0x0c400000 0 0x3000>,
+ <0 0x0c500000 0 0x4000000>,
+ <0 0x0c440000 0 0x80000>;
+ reg-names = "core", "chnls", "obsrvr";
+
+ qcom,ee = <0>;
+ qcom,channel = <0>;
+
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ spmi_bus0: spmi@c42d000 {
+ reg = <0 0x0c42d000 0 0x4000>,
+ <0 0x0c4c0000 0 0x10000>;
+ reg-names = "cnfg", "intr";
+
+ interrupt-names = "periph_irq";
+ interrupts-extended = <&pdc 1 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <4>;
+
+ #address-cells = <2>;
+ #size-cells = <0>;
+ };
+ };
+ };
--
2.34.1
^ permalink raw reply related
* [PATCH v9 2/7] dt-bindings: spmi: Deprecate qcom,bus-id
From: Abel Vesa @ 2024-04-07 16:23 UTC (permalink / raw)
To: Stephen Boyd, Matthias Brugger, Bjorn Andersson, Konrad Dybcio,
Dmitry Baryshkov, Neil Armstrong, AngeloGioacchino Del Regno,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Srini Kandagatla, Johan Hovold, David Collins, linux-kernel,
linux-arm-kernel, linux-arm-msm, linux-mediatek, devicetree,
Abel Vesa, Krzysztof Kozlowski
In-Reply-To: <20240407-spmi-multi-master-support-v9-0-fa151c1391f3@linaro.org>
As it is optional and no platform is actually using the secondary bus,
deprecate the qcom,bus-id property. For newer platforms that implement
SPMI PMIC ARB v7 in HW, the X1E80100 approach should be used.
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
---
Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml
index f983b4af6db9..51daf1b847a9 100644
--- a/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml
+++ b/Documentation/devicetree/bindings/spmi/qcom,spmi-pmic-arb.yaml
@@ -92,6 +92,7 @@ properties:
description: >
SPMI bus instance. only applicable to PMIC arbiter version 7 and beyond.
Supported values, 0 = primary bus, 1 = secondary bus
+ deprecated: true
required:
- compatible
--
2.34.1
^ permalink raw reply related
* [PATCH v9 3/7] spmi: pmic-arb: Fix some compile warnings about members not being described
From: Abel Vesa @ 2024-04-07 16:23 UTC (permalink / raw)
To: Stephen Boyd, Matthias Brugger, Bjorn Andersson, Konrad Dybcio,
Dmitry Baryshkov, Neil Armstrong, AngeloGioacchino Del Regno,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Srini Kandagatla, Johan Hovold, David Collins, linux-kernel,
linux-arm-kernel, linux-arm-msm, linux-mediatek, devicetree,
Abel Vesa
In-Reply-To: <20240407-spmi-multi-master-support-v9-0-fa151c1391f3@linaro.org>
Fix the following compile warnings:
warning: Function parameter or struct member 'core' not described in 'spmi_pmic_arb'
warning: Function parameter or struct member 'core_size' not described in 'spmi_pmic_arb'
warning: Function parameter or struct member 'mapping_table_valid' not described in 'spmi_pmic_arb'
warning: Function parameter or struct member 'pmic_arb' not described in 'pmic_arb_read_data'
warning: Function parameter or struct member 'pmic_arb' not described in 'pmic_arb_write_data'
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
---
drivers/spmi/spmi-pmic-arb.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 9ed1180fe31f..704fd4506971 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -132,6 +132,8 @@ struct apid_data {
* @wr_base: on v1 "core", on v2 "chnls" register base off DT.
* @intr: address of the SPMI interrupt control registers.
* @cnfg: address of the PMIC Arbiter configuration registers.
+ * @core: core register base for v2 and above only (see above)
+ * @core_size: core register base size
* @lock: lock to synchronize accesses.
* @channel: execution environment channel to use for accesses.
* @irq: PMIC ARB interrupt.
@@ -144,6 +146,7 @@ struct apid_data {
* @apid_count: on v5 and v7: number of APIDs associated with the
* particular SPMI bus instance
* @mapping_table: in-memory copy of PPID -> APID mapping table.
+ * @mapping_table_valid:bitmap containing valid-only periphs
* @domain: irq domain object for PMIC IRQ domain
* @spmic: SPMI controller object
* @ver_ops: version dependent operations.
@@ -232,6 +235,7 @@ static inline void pmic_arb_set_rd_cmd(struct spmi_pmic_arb *pmic_arb,
/**
* pmic_arb_read_data: reads pmic-arb's register and copy 1..4 bytes to buf
+ * @pmic_arb: the SPMI PMIC arbiter
* @bc: byte count -1. range: 0..3
* @reg: register's address
* @buf: output parameter, length must be bc + 1
@@ -246,6 +250,7 @@ pmic_arb_read_data(struct spmi_pmic_arb *pmic_arb, u8 *buf, u32 reg, u8 bc)
/**
* pmic_arb_write_data: write 1..4 bytes from buf to pmic-arb's register
+ * @pmic_arb: the SPMI PMIC arbiter
* @bc: byte-count -1. range: 0..3.
* @reg: register's address.
* @buf: buffer to write. length must be bc + 1.
--
2.34.1
^ permalink raw reply related
* [PATCH v9 4/7] spmi: pmic-arb: Make the APID init a version operation
From: Abel Vesa @ 2024-04-07 16:23 UTC (permalink / raw)
To: Stephen Boyd, Matthias Brugger, Bjorn Andersson, Konrad Dybcio,
Dmitry Baryshkov, Neil Armstrong, AngeloGioacchino Del Regno,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Srini Kandagatla, Johan Hovold, David Collins, linux-kernel,
linux-arm-kernel, linux-arm-msm, linux-mediatek, devicetree,
Abel Vesa
In-Reply-To: <20240407-spmi-multi-master-support-v9-0-fa151c1391f3@linaro.org>
Rather than using conditionals in probe function, add the APID init
as a version specific operation. Due to v7, which supports multiple
buses, pass on the bus index to be used for sorting out the apid base
and count.
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
---
drivers/spmi/spmi-pmic-arb.c | 144 +++++++++++++++++++++----------------------
1 file changed, 69 insertions(+), 75 deletions(-)
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 704fd4506971..dc969f8bed18 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -186,6 +186,7 @@ struct spmi_pmic_arb {
* struct pmic_arb_ver_ops - version dependent functionality.
*
* @ver_str: version string.
+ * @init_apid: finds the apid base and count
* @ppid_to_apid: finds the apid for a given ppid.
* @non_data_cmd: on v1 issues an spmi non-data command.
* on v2 no HW support, returns -EOPNOTSUPP.
@@ -205,6 +206,7 @@ struct spmi_pmic_arb {
*/
struct pmic_arb_ver_ops {
const char *ver_str;
+ int (*init_apid)(struct spmi_pmic_arb *pmic_arb);
int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid);
/* spmi commands (read_cmd, write_cmd, cmd) functionality */
int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
@@ -947,6 +949,32 @@ static int qpnpint_irq_domain_alloc(struct irq_domain *domain,
return 0;
}
+static int pmic_arb_init_apid_min_max(struct spmi_pmic_arb *pmic_arb)
+{
+ /*
+ * Initialize max_apid/min_apid to the opposite bounds, during
+ * the irq domain translation, we are sure to update these
+ */
+ pmic_arb->max_apid = 0;
+ pmic_arb->min_apid = pmic_arb->max_periphs - 1;
+
+ return 0;
+}
+
+static int pmic_arb_init_apid_v1(struct spmi_pmic_arb *pmic_arb)
+{
+ u32 *mapping_table;
+
+ mapping_table = devm_kcalloc(&pmic_arb->spmic->dev, pmic_arb->max_periphs,
+ sizeof(*mapping_table), GFP_KERNEL);
+ if (!mapping_table)
+ return -ENOMEM;
+
+ pmic_arb->mapping_table = mapping_table;
+
+ return pmic_arb_init_apid_min_max(pmic_arb);
+}
+
static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
{
u32 *mapping_table = pmic_arb->mapping_table;
@@ -1149,6 +1177,34 @@ static int pmic_arb_offset_v2(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
return 0x1000 * pmic_arb->ee + 0x8000 * apid;
}
+static int pmic_arb_init_apid_v5(struct spmi_pmic_arb *pmic_arb)
+{
+ int ret;
+
+ pmic_arb->base_apid = 0;
+ pmic_arb->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK;
+
+ if (pmic_arb->base_apid + pmic_arb->apid_count > pmic_arb->max_periphs) {
+ dev_err(&pmic_arb->spmic->dev, "Unsupported APID count %d detected\n",
+ pmic_arb->base_apid + pmic_arb->apid_count);
+ return -EINVAL;
+ }
+
+ ret = pmic_arb_init_apid_min_max(pmic_arb);
+ if (ret)
+ return ret;
+
+ ret = pmic_arb_read_apid_map_v5(pmic_arb);
+ if (ret) {
+ dev_err(&pmic_arb->spmic->dev, "could not read APID->PPID mapping table, rc= %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* v5 offset per ee and per apid for observer channels and per apid for
* read/write channels.
@@ -1363,6 +1419,7 @@ pmic_arb_apid_owner_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
static const struct pmic_arb_ver_ops pmic_arb_v1 = {
.ver_str = "v1",
+ .init_apid = pmic_arb_init_apid_v1,
.ppid_to_apid = pmic_arb_ppid_to_apid_v1,
.non_data_cmd = pmic_arb_non_data_cmd_v1,
.offset = pmic_arb_offset_v1,
@@ -1377,6 +1434,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = {
static const struct pmic_arb_ver_ops pmic_arb_v2 = {
.ver_str = "v2",
+ .init_apid = pmic_arb_init_apid_v1,
.ppid_to_apid = pmic_arb_ppid_to_apid_v2,
.non_data_cmd = pmic_arb_non_data_cmd_v2,
.offset = pmic_arb_offset_v2,
@@ -1391,6 +1449,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v2 = {
static const struct pmic_arb_ver_ops pmic_arb_v3 = {
.ver_str = "v3",
+ .init_apid = pmic_arb_init_apid_v1,
.ppid_to_apid = pmic_arb_ppid_to_apid_v2,
.non_data_cmd = pmic_arb_non_data_cmd_v2,
.offset = pmic_arb_offset_v2,
@@ -1405,6 +1464,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v3 = {
static const struct pmic_arb_ver_ops pmic_arb_v5 = {
.ver_str = "v5",
+ .init_apid = pmic_arb_init_apid_v5,
.ppid_to_apid = pmic_arb_ppid_to_apid_v5,
.non_data_cmd = pmic_arb_non_data_cmd_v2,
.offset = pmic_arb_offset_v5,
@@ -1419,6 +1479,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = {
static const struct pmic_arb_ver_ops pmic_arb_v7 = {
.ver_str = "v7",
+ .init_apid = pmic_arb_init_apid_v5,
.ppid_to_apid = pmic_arb_ppid_to_apid_v5,
.non_data_cmd = pmic_arb_non_data_cmd_v2,
.offset = pmic_arb_offset_v7,
@@ -1444,7 +1505,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
struct spmi_controller *ctrl;
struct resource *res;
void __iomem *core;
- u32 *mapping_table;
u32 channel, ee, hw_ver;
int err;
@@ -1472,12 +1532,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pmic_arb->core_size = resource_size(res);
- pmic_arb->ppid_to_apid = devm_kcalloc(&ctrl->dev, PMIC_ARB_MAX_PPID,
- sizeof(*pmic_arb->ppid_to_apid),
- GFP_KERNEL);
- if (!pmic_arb->ppid_to_apid)
- return -ENOMEM;
-
hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
if (hw_ver < PMIC_ARB_VERSION_V2_MIN) {
@@ -1511,58 +1565,17 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
return PTR_ERR(pmic_arb->wr_base);
}
- pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS;
+ dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
+ pmic_arb->ver_ops->ver_str, hw_ver);
- if (hw_ver >= PMIC_ARB_VERSION_V7_MIN) {
+ if (hw_ver < PMIC_ARB_VERSION_V7_MIN)
+ pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS;
+ else
pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS_V7;
- /* Optional property for v7: */
- of_property_read_u32(pdev->dev.of_node, "qcom,bus-id",
- &pmic_arb->bus_instance);
- if (pmic_arb->bus_instance > 1) {
- dev_err(&pdev->dev, "invalid bus instance (%u) specified\n",
- pmic_arb->bus_instance);
- return -EINVAL;
- }
- if (pmic_arb->bus_instance == 0) {
- pmic_arb->base_apid = 0;
- pmic_arb->apid_count =
- readl_relaxed(core + PMIC_ARB_FEATURES) &
- PMIC_ARB_FEATURES_PERIPH_MASK;
- } else {
- pmic_arb->base_apid =
- readl_relaxed(core + PMIC_ARB_FEATURES) &
- PMIC_ARB_FEATURES_PERIPH_MASK;
- pmic_arb->apid_count =
- readl_relaxed(core + PMIC_ARB_FEATURES1) &
- PMIC_ARB_FEATURES_PERIPH_MASK;
- }
-
- if (pmic_arb->base_apid + pmic_arb->apid_count > pmic_arb->max_periphs) {
- dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
- pmic_arb->base_apid + pmic_arb->apid_count);
- return -EINVAL;
- }
- } else if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) {
- pmic_arb->base_apid = 0;
- pmic_arb->apid_count = readl_relaxed(core + PMIC_ARB_FEATURES) &
- PMIC_ARB_FEATURES_PERIPH_MASK;
-
- if (pmic_arb->apid_count > pmic_arb->max_periphs) {
- dev_err(&pdev->dev, "Unsupported APID count %d detected\n",
- pmic_arb->apid_count);
- return -EINVAL;
- }
- }
-
- pmic_arb->apid_data = devm_kcalloc(&ctrl->dev, pmic_arb->max_periphs,
- sizeof(*pmic_arb->apid_data),
- GFP_KERNEL);
- if (!pmic_arb->apid_data)
- return -ENOMEM;
-
- dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
- pmic_arb->ver_ops->ver_str, hw_ver);
+ err = pmic_arb->ver_ops->init_apid(pmic_arb);
+ if (err)
+ return err;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
pmic_arb->intr = devm_ioremap_resource(&ctrl->dev, res);
@@ -1604,16 +1617,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
}
pmic_arb->ee = ee;
- mapping_table = devm_kcalloc(&ctrl->dev, pmic_arb->max_periphs,
- sizeof(*mapping_table), GFP_KERNEL);
- if (!mapping_table)
- return -ENOMEM;
-
- pmic_arb->mapping_table = mapping_table;
- /* Initialize max_apid/min_apid to the opposite bounds, during
- * the irq domain translation, we are sure to update these */
- pmic_arb->max_apid = 0;
- pmic_arb->min_apid = pmic_arb->max_periphs - 1;
platform_set_drvdata(pdev, ctrl);
raw_spin_lock_init(&pmic_arb->lock);
@@ -1622,15 +1625,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
ctrl->read_cmd = pmic_arb_read_cmd;
ctrl->write_cmd = pmic_arb_write_cmd;
- if (hw_ver >= PMIC_ARB_VERSION_V5_MIN) {
- err = pmic_arb_read_apid_map_v5(pmic_arb);
- if (err) {
- dev_err(&pdev->dev, "could not read APID->PPID mapping table, rc= %d\n",
- err);
- return err;
- }
- }
-
dev_dbg(&pdev->dev, "adding irq domain\n");
pmic_arb->domain = irq_domain_add_tree(pdev->dev.of_node,
&pmic_arb_irq_domain_ops, pmic_arb);
--
2.34.1
^ permalink raw reply related
* [PATCH v9 5/7] spmi: pmic-arb: Make core resources acquiring a version operation
From: Abel Vesa @ 2024-04-07 16:23 UTC (permalink / raw)
To: Stephen Boyd, Matthias Brugger, Bjorn Andersson, Konrad Dybcio,
Dmitry Baryshkov, Neil Armstrong, AngeloGioacchino Del Regno,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Srini Kandagatla, Johan Hovold, David Collins, linux-kernel,
linux-arm-kernel, linux-arm-msm, linux-mediatek, devicetree,
Abel Vesa
In-Reply-To: <20240407-spmi-multi-master-support-v9-0-fa151c1391f3@linaro.org>
Rather than setting up the core, obsrv and chnls in probe by using
version specific conditionals, add a dedicated "get_core_resources"
version specific op and move the acquiring in there. Since there are
no current users of the second bus yet, drop the comment about why
devm_platform_ioremap_resource can't be used in case of "core",
as it is not applicable anymore.
Don't switch to devm_platform_ioremap_resource though as we need
to keep track of core size.
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
---
drivers/spmi/spmi-pmic-arb.c | 114 +++++++++++++++++++++++++++----------------
1 file changed, 71 insertions(+), 43 deletions(-)
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index dc969f8bed18..ff777b4a6f33 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -186,6 +186,7 @@ struct spmi_pmic_arb {
* struct pmic_arb_ver_ops - version dependent functionality.
*
* @ver_str: version string.
+ * @get_core_resources: initializes the core, observer and channels
* @init_apid: finds the apid base and count
* @ppid_to_apid: finds the apid for a given ppid.
* @non_data_cmd: on v1 issues an spmi non-data command.
@@ -206,6 +207,7 @@ struct spmi_pmic_arb {
*/
struct pmic_arb_ver_ops {
const char *ver_str;
+ int (*get_core_resources)(struct platform_device *pdev, void __iomem *core);
int (*init_apid)(struct spmi_pmic_arb *pmic_arb);
int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid);
/* spmi commands (read_cmd, write_cmd, cmd) functionality */
@@ -961,6 +963,19 @@ static int pmic_arb_init_apid_min_max(struct spmi_pmic_arb *pmic_arb)
return 0;
}
+static int pmic_arb_get_core_resources_v1(struct platform_device *pdev,
+ void __iomem *core)
+{
+ struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev);
+
+ pmic_arb->wr_base = core;
+ pmic_arb->rd_base = core;
+
+ pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS;
+
+ return 0;
+}
+
static int pmic_arb_init_apid_v1(struct spmi_pmic_arb *pmic_arb)
{
u32 *mapping_table;
@@ -1062,6 +1077,33 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid)
return apid;
}
+static int pmic_arb_get_obsrvr_chnls_v2(struct platform_device *pdev)
+{
+ struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev);
+
+ pmic_arb->rd_base = devm_platform_ioremap_resource_byname(pdev, "obsrvr");
+ if (IS_ERR(pmic_arb->rd_base))
+ return PTR_ERR(pmic_arb->rd_base);
+
+ pmic_arb->wr_base = devm_platform_ioremap_resource_byname(pdev, "chnls");
+ if (IS_ERR(pmic_arb->wr_base))
+ return PTR_ERR(pmic_arb->wr_base);
+
+ return 0;
+}
+
+static int pmic_arb_get_core_resources_v2(struct platform_device *pdev,
+ void __iomem *core)
+{
+ struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev);
+
+ pmic_arb->core = core;
+
+ pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS;
+
+ return pmic_arb_get_obsrvr_chnls_v2(pdev);
+}
+
static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pmic_arb, u16 ppid)
{
u16 apid_valid;
@@ -1239,6 +1281,18 @@ static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
return offset;
}
+static int pmic_arb_get_core_resources_v7(struct platform_device *pdev,
+ void __iomem *core)
+{
+ struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev);
+
+ pmic_arb->core = core;
+
+ pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS_V7;
+
+ return pmic_arb_get_obsrvr_chnls_v2(pdev);
+}
+
/*
* v7 offset per ee and per apid for observer channels and per apid for
* read/write channels.
@@ -1419,6 +1473,7 @@ pmic_arb_apid_owner_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
static const struct pmic_arb_ver_ops pmic_arb_v1 = {
.ver_str = "v1",
+ .get_core_resources = pmic_arb_get_core_resources_v1,
.init_apid = pmic_arb_init_apid_v1,
.ppid_to_apid = pmic_arb_ppid_to_apid_v1,
.non_data_cmd = pmic_arb_non_data_cmd_v1,
@@ -1434,6 +1489,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v1 = {
static const struct pmic_arb_ver_ops pmic_arb_v2 = {
.ver_str = "v2",
+ .get_core_resources = pmic_arb_get_core_resources_v2,
.init_apid = pmic_arb_init_apid_v1,
.ppid_to_apid = pmic_arb_ppid_to_apid_v2,
.non_data_cmd = pmic_arb_non_data_cmd_v2,
@@ -1449,6 +1505,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v2 = {
static const struct pmic_arb_ver_ops pmic_arb_v3 = {
.ver_str = "v3",
+ .get_core_resources = pmic_arb_get_core_resources_v2,
.init_apid = pmic_arb_init_apid_v1,
.ppid_to_apid = pmic_arb_ppid_to_apid_v2,
.non_data_cmd = pmic_arb_non_data_cmd_v2,
@@ -1464,6 +1521,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v3 = {
static const struct pmic_arb_ver_ops pmic_arb_v5 = {
.ver_str = "v5",
+ .get_core_resources = pmic_arb_get_core_resources_v2,
.init_apid = pmic_arb_init_apid_v5,
.ppid_to_apid = pmic_arb_ppid_to_apid_v5,
.non_data_cmd = pmic_arb_non_data_cmd_v2,
@@ -1479,6 +1537,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = {
static const struct pmic_arb_ver_ops pmic_arb_v7 = {
.ver_str = "v7",
+ .get_core_resources = pmic_arb_get_core_resources_v7,
.init_apid = pmic_arb_init_apid_v5,
.ppid_to_apid = pmic_arb_ppid_to_apid_v5,
.non_data_cmd = pmic_arb_non_data_cmd_v2,
@@ -1515,16 +1574,6 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pmic_arb = spmi_controller_get_drvdata(ctrl);
pmic_arb->spmic = ctrl;
- /*
- * Please don't replace this with devm_platform_ioremap_resource() or
- * devm_ioremap_resource(). These both result in a call to
- * devm_request_mem_region() which prevents multiple mappings of this
- * register address range. SoCs with PMIC arbiter v7 may define two
- * arbiter devices, for the two physical SPMI interfaces, which share
- * some register address ranges (i.e. "core", "obsrvr", and "chnls").
- * Ensure that both devices probe successfully by calling devm_ioremap()
- * which does not result in a devm_request_mem_region() call.
- */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
core = devm_ioremap(&ctrl->dev, res->start, resource_size(res));
if (IS_ERR(core))
@@ -1534,44 +1583,23 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
- if (hw_ver < PMIC_ARB_VERSION_V2_MIN) {
+ if (hw_ver < PMIC_ARB_VERSION_V2_MIN)
pmic_arb->ver_ops = &pmic_arb_v1;
- pmic_arb->wr_base = core;
- pmic_arb->rd_base = core;
- } else {
- pmic_arb->core = core;
-
- if (hw_ver < PMIC_ARB_VERSION_V3_MIN)
- pmic_arb->ver_ops = &pmic_arb_v2;
- else if (hw_ver < PMIC_ARB_VERSION_V5_MIN)
- pmic_arb->ver_ops = &pmic_arb_v3;
- else if (hw_ver < PMIC_ARB_VERSION_V7_MIN)
- pmic_arb->ver_ops = &pmic_arb_v5;
- else
- pmic_arb->ver_ops = &pmic_arb_v7;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "obsrvr");
- pmic_arb->rd_base = devm_ioremap(&ctrl->dev, res->start,
- resource_size(res));
- if (IS_ERR(pmic_arb->rd_base))
- return PTR_ERR(pmic_arb->rd_base);
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "chnls");
- pmic_arb->wr_base = devm_ioremap(&ctrl->dev, res->start,
- resource_size(res));
- if (IS_ERR(pmic_arb->wr_base))
- return PTR_ERR(pmic_arb->wr_base);
- }
+ else if (hw_ver < PMIC_ARB_VERSION_V3_MIN)
+ pmic_arb->ver_ops = &pmic_arb_v2;
+ else if (hw_ver < PMIC_ARB_VERSION_V5_MIN)
+ pmic_arb->ver_ops = &pmic_arb_v3;
+ else if (hw_ver < PMIC_ARB_VERSION_V7_MIN)
+ pmic_arb->ver_ops = &pmic_arb_v5;
+ else
+ pmic_arb->ver_ops = &pmic_arb_v7;
dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
pmic_arb->ver_ops->ver_str, hw_ver);
- if (hw_ver < PMIC_ARB_VERSION_V7_MIN)
- pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS;
- else
- pmic_arb->max_periphs = PMIC_ARB_MAX_PERIPHS_V7;
+ err = pmic_arb->ver_ops->get_core_resources(pdev, core);
+ if (err)
+ return err;
err = pmic_arb->ver_ops->init_apid(pmic_arb);
if (err)
--
2.34.1
^ permalink raw reply related
* [PATCH v9 6/7] spmi: pmic-arb: Register controller for bus instead of arbiter
From: Abel Vesa @ 2024-04-07 16:23 UTC (permalink / raw)
To: Stephen Boyd, Matthias Brugger, Bjorn Andersson, Konrad Dybcio,
Dmitry Baryshkov, Neil Armstrong, AngeloGioacchino Del Regno,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Srini Kandagatla, Johan Hovold, David Collins, linux-kernel,
linux-arm-kernel, linux-arm-msm, linux-mediatek, devicetree,
Abel Vesa
In-Reply-To: <20240407-spmi-multi-master-support-v9-0-fa151c1391f3@linaro.org>
Introduce the bus object in order to decouple the resources
that are bus specific from the arbiter. This way the SPMI controller
is registered with the generic framework at a bus level rather than
arbiter. This is needed in order to prepare for multi bus support.
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
---
drivers/spmi/spmi-pmic-arb.c | 659 ++++++++++++++++++++++++-------------------
1 file changed, 374 insertions(+), 285 deletions(-)
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index ff777b4a6f33..65d8f45da24b 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spmi.h>
@@ -125,61 +126,72 @@ struct apid_data {
u8 irq_ee;
};
+struct spmi_pmic_arb;
+
/**
- * struct spmi_pmic_arb - SPMI PMIC Arbiter object
+ * struct spmi_pmic_arb_bus - SPMI PMIC Arbiter Bus object
*
- * @rd_base: on v1 "core", on v2 "observer" register base off DT.
- * @wr_base: on v1 "core", on v2 "chnls" register base off DT.
+ * @pmic_arb: the SPMI PMIC Arbiter the bus belongs to.
+ * @domain: irq domain object for PMIC IRQ domain
* @intr: address of the SPMI interrupt control registers.
* @cnfg: address of the PMIC Arbiter configuration registers.
- * @core: core register base for v2 and above only (see above)
- * @core_size: core register base size
+ * @spmic: spmi controller registered for this bus
* @lock: lock to synchronize accesses.
- * @channel: execution environment channel to use for accesses.
- * @irq: PMIC ARB interrupt.
- * @ee: the current Execution Environment
- * @bus_instance: on v7: 0 = primary SPMI bus, 1 = secondary SPMI bus
- * @min_apid: minimum APID (used for bounding IRQ search)
- * @max_apid: maximum APID
* @base_apid: on v7: minimum APID associated with the particular SPMI
* bus instance
* @apid_count: on v5 and v7: number of APIDs associated with the
* particular SPMI bus instance
* @mapping_table: in-memory copy of PPID -> APID mapping table.
* @mapping_table_valid:bitmap containing valid-only periphs
- * @domain: irq domain object for PMIC IRQ domain
- * @spmic: SPMI controller object
- * @ver_ops: version dependent operations.
* @ppid_to_apid: in-memory copy of PPID -> APID mapping table.
* @last_apid: Highest value APID in use
* @apid_data: Table of data for all APIDs
- * @max_periphs: Number of elements in apid_data[]
+ * @min_apid: minimum APID (used for bounding IRQ search)
+ * @max_apid: maximum APID
+ * @irq: PMIC ARB interrupt.
*/
-struct spmi_pmic_arb {
- void __iomem *rd_base;
- void __iomem *wr_base;
+struct spmi_pmic_arb_bus {
+ struct spmi_pmic_arb *pmic_arb;
+ struct irq_domain *domain;
void __iomem *intr;
void __iomem *cnfg;
- void __iomem *core;
- resource_size_t core_size;
+ struct spmi_controller *spmic;
raw_spinlock_t lock;
- u8 channel;
- int irq;
- u8 ee;
- u32 bus_instance;
- u16 min_apid;
- u16 max_apid;
u16 base_apid;
int apid_count;
u32 *mapping_table;
DECLARE_BITMAP(mapping_table_valid, PMIC_ARB_MAX_PERIPHS);
- struct irq_domain *domain;
- struct spmi_controller *spmic;
- const struct pmic_arb_ver_ops *ver_ops;
u16 *ppid_to_apid;
u16 last_apid;
struct apid_data *apid_data;
+ u16 min_apid;
+ u16 max_apid;
+ int irq;
+};
+
+/**
+ * struct spmi_pmic_arb - SPMI PMIC Arbiter object
+ *
+ * @rd_base: on v1 "core", on v2 "observer" register base off DT.
+ * @wr_base: on v1 "core", on v2 "chnls" register base off DT.
+ * @core: core register base for v2 and above only (see above)
+ * @core_size: core register base size
+ * @channel: execution environment channel to use for accesses.
+ * @ee: the current Execution Environment
+ * @ver_ops: version dependent operations.
+ * @max_periphs: Number of elements in apid_data[]
+ * @bus: per arbiter bus instance
+ */
+struct spmi_pmic_arb {
+ void __iomem *rd_base;
+ void __iomem *wr_base;
+ void __iomem *core;
+ resource_size_t core_size;
+ u8 channel;
+ u8 ee;
+ const struct pmic_arb_ver_ops *ver_ops;
int max_periphs;
+ struct spmi_pmic_arb_bus *bus;
};
/**
@@ -208,21 +220,21 @@ struct spmi_pmic_arb {
struct pmic_arb_ver_ops {
const char *ver_str;
int (*get_core_resources)(struct platform_device *pdev, void __iomem *core);
- int (*init_apid)(struct spmi_pmic_arb *pmic_arb);
- int (*ppid_to_apid)(struct spmi_pmic_arb *pmic_arb, u16 ppid);
+ int (*init_apid)(struct spmi_pmic_arb_bus *bus);
+ int (*ppid_to_apid)(struct spmi_pmic_arb_bus *bus, u16 ppid);
/* spmi commands (read_cmd, write_cmd, cmd) functionality */
- int (*offset)(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
- enum pmic_arb_channel ch_type);
+ int (*offset)(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
+ enum pmic_arb_channel ch_type);
u32 (*fmt_cmd)(u8 opc, u8 sid, u16 addr, u8 bc);
int (*non_data_cmd)(struct spmi_controller *ctrl, u8 opc, u8 sid);
/* Interrupts controller functionality (offset of PIC registers) */
- void __iomem *(*owner_acc_status)(struct spmi_pmic_arb *pmic_arb, u8 m,
+ void __iomem *(*owner_acc_status)(struct spmi_pmic_arb_bus *bus, u8 m,
u16 n);
- void __iomem *(*acc_enable)(struct spmi_pmic_arb *pmic_arb, u16 n);
- void __iomem *(*irq_status)(struct spmi_pmic_arb *pmic_arb, u16 n);
- void __iomem *(*irq_clear)(struct spmi_pmic_arb *pmic_arb, u16 n);
+ void __iomem *(*acc_enable)(struct spmi_pmic_arb_bus *bus, u16 n);
+ void __iomem *(*irq_status)(struct spmi_pmic_arb_bus *bus, u16 n);
+ void __iomem *(*irq_clear)(struct spmi_pmic_arb_bus *bus, u16 n);
u32 (*apid_map_offset)(u16 n);
- void __iomem *(*apid_owner)(struct spmi_pmic_arb *pmic_arb, u16 n);
+ void __iomem *(*apid_owner)(struct spmi_pmic_arb_bus *bus, u16 n);
};
static inline void pmic_arb_base_write(struct spmi_pmic_arb *pmic_arb,
@@ -272,13 +284,14 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
void __iomem *base, u8 sid, u16 addr,
enum pmic_arb_channel ch_type)
{
- struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u32 status = 0;
u32 timeout = PMIC_ARB_TIMEOUT_US;
u32 offset;
int rc;
- rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr, ch_type);
+ rc = pmic_arb->ver_ops->offset(bus, sid, addr, ch_type);
if (rc < 0)
return rc;
@@ -321,24 +334,25 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
static int
pmic_arb_non_data_cmd_v1(struct spmi_controller *ctrl, u8 opc, u8 sid)
{
- struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
unsigned long flags;
u32 cmd;
int rc;
u32 offset;
- rc = pmic_arb->ver_ops->offset(pmic_arb, sid, 0, PMIC_ARB_CHANNEL_RW);
+ rc = pmic_arb->ver_ops->offset(bus, sid, 0, PMIC_ARB_CHANNEL_RW);
if (rc < 0)
return rc;
offset = rc;
cmd = ((opc | 0x40) << 27) | ((sid & 0xf) << 20);
- raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+ raw_spin_lock_irqsave(&bus->lock, flags);
pmic_arb_base_write(pmic_arb, offset + PMIC_ARB_CMD, cmd);
rc = pmic_arb_wait_for_done(ctrl, pmic_arb->wr_base, sid, 0,
PMIC_ARB_CHANNEL_RW);
- raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+ raw_spin_unlock_irqrestore(&bus->lock, flags);
return rc;
}
@@ -363,20 +377,21 @@ static int pmic_arb_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid)
return pmic_arb->ver_ops->non_data_cmd(ctrl, opc, sid);
}
-static int pmic_arb_fmt_read_cmd(struct spmi_pmic_arb *pmic_arb, u8 opc, u8 sid,
+static int pmic_arb_fmt_read_cmd(struct spmi_pmic_arb_bus *bus, u8 opc, u8 sid,
u16 addr, size_t len, u32 *cmd, u32 *offset)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u8 bc = len - 1;
int rc;
- rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr,
+ rc = pmic_arb->ver_ops->offset(bus, sid, addr,
PMIC_ARB_CHANNEL_OBS);
if (rc < 0)
return rc;
*offset = rc;
if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
- dev_err(&pmic_arb->spmic->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
+ dev_err(&bus->spmic->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
PMIC_ARB_MAX_TRANS_BYTES, len);
return -EINVAL;
}
@@ -400,7 +415,8 @@ static int pmic_arb_read_cmd_unlocked(struct spmi_controller *ctrl, u32 cmd,
u32 offset, u8 sid, u16 addr, u8 *buf,
size_t len)
{
- struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u8 bc = len - 1;
int rc;
@@ -422,38 +438,39 @@ static int pmic_arb_read_cmd_unlocked(struct spmi_controller *ctrl, u32 cmd,
static int pmic_arb_read_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
u16 addr, u8 *buf, size_t len)
{
- struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
unsigned long flags;
u32 cmd, offset;
int rc;
- rc = pmic_arb_fmt_read_cmd(pmic_arb, opc, sid, addr, len, &cmd,
+ rc = pmic_arb_fmt_read_cmd(bus, opc, sid, addr, len, &cmd,
&offset);
if (rc)
return rc;
- raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+ raw_spin_lock_irqsave(&bus->lock, flags);
rc = pmic_arb_read_cmd_unlocked(ctrl, cmd, offset, sid, addr, buf, len);
- raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+ raw_spin_unlock_irqrestore(&bus->lock, flags);
return rc;
}
-static int pmic_arb_fmt_write_cmd(struct spmi_pmic_arb *pmic_arb, u8 opc,
+static int pmic_arb_fmt_write_cmd(struct spmi_pmic_arb_bus *bus, u8 opc,
u8 sid, u16 addr, size_t len, u32 *cmd,
u32 *offset)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u8 bc = len - 1;
int rc;
- rc = pmic_arb->ver_ops->offset(pmic_arb, sid, addr,
+ rc = pmic_arb->ver_ops->offset(bus, sid, addr,
PMIC_ARB_CHANNEL_RW);
if (rc < 0)
return rc;
*offset = rc;
if (bc >= PMIC_ARB_MAX_TRANS_BYTES) {
- dev_err(&pmic_arb->spmic->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
+ dev_err(&bus->spmic->dev, "pmic-arb supports 1..%d bytes per trans, but:%zu requested",
PMIC_ARB_MAX_TRANS_BYTES, len);
return -EINVAL;
}
@@ -479,7 +496,8 @@ static int pmic_arb_write_cmd_unlocked(struct spmi_controller *ctrl, u32 cmd,
u32 offset, u8 sid, u16 addr,
const u8 *buf, size_t len)
{
- struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u8 bc = len - 1;
/* Write data to FIFOs */
@@ -498,20 +516,20 @@ static int pmic_arb_write_cmd_unlocked(struct spmi_controller *ctrl, u32 cmd,
static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
u16 addr, const u8 *buf, size_t len)
{
- struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
unsigned long flags;
u32 cmd, offset;
int rc;
- rc = pmic_arb_fmt_write_cmd(pmic_arb, opc, sid, addr, len, &cmd,
+ rc = pmic_arb_fmt_write_cmd(bus, opc, sid, addr, len, &cmd,
&offset);
if (rc)
return rc;
- raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+ raw_spin_lock_irqsave(&bus->lock, flags);
rc = pmic_arb_write_cmd_unlocked(ctrl, cmd, offset, sid, addr, buf,
len);
- raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+ raw_spin_unlock_irqrestore(&bus->lock, flags);
return rc;
}
@@ -519,23 +537,23 @@ static int pmic_arb_write_cmd(struct spmi_controller *ctrl, u8 opc, u8 sid,
static int pmic_arb_masked_write(struct spmi_controller *ctrl, u8 sid, u16 addr,
const u8 *buf, const u8 *mask, size_t len)
{
- struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
+ struct spmi_pmic_arb_bus *bus = spmi_controller_get_drvdata(ctrl);
u32 read_cmd, read_offset, write_cmd, write_offset;
u8 temp[PMIC_ARB_MAX_TRANS_BYTES];
unsigned long flags;
int rc, i;
- rc = pmic_arb_fmt_read_cmd(pmic_arb, SPMI_CMD_EXT_READL, sid, addr, len,
+ rc = pmic_arb_fmt_read_cmd(bus, SPMI_CMD_EXT_READL, sid, addr, len,
&read_cmd, &read_offset);
if (rc)
return rc;
- rc = pmic_arb_fmt_write_cmd(pmic_arb, SPMI_CMD_EXT_WRITEL, sid, addr,
+ rc = pmic_arb_fmt_write_cmd(bus, SPMI_CMD_EXT_WRITEL, sid, addr,
len, &write_cmd, &write_offset);
if (rc)
return rc;
- raw_spin_lock_irqsave(&pmic_arb->lock, flags);
+ raw_spin_lock_irqsave(&bus->lock, flags);
rc = pmic_arb_read_cmd_unlocked(ctrl, read_cmd, read_offset, sid, addr,
temp, len);
if (rc)
@@ -547,7 +565,7 @@ static int pmic_arb_masked_write(struct spmi_controller *ctrl, u8 sid, u16 addr,
rc = pmic_arb_write_cmd_unlocked(ctrl, write_cmd, write_offset, sid,
addr, temp, len);
done:
- raw_spin_unlock_irqrestore(&pmic_arb->lock, flags);
+ raw_spin_unlock_irqrestore(&bus->lock, flags);
return rc;
}
@@ -573,25 +591,25 @@ struct spmi_pmic_arb_qpnpint_type {
static void qpnpint_spmi_write(struct irq_data *d, u8 reg, void *buf,
size_t len)
{
- struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
u8 sid = hwirq_to_sid(d->hwirq);
u8 per = hwirq_to_per(d->hwirq);
- if (pmic_arb_write_cmd(pmic_arb->spmic, SPMI_CMD_EXT_WRITEL, sid,
+ if (pmic_arb_write_cmd(bus->spmic, SPMI_CMD_EXT_WRITEL, sid,
(per << 8) + reg, buf, len))
- dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x\n",
+ dev_err_ratelimited(&bus->spmic->dev, "failed irqchip transaction on %x\n",
d->irq);
}
static void qpnpint_spmi_read(struct irq_data *d, u8 reg, void *buf, size_t len)
{
- struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
u8 sid = hwirq_to_sid(d->hwirq);
u8 per = hwirq_to_per(d->hwirq);
- if (pmic_arb_read_cmd(pmic_arb->spmic, SPMI_CMD_EXT_READL, sid,
+ if (pmic_arb_read_cmd(bus->spmic, SPMI_CMD_EXT_READL, sid,
(per << 8) + reg, buf, len))
- dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x\n",
+ dev_err_ratelimited(&bus->spmic->dev, "failed irqchip transaction on %x\n",
d->irq);
}
@@ -599,47 +617,49 @@ static int qpnpint_spmi_masked_write(struct irq_data *d, u8 reg,
const void *buf, const void *mask,
size_t len)
{
- struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
u8 sid = hwirq_to_sid(d->hwirq);
u8 per = hwirq_to_per(d->hwirq);
int rc;
- rc = pmic_arb_masked_write(pmic_arb->spmic, sid, (per << 8) + reg, buf,
+ rc = pmic_arb_masked_write(bus->spmic, sid, (per << 8) + reg, buf,
mask, len);
if (rc)
- dev_err_ratelimited(&pmic_arb->spmic->dev, "failed irqchip transaction on %x rc=%d\n",
+ dev_err_ratelimited(&bus->spmic->dev, "failed irqchip transaction on %x rc=%d\n",
d->irq, rc);
return rc;
}
-static void cleanup_irq(struct spmi_pmic_arb *pmic_arb, u16 apid, int id)
+static void cleanup_irq(struct spmi_pmic_arb_bus *bus, u16 apid, int id)
{
- u16 ppid = pmic_arb->apid_data[apid].ppid;
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
+ u16 ppid = bus->apid_data[apid].ppid;
u8 sid = ppid >> 8;
u8 per = ppid & 0xFF;
u8 irq_mask = BIT(id);
- dev_err_ratelimited(&pmic_arb->spmic->dev, "%s apid=%d sid=0x%x per=0x%x irq=%d\n",
- __func__, apid, sid, per, id);
- writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(pmic_arb, apid));
+ dev_err_ratelimited(&bus->spmic->dev, "%s apid=%d sid=0x%x per=0x%x irq=%d\n",
+ __func__, apid, sid, per, id);
+ writel_relaxed(irq_mask, pmic_arb->ver_ops->irq_clear(bus, apid));
}
-static int periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid)
+static int periph_interrupt(struct spmi_pmic_arb_bus *bus, u16 apid)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
unsigned int irq;
u32 status, id;
int handled = 0;
- u8 sid = (pmic_arb->apid_data[apid].ppid >> 8) & 0xF;
- u8 per = pmic_arb->apid_data[apid].ppid & 0xFF;
+ u8 sid = (bus->apid_data[apid].ppid >> 8) & 0xF;
+ u8 per = bus->apid_data[apid].ppid & 0xFF;
- status = readl_relaxed(pmic_arb->ver_ops->irq_status(pmic_arb, apid));
+ status = readl_relaxed(pmic_arb->ver_ops->irq_status(bus, apid));
while (status) {
id = ffs(status) - 1;
status &= ~BIT(id);
- irq = irq_find_mapping(pmic_arb->domain,
- spec_to_hwirq(sid, per, id, apid));
+ irq = irq_find_mapping(bus->domain,
+ spec_to_hwirq(sid, per, id, apid));
if (irq == 0) {
- cleanup_irq(pmic_arb, apid, id);
+ cleanup_irq(bus, apid, id);
continue;
}
generic_handle_irq(irq);
@@ -651,16 +671,17 @@ static int periph_interrupt(struct spmi_pmic_arb *pmic_arb, u16 apid)
static void pmic_arb_chained_irq(struct irq_desc *desc)
{
- struct spmi_pmic_arb *pmic_arb = irq_desc_get_handler_data(desc);
+ struct spmi_pmic_arb_bus *bus = irq_desc_get_handler_data(desc);
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops;
struct irq_chip *chip = irq_desc_get_chip(desc);
- int first = pmic_arb->min_apid;
- int last = pmic_arb->max_apid;
+ int first = bus->min_apid;
+ int last = bus->max_apid;
/*
* acc_offset will be non-zero for the secondary SPMI bus instance on
* v7 controllers.
*/
- int acc_offset = pmic_arb->base_apid >> 5;
+ int acc_offset = bus->base_apid >> 5;
u8 ee = pmic_arb->ee;
u32 status, enable, handled = 0;
int i, id, apid;
@@ -671,7 +692,7 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
chained_irq_enter(chip, desc);
for (i = first >> 5; i <= last >> 5; ++i) {
- status = readl_relaxed(ver_ops->owner_acc_status(pmic_arb, ee, i - acc_offset));
+ status = readl_relaxed(ver_ops->owner_acc_status(bus, ee, i - acc_offset));
if (status)
acc_valid = true;
@@ -685,9 +706,9 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
continue;
}
enable = readl_relaxed(
- ver_ops->acc_enable(pmic_arb, apid));
+ ver_ops->acc_enable(bus, apid));
if (enable & SPMI_PIC_ACC_ENABLE_BIT)
- if (periph_interrupt(pmic_arb, apid) != 0)
+ if (periph_interrupt(bus, apid) != 0)
handled++;
}
}
@@ -696,19 +717,19 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
if (!acc_valid) {
for (i = first; i <= last; i++) {
/* skip if APPS is not irq owner */
- if (pmic_arb->apid_data[i].irq_ee != pmic_arb->ee)
+ if (bus->apid_data[i].irq_ee != pmic_arb->ee)
continue;
irq_status = readl_relaxed(
- ver_ops->irq_status(pmic_arb, i));
+ ver_ops->irq_status(bus, i));
if (irq_status) {
enable = readl_relaxed(
- ver_ops->acc_enable(pmic_arb, i));
+ ver_ops->acc_enable(bus, i));
if (enable & SPMI_PIC_ACC_ENABLE_BIT) {
- dev_dbg(&pmic_arb->spmic->dev,
+ dev_dbg(&bus->spmic->dev,
"Dispatching IRQ for apid=%d status=%x\n",
i, irq_status);
- if (periph_interrupt(pmic_arb, i) != 0)
+ if (periph_interrupt(bus, i) != 0)
handled++;
}
}
@@ -723,12 +744,13 @@ static void pmic_arb_chained_irq(struct irq_desc *desc)
static void qpnpint_irq_ack(struct irq_data *d)
{
- struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u8 irq = hwirq_to_irq(d->hwirq);
u16 apid = hwirq_to_apid(d->hwirq);
u8 data;
- writel_relaxed(BIT(irq), pmic_arb->ver_ops->irq_clear(pmic_arb, apid));
+ writel_relaxed(BIT(irq), pmic_arb->ver_ops->irq_clear(bus, apid));
data = BIT(irq);
qpnpint_spmi_write(d, QPNPINT_REG_LATCHED_CLR, &data, 1);
@@ -744,14 +766,15 @@ static void qpnpint_irq_mask(struct irq_data *d)
static void qpnpint_irq_unmask(struct irq_data *d)
{
- struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
const struct pmic_arb_ver_ops *ver_ops = pmic_arb->ver_ops;
u8 irq = hwirq_to_irq(d->hwirq);
u16 apid = hwirq_to_apid(d->hwirq);
u8 buf[2];
writel_relaxed(SPMI_PIC_ACC_ENABLE_BIT,
- ver_ops->acc_enable(pmic_arb, apid));
+ ver_ops->acc_enable(bus, apid));
qpnpint_spmi_read(d, QPNPINT_REG_EN_SET, &buf[0], 1);
if (!(buf[0] & BIT(irq))) {
@@ -808,9 +831,9 @@ static int qpnpint_irq_set_type(struct irq_data *d, unsigned int flow_type)
static int qpnpint_irq_set_wake(struct irq_data *d, unsigned int on)
{
- struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
- return irq_set_irq_wake(pmic_arb->irq, on);
+ return irq_set_irq_wake(bus->irq, on);
}
static int qpnpint_get_irqchip_state(struct irq_data *d,
@@ -832,17 +855,18 @@ static int qpnpint_get_irqchip_state(struct irq_data *d,
static int qpnpint_irq_domain_activate(struct irq_domain *domain,
struct irq_data *d, bool reserve)
{
- struct spmi_pmic_arb *pmic_arb = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb_bus *bus = irq_data_get_irq_chip_data(d);
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u16 periph = hwirq_to_per(d->hwirq);
u16 apid = hwirq_to_apid(d->hwirq);
u16 sid = hwirq_to_sid(d->hwirq);
u16 irq = hwirq_to_irq(d->hwirq);
u8 buf;
- if (pmic_arb->apid_data[apid].irq_ee != pmic_arb->ee) {
- dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n",
+ if (bus->apid_data[apid].irq_ee != pmic_arb->ee) {
+ dev_err(&bus->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u: ee=%u but owner=%u\n",
sid, periph, irq, pmic_arb->ee,
- pmic_arb->apid_data[apid].irq_ee);
+ bus->apid_data[apid].irq_ee);
return -ENODEV;
}
@@ -869,15 +893,16 @@ static int qpnpint_irq_domain_translate(struct irq_domain *d,
unsigned long *out_hwirq,
unsigned int *out_type)
{
- struct spmi_pmic_arb *pmic_arb = d->host_data;
+ struct spmi_pmic_arb_bus *bus = d->host_data;
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u32 *intspec = fwspec->param;
u16 apid, ppid;
int rc;
- dev_dbg(&pmic_arb->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
+ dev_dbg(&bus->spmic->dev, "intspec[0] 0x%1x intspec[1] 0x%02x intspec[2] 0x%02x\n",
intspec[0], intspec[1], intspec[2]);
- if (irq_domain_get_of_node(d) != pmic_arb->spmic->dev.of_node)
+ if (irq_domain_get_of_node(d) != bus->spmic->dev.of_node)
return -EINVAL;
if (fwspec->param_count != 4)
return -EINVAL;
@@ -885,37 +910,37 @@ static int qpnpint_irq_domain_translate(struct irq_domain *d,
return -EINVAL;
ppid = intspec[0] << 8 | intspec[1];
- rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid);
+ rc = pmic_arb->ver_ops->ppid_to_apid(bus, ppid);
if (rc < 0) {
- dev_err(&pmic_arb->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u rc = %d\n",
- intspec[0], intspec[1], intspec[2], rc);
+ dev_err(&bus->spmic->dev, "failed to xlate sid = %#x, periph = %#x, irq = %u rc = %d\n",
+ intspec[0], intspec[1], intspec[2], rc);
return rc;
}
apid = rc;
/* Keep track of {max,min}_apid for bounding search during interrupt */
- if (apid > pmic_arb->max_apid)
- pmic_arb->max_apid = apid;
- if (apid < pmic_arb->min_apid)
- pmic_arb->min_apid = apid;
+ if (apid > bus->max_apid)
+ bus->max_apid = apid;
+ if (apid < bus->min_apid)
+ bus->min_apid = apid;
*out_hwirq = spec_to_hwirq(intspec[0], intspec[1], intspec[2], apid);
*out_type = intspec[3] & IRQ_TYPE_SENSE_MASK;
- dev_dbg(&pmic_arb->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
+ dev_dbg(&bus->spmic->dev, "out_hwirq = %lu\n", *out_hwirq);
return 0;
}
static struct lock_class_key qpnpint_irq_lock_class, qpnpint_irq_request_class;
-static void qpnpint_irq_domain_map(struct spmi_pmic_arb *pmic_arb,
+static void qpnpint_irq_domain_map(struct spmi_pmic_arb_bus *bus,
struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq, unsigned int type)
{
irq_flow_handler_t handler;
- dev_dbg(&pmic_arb->spmic->dev, "virq = %u, hwirq = %lu, type = %u\n",
+ dev_dbg(&bus->spmic->dev, "virq = %u, hwirq = %lu, type = %u\n",
virq, hwirq, type);
if (type & IRQ_TYPE_EDGE_BOTH)
@@ -926,7 +951,7 @@ static void qpnpint_irq_domain_map(struct spmi_pmic_arb *pmic_arb,
irq_set_lockdep_class(virq, &qpnpint_irq_lock_class,
&qpnpint_irq_request_class);
- irq_domain_set_info(domain, virq, hwirq, &pmic_arb_irqchip, pmic_arb,
+ irq_domain_set_info(domain, virq, hwirq, &pmic_arb_irqchip, bus,
handler, NULL, NULL);
}
@@ -934,7 +959,7 @@ static int qpnpint_irq_domain_alloc(struct irq_domain *domain,
unsigned int virq, unsigned int nr_irqs,
void *data)
{
- struct spmi_pmic_arb *pmic_arb = domain->host_data;
+ struct spmi_pmic_arb_bus *bus = domain->host_data;
struct irq_fwspec *fwspec = data;
irq_hw_number_t hwirq;
unsigned int type;
@@ -945,20 +970,22 @@ static int qpnpint_irq_domain_alloc(struct irq_domain *domain,
return ret;
for (i = 0; i < nr_irqs; i++)
- qpnpint_irq_domain_map(pmic_arb, domain, virq + i, hwirq + i,
+ qpnpint_irq_domain_map(bus, domain, virq + i, hwirq + i,
type);
return 0;
}
-static int pmic_arb_init_apid_min_max(struct spmi_pmic_arb *pmic_arb)
+static int pmic_arb_init_apid_min_max(struct spmi_pmic_arb_bus *bus)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
+
/*
* Initialize max_apid/min_apid to the opposite bounds, during
* the irq domain translation, we are sure to update these
*/
- pmic_arb->max_apid = 0;
- pmic_arb->min_apid = pmic_arb->max_periphs - 1;
+ bus->max_apid = 0;
+ bus->min_apid = pmic_arb->max_periphs - 1;
return 0;
}
@@ -976,37 +1003,38 @@ static int pmic_arb_get_core_resources_v1(struct platform_device *pdev,
return 0;
}
-static int pmic_arb_init_apid_v1(struct spmi_pmic_arb *pmic_arb)
+static int pmic_arb_init_apid_v1(struct spmi_pmic_arb_bus *bus)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u32 *mapping_table;
- mapping_table = devm_kcalloc(&pmic_arb->spmic->dev, pmic_arb->max_periphs,
+ mapping_table = devm_kcalloc(&bus->spmic->dev, pmic_arb->max_periphs,
sizeof(*mapping_table), GFP_KERNEL);
if (!mapping_table)
return -ENOMEM;
- pmic_arb->mapping_table = mapping_table;
+ bus->mapping_table = mapping_table;
- return pmic_arb_init_apid_min_max(pmic_arb);
+ return pmic_arb_init_apid_min_max(bus);
}
-static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
+static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb_bus *bus, u16 ppid)
{
- u32 *mapping_table = pmic_arb->mapping_table;
+ u32 *mapping_table = bus->mapping_table;
int index = 0, i;
u16 apid_valid;
u16 apid;
u32 data;
- apid_valid = pmic_arb->ppid_to_apid[ppid];
+ apid_valid = bus->ppid_to_apid[ppid];
if (apid_valid & PMIC_ARB_APID_VALID) {
apid = apid_valid & ~PMIC_ARB_APID_VALID;
return apid;
}
for (i = 0; i < SPMI_MAPPING_TABLE_TREE_DEPTH; ++i) {
- if (!test_and_set_bit(index, pmic_arb->mapping_table_valid))
- mapping_table[index] = readl_relaxed(pmic_arb->cnfg +
+ if (!test_and_set_bit(index, bus->mapping_table_valid))
+ mapping_table[index] = readl_relaxed(bus->cnfg +
SPMI_MAPPING_TABLE_REG(index));
data = mapping_table[index];
@@ -1016,9 +1044,9 @@ static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
index = SPMI_MAPPING_BIT_IS_1_RESULT(data);
} else {
apid = SPMI_MAPPING_BIT_IS_1_RESULT(data);
- pmic_arb->ppid_to_apid[ppid]
+ bus->ppid_to_apid[ppid]
= apid | PMIC_ARB_APID_VALID;
- pmic_arb->apid_data[apid].ppid = ppid;
+ bus->apid_data[apid].ppid = ppid;
return apid;
}
} else {
@@ -1026,9 +1054,9 @@ static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
index = SPMI_MAPPING_BIT_IS_0_RESULT(data);
} else {
apid = SPMI_MAPPING_BIT_IS_0_RESULT(data);
- pmic_arb->ppid_to_apid[ppid]
+ bus->ppid_to_apid[ppid]
= apid | PMIC_ARB_APID_VALID;
- pmic_arb->apid_data[apid].ppid = ppid;
+ bus->apid_data[apid].ppid = ppid;
return apid;
}
}
@@ -1038,24 +1066,26 @@ static int pmic_arb_ppid_to_apid_v1(struct spmi_pmic_arb *pmic_arb, u16 ppid)
}
/* v1 offset per ee */
-static int pmic_arb_offset_v1(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
- enum pmic_arb_channel ch_type)
+static int pmic_arb_offset_v1(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
+ enum pmic_arb_channel ch_type)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
return 0x800 + 0x80 * pmic_arb->channel;
}
-static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid)
+static u16 pmic_arb_find_apid(struct spmi_pmic_arb_bus *bus, u16 ppid)
{
- struct apid_data *apidd = &pmic_arb->apid_data[pmic_arb->last_apid];
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
+ struct apid_data *apidd = &bus->apid_data[bus->last_apid];
u32 regval, offset;
u16 id, apid;
- for (apid = pmic_arb->last_apid; ; apid++, apidd++) {
+ for (apid = bus->last_apid; ; apid++, apidd++) {
offset = pmic_arb->ver_ops->apid_map_offset(apid);
if (offset >= pmic_arb->core_size)
break;
- regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(pmic_arb,
+ regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(bus,
apid));
apidd->irq_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
apidd->write_ee = apidd->irq_ee;
@@ -1065,14 +1095,14 @@ static u16 pmic_arb_find_apid(struct spmi_pmic_arb *pmic_arb, u16 ppid)
continue;
id = (regval >> 8) & PMIC_ARB_PPID_MASK;
- pmic_arb->ppid_to_apid[id] = apid | PMIC_ARB_APID_VALID;
+ bus->ppid_to_apid[id] = apid | PMIC_ARB_APID_VALID;
apidd->ppid = id;
if (id == ppid) {
apid |= PMIC_ARB_APID_VALID;
break;
}
}
- pmic_arb->last_apid = apid & ~PMIC_ARB_APID_VALID;
+ bus->last_apid = apid & ~PMIC_ARB_APID_VALID;
return apid;
}
@@ -1104,21 +1134,22 @@ static int pmic_arb_get_core_resources_v2(struct platform_device *pdev,
return pmic_arb_get_obsrvr_chnls_v2(pdev);
}
-static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb *pmic_arb, u16 ppid)
+static int pmic_arb_ppid_to_apid_v2(struct spmi_pmic_arb_bus *bus, u16 ppid)
{
u16 apid_valid;
- apid_valid = pmic_arb->ppid_to_apid[ppid];
+ apid_valid = bus->ppid_to_apid[ppid];
if (!(apid_valid & PMIC_ARB_APID_VALID))
- apid_valid = pmic_arb_find_apid(pmic_arb, ppid);
+ apid_valid = pmic_arb_find_apid(bus, ppid);
if (!(apid_valid & PMIC_ARB_APID_VALID))
return -ENODEV;
return apid_valid & ~PMIC_ARB_APID_VALID;
}
-static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
+static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb_bus *bus)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
struct apid_data *apidd;
struct apid_data *prev_apidd;
u16 i, apid, ppid, apid_max;
@@ -1140,9 +1171,9 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
* where N = number of APIDs supported by the primary bus and
* M = number of APIDs supported by the secondary bus
*/
- apidd = &pmic_arb->apid_data[pmic_arb->base_apid];
- apid_max = pmic_arb->base_apid + pmic_arb->apid_count;
- for (i = pmic_arb->base_apid; i < apid_max; i++, apidd++) {
+ apidd = &bus->apid_data[bus->base_apid];
+ apid_max = bus->base_apid + bus->apid_count;
+ for (i = bus->base_apid; i < apid_max; i++, apidd++) {
offset = pmic_arb->ver_ops->apid_map_offset(i);
if (offset >= pmic_arb->core_size)
break;
@@ -1153,19 +1184,18 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
ppid = (regval >> 8) & PMIC_ARB_PPID_MASK;
is_irq_ee = PMIC_ARB_CHAN_IS_IRQ_OWNER(regval);
- regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(pmic_arb,
- i));
+ regval = readl_relaxed(pmic_arb->ver_ops->apid_owner(bus, i));
apidd->write_ee = SPMI_OWNERSHIP_PERIPH2OWNER(regval);
apidd->irq_ee = is_irq_ee ? apidd->write_ee : INVALID_EE;
- valid = pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID;
- apid = pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
- prev_apidd = &pmic_arb->apid_data[apid];
+ valid = bus->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID;
+ apid = bus->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
+ prev_apidd = &bus->apid_data[apid];
if (!valid || apidd->write_ee == pmic_arb->ee) {
/* First PPID mapping or one for this EE */
- pmic_arb->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID;
+ bus->ppid_to_apid[ppid] = i | PMIC_ARB_APID_VALID;
} else if (valid && is_irq_ee &&
prev_apidd->write_ee == pmic_arb->ee) {
/*
@@ -1176,42 +1206,43 @@ static int pmic_arb_read_apid_map_v5(struct spmi_pmic_arb *pmic_arb)
}
apidd->ppid = ppid;
- pmic_arb->last_apid = i;
+ bus->last_apid = i;
}
/* Dump the mapping table for debug purposes. */
- dev_dbg(&pmic_arb->spmic->dev, "PPID APID Write-EE IRQ-EE\n");
+ dev_dbg(&bus->spmic->dev, "PPID APID Write-EE IRQ-EE\n");
for (ppid = 0; ppid < PMIC_ARB_MAX_PPID; ppid++) {
- apid = pmic_arb->ppid_to_apid[ppid];
+ apid = bus->ppid_to_apid[ppid];
if (apid & PMIC_ARB_APID_VALID) {
apid &= ~PMIC_ARB_APID_VALID;
- apidd = &pmic_arb->apid_data[apid];
- dev_dbg(&pmic_arb->spmic->dev, "%#03X %3u %2u %2u\n",
- ppid, apid, apidd->write_ee, apidd->irq_ee);
+ apidd = &bus->apid_data[apid];
+ dev_dbg(&bus->spmic->dev, "%#03X %3u %2u %2u\n",
+ ppid, apid, apidd->write_ee, apidd->irq_ee);
}
}
return 0;
}
-static int pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb *pmic_arb, u16 ppid)
+static int pmic_arb_ppid_to_apid_v5(struct spmi_pmic_arb_bus *bus, u16 ppid)
{
- if (!(pmic_arb->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID))
+ if (!(bus->ppid_to_apid[ppid] & PMIC_ARB_APID_VALID))
return -ENODEV;
- return pmic_arb->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
+ return bus->ppid_to_apid[ppid] & ~PMIC_ARB_APID_VALID;
}
/* v2 offset per ppid and per ee */
-static int pmic_arb_offset_v2(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
- enum pmic_arb_channel ch_type)
+static int pmic_arb_offset_v2(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
+ enum pmic_arb_channel ch_type)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u16 apid;
u16 ppid;
int rc;
ppid = sid << 8 | ((addr >> 8) & 0xFF);
- rc = pmic_arb_ppid_to_apid_v2(pmic_arb, ppid);
+ rc = pmic_arb_ppid_to_apid_v2(bus, ppid);
if (rc < 0)
return rc;
@@ -1219,27 +1250,28 @@ static int pmic_arb_offset_v2(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
return 0x1000 * pmic_arb->ee + 0x8000 * apid;
}
-static int pmic_arb_init_apid_v5(struct spmi_pmic_arb *pmic_arb)
+static int pmic_arb_init_apid_v5(struct spmi_pmic_arb_bus *bus)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
int ret;
- pmic_arb->base_apid = 0;
- pmic_arb->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
- PMIC_ARB_FEATURES_PERIPH_MASK;
+ bus->base_apid = 0;
+ bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK;
- if (pmic_arb->base_apid + pmic_arb->apid_count > pmic_arb->max_periphs) {
- dev_err(&pmic_arb->spmic->dev, "Unsupported APID count %d detected\n",
- pmic_arb->base_apid + pmic_arb->apid_count);
+ if (bus->base_apid + bus->apid_count > pmic_arb->max_periphs) {
+ dev_err(&bus->spmic->dev, "Unsupported APID count %d detected\n",
+ bus->base_apid + bus->apid_count);
return -EINVAL;
}
- ret = pmic_arb_init_apid_min_max(pmic_arb);
+ ret = pmic_arb_init_apid_min_max(bus);
if (ret)
return ret;
- ret = pmic_arb_read_apid_map_v5(pmic_arb);
+ ret = pmic_arb_read_apid_map_v5(bus);
if (ret) {
- dev_err(&pmic_arb->spmic->dev, "could not read APID->PPID mapping table, rc= %d\n",
+ dev_err(&bus->spmic->dev, "could not read APID->PPID mapping table, rc= %d\n",
ret);
return ret;
}
@@ -1251,15 +1283,16 @@ static int pmic_arb_init_apid_v5(struct spmi_pmic_arb *pmic_arb)
* v5 offset per ee and per apid for observer channels and per apid for
* read/write channels.
*/
-static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
- enum pmic_arb_channel ch_type)
+static int pmic_arb_offset_v5(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
+ enum pmic_arb_channel ch_type)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u16 apid;
int rc;
u32 offset = 0;
u16 ppid = (sid << 8) | (addr >> 8);
- rc = pmic_arb_ppid_to_apid_v5(pmic_arb, ppid);
+ rc = pmic_arb_ppid_to_apid_v5(bus, ppid);
if (rc < 0)
return rc;
@@ -1269,8 +1302,8 @@ static int pmic_arb_offset_v5(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
offset = 0x10000 * pmic_arb->ee + 0x80 * apid;
break;
case PMIC_ARB_CHANNEL_RW:
- if (pmic_arb->apid_data[apid].write_ee != pmic_arb->ee) {
- dev_err(&pmic_arb->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
+ if (bus->apid_data[apid].write_ee != pmic_arb->ee) {
+ dev_err(&bus->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
sid, addr);
return -EPERM;
}
@@ -1297,15 +1330,16 @@ static int pmic_arb_get_core_resources_v7(struct platform_device *pdev,
* v7 offset per ee and per apid for observer channels and per apid for
* read/write channels.
*/
-static int pmic_arb_offset_v7(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
- enum pmic_arb_channel ch_type)
+static int pmic_arb_offset_v7(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
+ enum pmic_arb_channel ch_type)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u16 apid;
int rc;
u32 offset = 0;
u16 ppid = (sid << 8) | (addr >> 8);
- rc = pmic_arb->ver_ops->ppid_to_apid(pmic_arb, ppid);
+ rc = pmic_arb->ver_ops->ppid_to_apid(bus, ppid);
if (rc < 0)
return rc;
@@ -1315,8 +1349,8 @@ static int pmic_arb_offset_v7(struct spmi_pmic_arb *pmic_arb, u8 sid, u16 addr,
offset = 0x8000 * pmic_arb->ee + 0x20 * apid;
break;
case PMIC_ARB_CHANNEL_RW:
- if (pmic_arb->apid_data[apid].write_ee != pmic_arb->ee) {
- dev_err(&pmic_arb->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
+ if (bus->apid_data[apid].write_ee != pmic_arb->ee) {
+ dev_err(&bus->spmic->dev, "disallowed SPMI write to sid=%u, addr=0x%04X\n",
sid, addr);
return -EPERM;
}
@@ -1338,104 +1372,110 @@ static u32 pmic_arb_fmt_cmd_v2(u8 opc, u8 sid, u16 addr, u8 bc)
}
static void __iomem *
-pmic_arb_owner_acc_status_v1(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
+pmic_arb_owner_acc_status_v1(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
{
- return pmic_arb->intr + 0x20 * m + 0x4 * n;
+ return bus->intr + 0x20 * m + 0x4 * n;
}
static void __iomem *
-pmic_arb_owner_acc_status_v2(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
+pmic_arb_owner_acc_status_v2(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
{
- return pmic_arb->intr + 0x100000 + 0x1000 * m + 0x4 * n;
+ return bus->intr + 0x100000 + 0x1000 * m + 0x4 * n;
}
static void __iomem *
-pmic_arb_owner_acc_status_v3(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
+pmic_arb_owner_acc_status_v3(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
{
- return pmic_arb->intr + 0x200000 + 0x1000 * m + 0x4 * n;
+ return bus->intr + 0x200000 + 0x1000 * m + 0x4 * n;
}
static void __iomem *
-pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
+pmic_arb_owner_acc_status_v5(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
{
- return pmic_arb->intr + 0x10000 * m + 0x4 * n;
+ return bus->intr + 0x10000 * m + 0x4 * n;
}
static void __iomem *
-pmic_arb_owner_acc_status_v7(struct spmi_pmic_arb *pmic_arb, u8 m, u16 n)
+pmic_arb_owner_acc_status_v7(struct spmi_pmic_arb_bus *bus, u8 m, u16 n)
{
- return pmic_arb->intr + 0x1000 * m + 0x4 * n;
+ return bus->intr + 0x1000 * m + 0x4 * n;
}
static void __iomem *
-pmic_arb_acc_enable_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_acc_enable_v1(struct spmi_pmic_arb_bus *bus, u16 n)
{
- return pmic_arb->intr + 0x200 + 0x4 * n;
+ return bus->intr + 0x200 + 0x4 * n;
}
static void __iomem *
-pmic_arb_acc_enable_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_acc_enable_v2(struct spmi_pmic_arb_bus *bus, u16 n)
{
- return pmic_arb->intr + 0x1000 * n;
+ return bus->intr + 0x1000 * n;
}
static void __iomem *
-pmic_arb_acc_enable_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_acc_enable_v5(struct spmi_pmic_arb_bus *bus, u16 n)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
return pmic_arb->wr_base + 0x100 + 0x10000 * n;
}
static void __iomem *
-pmic_arb_acc_enable_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_acc_enable_v7(struct spmi_pmic_arb_bus *bus, u16 n)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
return pmic_arb->wr_base + 0x100 + 0x1000 * n;
}
static void __iomem *
-pmic_arb_irq_status_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_irq_status_v1(struct spmi_pmic_arb_bus *bus, u16 n)
{
- return pmic_arb->intr + 0x600 + 0x4 * n;
+ return bus->intr + 0x600 + 0x4 * n;
}
static void __iomem *
-pmic_arb_irq_status_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_irq_status_v2(struct spmi_pmic_arb_bus *bus, u16 n)
{
- return pmic_arb->intr + 0x4 + 0x1000 * n;
+ return bus->intr + 0x4 + 0x1000 * n;
}
static void __iomem *
-pmic_arb_irq_status_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_irq_status_v5(struct spmi_pmic_arb_bus *bus, u16 n)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
return pmic_arb->wr_base + 0x104 + 0x10000 * n;
}
static void __iomem *
-pmic_arb_irq_status_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_irq_status_v7(struct spmi_pmic_arb_bus *bus, u16 n)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
return pmic_arb->wr_base + 0x104 + 0x1000 * n;
}
static void __iomem *
-pmic_arb_irq_clear_v1(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_irq_clear_v1(struct spmi_pmic_arb_bus *bus, u16 n)
{
- return pmic_arb->intr + 0xA00 + 0x4 * n;
+ return bus->intr + 0xA00 + 0x4 * n;
}
static void __iomem *
-pmic_arb_irq_clear_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_irq_clear_v2(struct spmi_pmic_arb_bus *bus, u16 n)
{
- return pmic_arb->intr + 0x8 + 0x1000 * n;
+ return bus->intr + 0x8 + 0x1000 * n;
}
static void __iomem *
-pmic_arb_irq_clear_v5(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_irq_clear_v5(struct spmi_pmic_arb_bus *bus, u16 n)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
return pmic_arb->wr_base + 0x108 + 0x10000 * n;
}
static void __iomem *
-pmic_arb_irq_clear_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_irq_clear_v7(struct spmi_pmic_arb_bus *bus, u16 n)
{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
return pmic_arb->wr_base + 0x108 + 0x1000 * n;
}
@@ -1455,9 +1495,9 @@ static u32 pmic_arb_apid_map_offset_v7(u16 n)
}
static void __iomem *
-pmic_arb_apid_owner_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_apid_owner_v2(struct spmi_pmic_arb_bus *bus, u16 n)
{
- return pmic_arb->cnfg + 0x700 + 0x4 * n;
+ return bus->cnfg + 0x700 + 0x4 * n;
}
/*
@@ -1466,9 +1506,9 @@ pmic_arb_apid_owner_v2(struct spmi_pmic_arb *pmic_arb, u16 n)
* 0.
*/
static void __iomem *
-pmic_arb_apid_owner_v7(struct spmi_pmic_arb *pmic_arb, u16 n)
+pmic_arb_apid_owner_v7(struct spmi_pmic_arb_bus *bus, u16 n)
{
- return pmic_arb->cnfg + 0x4 * (n - pmic_arb->base_apid);
+ return bus->cnfg + 0x4 * (n - bus->base_apid);
}
static const struct pmic_arb_ver_ops pmic_arb_v1 = {
@@ -1558,29 +1598,121 @@ static const struct irq_domain_ops pmic_arb_irq_domain_ops = {
.translate = qpnpint_irq_domain_translate,
};
+static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
+ struct device_node *node,
+ struct spmi_pmic_arb *pmic_arb)
+{
+ struct spmi_pmic_arb_bus *bus;
+ struct device *dev = &pdev->dev;
+ struct spmi_controller *ctrl;
+ void __iomem *intr;
+ void __iomem *cnfg;
+ int index, ret;
+ u32 irq;
+
+ ctrl = devm_spmi_controller_alloc(dev, sizeof(*bus));
+ if (IS_ERR(ctrl))
+ return PTR_ERR(ctrl);
+
+ ctrl->cmd = pmic_arb_cmd;
+ ctrl->read_cmd = pmic_arb_read_cmd;
+ ctrl->write_cmd = pmic_arb_write_cmd;
+
+ bus = spmi_controller_get_drvdata(ctrl);
+
+ pmic_arb->bus = bus;
+
+ raw_spin_lock_init(&bus->lock);
+
+ bus->ppid_to_apid = devm_kcalloc(dev, PMIC_ARB_MAX_PPID,
+ sizeof(*bus->ppid_to_apid),
+ GFP_KERNEL);
+ if (!bus->ppid_to_apid)
+ return -ENOMEM;
+
+ bus->apid_data = devm_kcalloc(dev, pmic_arb->max_periphs,
+ sizeof(*bus->apid_data),
+ GFP_KERNEL);
+ if (!bus->apid_data)
+ return -ENOMEM;
+
+ index = of_property_match_string(node, "reg-names", "cnfg");
+ if (index < 0) {
+ dev_err(dev, "cnfg reg region missing");
+ return -EINVAL;
+ }
+
+ cnfg = devm_of_iomap(dev, node, index, NULL);
+ if (IS_ERR(cnfg))
+ return PTR_ERR(cnfg);
+
+ index = of_property_match_string(node, "reg-names", "intr");
+ if (index < 0) {
+ dev_err(dev, "intr reg region missing");
+ return -EINVAL;
+ }
+
+ intr = devm_of_iomap(dev, node, index, NULL);
+ if (IS_ERR(intr))
+ return PTR_ERR(intr);
+
+ irq = of_irq_get_byname(node, "periph_irq");
+ if (irq < 0)
+ return irq;
+
+ bus->pmic_arb = pmic_arb;
+ bus->intr = intr;
+ bus->cnfg = cnfg;
+ bus->irq = irq;
+ bus->spmic = ctrl;
+
+ ret = pmic_arb->ver_ops->init_apid(bus);
+ if (ret)
+ return ret;
+
+ dev_dbg(&pdev->dev, "adding irq domain\n");
+
+ bus->domain = irq_domain_add_tree(dev->of_node,
+ &pmic_arb_irq_domain_ops, bus);
+ if (!bus->domain) {
+ dev_err(&pdev->dev, "unable to create irq_domain\n");
+ return -ENOMEM;
+ }
+
+ irq_set_chained_handler_and_data(bus->irq,
+ pmic_arb_chained_irq, bus);
+
+ ctrl->dev.of_node = node;
+
+ ret = devm_spmi_controller_add(dev, ctrl);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
static int spmi_pmic_arb_probe(struct platform_device *pdev)
{
struct spmi_pmic_arb *pmic_arb;
- struct spmi_controller *ctrl;
+ struct device *dev = &pdev->dev;
struct resource *res;
void __iomem *core;
u32 channel, ee, hw_ver;
int err;
- ctrl = devm_spmi_controller_alloc(&pdev->dev, sizeof(*pmic_arb));
- if (IS_ERR(ctrl))
- return PTR_ERR(ctrl);
-
- pmic_arb = spmi_controller_get_drvdata(ctrl);
- pmic_arb->spmic = ctrl;
+ pmic_arb = devm_kzalloc(dev, sizeof(*pmic_arb), GFP_KERNEL);
+ if (!pmic_arb)
+ return -ENOMEM;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
- core = devm_ioremap(&ctrl->dev, res->start, resource_size(res));
+ core = devm_ioremap(dev, res->start, resource_size(res));
if (IS_ERR(core))
return PTR_ERR(core);
pmic_arb->core_size = resource_size(res);
+ platform_set_drvdata(pdev, pmic_arb);
+
hw_ver = readl_relaxed(core + PMIC_ARB_VERSION);
if (hw_ver < PMIC_ARB_VERSION_V2_MIN)
@@ -1594,30 +1726,12 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
else
pmic_arb->ver_ops = &pmic_arb_v7;
- dev_info(&ctrl->dev, "PMIC arbiter version %s (0x%x)\n",
- pmic_arb->ver_ops->ver_str, hw_ver);
-
err = pmic_arb->ver_ops->get_core_resources(pdev, core);
if (err)
return err;
- err = pmic_arb->ver_ops->init_apid(pmic_arb);
- if (err)
- return err;
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "intr");
- pmic_arb->intr = devm_ioremap_resource(&ctrl->dev, res);
- if (IS_ERR(pmic_arb->intr))
- return PTR_ERR(pmic_arb->intr);
-
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cnfg");
- pmic_arb->cnfg = devm_ioremap_resource(&ctrl->dev, res);
- if (IS_ERR(pmic_arb->cnfg))
- return PTR_ERR(pmic_arb->cnfg);
-
- pmic_arb->irq = platform_get_irq_byname(pdev, "periph_irq");
- if (pmic_arb->irq < 0)
- return pmic_arb->irq;
+ dev_info(dev, "PMIC arbiter version %s (0x%x)\n",
+ pmic_arb->ver_ops->ver_str, hw_ver);
err = of_property_read_u32(pdev->dev.of_node, "qcom,channel", &channel);
if (err) {
@@ -1646,42 +1760,17 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pmic_arb->ee = ee;
- platform_set_drvdata(pdev, ctrl);
- raw_spin_lock_init(&pmic_arb->lock);
-
- ctrl->cmd = pmic_arb_cmd;
- ctrl->read_cmd = pmic_arb_read_cmd;
- ctrl->write_cmd = pmic_arb_write_cmd;
-
- dev_dbg(&pdev->dev, "adding irq domain\n");
- pmic_arb->domain = irq_domain_add_tree(pdev->dev.of_node,
- &pmic_arb_irq_domain_ops, pmic_arb);
- if (!pmic_arb->domain) {
- dev_err(&pdev->dev, "unable to create irq_domain\n");
- return -ENOMEM;
- }
-
- irq_set_chained_handler_and_data(pmic_arb->irq, pmic_arb_chained_irq,
- pmic_arb);
- err = spmi_controller_add(ctrl);
- if (err)
- goto err_domain_remove;
-
- return 0;
-
-err_domain_remove:
- irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
- irq_domain_remove(pmic_arb->domain);
- return err;
+ return spmi_pmic_arb_bus_init(pdev, dev->of_node, pmic_arb);
}
static void spmi_pmic_arb_remove(struct platform_device *pdev)
{
- struct spmi_controller *ctrl = platform_get_drvdata(pdev);
- struct spmi_pmic_arb *pmic_arb = spmi_controller_get_drvdata(ctrl);
- spmi_controller_remove(ctrl);
- irq_set_chained_handler_and_data(pmic_arb->irq, NULL, NULL);
- irq_domain_remove(pmic_arb->domain);
+ struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev);
+ struct spmi_pmic_arb_bus *bus = pmic_arb->bus;
+
+ irq_set_chained_handler_and_data(bus->irq,
+ NULL, NULL);
+ irq_domain_remove(bus->domain);
}
static const struct of_device_id spmi_pmic_arb_match_table[] = {
--
2.34.1
^ permalink raw reply related
* [PATCH v9 7/7] spmi: pmic-arb: Add multi bus support
From: Abel Vesa @ 2024-04-07 16:23 UTC (permalink / raw)
To: Stephen Boyd, Matthias Brugger, Bjorn Andersson, Konrad Dybcio,
Dmitry Baryshkov, Neil Armstrong, AngeloGioacchino Del Regno,
Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: Srini Kandagatla, Johan Hovold, David Collins, linux-kernel,
linux-arm-kernel, linux-arm-msm, linux-mediatek, devicetree,
Abel Vesa
In-Reply-To: <20240407-spmi-multi-master-support-v9-0-fa151c1391f3@linaro.org>
Starting with HW version 7, there are actually two separate buses
(with two separate sets of wires). So add support for the second bus.
The first platform that needs this support for the second bus is the
Qualcomm X1 Elite, so add the compatible for it as well.
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Signed-off-by: Abel Vesa <abel.vesa@linaro.org>
---
drivers/spmi/spmi-pmic-arb.c | 138 +++++++++++++++++++++++++++++++++++++------
1 file changed, 120 insertions(+), 18 deletions(-)
diff --git a/drivers/spmi/spmi-pmic-arb.c b/drivers/spmi/spmi-pmic-arb.c
index 65d8f45da24b..cfa8ec21cd56 100644
--- a/drivers/spmi/spmi-pmic-arb.c
+++ b/drivers/spmi/spmi-pmic-arb.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@@ -95,6 +96,8 @@ enum pmic_arb_channel {
PMIC_ARB_CHANNEL_OBS,
};
+#define PMIC_ARB_MAX_BUSES 2
+
/* Maximum number of support PMIC peripherals */
#define PMIC_ARB_MAX_PERIPHS 512
#define PMIC_ARB_MAX_PERIPHS_V7 1024
@@ -149,6 +152,7 @@ struct spmi_pmic_arb;
* @min_apid: minimum APID (used for bounding IRQ search)
* @max_apid: maximum APID
* @irq: PMIC ARB interrupt.
+ * @id: unique ID of the bus
*/
struct spmi_pmic_arb_bus {
struct spmi_pmic_arb *pmic_arb;
@@ -167,6 +171,7 @@ struct spmi_pmic_arb_bus {
u16 min_apid;
u16 max_apid;
int irq;
+ u8 id;
};
/**
@@ -180,7 +185,8 @@ struct spmi_pmic_arb_bus {
* @ee: the current Execution Environment
* @ver_ops: version dependent operations.
* @max_periphs: Number of elements in apid_data[]
- * @bus: per arbiter bus instance
+ * @buses: per arbiter buses instances
+ * @buses_available: number of buses registered
*/
struct spmi_pmic_arb {
void __iomem *rd_base;
@@ -191,7 +197,8 @@ struct spmi_pmic_arb {
u8 ee;
const struct pmic_arb_ver_ops *ver_ops;
int max_periphs;
- struct spmi_pmic_arb_bus *bus;
+ struct spmi_pmic_arb_bus *buses[PMIC_ARB_MAX_BUSES];
+ int buses_available;
};
/**
@@ -220,7 +227,7 @@ struct spmi_pmic_arb {
struct pmic_arb_ver_ops {
const char *ver_str;
int (*get_core_resources)(struct platform_device *pdev, void __iomem *core);
- int (*init_apid)(struct spmi_pmic_arb_bus *bus);
+ int (*init_apid)(struct spmi_pmic_arb_bus *bus, int index);
int (*ppid_to_apid)(struct spmi_pmic_arb_bus *bus, u16 ppid);
/* spmi commands (read_cmd, write_cmd, cmd) functionality */
int (*offset)(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
@@ -309,8 +316,8 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
}
if (status & PMIC_ARB_STATUS_FAILURE) {
- dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x)\n",
- __func__, sid, addr, status);
+ dev_err(&ctrl->dev, "%s: %#x %#x: transaction failed (%#x) reg: 0x%x\n",
+ __func__, sid, addr, status, offset);
WARN_ON(1);
return -EIO;
}
@@ -326,8 +333,8 @@ static int pmic_arb_wait_for_done(struct spmi_controller *ctrl,
udelay(1);
}
- dev_err(&ctrl->dev, "%s: %#x %#x: timeout, status %#x\n",
- __func__, sid, addr, status);
+ dev_err(&ctrl->dev, "%s: %#x %#x %#x: timeout, status %#x\n",
+ __func__, bus->id, sid, addr, status);
return -ETIMEDOUT;
}
@@ -1003,11 +1010,17 @@ static int pmic_arb_get_core_resources_v1(struct platform_device *pdev,
return 0;
}
-static int pmic_arb_init_apid_v1(struct spmi_pmic_arb_bus *bus)
+static int pmic_arb_init_apid_v1(struct spmi_pmic_arb_bus *bus, int index)
{
struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
u32 *mapping_table;
+ if (index) {
+ dev_err(&bus->spmic->dev, "Unsupported buses count %d detected\n",
+ index);
+ return -EINVAL;
+ }
+
mapping_table = devm_kcalloc(&bus->spmic->dev, pmic_arb->max_periphs,
sizeof(*mapping_table), GFP_KERNEL);
if (!mapping_table)
@@ -1250,11 +1263,17 @@ static int pmic_arb_offset_v2(struct spmi_pmic_arb_bus *bus, u8 sid, u16 addr,
return 0x1000 * pmic_arb->ee + 0x8000 * apid;
}
-static int pmic_arb_init_apid_v5(struct spmi_pmic_arb_bus *bus)
+static int pmic_arb_init_apid_v5(struct spmi_pmic_arb_bus *bus, int index)
{
struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
int ret;
+ if (index) {
+ dev_err(&bus->spmic->dev, "Unsupported buses count %d detected\n",
+ index);
+ return -EINVAL;
+ }
+
bus->base_apid = 0;
bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
PMIC_ARB_FEATURES_PERIPH_MASK;
@@ -1326,6 +1345,50 @@ static int pmic_arb_get_core_resources_v7(struct platform_device *pdev,
return pmic_arb_get_obsrvr_chnls_v2(pdev);
}
+/*
+ * Only v7 supports 2 buses. Each bus will get a different apid count, read
+ * from different registers.
+ */
+static int pmic_arb_init_apid_v7(struct spmi_pmic_arb_bus *bus, int index)
+{
+ struct spmi_pmic_arb *pmic_arb = bus->pmic_arb;
+ int ret;
+
+ if (index == 0) {
+ bus->base_apid = 0;
+ bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK;
+ } else if (index == 1) {
+ bus->base_apid = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES) &
+ PMIC_ARB_FEATURES_PERIPH_MASK;
+ bus->apid_count = readl_relaxed(pmic_arb->core + PMIC_ARB_FEATURES1) &
+ PMIC_ARB_FEATURES_PERIPH_MASK;
+ } else {
+ dev_err(&bus->spmic->dev, "Unsupported buses count %d detected\n",
+ bus->id);
+ return -EINVAL;
+ }
+
+ if (bus->base_apid + bus->apid_count > pmic_arb->max_periphs) {
+ dev_err(&bus->spmic->dev, "Unsupported APID count %d detected\n",
+ bus->base_apid + bus->apid_count);
+ return -EINVAL;
+ }
+
+ ret = pmic_arb_init_apid_min_max(bus);
+ if (ret)
+ return ret;
+
+ ret = pmic_arb_read_apid_map_v5(bus);
+ if (ret) {
+ dev_err(&bus->spmic->dev, "could not read APID->PPID mapping table, rc= %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* v7 offset per ee and per apid for observer channels and per apid for
* read/write channels.
@@ -1578,7 +1641,7 @@ static const struct pmic_arb_ver_ops pmic_arb_v5 = {
static const struct pmic_arb_ver_ops pmic_arb_v7 = {
.ver_str = "v7",
.get_core_resources = pmic_arb_get_core_resources_v7,
- .init_apid = pmic_arb_init_apid_v5,
+ .init_apid = pmic_arb_init_apid_v7,
.ppid_to_apid = pmic_arb_ppid_to_apid_v5,
.non_data_cmd = pmic_arb_non_data_cmd_v2,
.offset = pmic_arb_offset_v7,
@@ -1602,6 +1665,7 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
struct device_node *node,
struct spmi_pmic_arb *pmic_arb)
{
+ int bus_index = pmic_arb->buses_available;
struct spmi_pmic_arb_bus *bus;
struct device *dev = &pdev->dev;
struct spmi_controller *ctrl;
@@ -1620,7 +1684,7 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
bus = spmi_controller_get_drvdata(ctrl);
- pmic_arb->bus = bus;
+ pmic_arb->buses[bus_index] = bus;
raw_spin_lock_init(&bus->lock);
@@ -1665,12 +1729,13 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
bus->cnfg = cnfg;
bus->irq = irq;
bus->spmic = ctrl;
+ bus->id = bus_index;
- ret = pmic_arb->ver_ops->init_apid(bus);
+ ret = pmic_arb->ver_ops->init_apid(bus, bus_index);
if (ret)
return ret;
- dev_dbg(&pdev->dev, "adding irq domain\n");
+ dev_dbg(&pdev->dev, "adding irq domain for bus %d\n", bus_index);
bus->domain = irq_domain_add_tree(dev->of_node,
&pmic_arb_irq_domain_ops, bus);
@@ -1683,14 +1748,53 @@ static int spmi_pmic_arb_bus_init(struct platform_device *pdev,
pmic_arb_chained_irq, bus);
ctrl->dev.of_node = node;
+ dev_set_name(&ctrl->dev, "spmi-%d", bus_index);
ret = devm_spmi_controller_add(dev, ctrl);
if (ret)
return ret;
+ pmic_arb->buses_available++;
+
return 0;
}
+static int spmi_pmic_arb_register_buses(struct spmi_pmic_arb *pmic_arb,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct device_node *child;
+ int ret;
+
+ /* legacy mode doesn't provide child node for the bus */
+ if (of_device_is_compatible(node, "qcom,spmi-pmic-arb"))
+ return spmi_pmic_arb_bus_init(pdev, node, pmic_arb);
+
+ for_each_available_child_of_node(node, child) {
+ if (of_node_name_eq(child, "spmi")) {
+ ret = spmi_pmic_arb_bus_init(pdev, child, pmic_arb);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static void spmi_pmic_arb_deregister_buses(struct spmi_pmic_arb *pmic_arb)
+{
+ int i;
+
+ for (i = 0; i < pmic_arb->buses_available; i++) {
+ struct spmi_pmic_arb_bus *bus = pmic_arb->buses[i];
+
+ irq_set_chained_handler_and_data(bus->irq,
+ NULL, NULL);
+ irq_domain_remove(bus->domain);
+ }
+}
+
static int spmi_pmic_arb_probe(struct platform_device *pdev)
{
struct spmi_pmic_arb *pmic_arb;
@@ -1760,21 +1864,19 @@ static int spmi_pmic_arb_probe(struct platform_device *pdev)
pmic_arb->ee = ee;
- return spmi_pmic_arb_bus_init(pdev, dev->of_node, pmic_arb);
+ return spmi_pmic_arb_register_buses(pmic_arb, pdev);
}
static void spmi_pmic_arb_remove(struct platform_device *pdev)
{
struct spmi_pmic_arb *pmic_arb = platform_get_drvdata(pdev);
- struct spmi_pmic_arb_bus *bus = pmic_arb->bus;
- irq_set_chained_handler_and_data(bus->irq,
- NULL, NULL);
- irq_domain_remove(bus->domain);
+ spmi_pmic_arb_deregister_buses(pmic_arb);
}
static const struct of_device_id spmi_pmic_arb_match_table[] = {
{ .compatible = "qcom,spmi-pmic-arb", },
+ { .compatible = "qcom,x1e80100-spmi-pmic-arb", },
{},
};
MODULE_DEVICE_TABLE(of, spmi_pmic_arb_match_table);
--
2.34.1
^ permalink raw reply related
* [PATCH RESEND v8 0/6] riscv: add initial support for Canaan Kendryte K230
From: Yangyu Chen @ 2024-04-07 16:26 UTC (permalink / raw)
To: linux-riscv
Cc: Conor Dooley, Damien Le Moal, Rob Herring, Krzysztof Kozlowski,
Dan Carpenter, Paul Walmsley, Palmer Dabbelt, Albert Ou, Guo Ren,
devicetree, linux-kernel, Yangyu Chen
K230 is an ideal chip for RISC-V Vector 1.0 evaluation now. Add initial
support for it to allow more people to participate in building drivers
to mainline for it.
This kernel has been tested upon factory SDK [1] with
k230_evb_only_linux_defconfig and patched mainline opensbi [2] to skip
locked pmp and successfully booted to busybox on initrd with this log [3].
Changes in resend v8:
- Add missing cc to lkml and linux-dt list and correct Krzysztof's address
- No change in content
v8: https://lore.kernel.org/linux-riscv/tencent_9F423E3DC13F6D5FC7415C89988490F04607@qq.com/
Changes since v7:
- Add missing riscv,cbop-block-size and riscv,cboz-block-size in dts
v7: https://lore.kernel.org/linux-riscv/tencent_F6392EE11AC6A485C43406F1BD09C268DB0A@qq.com/
Changes since v6:
- Split SOC_CANAAN clean up to a separate patch [4]
- Add zicbop and zicboz in dts
- Rebase to riscv-dt-for-next branch
v6: https://lore.kernel.org/linux-riscv/tencent_F76EB8D731C521C18D5D7C4F8229DAA58E08@qq.com/
Changes since v5:
- Deprecate SOC_CANAAN and use SOC_CANAAN_K210 for K210 SoCs
- Modify existing K210 drivers depends on SOC_CANAAN_K210 symbol
- Reword dts commit message
- Modify dts to use Full 512MB memory
- Rebase to linux mainline master
v5: https://lore.kernel.org/linux-riscv/tencent_FC10B3C630BE27412FED2547245CBE18D807@qq.com/
Changes since v4:
- Reword commit message on dts that the B-ext version of c908 is 1.0 rather
than 1.0-rc1
v4: https://lore.kernel.org/linux-riscv/tencent_587730262984A011834F42D0563BC6B10405@qq.com/
Changes since v3:
- Refactor Kconfig.soc which uses ARCH_CANAAN for regular Canaan SoCs and
rename SOC_CANAAN to SOC_CANAAN_K210 for K210 in patch [5/7]
- Sort dt-binding stings on Cannan SoCs in alphanumerical order
v3: https://lore.kernel.org/linux-riscv/tencent_BB2364BBF1812F4E304F7BDDD11E57356605@qq.com/
Changes since v2:
- Add MIT License to dts file
- Sort dt-binding stings in alphanumerical order
- Sort filename in dts Makefile in alphanumerical order
- Rename canmv-k230.dts to k230-canmv.dts
v2: https://lore.kernel.org/linux-riscv/tencent_64A9B4B31C2D70D5633042461AC9F80C0509@qq.com/
Changes since v1:
- Patch dt-bindings in clint and plic
- Use enum in K230 compatible dt bindings
- Fix dts to pass `make dtbs_check`
- Add more details in commit message
v1: https://lore.kernel.org/linux-riscv/tencent_E15F8FE0B6769E6338AE690C7F4844A31706@qq.com/
[1] https://github.com/kendryte/k230_sdk
[2] https://github.com/cyyself/opensbi/tree/k230
[3] https://gist.github.com/cyyself/b9445f38cc3ba1094924bd41c9086176
[4] https://lore.kernel.org/linux-riscv/tencent_2E60E33C1F88A090B6B3A332AE528C6B8806@qq.com/
Yangyu Chen (6):
dt-bindings: riscv: Add T-HEAD C908 compatible
dt-bindings: add Canaan K230 boards compatible strings
dt-bindings: timer: Add Canaan K230 CLINT
dt-bindings: interrupt-controller: Add Canaan K230 PLIC
riscv: dts: add initial canmv-k230 and k230-evb dts
riscv: config: enable ARCH_CANAAN in defconfig
.../sifive,plic-1.0.0.yaml | 1 +
.../devicetree/bindings/riscv/canaan.yaml | 8 +-
.../devicetree/bindings/riscv/cpus.yaml | 1 +
.../bindings/timer/sifive,clint.yaml | 1 +
arch/riscv/boot/dts/canaan/Makefile | 2 +
arch/riscv/boot/dts/canaan/k230-canmv.dts | 24 +++
arch/riscv/boot/dts/canaan/k230-evb.dts | 24 +++
arch/riscv/boot/dts/canaan/k230.dtsi | 142 ++++++++++++++++++
arch/riscv/configs/defconfig | 1 +
9 files changed, 203 insertions(+), 1 deletion(-)
create mode 100644 arch/riscv/boot/dts/canaan/k230-canmv.dts
create mode 100644 arch/riscv/boot/dts/canaan/k230-evb.dts
create mode 100644 arch/riscv/boot/dts/canaan/k230.dtsi
base-commit: 0eea987088a22d73d81e968de7347cdc7e594f72
--
2.43.0
^ permalink raw reply
* [PATCH RESEND v8 1/6] dt-bindings: riscv: Add T-HEAD C908 compatible
From: Yangyu Chen @ 2024-04-07 16:28 UTC (permalink / raw)
To: linux-riscv
Cc: Conor Dooley, Damien Le Moal, Rob Herring, Krzysztof Kozlowski,
Dan Carpenter, Paul Walmsley, Palmer Dabbelt, Albert Ou, Guo Ren,
devicetree, linux-kernel, Yangyu Chen, Conor Dooley
In-Reply-To: <tencent_22BA0425B4DF1CA1713B62E4423C1BFBF809@qq.com>
The thead,c908 is a RISC-V CPU core from T-HEAD Semiconductor which used
in Canaan Kendryte K230 SoC.
Signed-off-by: Yangyu Chen <cyy@cyyself.name>
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Reviewed-by: Guo Ren <guoren@kernel.org>
---
Documentation/devicetree/bindings/riscv/cpus.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml
index d87dd50f1a4b..d067f2a468ee 100644
--- a/Documentation/devicetree/bindings/riscv/cpus.yaml
+++ b/Documentation/devicetree/bindings/riscv/cpus.yaml
@@ -47,6 +47,7 @@ properties:
- sifive,u74
- sifive,u74-mc
- thead,c906
+ - thead,c908
- thead,c910
- thead,c920
- const: riscv
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox