Message ID | 20220830125249.2373416-3-conor.dooley@microchip.com (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
Series | PolarFire SoC reset controller & clock cleanups | expand |
On 30.08.2022 15:52, Conor Dooley wrote: > EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe > > Add a reset controller to PolarFire SoC's clock driver. This reset > controller is registered as an aux device and read/write functions > exported to the drivers namespace so that the reset controller can > access the peripheral device reset register. > > Reviewed-by: Daire McNamara <daire.mcnamara@microchip.com> > Signed-off-by: Conor Dooley <conor.dooley@microchip.com> Reviewed-by: Claudiu Beznea <claudiu.beznea@microchip.com> > --- > drivers/clk/microchip/Kconfig | 1 + > drivers/clk/microchip/clk-mpfs.c | 110 +++++++++++++++++++++++++++---- > include/soc/microchip/mpfs.h | 8 +++ > 3 files changed, 107 insertions(+), 12 deletions(-) > > diff --git a/drivers/clk/microchip/Kconfig b/drivers/clk/microchip/Kconfig > index a5a99873c4f5..b46e864b3bd8 100644 > --- a/drivers/clk/microchip/Kconfig > +++ b/drivers/clk/microchip/Kconfig > @@ -6,5 +6,6 @@ config COMMON_CLK_PIC32 > config MCHP_CLK_MPFS > bool "Clk driver for PolarFire SoC" > depends on (RISCV && SOC_MICROCHIP_POLARFIRE) || COMPILE_TEST > + select AUXILIARY_BUS > help > Supports Clock Configuration for PolarFire SoC > diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c > index 9e41f07b3fa6..43cc9583cd14 100644 > --- a/drivers/clk/microchip/clk-mpfs.c > +++ b/drivers/clk/microchip/clk-mpfs.c > @@ -3,12 +3,14 @@ > * Daire McNamara,<daire.mcnamara@microchip.com> > * Copyright (C) 2020 Microchip Technology Inc. All rights reserved. > */ > +#include <linux/auxiliary_bus.h> > #include <linux/clk-provider.h> > #include <linux/io.h> > #include <linux/module.h> > #include <linux/platform_device.h> > #include <linux/slab.h> > #include <dt-bindings/clock/microchip,mpfs-clock.h> > +#include <soc/microchip/mpfs.h> > > /* address offset of control registers */ > #define REG_MSSPLL_REF_CR 0x08u > @@ -30,6 +32,7 @@ > #define RTCREF_OFFSET (CLK_RTCREF - CLK_ENVM) > > struct mpfs_clock_data { > + struct device *dev; > void __iomem *base; > void __iomem *msspll_base; > struct clk_hw_onecell_data hw_data; > @@ -304,10 +307,6 @@ static int mpfs_periph_clk_enable(struct clk_hw *hw) > > spin_lock_irqsave(&mpfs_clk_lock, flags); > > - reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR); > - val = reg & ~(1u << periph->shift); > - writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR); > - > reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR); > val = reg | (1u << periph->shift); > writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR); > @@ -341,12 +340,9 @@ static int mpfs_periph_clk_is_enabled(struct clk_hw *hw) > void __iomem *base_addr = periph_hw->sys_base; > u32 reg; > > - reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR); > - if ((reg & (1u << periph->shift)) == 0u) { > - reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR); > - if (reg & (1u << periph->shift)) > - return 1; > - } > + reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR); > + if (reg & (1u << periph->shift)) > + return 1; > > return 0; > } > @@ -441,6 +437,94 @@ static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_c > return 0; > } > > +/* > + * Peripheral clock resets > + */ > + > +#if IS_ENABLED(CONFIG_RESET_CONTROLLER) > + > +u32 mpfs_reset_read(struct device *dev) > +{ > + struct mpfs_clock_data *clock_data = dev_get_drvdata(dev->parent); > + > + return readl_relaxed(clock_data->base + REG_SUBBLK_RESET_CR); > +} > +EXPORT_SYMBOL_NS_GPL(mpfs_reset_read, MCHP_CLK_MPFS); > + > +void mpfs_reset_write(struct device *dev, u32 val) > +{ > + struct mpfs_clock_data *clock_data = dev_get_drvdata(dev->parent); > + > + writel_relaxed(val, clock_data->base + REG_SUBBLK_RESET_CR); > +} > +EXPORT_SYMBOL_NS_GPL(mpfs_reset_write, MCHP_CLK_MPFS); > + > +static void mpfs_reset_unregister_adev(void *_adev) > +{ > + struct auxiliary_device *adev = _adev; > + > + auxiliary_device_delete(adev); > +} > + > +static void mpfs_reset_adev_release(struct device *dev) > +{ > + struct auxiliary_device *adev = to_auxiliary_dev(dev); > + > + auxiliary_device_uninit(adev); > + > + kfree(adev); > +} > + > +static struct auxiliary_device *mpfs_reset_adev_alloc(struct mpfs_clock_data *clk_data) > +{ > + struct auxiliary_device *adev; > + int ret; > + > + adev = kzalloc(sizeof(*adev), GFP_KERNEL); > + if (!adev) > + return ERR_PTR(-ENOMEM); > + > + adev->name = "reset-mpfs"; > + adev->dev.parent = clk_data->dev; > + adev->dev.release = mpfs_reset_adev_release; > + adev->id = 666u; > + > + ret = auxiliary_device_init(adev); > + if (ret) { > + kfree(adev); > + return ERR_PTR(ret); > + } > + > + return adev; > +} > + > +static int mpfs_reset_controller_register(struct mpfs_clock_data *clk_data) > +{ > + struct auxiliary_device *adev; > + int ret; > + > + adev = mpfs_reset_adev_alloc(clk_data); > + if (IS_ERR(adev)) > + return PTR_ERR(adev); > + > + ret = auxiliary_device_add(adev); > + if (ret) { > + auxiliary_device_uninit(adev); > + return ret; > + } > + > + return devm_add_action_or_reset(clk_data->dev, mpfs_reset_unregister_adev, adev); > +} > + > +#else /* !CONFIG_RESET_CONTROLLER */ > + > +static int mpfs_reset_controller_register(struct mpfs_clock_data *clk_data) > +{ > + return 0; > +} > + > +#endif /* !CONFIG_RESET_CONTROLLER */ > + > static int mpfs_clk_probe(struct platform_device *pdev) > { > struct device *dev = &pdev->dev; > @@ -465,6 +549,8 @@ static int mpfs_clk_probe(struct platform_device *pdev) > return PTR_ERR(clk_data->msspll_base); > > clk_data->hw_data.num = num_clks; > + clk_data->dev = dev; > + dev_set_drvdata(dev, clk_data); > > ret = mpfs_clk_register_mssplls(dev, mpfs_msspll_clks, ARRAY_SIZE(mpfs_msspll_clks), > clk_data); > @@ -484,14 +570,14 @@ static int mpfs_clk_probe(struct platform_device *pdev) > if (ret) > return ret; > > - return ret; > + return mpfs_reset_controller_register(clk_data); > } > > static const struct of_device_id mpfs_clk_of_match_table[] = { > { .compatible = "microchip,mpfs-clkcfg", }, > {} > }; > -MODULE_DEVICE_TABLE(of, mpfs_clk_match_table); > +MODULE_DEVICE_TABLE(of, mpfs_clk_of_match_table); > > static struct platform_driver mpfs_clk_driver = { > .probe = mpfs_clk_probe, > diff --git a/include/soc/microchip/mpfs.h b/include/soc/microchip/mpfs.h > index 6466515262bd..f916dcde457f 100644 > --- a/include/soc/microchip/mpfs.h > +++ b/include/soc/microchip/mpfs.h > @@ -40,4 +40,12 @@ struct mpfs_sys_controller *mpfs_sys_controller_get(struct device *dev); > > #endif /* if IS_ENABLED(CONFIG_POLARFIRE_SOC_SYS_CTRL) */ > > +#if IS_ENABLED(CONFIG_MCHP_CLK_MPFS) > + > +u32 mpfs_reset_read(struct device *dev); > + > +void mpfs_reset_write(struct device *dev, u32 val); > + > +#endif /* if IS_ENABLED(CONFIG_MCHP_CLK_MPFS) */ > + > #endif /* __SOC_MPFS_H__ */ > -- > 2.36.1 >
diff --git a/drivers/clk/microchip/Kconfig b/drivers/clk/microchip/Kconfig index a5a99873c4f5..b46e864b3bd8 100644 --- a/drivers/clk/microchip/Kconfig +++ b/drivers/clk/microchip/Kconfig @@ -6,5 +6,6 @@ config COMMON_CLK_PIC32 config MCHP_CLK_MPFS bool "Clk driver for PolarFire SoC" depends on (RISCV && SOC_MICROCHIP_POLARFIRE) || COMPILE_TEST + select AUXILIARY_BUS help Supports Clock Configuration for PolarFire SoC diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c index 9e41f07b3fa6..43cc9583cd14 100644 --- a/drivers/clk/microchip/clk-mpfs.c +++ b/drivers/clk/microchip/clk-mpfs.c @@ -3,12 +3,14 @@ * Daire McNamara,<daire.mcnamara@microchip.com> * Copyright (C) 2020 Microchip Technology Inc. All rights reserved. */ +#include <linux/auxiliary_bus.h> #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <dt-bindings/clock/microchip,mpfs-clock.h> +#include <soc/microchip/mpfs.h> /* address offset of control registers */ #define REG_MSSPLL_REF_CR 0x08u @@ -30,6 +32,7 @@ #define RTCREF_OFFSET (CLK_RTCREF - CLK_ENVM) struct mpfs_clock_data { + struct device *dev; void __iomem *base; void __iomem *msspll_base; struct clk_hw_onecell_data hw_data; @@ -304,10 +307,6 @@ static int mpfs_periph_clk_enable(struct clk_hw *hw) spin_lock_irqsave(&mpfs_clk_lock, flags); - reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR); - val = reg & ~(1u << periph->shift); - writel_relaxed(val, base_addr + REG_SUBBLK_RESET_CR); - reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR); val = reg | (1u << periph->shift); writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR); @@ -341,12 +340,9 @@ static int mpfs_periph_clk_is_enabled(struct clk_hw *hw) void __iomem *base_addr = periph_hw->sys_base; u32 reg; - reg = readl_relaxed(base_addr + REG_SUBBLK_RESET_CR); - if ((reg & (1u << periph->shift)) == 0u) { - reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR); - if (reg & (1u << periph->shift)) - return 1; - } + reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR); + if (reg & (1u << periph->shift)) + return 1; return 0; } @@ -441,6 +437,94 @@ static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_c return 0; } +/* + * Peripheral clock resets + */ + +#if IS_ENABLED(CONFIG_RESET_CONTROLLER) + +u32 mpfs_reset_read(struct device *dev) +{ + struct mpfs_clock_data *clock_data = dev_get_drvdata(dev->parent); + + return readl_relaxed(clock_data->base + REG_SUBBLK_RESET_CR); +} +EXPORT_SYMBOL_NS_GPL(mpfs_reset_read, MCHP_CLK_MPFS); + +void mpfs_reset_write(struct device *dev, u32 val) +{ + struct mpfs_clock_data *clock_data = dev_get_drvdata(dev->parent); + + writel_relaxed(val, clock_data->base + REG_SUBBLK_RESET_CR); +} +EXPORT_SYMBOL_NS_GPL(mpfs_reset_write, MCHP_CLK_MPFS); + +static void mpfs_reset_unregister_adev(void *_adev) +{ + struct auxiliary_device *adev = _adev; + + auxiliary_device_delete(adev); +} + +static void mpfs_reset_adev_release(struct device *dev) +{ + struct auxiliary_device *adev = to_auxiliary_dev(dev); + + auxiliary_device_uninit(adev); + + kfree(adev); +} + +static struct auxiliary_device *mpfs_reset_adev_alloc(struct mpfs_clock_data *clk_data) +{ + struct auxiliary_device *adev; + int ret; + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return ERR_PTR(-ENOMEM); + + adev->name = "reset-mpfs"; + adev->dev.parent = clk_data->dev; + adev->dev.release = mpfs_reset_adev_release; + adev->id = 666u; + + ret = auxiliary_device_init(adev); + if (ret) { + kfree(adev); + return ERR_PTR(ret); + } + + return adev; +} + +static int mpfs_reset_controller_register(struct mpfs_clock_data *clk_data) +{ + struct auxiliary_device *adev; + int ret; + + adev = mpfs_reset_adev_alloc(clk_data); + if (IS_ERR(adev)) + return PTR_ERR(adev); + + ret = auxiliary_device_add(adev); + if (ret) { + auxiliary_device_uninit(adev); + return ret; + } + + return devm_add_action_or_reset(clk_data->dev, mpfs_reset_unregister_adev, adev); +} + +#else /* !CONFIG_RESET_CONTROLLER */ + +static int mpfs_reset_controller_register(struct mpfs_clock_data *clk_data) +{ + return 0; +} + +#endif /* !CONFIG_RESET_CONTROLLER */ + static int mpfs_clk_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -465,6 +549,8 @@ static int mpfs_clk_probe(struct platform_device *pdev) return PTR_ERR(clk_data->msspll_base); clk_data->hw_data.num = num_clks; + clk_data->dev = dev; + dev_set_drvdata(dev, clk_data); ret = mpfs_clk_register_mssplls(dev, mpfs_msspll_clks, ARRAY_SIZE(mpfs_msspll_clks), clk_data); @@ -484,14 +570,14 @@ static int mpfs_clk_probe(struct platform_device *pdev) if (ret) return ret; - return ret; + return mpfs_reset_controller_register(clk_data); } static const struct of_device_id mpfs_clk_of_match_table[] = { { .compatible = "microchip,mpfs-clkcfg", }, {} }; -MODULE_DEVICE_TABLE(of, mpfs_clk_match_table); +MODULE_DEVICE_TABLE(of, mpfs_clk_of_match_table); static struct platform_driver mpfs_clk_driver = { .probe = mpfs_clk_probe, diff --git a/include/soc/microchip/mpfs.h b/include/soc/microchip/mpfs.h index 6466515262bd..f916dcde457f 100644 --- a/include/soc/microchip/mpfs.h +++ b/include/soc/microchip/mpfs.h @@ -40,4 +40,12 @@ struct mpfs_sys_controller *mpfs_sys_controller_get(struct device *dev); #endif /* if IS_ENABLED(CONFIG_POLARFIRE_SOC_SYS_CTRL) */ +#if IS_ENABLED(CONFIG_MCHP_CLK_MPFS) + +u32 mpfs_reset_read(struct device *dev); + +void mpfs_reset_write(struct device *dev, u32 val); + +#endif /* if IS_ENABLED(CONFIG_MCHP_CLK_MPFS) */ + #endif /* __SOC_MPFS_H__ */