Hey all,
I know I have not sat on the RFC I sent about the aux. bus parts
for too long, but figured I'd just send the whole thing anyway to all
lists etc.
Kinda two things happening in this series, but I sent it together to
ensure the second part would apply correctly.
The first is the reset controller that I promised after discovering the
issue triggered by CONFIG_PM & the phy not coming up correctly. I have
now removed all the messing with resets from clock enable/disable
functions & now use the aux bus to set up a reset controller driver.
Since I needed something to test it, I hooked up the reset for the
Cadence MACB on PolarFire SoC.
The second part adds rate control for the MSS PLL clock, followed by
some simplifications to the driver & conversions of some custom structs
to the corresponding structs in the framework.
Thanks,
Conor.
FYI, there'll be maintainers conflicts with an obvious resolution in
-next, but I cannot rebase on then b/c unrelated changes have broken
boot there at the moment.
Conor Dooley (14):
dt-bindings: clk: microchip: mpfs: add reset controller support
dt-bindings: net: cdns,macb: document polarfire soc's macb
clk: microchip: mpfs: add reset controller
reset: add polarfire soc reset support
MAINTAINERS: add polarfire soc reset controller
net: macb: add polarfire soc reset support
riscv: dts: microchip: add mpfs specific macb reset support
clk: microchip: mpfs: add module_authors entries
clk: microchip: mpfs: add MSS pll's set & round rate
clk: microchip: mpfs: move id & offset out of clock structs
clk: microchip: mpfs: simplify control reg access
clk: microchip: mpfs: delete 2 line mpfs_clk_register_foo()
clk: microchip: mpfs: convert cfg_clk to clk_divider
clk: microchip: mpfs: convert periph_clk to clk_gate
.../bindings/clock/microchip,mpfs.yaml | 17 +-
.../devicetree/bindings/net/cdns,macb.yaml | 1 +
MAINTAINERS | 1 +
arch/riscv/boot/dts/microchip/mpfs.dtsi | 7 +-
drivers/clk/microchip/Kconfig | 1 +
drivers/clk/microchip/clk-mpfs.c | 377 +++++++++---------
drivers/net/ethernet/cadence/macb_main.c | 25 +-
drivers/reset/Kconfig | 9 +
drivers/reset/Makefile | 2 +-
drivers/reset/reset-mpfs.c | 145 +++++++
include/soc/microchip/mpfs.h | 8 +
11 files changed, 393 insertions(+), 200 deletions(-)
create mode 100644 drivers/reset/reset-mpfs.c
base-commit: b13baccc3850ca8b8cccbf8ed9912dbaa0fdf7f3
--
2.36.1
Add the newly added reset controller for the PolarFire SoC (MPFS) to
the existing MAINTAINERS entry.
Signed-off-by: Conor Dooley <[email protected]>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 1fc9ead83d2a..7b82ffce6c22 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17159,6 +17159,7 @@ L: [email protected]
S: Supported
F: arch/riscv/boot/dts/microchip/
F: drivers/mailbox/mailbox-mpfs.c
+F: drivers/reset/reset-mpfs.c
F: drivers/soc/microchip/
F: include/soc/microchip/mpfs.h
--
2.36.1
To date, the Microchip PolarFire SoC (MPFS) has been using the
cdns,macb compatible, however the generic device does not have reset
support. Add a new compatible & .data for MPFS to hook into the reset
functionality added for zynqmp support (and make the zynqmp init
function generic in the process).
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/net/ethernet/cadence/macb_main.c | 25 +++++++++++++++++-------
1 file changed, 18 insertions(+), 7 deletions(-)
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index d89098f4ede8..325f0463fd42 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -4689,33 +4689,32 @@ static const struct macb_config np4_config = {
.usrio = &macb_default_usrio,
};
-static int zynqmp_init(struct platform_device *pdev)
+static int init_reset_optional(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct macb *bp = netdev_priv(dev);
int ret;
if (bp->phy_interface == PHY_INTERFACE_MODE_SGMII) {
- /* Ensure PS-GTR PHY device used in SGMII mode is ready */
+ /* Ensure PHY device used in SGMII mode is ready */
bp->sgmii_phy = devm_phy_optional_get(&pdev->dev, NULL);
if (IS_ERR(bp->sgmii_phy)) {
ret = PTR_ERR(bp->sgmii_phy);
dev_err_probe(&pdev->dev, ret,
- "failed to get PS-GTR PHY\n");
+ "failed to get SGMII PHY\n");
return ret;
}
ret = phy_init(bp->sgmii_phy);
if (ret) {
- dev_err(&pdev->dev, "failed to init PS-GTR PHY: %d\n",
+ dev_err(&pdev->dev, "failed to init SGMII PHY: %d\n",
ret);
return ret;
}
}
- /* Fully reset GEM controller at hardware level using zynqmp-reset driver,
- * if mapped in device tree.
+ /* Fully reset controller at hardware level if mapped in device tree
*/
ret = device_reset_optional(&pdev->dev);
if (ret) {
@@ -4737,7 +4736,7 @@ static const struct macb_config zynqmp_config = {
MACB_CAPS_GEM_HAS_PTP | MACB_CAPS_BD_RD_PREFETCH,
.dma_burst_length = 16,
.clk_init = macb_clk_init,
- .init = zynqmp_init,
+ .init = init_reset_optional,
.jumbo_max_len = 10240,
.usrio = &macb_default_usrio,
};
@@ -4751,6 +4750,17 @@ static const struct macb_config zynq_config = {
.usrio = &macb_default_usrio,
};
+static const struct macb_config mpfs_config = {
+ .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE |
+ MACB_CAPS_JUMBO |
+ MACB_CAPS_GEM_HAS_PTP,
+ .dma_burst_length = 16,
+ .clk_init = macb_clk_init,
+ .init = init_reset_optional,
+ .usrio = &macb_default_usrio,
+ .jumbo_max_len = 10240,
+};
+
static const struct macb_config sama7g5_gem_config = {
.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_CLK_HW_CHG |
MACB_CAPS_MIIONRGMII,
@@ -4787,6 +4797,7 @@ static const struct of_device_id macb_dt_ids[] = {
{ .compatible = "cdns,zynqmp-gem", .data = &zynqmp_config},
{ .compatible = "cdns,zynq-gem", .data = &zynq_config },
{ .compatible = "sifive,fu540-c000-gem", .data = &fu540_c000_config },
+ { .compatible = "microchip,mpfs-macb", .data = &mpfs_config },
{ .compatible = "microchip,sama7g5-gem", .data = &sama7g5_gem_config },
{ .compatible = "microchip,sama7g5-emac", .data = &sama7g5_emac_config },
{ /* sentinel */ }
--
2.36.1
The macb on PolarFire SoC has reset support which the generic compatible
does not use. Add the newly introduced MPFS specific compatible as the
primary compatible to avail of this support & wire up the reset to the
clock controllers devicetree entry.
Signed-off-by: Conor Dooley <[email protected]>
---
arch/riscv/boot/dts/microchip/mpfs.dtsi | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/arch/riscv/boot/dts/microchip/mpfs.dtsi b/arch/riscv/boot/dts/microchip/mpfs.dtsi
index 8c3259134194..5a33cbf9467a 100644
--- a/arch/riscv/boot/dts/microchip/mpfs.dtsi
+++ b/arch/riscv/boot/dts/microchip/mpfs.dtsi
@@ -197,6 +197,7 @@ clkcfg: clkcfg@20002000 {
reg = <0x0 0x20002000 0x0 0x1000>, <0x0 0x3E001000 0x0 0x1000>;
clocks = <&refclk>;
#clock-cells = <1>;
+ #reset-cells = <1>;
};
mmuart0: serial@20000000 {
@@ -331,7 +332,7 @@ i2c1: i2c@2010b000 {
};
mac0: ethernet@20110000 {
- compatible = "cdns,macb";
+ compatible = "microchip,mpfs-macb", "cdns,macb";
reg = <0x0 0x20110000 0x0 0x2000>;
#address-cells = <1>;
#size-cells = <0>;
@@ -340,11 +341,12 @@ mac0: ethernet@20110000 {
local-mac-address = [00 00 00 00 00 00];
clocks = <&clkcfg CLK_MAC0>, <&clkcfg CLK_AHB>;
clock-names = "pclk", "hclk";
+ resets = <&clkcfg CLK_MAC0>;
status = "disabled";
};
mac1: ethernet@20112000 {
- compatible = "cdns,macb";
+ compatible = "microchip,mpfs-macb", "cdns,macb";
reg = <0x0 0x20112000 0x0 0x2000>;
#address-cells = <1>;
#size-cells = <0>;
@@ -353,6 +355,7 @@ mac1: ethernet@20112000 {
local-mac-address = [00 00 00 00 00 00];
clocks = <&clkcfg CLK_MAC1>, <&clkcfg CLK_AHB>;
clock-names = "pclk", "hclk";
+ resets = <&clkcfg CLK_MAC1>;
status = "disabled";
};
--
2.36.1
The cfg_clk struct is now just a redefinition of the clk_divider struct
with custom implentations of the ops, that implement an extra level of
redirection. Remove the custom struct and replace it with clk_divider.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/clk/microchip/clk-mpfs.c | 75 +++-----------------------------
1 file changed, 7 insertions(+), 68 deletions(-)
diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
index e58d0bc4669a..c4d1c48d6d3d 100644
--- a/drivers/clk/microchip/clk-mpfs.c
+++ b/drivers/clk/microchip/clk-mpfs.c
@@ -51,24 +51,13 @@ struct mpfs_msspll_hw_clock {
#define to_mpfs_msspll_clk(_hw) container_of(_hw, struct mpfs_msspll_hw_clock, hw)
-struct mpfs_cfg_clock {
- void __iomem *reg;
- const struct clk_div_table *table;
- u8 shift;
- u8 width;
- u8 flags;
-};
-
struct mpfs_cfg_hw_clock {
- struct mpfs_cfg_clock cfg;
- struct clk_hw hw;
+ struct clk_divider cfg;
struct clk_init_data init;
unsigned int id;
u32 reg_offset;
};
-#define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw)
-
struct mpfs_periph_clock {
void __iomem *reg;
u8 shift;
@@ -228,56 +217,6 @@ static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_c
* "CFG" clocks
*/
-static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long prate)
-{
- struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
- struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
- u32 val;
-
- val = readl_relaxed(cfg->reg) >> cfg->shift;
- val &= clk_div_mask(cfg->width);
-
- return divider_recalc_rate(hw, prate, val, cfg->table, cfg->flags, cfg->width);
-}
-
-static long mpfs_cfg_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
-{
- struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
- struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
-
- return divider_round_rate(hw, rate, prate, cfg->table, cfg->width, 0);
-}
-
-static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
-{
- struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
- struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
- unsigned long flags;
- u32 val;
- int divider_setting;
-
- divider_setting = divider_get_val(rate, prate, cfg->table, cfg->width, 0);
-
- if (divider_setting < 0)
- return divider_setting;
-
- spin_lock_irqsave(&mpfs_clk_lock, flags);
- val = readl_relaxed(cfg->reg);
- val &= ~(clk_div_mask(cfg->width) << cfg_hw->cfg.shift);
- val |= divider_setting << cfg->shift;
- writel_relaxed(val, cfg->reg);
-
- spin_unlock_irqrestore(&mpfs_clk_lock, flags);
-
- return 0;
-}
-
-static const struct clk_ops mpfs_clk_cfg_ops = {
- .recalc_rate = mpfs_cfg_clk_recalc_rate,
- .round_rate = mpfs_cfg_clk_round_rate,
- .set_rate = mpfs_cfg_clk_set_rate,
-};
-
#define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags, _offset) { \
.id = _id, \
.cfg.shift = _shift, \
@@ -285,7 +224,7 @@ static const struct clk_ops mpfs_clk_cfg_ops = {
.cfg.table = _table, \
.reg_offset = _offset, \
.cfg.flags = _flags, \
- .hw.init = CLK_HW_INIT(_name, _parent, &mpfs_clk_cfg_ops, 0), \
+ .cfg.hw.init = CLK_HW_INIT(_name, _parent, &clk_divider_ops, 0), \
}
static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
@@ -302,8 +241,8 @@ static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
.cfg.table = mpfs_div_rtcref_table,
.reg_offset = REG_RTC_CLOCK_CR,
.cfg.flags = CLK_DIVIDER_ONE_BASED,
- .hw.init =
- CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &mpfs_clk_cfg_ops, 0),
+ .cfg.hw.init =
+ CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &clk_divider_ops, 0),
}
};
@@ -317,13 +256,13 @@ static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *
struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i];
cfg_hw->cfg.reg = data->base + cfg_hw->reg_offset;
- ret = devm_clk_hw_register(dev, &cfg_hw->hw);
+ ret = devm_clk_hw_register(dev, &cfg_hw->cfg.hw);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
cfg_hw->id);
id = cfg_hw->id;
- data->hw_data.hws[id] = &cfg_hw->hw;
+ data->hw_data.hws[id] = &cfg_hw->cfg.hw;
}
return 0;
@@ -393,7 +332,7 @@ static const struct clk_ops mpfs_periph_clk_ops = {
_flags), \
}
-#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT].hw)
+#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT].cfg.hw)
/*
* Critical clocks:
--
2.36.1
Until now the PolarFire SoC (MPFS) has been using the generic
"cdns,macb" compatible but has optional reset support. Add a specific
compatible which falls back to the currently used generic binding.
Signed-off-by: Conor Dooley <[email protected]>
---
Documentation/devicetree/bindings/net/cdns,macb.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/net/cdns,macb.yaml b/Documentation/devicetree/bindings/net/cdns,macb.yaml
index 86fc31c2d91b..9c92156869b2 100644
--- a/Documentation/devicetree/bindings/net/cdns,macb.yaml
+++ b/Documentation/devicetree/bindings/net/cdns,macb.yaml
@@ -28,6 +28,7 @@ properties:
- enum:
- cdns,at91sam9260-macb # Atmel at91sam9 SoCs
- cdns,sam9x60-macb # Microchip sam9x60 SoC
+ - microchip,mpfs-macb # Microchip PolarFire SoC
- const: cdns,macb # Generic
- items:
--
2.36.1
The MSS pll is not a fixed frequency clock, so add set() & round_rate()
support.
Control is limited to a 7 bit output divider as other devices on the
FPGA occupy the other three outputs of the PLL & prevent changing
the multiplier.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/clk/microchip/clk-mpfs.c | 54 ++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
index c7cafd61b7f7..a23f63bcd074 100644
--- a/drivers/clk/microchip/clk-mpfs.c
+++ b/drivers/clk/microchip/clk-mpfs.c
@@ -131,8 +131,62 @@ static unsigned long mpfs_clk_msspll_recalc_rate(struct clk_hw *hw, unsigned lon
return prate * mult / (ref_div * MSSPLL_FIXED_DIV * postdiv);
}
+static long mpfs_clk_msspll_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
+{
+ struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
+ void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
+ void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
+ u32 mult, ref_div;
+ unsigned long rate_before_ctrl;
+
+ mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
+ mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
+ ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
+ ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);
+
+ rate_before_ctrl = rate * (ref_div * MSSPLL_FIXED_DIV) / mult;
+
+ return divider_round_rate(hw, rate_before_ctrl, prate, NULL, MSSPLL_POSTDIV_WIDTH,
+ msspll_hw->flags);
+}
+
+static int mpfs_clk_msspll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
+{
+ struct mpfs_msspll_hw_clock *msspll_hw = to_mpfs_msspll_clk(hw);
+ void __iomem *mult_addr = msspll_hw->base + msspll_hw->reg_offset;
+ void __iomem *ref_div_addr = msspll_hw->base + REG_MSSPLL_REF_CR;
+ void __iomem *postdiv_addr = msspll_hw->base + REG_MSSPLL_POSTDIV_CR;
+ u32 mult, ref_div, postdiv;
+ int divider_setting;
+ unsigned long rate_before_ctrl, flags;
+
+ mult = readl_relaxed(mult_addr) >> MSSPLL_FBDIV_SHIFT;
+ mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH);
+ ref_div = readl_relaxed(ref_div_addr) >> MSSPLL_REFDIV_SHIFT;
+ ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH);
+
+ rate_before_ctrl = rate * (ref_div * MSSPLL_FIXED_DIV) / mult;
+ divider_setting = divider_get_val(rate_before_ctrl, prate, NULL, MSSPLL_POSTDIV_WIDTH,
+ msspll_hw->flags);
+
+ if (divider_setting < 0)
+ return divider_setting;
+
+ spin_lock_irqsave(&mpfs_clk_lock, flags);
+
+ postdiv = readl_relaxed(postdiv_addr);
+ postdiv &= ~(clk_div_mask(MSSPLL_POSTDIV_WIDTH) << MSSPLL_POSTDIV_SHIFT);
+ writel_relaxed(postdiv, postdiv_addr);
+
+ spin_unlock_irqrestore(&mpfs_clk_lock, flags);
+
+ return 0;
+}
+
static const struct clk_ops mpfs_clk_msspll_ops = {
.recalc_rate = mpfs_clk_msspll_recalc_rate,
+ .round_rate = mpfs_clk_msspll_round_rate,
+ .set_rate = mpfs_clk_msspll_set_rate,
};
#define CLK_PLL(_id, _name, _parent, _shift, _width, _flags, _offset) { \
--
2.36.1
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.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/clk/microchip/Kconfig | 1 +
drivers/clk/microchip/clk-mpfs.c | 116 ++++++++++++++++++++++++++++---
include/soc/microchip/mpfs.h | 8 +++
3 files changed, 114 insertions(+), 11 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 070c3b896559..a93f78619dc3 100644
--- a/drivers/clk/microchip/clk-mpfs.c
+++ b/drivers/clk/microchip/clk-mpfs.c
@@ -3,12 +3,14 @@
* Daire McNamara,<[email protected]>
* 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
@@ -28,6 +30,7 @@
#define MSSPLL_FIXED_DIV 4u
struct mpfs_clock_data {
+ struct device *dev;
void __iomem *base;
void __iomem *msspll_base;
struct clk_hw_onecell_data hw_data;
@@ -302,10 +305,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);
@@ -339,12 +338,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;
}
@@ -438,6 +434,98 @@ 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;
+ }
+
+ ret = devm_add_action_or_reset(clk_data->dev, mpfs_reset_unregister_adev, adev);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+#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;
@@ -462,6 +550,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);
@@ -481,6 +571,10 @@ static int mpfs_clk_probe(struct platform_device *pdev)
if (ret)
return ret;
+ ret = mpfs_reset_controller_register(clk_data);
+ if (ret)
+ return ret;
+
return ret;
}
@@ -488,7 +582,7 @@ 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
The id and offset are the only thing differentiating the clock structs
from "regular" clock structures. On the pretext of converting to more
normal structures, move the id and offset out of the clock structs and
into the hw structs instead.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/clk/microchip/clk-mpfs.c | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
index a23f63bcd074..750f28481498 100644
--- a/drivers/clk/microchip/clk-mpfs.c
+++ b/drivers/clk/microchip/clk-mpfs.c
@@ -53,8 +53,6 @@ struct mpfs_msspll_hw_clock {
struct mpfs_cfg_clock {
const struct clk_div_table *table;
- unsigned int id;
- u32 reg_offset;
u8 shift;
u8 width;
u8 flags;
@@ -65,12 +63,13 @@ struct mpfs_cfg_hw_clock {
void __iomem *sys_base;
struct clk_hw hw;
struct clk_init_data init;
+ unsigned int id;
+ u32 reg_offset;
};
#define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw)
struct mpfs_periph_clock {
- unsigned int id;
u8 shift;
};
@@ -78,6 +77,7 @@ struct mpfs_periph_hw_clock {
struct mpfs_periph_clock periph;
void __iomem *sys_base;
struct clk_hw hw;
+ unsigned int id;
};
#define to_mpfs_periph_clk(_hw) container_of(_hw, struct mpfs_periph_hw_clock, hw)
@@ -243,7 +243,7 @@ static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long p
void __iomem *base_addr = cfg_hw->sys_base;
u32 val;
- val = readl_relaxed(base_addr + cfg->reg_offset) >> cfg->shift;
+ val = readl_relaxed(base_addr + cfg_hw->reg_offset) >> cfg->shift;
val &= clk_div_mask(cfg->width);
return divider_recalc_rate(hw, prate, val, cfg->table, cfg->flags, cfg->width);
@@ -272,10 +272,10 @@ static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned
return divider_setting;
spin_lock_irqsave(&mpfs_clk_lock, flags);
- val = readl_relaxed(base_addr + cfg->reg_offset);
+ val = readl_relaxed(base_addr + cfg_hw->reg_offset);
val &= ~(clk_div_mask(cfg->width) << cfg_hw->cfg.shift);
val |= divider_setting << cfg->shift;
- writel_relaxed(val, base_addr + cfg->reg_offset);
+ writel_relaxed(val, base_addr + cfg_hw->reg_offset);
spin_unlock_irqrestore(&mpfs_clk_lock, flags);
@@ -289,11 +289,11 @@ static const struct clk_ops mpfs_clk_cfg_ops = {
};
#define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags, _offset) { \
- .cfg.id = _id, \
+ .id = _id, \
.cfg.shift = _shift, \
.cfg.width = _width, \
.cfg.table = _table, \
- .cfg.reg_offset = _offset, \
+ .reg_offset = _offset, \
.cfg.flags = _flags, \
.hw.init = CLK_HW_INIT(_name, _parent, &mpfs_clk_cfg_ops, 0), \
}
@@ -306,11 +306,11 @@ static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
CLK_CFG(CLK_AHB, "clk_ahb", "clk_msspll", 4, 2, mpfs_div_ahb_table, 0,
REG_CLOCK_CONFIG_CR),
{
- .cfg.id = CLK_RTCREF,
+ .id = CLK_RTCREF,
.cfg.shift = 0,
.cfg.width = 12,
.cfg.table = mpfs_div_rtcref_table,
- .cfg.reg_offset = REG_RTC_CLOCK_CR,
+ .reg_offset = REG_RTC_CLOCK_CR,
.cfg.flags = CLK_DIVIDER_ONE_BASED,
.hw.init =
CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &mpfs_clk_cfg_ops, 0),
@@ -338,9 +338,9 @@ static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *
ret = mpfs_clk_register_cfg(dev, cfg_hw, sys_base);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
- cfg_hw->cfg.id);
+ cfg_hw->id);
- id = cfg_hw->cfg.id;
+ id = cfg_hw->id;
data->hw_data.hws[id] = &cfg_hw->hw;
}
@@ -408,7 +408,7 @@ static const struct clk_ops mpfs_periph_clk_ops = {
};
#define CLK_PERIPH(_id, _name, _parent, _shift, _flags) { \
- .periph.id = _id, \
+ .id = _id, \
.periph.shift = _shift, \
.hw.init = CLK_HW_INIT_HW(_name, _parent, &mpfs_periph_clk_ops, \
_flags), \
@@ -481,9 +481,9 @@ static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_c
ret = mpfs_clk_register_periph(dev, periph_hw, sys_base);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
- periph_hw->periph.id);
+ periph_hw->id);
- id = periph_hws[i].periph.id;
+ id = periph_hws[i].id;
data->hw_data.hws[id] = &periph_hw->hw;
}
--
2.36.1
With the reset code moved to the recently added reset controller, there
is no need for custom ops any longer. Remove the custom ops and the
custom struct by converting to a clk_gate.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/clk/microchip/clk-mpfs.c | 73 +++-----------------------------
1 file changed, 6 insertions(+), 67 deletions(-)
diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
index c4d1c48d6d3d..9c3bff4f147a 100644
--- a/drivers/clk/microchip/clk-mpfs.c
+++ b/drivers/clk/microchip/clk-mpfs.c
@@ -58,19 +58,11 @@ struct mpfs_cfg_hw_clock {
u32 reg_offset;
};
-struct mpfs_periph_clock {
- void __iomem *reg;
- u8 shift;
-};
-
struct mpfs_periph_hw_clock {
- struct mpfs_periph_clock periph;
- struct clk_hw hw;
+ struct clk_gate periph;
unsigned int id;
};
-#define to_mpfs_periph_clk(_hw) container_of(_hw, struct mpfs_periph_hw_clock, hw)
-
/*
* mpfs_clk_lock prevents anything else from writing to the
* mpfs clk block while a software locked register is being written.
@@ -272,63 +264,10 @@ static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *
* peripheral clocks - devices connected to axi or ahb buses.
*/
-static int mpfs_periph_clk_enable(struct clk_hw *hw)
-{
- struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
- struct mpfs_periph_clock *periph = &periph_hw->periph;
- u32 reg, val;
- unsigned long flags;
-
- spin_lock_irqsave(&mpfs_clk_lock, flags);
-
- reg = readl_relaxed(periph->reg);
- val = reg | (1u << periph->shift);
- writel_relaxed(val, periph->reg);
-
- spin_unlock_irqrestore(&mpfs_clk_lock, flags);
-
- return 0;
-}
-
-static void mpfs_periph_clk_disable(struct clk_hw *hw)
-{
- struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
- struct mpfs_periph_clock *periph = &periph_hw->periph;
- u32 reg, val;
- unsigned long flags;
-
- spin_lock_irqsave(&mpfs_clk_lock, flags);
-
- reg = readl_relaxed(periph->reg);
- val = reg & ~(1u << periph->shift);
- writel_relaxed(val, periph->reg);
-
- spin_unlock_irqrestore(&mpfs_clk_lock, flags);
-}
-
-static int mpfs_periph_clk_is_enabled(struct clk_hw *hw)
-{
- struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
- struct mpfs_periph_clock *periph = &periph_hw->periph;
- u32 reg;
-
- reg = readl_relaxed(periph->reg);
- if (reg & (1u << periph->shift))
- return 1;
-
- return 0;
-}
-
-static const struct clk_ops mpfs_periph_clk_ops = {
- .enable = mpfs_periph_clk_enable,
- .disable = mpfs_periph_clk_disable,
- .is_enabled = mpfs_periph_clk_is_enabled,
-};
-
#define CLK_PERIPH(_id, _name, _parent, _shift, _flags) { \
- .id = _id, \
- .periph.shift = _shift, \
- .hw.init = CLK_HW_INIT_HW(_name, _parent, &mpfs_periph_clk_ops, \
+ .id = _id, \
+ .periph.bit_idx = _shift, \
+ .periph.hw.init = CLK_HW_INIT_HW(_name, _parent, &clk_gate_ops, \
_flags), \
}
@@ -388,13 +327,13 @@ static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_c
struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i];
periph_hw->periph.reg = data->base + REG_SUBBLK_CLOCK_CR;
- ret = devm_clk_hw_register(dev, &periph_hw->hw);
+ ret = devm_clk_hw_register(dev, &periph_hw->periph.hw);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
periph_hw->id);
id = periph_hws[i].id;
- data->hw_data.hws[id] = &periph_hw->hw;
+ data->hw_data.hws[id] = &periph_hw->periph.hw;
}
return 0;
--
2.36.1
Add support for the resets on Microchip's PolarFire SoC (MPFS).
Reset control is a single register, wedged in between registers for
clock control. To fit with existed DT etc, the reset controller is
created using the aux device framework & set up in the clock driver.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/reset/Kconfig | 9 +++
drivers/reset/Makefile | 2 +-
drivers/reset/reset-mpfs.c | 145 +++++++++++++++++++++++++++++++++++++
3 files changed, 155 insertions(+), 1 deletion(-)
create mode 100644 drivers/reset/reset-mpfs.c
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 93c8d07ee328..edf48951f763 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -122,6 +122,15 @@ config RESET_MCHP_SPARX5
help
This driver supports switch core reset for the Microchip Sparx5 SoC.
+config RESET_POLARFIRE_SOC
+ bool "Microchip PolarFire SoC (MPFS) Reset Driver"
+ depends on AUXILIARY_BUS && MCHP_CLK_MPFS
+ default MCHP_CLK_MPFS
+ help
+ This driver supports peripheral reset for the Microchip PolarFire SoC
+
+ CONFIG_RESET_MPFS
+
config RESET_MESON
tristate "Meson Reset Driver"
depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index a80a9c4008a7..5fac3a753858 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_RESET_K210) += reset-k210.o
obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o
+obj-$(CONFIG_RESET_POLARFIRE_SOC) += reset-mpfs.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
obj-$(CONFIG_RESET_NPCM) += reset-npcm.o
@@ -38,4 +39,3 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
-
diff --git a/drivers/reset/reset-mpfs.c b/drivers/reset/reset-mpfs.c
new file mode 100644
index 000000000000..49c47a3e6c70
--- /dev/null
+++ b/drivers/reset/reset-mpfs.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PolarFire SoC (MPFS) Peripheral Clock Reset Controller
+ *
+ * Author: Conor Dooley <[email protected]>
+ * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
+ *
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <dt-bindings/clock/microchip,mpfs-clock.h>
+#include <soc/microchip/mpfs.h>
+
+/*
+ * The ENVM reset is the lowest bit in the register & I am using the CLK_FOO
+ * defines in the dt to make things easier to configure - so this is accounting
+ * for the offset of 3 there.
+ */
+#define MPFS_PERIPH_OFFSET CLK_ENVM
+#define MPFS_NUM_RESETS 30u
+#define MPFS_SLEEP_MIN_US 100
+#define MPFS_SLEEP_MAX_US 200
+
+/*
+ * Peripheral clock resets
+ */
+
+static int mpfs_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ u32 reg;
+
+ reg = mpfs_reset_read(rcdev->dev);
+ reg |= (1u << id);
+ mpfs_reset_write(rcdev->dev, reg);
+
+ return 0;
+}
+
+static int mpfs_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ u32 reg, val;
+
+ reg = mpfs_reset_read(rcdev->dev);
+ val = reg & ~(1u << id);
+ mpfs_reset_write(rcdev->dev, val);
+
+ return 0;
+}
+
+static int mpfs_status(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ u32 reg = mpfs_reset_read(rcdev->dev);
+
+ return (reg & (1u << id));
+}
+
+static int mpfs_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ mpfs_assert(rcdev, id);
+
+ usleep_range(MPFS_SLEEP_MIN_US, MPFS_SLEEP_MAX_US);
+
+ mpfs_deassert(rcdev, id);
+
+ return 0;
+}
+
+static const struct reset_control_ops mpfs_reset_ops = {
+ .reset = mpfs_reset,
+ .assert = mpfs_assert,
+ .deassert = mpfs_deassert,
+ .status = mpfs_status,
+};
+
+static int mpfs_reset_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ unsigned int index = reset_spec->args[0];
+
+ /*
+ * CLK_RESERVED does not map to a clock, but it does map to a reset,
+ * so it has to be accounted for here. It is the reset for the fabric,
+ * so if this reset gets called - do not reset it.
+ */
+ if (index == CLK_RESERVED) {
+ dev_err(rcdev->dev, "Resetting the fabric is not supported\n");
+ return -EINVAL;
+ }
+
+ if (index < MPFS_PERIPH_OFFSET || index >= (MPFS_PERIPH_OFFSET + rcdev->nr_resets)) {
+ dev_err(rcdev->dev, "Invalid reset index %u\n", reset_spec->args[0]);
+ return -EINVAL;
+ }
+
+ return index - MPFS_PERIPH_OFFSET;
+}
+
+static int mpfs_reset_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct device *dev = &adev->dev;
+ struct reset_controller_dev *rcdev;
+ int ret;
+
+ rcdev = devm_kzalloc(dev, sizeof(*rcdev), GFP_KERNEL);
+ if (!rcdev)
+ return -ENOMEM;
+
+ rcdev->dev = dev;
+ rcdev->dev->parent = adev->dev.parent;
+ rcdev->ops = &mpfs_reset_ops;
+ rcdev->of_node = adev->dev.parent->of_node;
+ rcdev->of_reset_n_cells = 1;
+ rcdev->of_xlate = mpfs_reset_xlate;
+ rcdev->nr_resets = MPFS_NUM_RESETS;
+
+ ret = devm_reset_controller_register(dev, rcdev);
+ if (!ret)
+ dev_info(dev, "Registered MPFS reset controller\n");
+
+ return ret;
+}
+
+static const struct auxiliary_device_id mpfs_reset_ids[] = {
+ {
+ .name = "clk_mpfs.reset-mpfs",
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(auxiliary, mpfs_reset_ids);
+
+static struct auxiliary_driver mpfs_reset_driver = {
+ .probe = mpfs_reset_probe,
+ .id_table = mpfs_reset_ids,
+};
+
+module_auxiliary_driver(mpfs_reset_driver);
+
+MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver");
+MODULE_AUTHOR("Conor Dooley <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(MCHP_CLK_MPFS);
--
2.36.1
The "peripheral" devices on PolarFire SoC can be put into reset, so
update the device tree binding to reflect the presence of a reset
controller.
Signed-off-by: Conor Dooley <[email protected]>
---
.../bindings/clock/microchip,mpfs.yaml | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/clock/microchip,mpfs.yaml b/Documentation/devicetree/bindings/clock/microchip,mpfs.yaml
index 016a4f378b9b..1d0b6a4fda42 100644
--- a/Documentation/devicetree/bindings/clock/microchip,mpfs.yaml
+++ b/Documentation/devicetree/bindings/clock/microchip,mpfs.yaml
@@ -40,8 +40,21 @@ properties:
const: 1
description: |
The clock consumer should specify the desired clock by having the clock
- ID in its "clocks" phandle cell. See include/dt-bindings/clock/microchip,mpfs-clock.h
- for the full list of PolarFire clock IDs.
+ ID in its "clocks" phandle cell.
+ See include/dt-bindings/clock/microchip,mpfs-clock.h for the full list of
+ PolarFire clock IDs.
+
+ resets:
+ maxItems: 1
+
+ '#reset-cells':
+ description:
+ The AHB/AXI peripherals on the PolarFire SoC have reset support, so from
+ CLK_ENVM to CLK_CFM. The reset consumer should specify the desired
+ peripheral via the clock ID in its "resets" phandle cell.
+ See include/dt-bindings/clock/microchip,mpfs-clock.h for the full list of
+ PolarFire clock IDs.
+ const: 1
required:
- compatible
--
2.36.1
The control reg addresses are known when the clocks are registered, so
we can, instead of assigning a base pointer to the structs, assign the
control reg addresses directly. Accordingly, remove the interim
variables used during reads/writes to those registers.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/clk/microchip/clk-mpfs.c | 42 +++++++++++++-------------------
1 file changed, 17 insertions(+), 25 deletions(-)
diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
index 750f28481498..0330c2839a24 100644
--- a/drivers/clk/microchip/clk-mpfs.c
+++ b/drivers/clk/microchip/clk-mpfs.c
@@ -52,6 +52,7 @@ struct mpfs_msspll_hw_clock {
#define to_mpfs_msspll_clk(_hw) container_of(_hw, struct mpfs_msspll_hw_clock, hw)
struct mpfs_cfg_clock {
+ void __iomem *reg;
const struct clk_div_table *table;
u8 shift;
u8 width;
@@ -60,7 +61,6 @@ struct mpfs_cfg_clock {
struct mpfs_cfg_hw_clock {
struct mpfs_cfg_clock cfg;
- void __iomem *sys_base;
struct clk_hw hw;
struct clk_init_data init;
unsigned int id;
@@ -70,12 +70,12 @@ struct mpfs_cfg_hw_clock {
#define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw)
struct mpfs_periph_clock {
+ void __iomem *reg;
u8 shift;
};
struct mpfs_periph_hw_clock {
struct mpfs_periph_clock periph;
- void __iomem *sys_base;
struct clk_hw hw;
unsigned int id;
};
@@ -214,14 +214,13 @@ static int mpfs_clk_register_msspll(struct device *dev, struct mpfs_msspll_hw_cl
static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_clock *msspll_hws,
unsigned int num_clks, struct mpfs_clock_data *data)
{
- void __iomem *base = data->msspll_base;
unsigned int i;
int ret;
for (i = 0; i < num_clks; i++) {
struct mpfs_msspll_hw_clock *msspll_hw = &msspll_hws[i];
- ret = mpfs_clk_register_msspll(dev, msspll_hw, base);
+ ret = mpfs_clk_register_msspll(dev, msspll_hw, data->msspll_base);
if (ret)
return dev_err_probe(dev, ret, "failed to register msspll id: %d\n",
CLK_MSSPLL);
@@ -240,10 +239,9 @@ static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long p
{
struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
- void __iomem *base_addr = cfg_hw->sys_base;
u32 val;
- val = readl_relaxed(base_addr + cfg_hw->reg_offset) >> cfg->shift;
+ val = readl_relaxed(cfg->reg) >> cfg->shift;
val &= clk_div_mask(cfg->width);
return divider_recalc_rate(hw, prate, val, cfg->table, cfg->flags, cfg->width);
@@ -261,7 +259,6 @@ static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned
{
struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
- void __iomem *base_addr = cfg_hw->sys_base;
unsigned long flags;
u32 val;
int divider_setting;
@@ -272,10 +269,10 @@ static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned
return divider_setting;
spin_lock_irqsave(&mpfs_clk_lock, flags);
- val = readl_relaxed(base_addr + cfg_hw->reg_offset);
+ val = readl_relaxed(cfg->reg);
val &= ~(clk_div_mask(cfg->width) << cfg_hw->cfg.shift);
val |= divider_setting << cfg->shift;
- writel_relaxed(val, base_addr + cfg_hw->reg_offset);
+ writel_relaxed(val, cfg->reg);
spin_unlock_irqrestore(&mpfs_clk_lock, flags);
@@ -318,9 +315,9 @@ static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
};
static int mpfs_clk_register_cfg(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hw,
- void __iomem *sys_base)
+ void __iomem *base)
{
- cfg_hw->sys_base = sys_base;
+ cfg_hw->cfg.reg = base + cfg_hw->reg_offset;
return devm_clk_hw_register(dev, &cfg_hw->hw);
}
@@ -328,14 +325,13 @@ static int mpfs_clk_register_cfg(struct device *dev, struct mpfs_cfg_hw_clock *c
static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hws,
unsigned int num_clks, struct mpfs_clock_data *data)
{
- void __iomem *sys_base = data->base;
unsigned int i, id;
int ret;
for (i = 0; i < num_clks; i++) {
struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i];
- ret = mpfs_clk_register_cfg(dev, cfg_hw, sys_base);
+ ret = mpfs_clk_register_cfg(dev, cfg_hw, data->base);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
cfg_hw->id);
@@ -355,15 +351,14 @@ static int mpfs_periph_clk_enable(struct clk_hw *hw)
{
struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
struct mpfs_periph_clock *periph = &periph_hw->periph;
- void __iomem *base_addr = periph_hw->sys_base;
u32 reg, val;
unsigned long flags;
spin_lock_irqsave(&mpfs_clk_lock, flags);
- reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
+ reg = readl_relaxed(periph->reg);
val = reg | (1u << periph->shift);
- writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR);
+ writel_relaxed(val, periph->reg);
spin_unlock_irqrestore(&mpfs_clk_lock, flags);
@@ -374,15 +369,14 @@ static void mpfs_periph_clk_disable(struct clk_hw *hw)
{
struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
struct mpfs_periph_clock *periph = &periph_hw->periph;
- void __iomem *base_addr = periph_hw->sys_base;
u32 reg, val;
unsigned long flags;
spin_lock_irqsave(&mpfs_clk_lock, flags);
- reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
+ reg = readl_relaxed(periph->reg);
val = reg & ~(1u << periph->shift);
- writel_relaxed(val, base_addr + REG_SUBBLK_CLOCK_CR);
+ writel_relaxed(val, periph->reg);
spin_unlock_irqrestore(&mpfs_clk_lock, flags);
}
@@ -391,10 +385,9 @@ static int mpfs_periph_clk_is_enabled(struct clk_hw *hw)
{
struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw);
struct mpfs_periph_clock *periph = &periph_hw->periph;
- void __iomem *base_addr = periph_hw->sys_base;
u32 reg;
- reg = readl_relaxed(base_addr + REG_SUBBLK_CLOCK_CR);
+ reg = readl_relaxed(periph->reg);
if (reg & (1u << periph->shift))
return 1;
@@ -461,9 +454,9 @@ static struct mpfs_periph_hw_clock mpfs_periph_clks[] = {
};
static int mpfs_clk_register_periph(struct device *dev, struct mpfs_periph_hw_clock *periph_hw,
- void __iomem *sys_base)
+ void __iomem *base)
{
- periph_hw->sys_base = sys_base;
+ periph_hw->periph.reg = base + REG_SUBBLK_CLOCK_CR;
return devm_clk_hw_register(dev, &periph_hw->hw);
}
@@ -471,14 +464,13 @@ static int mpfs_clk_register_periph(struct device *dev, struct mpfs_periph_hw_cl
static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_clock *periph_hws,
int num_clks, struct mpfs_clock_data *data)
{
- void __iomem *sys_base = data->base;
unsigned int i, id;
int ret;
for (i = 0; i < num_clks; i++) {
struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i];
- ret = mpfs_clk_register_periph(dev, periph_hw, sys_base);
+ ret = mpfs_clk_register_periph(dev, periph_hw, data->base);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
periph_hw->id);
--
2.36.1
The register functions are now comprised of only a single operation
each and no longer add anything to the driver. Delete them.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/clk/microchip/clk-mpfs.c | 33 ++++++--------------------------
1 file changed, 6 insertions(+), 27 deletions(-)
diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
index 0330c2839a24..e58d0bc4669a 100644
--- a/drivers/clk/microchip/clk-mpfs.c
+++ b/drivers/clk/microchip/clk-mpfs.c
@@ -203,14 +203,6 @@ static struct mpfs_msspll_hw_clock mpfs_msspll_clks[] = {
MSSPLL_FBDIV_WIDTH, 0, REG_MSSPLL_SSCG_2_CR),
};
-static int mpfs_clk_register_msspll(struct device *dev, struct mpfs_msspll_hw_clock *msspll_hw,
- void __iomem *base)
-{
- msspll_hw->base = base;
-
- return devm_clk_hw_register(dev, &msspll_hw->hw);
-}
-
static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_clock *msspll_hws,
unsigned int num_clks, struct mpfs_clock_data *data)
{
@@ -220,7 +212,8 @@ static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_c
for (i = 0; i < num_clks; i++) {
struct mpfs_msspll_hw_clock *msspll_hw = &msspll_hws[i];
- ret = mpfs_clk_register_msspll(dev, msspll_hw, data->msspll_base);
+ msspll_hw->base = data->msspll_base;
+ ret = devm_clk_hw_register(dev, &msspll_hw->hw);
if (ret)
return dev_err_probe(dev, ret, "failed to register msspll id: %d\n",
CLK_MSSPLL);
@@ -314,14 +307,6 @@ static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
}
};
-static int mpfs_clk_register_cfg(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hw,
- void __iomem *base)
-{
- cfg_hw->cfg.reg = base + cfg_hw->reg_offset;
-
- return devm_clk_hw_register(dev, &cfg_hw->hw);
-}
-
static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *cfg_hws,
unsigned int num_clks, struct mpfs_clock_data *data)
{
@@ -331,7 +316,8 @@ static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *
for (i = 0; i < num_clks; i++) {
struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i];
- ret = mpfs_clk_register_cfg(dev, cfg_hw, data->base);
+ cfg_hw->cfg.reg = data->base + cfg_hw->reg_offset;
+ ret = devm_clk_hw_register(dev, &cfg_hw->hw);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
cfg_hw->id);
@@ -453,14 +439,6 @@ static struct mpfs_periph_hw_clock mpfs_periph_clks[] = {
CLK_PERIPH(CLK_CFM, "clk_periph_cfm", PARENT_CLK(AHB), 29, 0),
};
-static int mpfs_clk_register_periph(struct device *dev, struct mpfs_periph_hw_clock *periph_hw,
- void __iomem *base)
-{
- periph_hw->periph.reg = base + REG_SUBBLK_CLOCK_CR;
-
- return devm_clk_hw_register(dev, &periph_hw->hw);
-}
-
static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_clock *periph_hws,
int num_clks, struct mpfs_clock_data *data)
{
@@ -470,7 +448,8 @@ static int mpfs_clk_register_periphs(struct device *dev, struct mpfs_periph_hw_c
for (i = 0; i < num_clks; i++) {
struct mpfs_periph_hw_clock *periph_hw = &periph_hws[i];
- ret = mpfs_clk_register_periph(dev, periph_hw, data->base);
+ periph_hw->periph.reg = data->base + REG_SUBBLK_CLOCK_CR;
+ ret = devm_clk_hw_register(dev, &periph_hw->hw);
if (ret)
return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
periph_hw->id);
--
2.36.1
Add myself and Daire as authors since we were mainly responsible for the
drivers development.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/clk/microchip/clk-mpfs.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
index a93f78619dc3..c7cafd61b7f7 100644
--- a/drivers/clk/microchip/clk-mpfs.c
+++ b/drivers/clk/microchip/clk-mpfs.c
@@ -1,7 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
- * Daire McNamara,<[email protected]>
- * Copyright (C) 2020 Microchip Technology Inc. All rights reserved.
+ * Author: Daire McNamara <[email protected]>
+ * Author: Conor Dooley <[email protected]>
+ *
+ * Copyright (C) 2020-2022 Microchip Technology Inc. All rights reserved.
*/
#include <linux/auxiliary_bus.h>
#include <linux/clk-provider.h>
@@ -605,4 +607,6 @@ static void __exit clk_mpfs_exit(void)
module_exit(clk_mpfs_exit);
MODULE_DESCRIPTION("Microchip PolarFire SoC Clock Driver");
+MODULE_AUTHOR("Daire McNamara <[email protected]>");
+MODULE_AUTHOR("Conor Dooley <[email protected]>");
MODULE_LICENSE("GPL v2");
--
2.36.1
Hi Conor,
On Do, 2022-06-30 at 09:05 +0100, Conor Dooley wrote:
Add support for the resets on Microchip's PolarFire SoC (MPFS).
Reset control is a single register, wedged in between registers for
clock control. To fit with existed DT etc, the reset controller is
existing ^
created using the aux device framework & set up in the clock driver.
Signed-off-by: Conor Dooley <[email protected]>
---
drivers/reset/Kconfig | 9 +++
drivers/reset/Makefile | 2 +-
drivers/reset/reset-mpfs.c | 145 +++++++++++++++++++++++++++++++++++++
3 files changed, 155 insertions(+), 1 deletion(-)
create mode 100644 drivers/reset/reset-mpfs.c
diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
index 93c8d07ee328..edf48951f763 100644
--- a/drivers/reset/Kconfig
+++ b/drivers/reset/Kconfig
@@ -122,6 +122,15 @@ config RESET_MCHP_SPARX5
help
This driver supports switch core reset for the Microchip Sparx5 SoC.
+config RESET_POLARFIRE_SOC
+ bool "Microchip PolarFire SoC (MPFS) Reset Driver"
+ depends on AUXILIARY_BUS && MCHP_CLK_MPFS
+ default MCHP_CLK_MPFS
+ help
+ This driver supports peripheral reset for the Microchip PolarFire SoC
+
+ CONFIG_RESET_MPFS
This doesn't look intentional.
+
config RESET_MESON
tristate "Meson Reset Driver"
depends on ARCH_MESON || COMPILE_TEST
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index a80a9c4008a7..5fac3a753858 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_RESET_K210) += reset-k210.o
obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o
+obj-$(CONFIG_RESET_POLARFIRE_SOC) += reset-mpfs.o
obj-$(CONFIG_RESET_MESON) += reset-meson.o
obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
obj-$(CONFIG_RESET_NPCM) += reset-npcm.o
@@ -38,4 +39,3 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
-
diff --git a/drivers/reset/reset-mpfs.c b/drivers/reset/reset-mpfs.c
new file mode 100644
index 000000000000..49c47a3e6c70
--- /dev/null
+++ b/drivers/reset/reset-mpfs.c
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * PolarFire SoC (MPFS) Peripheral Clock Reset Controller
+ *
+ * Author: Conor Dooley <[email protected]>
+ * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
+ *
+ */
+#include <linux/auxiliary_bus.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <dt-bindings/clock/microchip,mpfs-clock.h>
+#include <soc/microchip/mpfs.h>
+
+/*
+ * The ENVM reset is the lowest bit in the register & I am using the CLK_FOO
+ * defines in the dt to make things easier to configure - so this is accounting
+ * for the offset of 3 there.
+ */
+#define MPFS_PERIPH_OFFSET CLK_ENVM
+#define MPFS_NUM_RESETS 30u
+#define MPFS_SLEEP_MIN_US 100
+#define MPFS_SLEEP_MAX_US 200
+
+/*
+ * Peripheral clock resets
+ */
+
+static int mpfs_assert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ u32 reg;
+
+ reg = mpfs_reset_read(rcdev->dev);
+ reg |= (1u << id);
+ mpfs_reset_write(rcdev->dev, reg);
This is missing a spinlock to protect against concurrent read-modify-
writes.
+
+ return 0;
+}
+
+static int mpfs_deassert(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ u32 reg, val;
+
+ reg = mpfs_reset_read(rcdev->dev);
+ val = reg & ~(1u << id);
You could use BIT(id) instead of (1u << id).
+ mpfs_reset_write(rcdev->dev, val);
+
+ return 0;
+}
+
+static int mpfs_status(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ u32 reg = mpfs_reset_read(rcdev->dev);
+
+ return (reg & (1u << id));
Side note, this works because MPFS_NUM_RESETS makes sure the sign bit
is never hit.
+}
+
+static int mpfs_reset(struct reset_controller_dev *rcdev, unsigned long id)
+{
+ mpfs_assert(rcdev, id);
+
+ usleep_range(MPFS_SLEEP_MIN_US, MPFS_SLEEP_MAX_US);
+
+ mpfs_deassert(rcdev, id);
+
+ return 0;
+}
+
+static const struct reset_control_ops mpfs_reset_ops = {
+ .reset = mpfs_reset,
+ .assert = mpfs_assert,
+ .deassert = mpfs_deassert,
+ .status = mpfs_status,
+};
+
+static int mpfs_reset_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ unsigned int index = reset_spec->args[0];
+
+ /*
+ * CLK_RESERVED does not map to a clock, but it does map to a reset,
+ * so it has to be accounted for here. It is the reset for the fabric,
+ * so if this reset gets called - do not reset it.
+ */
+ if (index == CLK_RESERVED) {
+ dev_err(rcdev->dev, "Resetting the fabric is not supported\n");
+ return -EINVAL;
+ }
+
+ if (index < MPFS_PERIPH_OFFSET || index >= (MPFS_PERIPH_OFFSET + rcdev->nr_resets)) {
+ dev_err(rcdev->dev, "Invalid reset index %u\n", reset_spec->args[0]);
s/reset_spec->args[0]/index/
+ return -EINVAL;
+ }
+
+ return index - MPFS_PERIPH_OFFSET;
+}
+
+static int mpfs_reset_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
+{
+ struct device *dev = &adev->dev;
+ struct reset_controller_dev *rcdev;
+ int ret;
+
+ rcdev = devm_kzalloc(dev, sizeof(*rcdev), GFP_KERNEL);
+ if (!rcdev)
+ return -ENOMEM;
+
+ rcdev->dev = dev;
+ rcdev->dev->parent = adev->dev.parent;
s/adev->dev./dev->/
+ rcdev->ops = &mpfs_reset_ops;
+ rcdev->of_node = adev->dev.parent->of_node;
s/adev->dev./dev->/
+ rcdev->of_reset_n_cells = 1;
+ rcdev->of_xlate = mpfs_reset_xlate;
+ rcdev->nr_resets = MPFS_NUM_RESETS;
+
+ ret = devm_reset_controller_register(dev, rcdev);
+ if (!ret)
+ dev_info(dev, "Registered MPFS reset controller\n");
Is this really useful information for most users?
+
+ return ret;
+}
+
+static const struct auxiliary_device_id mpfs_reset_ids[] = {
+ {
+ .name = "clk_mpfs.reset-mpfs",
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(auxiliary, mpfs_reset_ids);
+
+static struct auxiliary_driver mpfs_reset_driver = {
+ .probe = mpfs_reset_probe,
+ .id_table = mpfs_reset_ids,
+};
+
+module_auxiliary_driver(mpfs_reset_driver);
+
+MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver");
+MODULE_AUTHOR("Conor Dooley <[email protected]>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS(MCHP_CLK_MPFS);
regards
Philipp
On Thu, 30 Jun 2022 09:05:25 +0100 Conor Dooley wrote:
> To date, the Microchip PolarFire SoC (MPFS) has been using the
> cdns,macb compatible, however the generic device does not have reset
> support. Add a new compatible & .data for MPFS to hook into the reset
> functionality added for zynqmp support (and make the zynqmp init
> function generic in the process).
>
> Signed-off-by: Conor Dooley <[email protected]>
Please repost 2 and 6 separately with [PATCH net-next] in the subject.
On 30/06/2022 17:02, Jakub Kicinski wrote:
> On Thu, 30 Jun 2022 09:05:25 +0100 Conor Dooley wrote:
>> To date, the Microchip PolarFire SoC (MPFS) has been using the
>> cdns,macb compatible, however the generic device does not have reset
>> support. Add a new compatible & .data for MPFS to hook into the reset
>> functionality added for zynqmp support (and make the zynqmp init
>> function generic in the process).
>>
>> Signed-off-by: Conor Dooley <[email protected]>
>
> Please repost 2 and 6 separately with [PATCH net-next] in the subject.
Aye
On 30/06/2022 10:12, Philipp Zabel wrote:
(This came to me oddly quoted, so I have fixed it myself)
>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>
>> Hi Conor,
>>
>> On Do, 2022-06-30 at 09:05 +0100, Conor Dooley wrote:
>> Add support for the resets on Microchip's PolarFire SoC (MPFS).
>> Reset control is a single register, wedged in between registers for
>> clock control. To fit with existed DT etc, the reset controller is
>>
> existing ^
>>
>> created using the aux device framework & set up in the clock driver.
>>
>> Signed-off-by: Conor Dooley <[email protected]>
>> ---
>> drivers/reset/Kconfig | 9 +++
>> drivers/reset/Makefile | 2 +-
>> drivers/reset/reset-mpfs.c | 145 +++++++++++++++++++++++++++++++++++++
>> 3 files changed, 155 insertions(+), 1 deletion(-)
>> create mode 100644 drivers/reset/reset-mpfs.c
>>
>> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
>> index 93c8d07ee328..edf48951f763 100644
>> --- a/drivers/reset/Kconfig
>> +++ b/drivers/reset/Kconfig
>> @@ -122,6 +122,15 @@ config RESET_MCHP_SPARX5
>> help
>> This driver supports switch core reset for the Microchip Sparx5 SoC.
>>
>>
>> +config RESET_POLARFIRE_SOC
>> + bool "Microchip PolarFire SoC (MPFS) Reset Driver"
>> + depends on AUXILIARY_BUS && MCHP_CLK_MPFS
>> + default MCHP_CLK_MPFS
>> + help
>> + This driver supports peripheral reset for the Microchip PolarFire SoC
>> +
>> + CONFIG_RESET_MPFS
>>
>This doesn't look intentional.
Correct. I fixed it when rebasing on -next and forgot to re-fix it
when I had to reset back to -rc2...
>>
>> +
>> config RESET_MESON
>> tristate "Meson Reset Driver"
>> depends on ARCH_MESON || COMPILE_TEST
>> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
>> index a80a9c4008a7..5fac3a753858 100644
>> --- a/drivers/reset/Makefile
>> +++ b/drivers/reset/Makefile
>> @@ -17,6 +17,7 @@ obj-$(CONFIG_RESET_K210) += reset-k210.o
>> obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
>> obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
>> obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o
>> +obj-$(CONFIG_RESET_POLARFIRE_SOC) += reset-mpfs.o
>> obj-$(CONFIG_RESET_MESON) += reset-meson.o
>> obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
>> obj-$(CONFIG_RESET_NPCM) += reset-npcm.o
>> @@ -38,4 +39,3 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
>> obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
>> obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
>> obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
>> -
>> diff --git a/drivers/reset/reset-mpfs.c b/drivers/reset/reset-mpfs.c
>> new file mode 100644
>> index 000000000000..49c47a3e6c70
>> --- /dev/null
>> +++ b/drivers/reset/reset-mpfs.c
>> @@ -0,0 +1,145 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * PolarFire SoC (MPFS) Peripheral Clock Reset Controller
>> + *
>> + * Author: Conor Dooley <[email protected]>
>> + * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
>> + *
>> + */
>> +#include <linux/auxiliary_bus.h>
>> +#include <linux/delay.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reset-controller.h>
>> +#include <dt-bindings/clock/microchip,mpfs-clock.h>
>> +#include <soc/microchip/mpfs.h>
>> +
>> +/*
>> + * The ENVM reset is the lowest bit in the register & I am using the CLK_FOO
>> + * defines in the dt to make things easier to configure - so this is accounting
>> + * for the offset of 3 there.
>> + */
>> +#define MPFS_PERIPH_OFFSET CLK_ENVM
>> +#define MPFS_NUM_RESETS 30u
>> +#define MPFS_SLEEP_MIN_US 100
>> +#define MPFS_SLEEP_MAX_US 200
>> +
>> +/*
>> + * Peripheral clock resets
>> + */
>> +
>> +static int mpfs_assert(struct reset_controller_dev *rcdev, unsigned long id)
>> +{
>> + u32 reg;
>> +
>> + reg = mpfs_reset_read(rcdev->dev);
>> + reg |= (1u << id);
>> + mpfs_reset_write(rcdev->dev, reg);
>
> This is missing a spinlock to protect against concurrent read-modify-
> writes.
>>
>> +
>> + return 0;
>> +}
>> +
>> +static int mpfs_deassert(struct reset_controller_dev *rcdev, unsigned long id)
>> +{
>> + u32 reg, val;
>> +
>> + reg = mpfs_reset_read(rcdev->dev);
>> + val = reg & ~(1u << id);
>
> You could use BIT(id) instead of (1u << id).
>
>> + mpfs_reset_write(rcdev->dev, val);
>> +
>> + return 0;
>> +}
>> +
>> +static int mpfs_status(struct reset_controller_dev *rcdev, unsigned long id)
>> +{
>> + u32 reg = mpfs_reset_read(rcdev->dev);
>> +
>> + return (reg & (1u << id));
>
> Side note, this works because MPFS_NUM_RESETS makes sure the sign bit
> is never hit.
I can add a comment to that effect if you want?
>>
>> +}
>> +
>> +static int mpfs_reset(struct reset_controller_dev *rcdev, unsigned long id)
>> +{
>> + mpfs_assert(rcdev, id);
>> +
>> + usleep_range(MPFS_SLEEP_MIN_US, MPFS_SLEEP_MAX_US);
>> +
>> + mpfs_deassert(rcdev, id);
>> +
>> + return 0;
>> +}
>> +
>> +static const struct reset_control_ops mpfs_reset_ops = {
>> + .reset = mpfs_reset,
>> + .assert = mpfs_assert,
>> + .deassert = mpfs_deassert,
>> + .status = mpfs_status,
>> +};
>> +
>> +static int mpfs_reset_xlate(struct reset_controller_dev *rcdev,
>> + const struct of_phandle_args *reset_spec)
>> +{
>> + unsigned int index = reset_spec->args[0];
>> +
>> + /*
>> + * CLK_RESERVED does not map to a clock, but it does map to a reset,
>> + * so it has to be accounted for here. It is the reset for the fabric,
>> + * so if this reset gets called - do not reset it.
>> + */
>> + if (index == CLK_RESERVED) {
>> + dev_err(rcdev->dev, "Resetting the fabric is not supported\n");
>> + return -EINVAL;
>> + }
>> +
>> + if (index < MPFS_PERIPH_OFFSET || index >= (MPFS_PERIPH_OFFSET + rcdev->nr_resets)) {
>> + dev_err(rcdev->dev, "Invalid reset index %u\n", reset_spec->args[0]);
>
> s/reset_spec->args[0]/index/
>
>> + return -EINVAL;
>> + }
>> +
>> + return index - MPFS_PERIPH_OFFSET;
>> +}
>> +
>> +static int mpfs_reset_probe(struct auxiliary_device *adev,
>> + const struct auxiliary_device_id *id)
>> +{
>> + struct device *dev = &adev->dev;
>> + struct reset_controller_dev *rcdev;
>> + int ret;
>> +
>> + rcdev = devm_kzalloc(dev, sizeof(*rcdev), GFP_KERNEL);
>> + if (!rcdev)
>> + return -ENOMEM;
>> +
>> + rcdev->dev = dev;
>> + rcdev->dev->parent = adev->dev.parent;
>>
>> s/adev->dev./dev->/
>>
>> + rcdev->ops = &mpfs_reset_ops;
>> + rcdev->of_node = adev->dev.parent->of_node;
>>
>> s/adev->dev./dev->/
>>
>> + rcdev->of_reset_n_cells = 1;
>> + rcdev->of_xlate = mpfs_reset_xlate;
>> + rcdev->nr_resets = MPFS_NUM_RESETS;
>> +
>> + ret = devm_reset_controller_register(dev, rcdev);
>> + if (!ret)
>> + dev_info(dev, "Registered MPFS reset controller\n");
>
> Is this really useful information for most users?
Probably not, but it is useful for my CI haha.
If you don't like it, I will remove it.
>
>> +
>> + return ret;
>> +}
>> +
>> +static const struct auxiliary_device_id mpfs_reset_ids[] = {
>> + {
>> + .name = "clk_mpfs.reset-mpfs",
>> + },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(auxiliary, mpfs_reset_ids);
>> +
>> +static struct auxiliary_driver mpfs_reset_driver = {
>> + .probe = mpfs_reset_probe,
>> + .id_table = mpfs_reset_ids,
>> +};
>> +
>> +module_auxiliary_driver(mpfs_reset_driver);
>> +
>> +MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver");
>> +MODULE_AUTHOR("Conor Dooley <[email protected]>");
>> +MODULE_LICENSE("GPL");
>> +MODULE_IMPORT_NS(MCHP_CLK_MPFS);
>>
> regards
> Philipp
On 30/06/2022 17:20, Conor Dooley - M52691 wrote:
> On 30/06/2022 10:12, Philipp Zabel wrote:
>
> (This came to me oddly quoted, so I have fixed it myself)
>
>>> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>>>
>>> Hi Conor,
>>>
>>> On Do, 2022-06-30 at 09:05 +0100, Conor Dooley wrote:
>>> Add support for the resets on Microchip's PolarFire SoC (MPFS).
>>> Reset control is a single register, wedged in between registers for
>>> clock control. To fit with existed DT etc, the reset controller is
>>>
>> existing ^
>>>
>>> created using the aux device framework & set up in the clock driver.
>>>
>>> Signed-off-by: Conor Dooley <[email protected]>
>>> ---
>>> drivers/reset/Kconfig | 9 +++
>>> drivers/reset/Makefile | 2 +-
>>> drivers/reset/reset-mpfs.c | 145 +++++++++++++++++++++++++++++++++++++
>>> 3 files changed, 155 insertions(+), 1 deletion(-)
>>> create mode 100644 drivers/reset/reset-mpfs.c
>>>
>>> diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig
>>> index 93c8d07ee328..edf48951f763 100644
>>> --- a/drivers/reset/Kconfig
>>> +++ b/drivers/reset/Kconfig
>>> @@ -122,6 +122,15 @@ config RESET_MCHP_SPARX5
>>> help
>>> This driver supports switch core reset for the Microchip Sparx5 SoC.
>>>
>>>
>>> +config RESET_POLARFIRE_SOC
>>> + bool "Microchip PolarFire SoC (MPFS) Reset Driver"
>>> + depends on AUXILIARY_BUS && MCHP_CLK_MPFS
>>> + default MCHP_CLK_MPFS
>>> + help
>>> + This driver supports peripheral reset for the Microchip PolarFire SoC
>>> +
>>> + CONFIG_RESET_MPFS
>>>
>> This doesn't look intentional.
>
> Correct. I fixed it when rebasing on -next and forgot to re-fix it
> when I had to reset back to -rc2...
>
>>>
>>> +
>>> config RESET_MESON
>>> tristate "Meson Reset Driver"
>>> depends on ARCH_MESON || COMPILE_TEST
>>> diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
>>> index a80a9c4008a7..5fac3a753858 100644
>>> --- a/drivers/reset/Makefile
>>> +++ b/drivers/reset/Makefile
>>> @@ -17,6 +17,7 @@ obj-$(CONFIG_RESET_K210) += reset-k210.o
>>> obj-$(CONFIG_RESET_LANTIQ) += reset-lantiq.o
>>> obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o
>>> obj-$(CONFIG_RESET_MCHP_SPARX5) += reset-microchip-sparx5.o
>>> +obj-$(CONFIG_RESET_POLARFIRE_SOC) += reset-mpfs.o
>>> obj-$(CONFIG_RESET_MESON) += reset-meson.o
>>> obj-$(CONFIG_RESET_MESON_AUDIO_ARB) += reset-meson-audio-arb.o
>>> obj-$(CONFIG_RESET_NPCM) += reset-npcm.o
>>> @@ -38,4 +39,3 @@ obj-$(CONFIG_RESET_UNIPHIER) += reset-uniphier.o
>>> obj-$(CONFIG_RESET_UNIPHIER_GLUE) += reset-uniphier-glue.o
>>> obj-$(CONFIG_RESET_ZYNQ) += reset-zynq.o
>>> obj-$(CONFIG_ARCH_ZYNQMP) += reset-zynqmp.o
>>> -
>>> diff --git a/drivers/reset/reset-mpfs.c b/drivers/reset/reset-mpfs.c
>>> new file mode 100644
>>> index 000000000000..49c47a3e6c70
>>> --- /dev/null
>>> +++ b/drivers/reset/reset-mpfs.c
>>> @@ -0,0 +1,145 @@
>>> +// SPDX-License-Identifier: GPL-2.0-only
>>> +/*
>>> + * PolarFire SoC (MPFS) Peripheral Clock Reset Controller
>>> + *
>>> + * Author: Conor Dooley <[email protected]>
>>> + * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
>>> + *
>>> + */
>>> +#include <linux/auxiliary_bus.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/module.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/reset-controller.h>
>>> +#include <dt-bindings/clock/microchip,mpfs-clock.h>
>>> +#include <soc/microchip/mpfs.h>
>>> +
>>> +/*
>>> + * The ENVM reset is the lowest bit in the register & I am using the CLK_FOO
>>> + * defines in the dt to make things easier to configure - so this is accounting
>>> + * for the offset of 3 there.
>>> + */
>>> +#define MPFS_PERIPH_OFFSET CLK_ENVM
>>> +#define MPFS_NUM_RESETS 30u
>>> +#define MPFS_SLEEP_MIN_US 100
>>> +#define MPFS_SLEEP_MAX_US 200
>>> +
>>> +/*
>>> + * Peripheral clock resets
>>> + */
>>> +
>>> +static int mpfs_assert(struct reset_controller_dev *rcdev, unsigned long id)
>>> +{
>>> + u32 reg;
>>> +
>>> + reg = mpfs_reset_read(rcdev->dev);
>>> + reg |= (1u << id);
>>> + mpfs_reset_write(rcdev->dev, reg);
>>
>> This is missing a spinlock to protect against concurrent read-modify-
>> writes.
>>>
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int mpfs_deassert(struct reset_controller_dev *rcdev, unsigned long id)
>>> +{
>>> + u32 reg, val;
>>> +
>>> + reg = mpfs_reset_read(rcdev->dev);
>>> + val = reg & ~(1u << id);
>>
>> You could use BIT(id) instead of (1u << id).
>>
>>> + mpfs_reset_write(rcdev->dev, val);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int mpfs_status(struct reset_controller_dev *rcdev, unsigned long id)
>>> +{
>>> + u32 reg = mpfs_reset_read(rcdev->dev);
>>> +
>>> + return (reg & (1u << id));
>>
>> Side note, this works because MPFS_NUM_RESETS makes sure the sign bit
>> is never hit.
>
> I can add a comment to that effect if you want?
I'm going to respin with the two net patches removed.
I'll operate on the assumption of adding a comment here...
>
>>>
>>> +}
>>> +
>>> +static int mpfs_reset(struct reset_controller_dev *rcdev, unsigned long id)
>>> +{
>>> + mpfs_assert(rcdev, id);
>>> +
>>> + usleep_range(MPFS_SLEEP_MIN_US, MPFS_SLEEP_MAX_US);
>>> +
>>> + mpfs_deassert(rcdev, id);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static const struct reset_control_ops mpfs_reset_ops = {
>>> + .reset = mpfs_reset,
>>> + .assert = mpfs_assert,
>>> + .deassert = mpfs_deassert,
>>> + .status = mpfs_status,
>>> +};
>>> +
>>> +static int mpfs_reset_xlate(struct reset_controller_dev *rcdev,
>>> + const struct of_phandle_args *reset_spec)
>>> +{
>>> + unsigned int index = reset_spec->args[0];
>>> +
>>> + /*
>>> + * CLK_RESERVED does not map to a clock, but it does map to a reset,
>>> + * so it has to be accounted for here. It is the reset for the fabric,
>>> + * so if this reset gets called - do not reset it.
>>> + */
>>> + if (index == CLK_RESERVED) {
>>> + dev_err(rcdev->dev, "Resetting the fabric is not supported\n");
>>> + return -EINVAL;
>>> + }
>>> +
>>> + if (index < MPFS_PERIPH_OFFSET || index >= (MPFS_PERIPH_OFFSET + rcdev->nr_resets)) {
>>> + dev_err(rcdev->dev, "Invalid reset index %u\n", reset_spec->args[0]);
>>
>> s/reset_spec->args[0]/index/
>>
>>> + return -EINVAL;
>>> + }
>>> +
>>> + return index - MPFS_PERIPH_OFFSET;
>>> +}
>>> +
>>> +static int mpfs_reset_probe(struct auxiliary_device *adev,
>>> + const struct auxiliary_device_id *id)
>>> +{
>>> + struct device *dev = &adev->dev;
>>> + struct reset_controller_dev *rcdev;
>>> + int ret;
>>> +
>>> + rcdev = devm_kzalloc(dev, sizeof(*rcdev), GFP_KERNEL);
>>> + if (!rcdev)
>>> + return -ENOMEM;
>>> +
>>> + rcdev->dev = dev;
>>> + rcdev->dev->parent = adev->dev.parent;
>>>
>>> s/adev->dev./dev->/
>>>
>>> + rcdev->ops = &mpfs_reset_ops;
>>> + rcdev->of_node = adev->dev.parent->of_node;
>>>
>>> s/adev->dev./dev->/
>>>
>>> + rcdev->of_reset_n_cells = 1;
>>> + rcdev->of_xlate = mpfs_reset_xlate;
>>> + rcdev->nr_resets = MPFS_NUM_RESETS;
>>> +
>>> + ret = devm_reset_controller_register(dev, rcdev);
>>> + if (!ret)
>>> + dev_info(dev, "Registered MPFS reset controller\n");
>>
>> Is this really useful information for most users?
>
> Probably not, but it is useful for my CI haha.
> If you don't like it, I will remove it.
...and removal here.
Thanks for your review Philipp :)
Conor.
>
>>
>>> +
>>> + return ret;
>>> +}
>>> +
>>> +static const struct auxiliary_device_id mpfs_reset_ids[] = {
>>> + {
>>> + .name = "clk_mpfs.reset-mpfs",
>>> + },
>>> + { }
>>> +};
>>> +MODULE_DEVICE_TABLE(auxiliary, mpfs_reset_ids);
>>> +
>>> +static struct auxiliary_driver mpfs_reset_driver = {
>>> + .probe = mpfs_reset_probe,
>>> + .id_table = mpfs_reset_ids,
>>> +};
>>> +
>>> +module_auxiliary_driver(mpfs_reset_driver);
>>> +
>>> +MODULE_DESCRIPTION("Microchip PolarFire SoC Reset Driver");
>>> +MODULE_AUTHOR("Conor Dooley <[email protected]>");
>>> +MODULE_LICENSE("GPL");
>>> +MODULE_IMPORT_NS(MCHP_CLK_MPFS);
>>>
>> regards
>> Philipp
On Thu, 30 Jun 2022 09:05:20 +0100, Conor Dooley wrote:
> The "peripheral" devices on PolarFire SoC can be put into reset, so
> update the device tree binding to reflect the presence of a reset
> controller.
>
> Signed-off-by: Conor Dooley <[email protected]>
> ---
> .../bindings/clock/microchip,mpfs.yaml | 17 +++++++++++++++--
> 1 file changed, 15 insertions(+), 2 deletions(-)
>
Reviewed-by: Rob Herring <[email protected]>
On 30/06/2022 09:05, Conor Dooley wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
>
> The cfg_clk struct is now just a redefinition of the clk_divider struct
> with custom implentations of the ops, that implement an extra level of
> redirection. Remove the custom struct and replace it with clk_divider.
Looks like I forgot to assign the spinlock in this and the periph_clk
patches. I'm respinning anyway to fix Philipp's comments on the reset
controller & to drop the two net-next patches so I'll fix this too.
Thanks,
Conor.
>
> Signed-off-by: Conor Dooley <[email protected]>
> ---
> drivers/clk/microchip/clk-mpfs.c | 75 +++-----------------------------
> 1 file changed, 7 insertions(+), 68 deletions(-)
>
> diff --git a/drivers/clk/microchip/clk-mpfs.c b/drivers/clk/microchip/clk-mpfs.c
> index e58d0bc4669a..c4d1c48d6d3d 100644
> --- a/drivers/clk/microchip/clk-mpfs.c
> +++ b/drivers/clk/microchip/clk-mpfs.c
> @@ -51,24 +51,13 @@ struct mpfs_msspll_hw_clock {
>
> #define to_mpfs_msspll_clk(_hw) container_of(_hw, struct mpfs_msspll_hw_clock, hw)
>
> -struct mpfs_cfg_clock {
> - void __iomem *reg;
> - const struct clk_div_table *table;
> - u8 shift;
> - u8 width;
> - u8 flags;
> -};
> -
> struct mpfs_cfg_hw_clock {
> - struct mpfs_cfg_clock cfg;
> - struct clk_hw hw;
> + struct clk_divider cfg;
> struct clk_init_data init;
> unsigned int id;
> u32 reg_offset;
> };
>
> -#define to_mpfs_cfg_clk(_hw) container_of(_hw, struct mpfs_cfg_hw_clock, hw)
> -
> struct mpfs_periph_clock {
> void __iomem *reg;
> u8 shift;
> @@ -228,56 +217,6 @@ static int mpfs_clk_register_mssplls(struct device *dev, struct mpfs_msspll_hw_c
> * "CFG" clocks
> */
>
> -static unsigned long mpfs_cfg_clk_recalc_rate(struct clk_hw *hw, unsigned long prate)
> -{
> - struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
> - struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
> - u32 val;
> -
> - val = readl_relaxed(cfg->reg) >> cfg->shift;
> - val &= clk_div_mask(cfg->width);
> -
> - return divider_recalc_rate(hw, prate, val, cfg->table, cfg->flags, cfg->width);
> -}
> -
> -static long mpfs_cfg_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate)
> -{
> - struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
> - struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
> -
> - return divider_round_rate(hw, rate, prate, cfg->table, cfg->width, 0);
> -}
> -
> -static int mpfs_cfg_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate)
> -{
> - struct mpfs_cfg_hw_clock *cfg_hw = to_mpfs_cfg_clk(hw);
> - struct mpfs_cfg_clock *cfg = &cfg_hw->cfg;
> - unsigned long flags;
> - u32 val;
> - int divider_setting;
> -
> - divider_setting = divider_get_val(rate, prate, cfg->table, cfg->width, 0);
> -
> - if (divider_setting < 0)
> - return divider_setting;
> -
> - spin_lock_irqsave(&mpfs_clk_lock, flags);
> - val = readl_relaxed(cfg->reg);
> - val &= ~(clk_div_mask(cfg->width) << cfg_hw->cfg.shift);
> - val |= divider_setting << cfg->shift;
> - writel_relaxed(val, cfg->reg);
> -
> - spin_unlock_irqrestore(&mpfs_clk_lock, flags);
> -
> - return 0;
> -}
> -
> -static const struct clk_ops mpfs_clk_cfg_ops = {
> - .recalc_rate = mpfs_cfg_clk_recalc_rate,
> - .round_rate = mpfs_cfg_clk_round_rate,
> - .set_rate = mpfs_cfg_clk_set_rate,
> -};
> -
> #define CLK_CFG(_id, _name, _parent, _shift, _width, _table, _flags, _offset) { \
> .id = _id, \
> .cfg.shift = _shift, \
> @@ -285,7 +224,7 @@ static const struct clk_ops mpfs_clk_cfg_ops = {
> .cfg.table = _table, \
> .reg_offset = _offset, \
> .cfg.flags = _flags, \
> - .hw.init = CLK_HW_INIT(_name, _parent, &mpfs_clk_cfg_ops, 0), \
> + .cfg.hw.init = CLK_HW_INIT(_name, _parent, &clk_divider_ops, 0), \
> }
>
> static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
> @@ -302,8 +241,8 @@ static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = {
> .cfg.table = mpfs_div_rtcref_table,
> .reg_offset = REG_RTC_CLOCK_CR,
> .cfg.flags = CLK_DIVIDER_ONE_BASED,
> - .hw.init =
> - CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &mpfs_clk_cfg_ops, 0),
> + .cfg.hw.init =
> + CLK_HW_INIT_PARENTS_DATA("clk_rtcref", mpfs_ext_ref, &clk_divider_ops, 0),
> }
> };
>
> @@ -317,13 +256,13 @@ static int mpfs_clk_register_cfgs(struct device *dev, struct mpfs_cfg_hw_clock *
> struct mpfs_cfg_hw_clock *cfg_hw = &cfg_hws[i];
>
> cfg_hw->cfg.reg = data->base + cfg_hw->reg_offset;
> - ret = devm_clk_hw_register(dev, &cfg_hw->hw);
> + ret = devm_clk_hw_register(dev, &cfg_hw->cfg.hw);
> if (ret)
> return dev_err_probe(dev, ret, "failed to register clock id: %d\n",
> cfg_hw->id);
>
> id = cfg_hw->id;
> - data->hw_data.hws[id] = &cfg_hw->hw;
> + data->hw_data.hws[id] = &cfg_hw->cfg.hw;
> }
>
> return 0;
> @@ -393,7 +332,7 @@ static const struct clk_ops mpfs_periph_clk_ops = {
> _flags), \
> }
>
> -#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT].hw)
> +#define PARENT_CLK(PARENT) (&mpfs_cfg_clks[CLK_##PARENT].cfg.hw)
>
> /*
> * Critical clocks:
> --
> 2.36.1
>
>
> _______________________________________________
> linux-riscv mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-riscv