On Tue, Nov 19, 2024 at 03:07:26PM +0200, Daniel Baluta wrote: > This is a RFC patch in order to allow AHB to IP Bridge (AIPSTZ) > configuration to be restored after a suspend/resume operation. > > This is particularly useful for aips5 bus where the aipstz > configuration is lost at suspend. > > In order to configure aipstz bridge we register a platform driver > that will set default configuration permission at probe. > > Because AIPS configuration is lost at suspend/resume time we register > a power notifier callback that will take care of re-initializing the > configuration at resume. why not use suspend/resume callback? what's happen if devices under AIPS suspend/resume before AIPS resume function. > > More details about AHB to IP Bridge: > > This peripheral is designated as the bridge between AHB bus and > peripherals with the lower bandwidth IP Slave (IPS) buses. > > The bridge is responsible for indicating to IPS peripherals if > an access is in supervisor or user mode. It may block user mode > accesses to certain IPS peripherals or it may allow the individual > IPS peripherals to determine if user mode accesses are allowed. > > The bridge supports the notion of "trusted" masters for security > purposes. Masters may be individually designated as trusted for > reads, writes or both. > > Even more details (including register description) can be found > in Chapter 4.7 AHB to IP Bridge (AIPSTZ) > of i.MX8M Plus Application Processor Reference Manual. > > Signed-off-by: Daniel Baluta <daniel.baluta@xxxxxxx> > --- > > This RFC patch is to get your opinion on the direction on how should > we proceed with handling configuration registers for this kind of > device. > > It registers itself as a platform driver at boot time and then is probed > once the dts node is discovered. > > TBD: > - device tree binding file > - enhance error checking > - is this the correct way to handle this kind of "peripheral". > > arch/arm64/boot/dts/freescale/imx8mp.dtsi | 7 ++ > drivers/soc/imx/aipstz.c | 114 ++++++++++++++++++++++ > 2 files changed, 121 insertions(+) > create mode 100644 drivers/soc/imx/aipstz.c > > diff --git a/arch/arm64/boot/dts/freescale/imx8mp.dtsi b/arch/arm64/boot/dts/freescale/imx8mp.dtsi > index e0d3b8cba221..7775f5f58036 100644 > --- a/arch/arm64/boot/dts/freescale/imx8mp.dtsi > +++ b/arch/arm64/boot/dts/freescale/imx8mp.dtsi > @@ -1406,6 +1406,13 @@ aips5: bus@30c00000 { > #size-cells = <1>; > ranges; > > + aipstz5: bridge@30df0000 { > + compatible = "fsl,imx8mp-aipstz"; > + reg = <0x30df0000 0x10000>; > + power-domains = <&pgc_audio>; > + status = "okay"; > + }; supposed bridge@30df0000 { ... some child node { } so child node's devies suspend/resume will after bidged's suspend resume. } > + > spba-bus@30c00000 { > compatible = "fsl,spba-bus", "simple-bus"; > reg = <0x30c00000 0x100000>; > diff --git a/drivers/soc/imx/aipstz.c b/drivers/soc/imx/aipstz.c > new file mode 100644 > index 000000000000..49a619f17dda > --- /dev/null > +++ b/drivers/soc/imx/aipstz.c > @@ -0,0 +1,114 @@ > +#include <linux/module.h> > +#include <linux/platform_device.h> > +#include <linux/of.h> > +#include <linux/pm_domain.h> > +#include <linux/io.h> > +#include <linux/of.h> > +#include <linux/of_address.h> > + > +#define DRV_NAME "aips-bridge" > + > +#define AIPSTZ_MPR0 0x0 > +#define AIPSTZ_MPR1 0x4 > + > +#define AIPSTZ_OPACR_NUM (0x5) > +#define OPACR_OFFSET(i) ((i) * 4 + 0x40) > + > +struct aipstz_drv { > + void __iomem *base; > + struct notifier_block power_nb; > + struct aipstz_cfg *cfg; > +}; > + > +struct aipstz_cfg { > + uint32_t mpr0; > + uint32_t mpr1; > + uint32_t opacr[AIPSTZ_OPACR_NUM]; > +}; > + > +static struct aipstz_cfg aipstz5 = { > + 0x77777777, > + 0x77777777, > + .opacr = {0x0, 0x0, 0x0, 0x0, 0x0} > +}; > + > +static void imx_aipstz_config_init(const struct aipstz_drv *drv) > + > +{ > + const struct aipstz_cfg *aipstz = drv->cfg; > + > + writel(aipstz->mpr0, drv->base + AIPSTZ_MPR0); > + writel(aipstz->mpr1, drv->base + AIPSTZ_MPR1); > + > + for (int i = 0; i < AIPSTZ_OPACR_NUM; i++) > + writel(aipstz->opacr[i], drv->base + OPACR_OFFSET(i)); > +} > + > +static int aipstz_power_notifier(struct notifier_block *nb, > + unsigned long action, void *data) > +{ > + struct aipstz_drv *drv = container_of(nb, struct aipstz_drv, power_nb); > + > + if (action != GENPD_NOTIFY_ON) > + return NOTIFY_OK; > + > + imx_aipstz_config_init(drv); > + > + return NOTIFY_OK; > +} > + > +static int aipstz_probe(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + struct aipstz_drv *drv; > + > + drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); > + if (!drv) > + return -ENOMEM; > + > + drv->base = of_iomap(pdev->dev.of_node, 0); > + drv->power_nb.notifier_call = aipstz_power_notifier; > + drv->cfg = &aipstz5; > + > + imx_aipstz_config_init(drv); > + > + if (dev->pm_domain) > + dev_pm_genpd_add_notifier(dev, &drv->power_nb); > + > + dev_set_drvdata(dev, drv); > + > + return 0; > +} > + > +static const struct of_device_id aipstz_of_match[] = { > + {.compatible = "fsl,imx8mp-aipstz", }, > + {} > +}; > + > +static struct platform_driver aipstz_driver = { > + .probe = aipstz_probe, > + .driver = { > + .name = DRV_NAME, > + .of_match_table = of_match_ptr(aipstz_of_match), > + }, > +}; > + > +static int __init aipstz_driver_init(void) > +{ > + int ret; > + > + ret = platform_driver_register(&aipstz_driver); > + if (ret) { > + pr_err("Failed to register aipstz platform driver\n"); > + return ret; > + } > + > + return 0; > +} > + > +device_initcall(aipstz_driver_init); > + > +MODULE_DESCRIPTION("i.MX8 AIPS bus configuration driver"); > +MODULE_AUTHOR("Daniel Baluta <daniel.baluta@xxxxxxx>"); > +MODULE_LICENSE("GPL"); > +MODULE_ALIAS("platform:" DRV_NAME); > -- > 2.43.0 >