From 540d02217f8f997c55818ecd16d8624c520ca750 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Tue, 25 Oct 2022 08:58:44 +0100 Subject: [PATCH 1/9] dt-bindings: clk: add missing clk ids for microchip mpfs When this binding header was initally upstreamed, the PLL clocking the microprocessor subsystem (MSS) and the RTC reference clocks were omitted. Add them now, matching the IDs used in Linux. Signed-off-by: Conor Dooley Reviewed-by: Leo Yu-Chi Liang Reviewed-by: Padmarao Begari --- include/dt-bindings/clock/microchip-mpfs-clock.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/dt-bindings/clock/microchip-mpfs-clock.h b/include/dt-bindings/clock/microchip-mpfs-clock.h index 55fe64693f6..c7ed0a8db78 100644 --- a/include/dt-bindings/clock/microchip-mpfs-clock.h +++ b/include/dt-bindings/clock/microchip-mpfs-clock.h @@ -42,4 +42,7 @@ #define CLK_ATHENA 31 #define CLK_CFM 32 +#define CLK_RTCREF 33 +#define CLK_MSSPLL 34 + #endif /* _DT_BINDINGS_CLK_MICROCHIP_MPFS_H_ */ From fb103971feb637809a96fe739d81fe2f887cf3ac Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Tue, 25 Oct 2022 08:58:45 +0100 Subject: [PATCH 2/9] clk: microchip: mpfs: convert parent rate acquistion to get_get_rate() Currently the clock driver for PolarFire SoC takes a very naive approach to the relationship between clocks. It reads the dt to get an input clock, assumes that that is fixed frequency, reads the "clock-frequency" property & uses that to set up both the "cfg" and "periph" clocks. Simplifying for the sake of incremental fixes, the "correct" parentage for the clocks currently supported in U-Boot is that the "cfg" clocks should be children of the fixed frequency clock in the dt. The AHB clock is one of these "cfg" clocks and is the parent of the "periph" clocks. Instead of passing the clock rate of the fixed-frequency clock to the "cfg" and "periph" registration functions and the name of the parents, pass their actual parents & use clk_get_rate() to determine their parents rates. The "periph" clocks are purely gate clocks and should not be reading the AHB clocks registers to determine their rates, as they can simply report the output of clk_get_rate() on their parent. Signed-off-by: Conor Dooley Reviewed-by: Leo Yu-Chi Liang Reviewed-by: Padmarao Begari --- drivers/clk/microchip/Makefile | 2 +- drivers/clk/microchip/mpfs_clk.c | 18 ++++++++---------- drivers/clk/microchip/mpfs_clk.h | 12 ++++-------- drivers/clk/microchip/mpfs_clk_cfg.c | 7 +++---- drivers/clk/microchip/mpfs_clk_periph.c | 16 ++++------------ 5 files changed, 20 insertions(+), 35 deletions(-) diff --git a/drivers/clk/microchip/Makefile b/drivers/clk/microchip/Makefile index 904b345d75f..329b2c0c93f 100644 --- a/drivers/clk/microchip/Makefile +++ b/drivers/clk/microchip/Makefile @@ -1 +1 @@ -obj-y += mpfs_clk.o mpfs_clk_cfg.o mpfs_clk_periph.o +obj-y += mpfs_clk.o mpfs_clk_cfg.o mpfs_clk_periph.o mpfs_clk_msspll.o diff --git a/drivers/clk/microchip/mpfs_clk.c b/drivers/clk/microchip/mpfs_clk.c index 67828c9bf40..7ba1218b56e 100644 --- a/drivers/clk/microchip/mpfs_clk.c +++ b/drivers/clk/microchip/mpfs_clk.c @@ -11,34 +11,32 @@ #include #include #include +#include #include #include "mpfs_clk.h" static int mpfs_clk_probe(struct udevice *dev) { - int ret; + struct clk *parent_clk = dev_get_priv(dev); + struct clk clk_ahb = { .id = CLK_AHB }; void __iomem *base; - u32 clk_rate; - const char *parent_clk_name; - struct clk *clk = dev_get_priv(dev); + int ret; base = dev_read_addr_ptr(dev); if (!base) return -EINVAL; - ret = clk_get_by_index(dev, 0, clk); + ret = clk_get_by_index(dev, 0, parent_clk); if (ret) return ret; - dev_read_u32(clk->dev, "clock-frequency", &clk_rate); - parent_clk_name = clk->dev->name; - - ret = mpfs_clk_register_cfgs(base, clk_rate, parent_clk_name); + ret = mpfs_clk_register_cfgs(base, parent_clk); if (ret) return ret; - ret = mpfs_clk_register_periphs(base, clk_rate, "clk_ahb"); + clk_request(dev, &clk_ahb); + ret = mpfs_clk_register_periphs(base, &clk_ahb); return ret; } diff --git a/drivers/clk/microchip/mpfs_clk.h b/drivers/clk/microchip/mpfs_clk.h index 442562a5e7b..35cfeac92e8 100644 --- a/drivers/clk/microchip/mpfs_clk.h +++ b/drivers/clk/microchip/mpfs_clk.h @@ -11,22 +11,18 @@ * mpfs_clk_register_cfgs() - register configuration clocks * * @base: base address of the mpfs system register. - * @clk_rate: the mpfs pll clock rate. - * @parent_name: a pointer to parent clock name. + * @parent: a pointer to parent clock. * Return: zero on success, or a negative error code. */ -int mpfs_clk_register_cfgs(void __iomem *base, u32 clk_rate, - const char *parent_name); +int mpfs_clk_register_cfgs(void __iomem *base, struct clk *parent); /** * mpfs_clk_register_periphs() - register peripheral clocks * * @base: base address of the mpfs system register. - * @clk_rate: the mpfs pll clock rate. - * @parent_name: a pointer to parent clock name. + * @parent: a pointer to parent clock. * Return: zero on success, or a negative error code. */ -int mpfs_clk_register_periphs(void __iomem *base, u32 clk_rate, - const char *parent_name); +int mpfs_clk_register_periphs(void __iomem *base, struct clk *parent); /** * divider_get_val() - get the clock divider value * diff --git a/drivers/clk/microchip/mpfs_clk_cfg.c b/drivers/clk/microchip/mpfs_clk_cfg.c index fefddd14137..5739fd66e8d 100644 --- a/drivers/clk/microchip/mpfs_clk_cfg.c +++ b/drivers/clk/microchip/mpfs_clk_cfg.c @@ -117,8 +117,7 @@ static struct mpfs_cfg_hw_clock mpfs_cfg_clks[] = { CLK_CFG(CLK_AHB, "clk_ahb", 4, 2, mpfs_div_ahb_table, 0), }; -int mpfs_clk_register_cfgs(void __iomem *base, u32 clk_rate, - const char *parent_name) +int mpfs_clk_register_cfgs(void __iomem *base, struct clk *parent) { int ret; int i, id, num_clks; @@ -129,9 +128,9 @@ int mpfs_clk_register_cfgs(void __iomem *base, u32 clk_rate, for (i = 0; i < num_clks; i++) { hw = &mpfs_cfg_clks[i].hw; mpfs_cfg_clks[i].sys_base = base; - mpfs_cfg_clks[i].prate = clk_rate; + mpfs_cfg_clks[i].prate = clk_get_rate(parent); name = mpfs_cfg_clks[i].cfg.name; - ret = clk_register(hw, MPFS_CFG_CLOCK, name, parent_name); + ret = clk_register(hw, MPFS_CFG_CLOCK, name, parent->dev->name); if (ret) ERR_PTR(ret); id = mpfs_cfg_clks[i].cfg.id; diff --git a/drivers/clk/microchip/mpfs_clk_periph.c b/drivers/clk/microchip/mpfs_clk_periph.c index 61d90eb4a85..1488ef503ed 100644 --- a/drivers/clk/microchip/mpfs_clk_periph.c +++ b/drivers/clk/microchip/mpfs_clk_periph.c @@ -99,16 +99,9 @@ static int mpfs_periph_clk_disable(struct clk *hw) static ulong mpfs_periph_clk_recalc_rate(struct clk *hw) { struct mpfs_periph_hw_clock *periph_hw = to_mpfs_periph_clk(hw); - void __iomem *base_addr = periph_hw->sys_base; - unsigned long rate; - u32 val; - val = readl(base_addr + REG_CLOCK_CONFIG_CR) >> CFG_AHB_SHIFT; - val &= clk_div_mask(CFG_WIDTH); - rate = periph_hw->prate / (1u << val); - hw->rate = rate; + return periph_hw->prate; - return rate; } #define CLK_PERIPH(_id, _name, _shift, _flags) { \ @@ -150,8 +143,7 @@ static struct mpfs_periph_hw_clock mpfs_periph_clks[] = { CLK_PERIPH(CLK_CFM, "clk_periph_cfm", 29, 0), }; -int mpfs_clk_register_periphs(void __iomem *base, u32 clk_rate, - const char *parent_name) +int mpfs_clk_register_periphs(void __iomem *base, struct clk *parent) { int ret; int i, id, num_clks; @@ -162,9 +154,9 @@ int mpfs_clk_register_periphs(void __iomem *base, u32 clk_rate, for (i = 0; i < num_clks; i++) { hw = &mpfs_periph_clks[i].hw; mpfs_periph_clks[i].sys_base = base; - mpfs_periph_clks[i].prate = clk_rate; + mpfs_periph_clks[i].prate = clk_get_rate(parent); name = mpfs_periph_clks[i].periph.name; - ret = clk_register(hw, MPFS_PERIPH_CLOCK, name, parent_name); + ret = clk_register(hw, MPFS_PERIPH_CLOCK, name, parent->dev->name); if (ret) ERR_PTR(ret); id = mpfs_periph_clks[i].periph.id; From 32cfdd51630506393ca078aa36fa70248d549109 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Tue, 25 Oct 2022 08:58:46 +0100 Subject: [PATCH 3/9] clk: microchip: mpfs: fix reference clock handling The original devicetrees for PolarFire SoC messed up & defined the msspll's output as a fixed-frequency, 600 MHz clock & used that as the input for the clock controller node. The msspll is not a fixed frequency clock and later devicetrees handled this properly. Check the devicetree & if it is one of the fixed ones, register the msspll. Otherwise, skip registering it & pass the reference clock directly to the cfg clock registration function so that existing devicetrees are not broken by this change. As the MSS PLL is not a "cfg" or a "periph" clock, add a new driver for it, based on the one in Linux. Fixes: 2f27c9219e ("clk: Add Microchip PolarFire SoC clock driver") Signed-off-by: Conor Dooley Reviewed-by: Leo Yu-Chi Liang Reviewed-by: Padmarao Begari Tested-by: Padmarao Begari --- drivers/clk/microchip/mpfs_clk.c | 23 ++++- drivers/clk/microchip/mpfs_clk.h | 8 ++ drivers/clk/microchip/mpfs_clk_msspll.c | 119 ++++++++++++++++++++++++ 3 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 drivers/clk/microchip/mpfs_clk_msspll.c diff --git a/drivers/clk/microchip/mpfs_clk.c b/drivers/clk/microchip/mpfs_clk.c index 7ba1218b56e..f16f716f00e 100644 --- a/drivers/clk/microchip/mpfs_clk.c +++ b/drivers/clk/microchip/mpfs_clk.c @@ -20,10 +20,12 @@ static int mpfs_clk_probe(struct udevice *dev) { struct clk *parent_clk = dev_get_priv(dev); struct clk clk_ahb = { .id = CLK_AHB }; + struct clk clk_msspll = { .id = CLK_MSSPLL }; void __iomem *base; + void __iomem *msspll_base; int ret; - base = dev_read_addr_ptr(dev); + base = dev_read_addr_index_ptr(dev, 0); if (!base) return -EINVAL; @@ -31,6 +33,25 @@ static int mpfs_clk_probe(struct udevice *dev) if (ret) return ret; + /* + * The original devicetrees for mpfs messed up & defined the msspll's + * output as a fixed-frequency, 600 MHz clock & used that as the input + * for the clock controller node. The msspll is however not a fixed + * frequency clock and later devicetrees handled this properly. Check + * the devicetree & if it is one of the fixed ones, register the msspll. + * Otherwise, skip registering it & pass the reference clock directly + * to the cfg clock registration function. + */ + msspll_base = dev_read_addr_index_ptr(dev, 1); + if (msspll_base) { + ret = mpfs_clk_register_msspll(msspll_base, parent_clk); + if (ret) + return ret; + + clk_request(dev, &clk_msspll); + parent_clk = &clk_msspll; + } + ret = mpfs_clk_register_cfgs(base, parent_clk); if (ret) return ret; diff --git a/drivers/clk/microchip/mpfs_clk.h b/drivers/clk/microchip/mpfs_clk.h index 35cfeac92e8..cb7d303e67a 100644 --- a/drivers/clk/microchip/mpfs_clk.h +++ b/drivers/clk/microchip/mpfs_clk.h @@ -15,6 +15,14 @@ * Return: zero on success, or a negative error code. */ int mpfs_clk_register_cfgs(void __iomem *base, struct clk *parent); +/** + * mpfs_clk_register_msspll() - register the mss pll + * + * @base: base address of the mpfs system register. + * @parent: a pointer to parent clock. + * Return: zero on success, or a negative error code. + */ +int mpfs_clk_register_msspll(void __iomem *base, struct clk *parent); /** * mpfs_clk_register_periphs() - register peripheral clocks * diff --git a/drivers/clk/microchip/mpfs_clk_msspll.c b/drivers/clk/microchip/mpfs_clk_msspll.c new file mode 100644 index 00000000000..f37c0d86047 --- /dev/null +++ b/drivers/clk/microchip/mpfs_clk_msspll.c @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022 Microchip Technology Inc. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mpfs_clk.h" + +#define MPFS_MSSPLL_CLOCK "mpfs_msspll_clock" + +/* address offset of control registers */ +#define REG_MSSPLL_REF_CR 0x08u +#define REG_MSSPLL_POSTDIV_CR 0x10u +#define REG_MSSPLL_SSCG_2_CR 0x2Cu + +#define MSSPLL_FBDIV_SHIFT 0x00u +#define MSSPLL_FBDIV_WIDTH 0x0Cu +#define MSSPLL_REFDIV_SHIFT 0x08u +#define MSSPLL_REFDIV_WIDTH 0x06u +#define MSSPLL_POSTDIV_SHIFT 0x08u +#define MSSPLL_POSTDIV_WIDTH 0x07u +#define MSSPLL_FIXED_DIV 4u + +/** + * struct mpfs_msspll_hw_clock + * @id: index of the msspll clock + * @name: the msspll clocks name + * @reg_offset: offset to the core complex's output of the msspll + * @shift: shift to the divider bit field of a msspll clock output + * @width: width of the divider bit field of the msspll clock output + * @flags: common clock framework flags + * @prate: the reference clock rate + * @hw: clock instance + */ +struct mpfs_msspll_hw_clock { + void __iomem *base; + unsigned int id; + const char *name; + u32 reg_offset; + u32 shift; + u32 width; + u32 flags; + u32 prate; + struct clk hw; +}; + +#define to_mpfs_msspll_clk(_hw) container_of(_hw, struct mpfs_msspll_hw_clock, hw) + +static unsigned long mpfs_clk_msspll_recalc_rate(struct clk *hw) +{ + 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; + unsigned long temp; + + mult = readl(mult_addr) >> MSSPLL_FBDIV_SHIFT; + mult &= clk_div_mask(MSSPLL_FBDIV_WIDTH); + ref_div = readl(ref_div_addr) >> MSSPLL_REFDIV_SHIFT; + ref_div &= clk_div_mask(MSSPLL_REFDIV_WIDTH); + postdiv = readl(postdiv_addr) >> MSSPLL_POSTDIV_SHIFT; + postdiv &= clk_div_mask(MSSPLL_POSTDIV_WIDTH); + + temp = msspll_hw->prate / (ref_div * MSSPLL_FIXED_DIV * postdiv); + return temp * mult; +} + +#define CLK_PLL(_id, _name, _shift, _width, _reg_offset, _flags) { \ + .id = _id, \ + .name = _name, \ + .shift = _shift, \ + .width = _width, \ + .reg_offset = _reg_offset, \ + .flags = _flags, \ +} + +static struct mpfs_msspll_hw_clock mpfs_msspll_clks[] = { + CLK_PLL(CLK_MSSPLL, "clk_msspll", MSSPLL_FBDIV_SHIFT, + MSSPLL_FBDIV_WIDTH, REG_MSSPLL_SSCG_2_CR, 0), +}; + +int mpfs_clk_register_msspll(void __iomem *base, struct clk *parent) +{ + int id, ret; + const char *name; + struct clk *hw; + + hw = &mpfs_msspll_clks[0].hw; + mpfs_msspll_clks[0].base = base; + mpfs_msspll_clks[0].prate = clk_get_rate(parent); + name = mpfs_msspll_clks[0].name; + ret = clk_register(hw, MPFS_MSSPLL_CLOCK, name, parent->dev->name); + if (ret) + ERR_PTR(ret); + id = mpfs_msspll_clks[0].id; + clk_dm(id, hw); + + return 0; +} + +const struct clk_ops mpfs_msspll_clk_ops = { + .get_rate = mpfs_clk_msspll_recalc_rate, +}; + +U_BOOT_DRIVER(mpfs_msspll_clock) = { + .name = MPFS_MSSPLL_CLOCK, + .id = UCLASS_CLK, + .ops = &mpfs_msspll_clk_ops, +}; + From 88b697fb37432b95bd87525e718726607bdb2123 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Tue, 25 Oct 2022 08:58:47 +0100 Subject: [PATCH 4/9] clk: microchip: mpfs: fix periph clk parentage Not all "periph" clocks are children of the AHB clock, some have the AXI clock as their parent & the mtimer clock is derived from the external reference clock directly. Stop assuming the AHB clock to be the parent of all "periph" clocks and define their correct parents instead. Fixes: 2f27c9219e ("clk: Add Microchip PolarFire SoC clock driver") Signed-off-by: Conor Dooley Reviewed-by: Leo Yu-Chi Liang Reviewed-by: Padmarao Begari Tested-by: Padmarao Begari --- drivers/clk/microchip/mpfs_clk.c | 4 +- drivers/clk/microchip/mpfs_clk.h | 4 +- drivers/clk/microchip/mpfs_clk_periph.c | 72 +++++++++++++------------ 3 files changed, 42 insertions(+), 38 deletions(-) diff --git a/drivers/clk/microchip/mpfs_clk.c b/drivers/clk/microchip/mpfs_clk.c index f16f716f00e..08f8bfcecbe 100644 --- a/drivers/clk/microchip/mpfs_clk.c +++ b/drivers/clk/microchip/mpfs_clk.c @@ -19,7 +19,6 @@ static int mpfs_clk_probe(struct udevice *dev) { struct clk *parent_clk = dev_get_priv(dev); - struct clk clk_ahb = { .id = CLK_AHB }; struct clk clk_msspll = { .id = CLK_MSSPLL }; void __iomem *base; void __iomem *msspll_base; @@ -56,8 +55,7 @@ static int mpfs_clk_probe(struct udevice *dev) if (ret) return ret; - clk_request(dev, &clk_ahb); - ret = mpfs_clk_register_periphs(base, &clk_ahb); + ret = mpfs_clk_register_periphs(base, dev); return ret; } diff --git a/drivers/clk/microchip/mpfs_clk.h b/drivers/clk/microchip/mpfs_clk.h index cb7d303e67a..72288cc971b 100644 --- a/drivers/clk/microchip/mpfs_clk.h +++ b/drivers/clk/microchip/mpfs_clk.h @@ -27,10 +27,10 @@ int mpfs_clk_register_msspll(void __iomem *base, struct clk *parent); * mpfs_clk_register_periphs() - register peripheral clocks * * @base: base address of the mpfs system register. - * @parent: a pointer to parent clock. + * @dev: udevice representing the clock controller. * Return: zero on success, or a negative error code. */ -int mpfs_clk_register_periphs(void __iomem *base, struct clk *parent); +int mpfs_clk_register_periphs(void __iomem *base, struct udevice *dev); /** * divider_get_val() - get the clock divider value * diff --git a/drivers/clk/microchip/mpfs_clk_periph.c b/drivers/clk/microchip/mpfs_clk_periph.c index 1488ef503ed..e23eb552c36 100644 --- a/drivers/clk/microchip/mpfs_clk_periph.c +++ b/drivers/clk/microchip/mpfs_clk_periph.c @@ -29,12 +29,14 @@ /** * struct mpfs_periph_clock - per instance of peripheral clock * @id: index of a peripheral clock + * @parent_id: index of the parent clock * @name: name of a peripheral clock * @shift: shift to a peripheral clock bit field * @flags: common clock framework flags */ struct mpfs_periph_clock { unsigned int id; + unsigned int parent_id; const char *name; u8 shift; unsigned long flags; @@ -104,46 +106,47 @@ static ulong mpfs_periph_clk_recalc_rate(struct clk *hw) } -#define CLK_PERIPH(_id, _name, _shift, _flags) { \ +#define CLK_PERIPH(_id, _name, _parent_id, _shift, _flags) { \ .periph.id = _id, \ + .periph.parent_id = _parent_id, \ .periph.name = _name, \ .periph.shift = _shift, \ .periph.flags = _flags, \ } static struct mpfs_periph_hw_clock mpfs_periph_clks[] = { - CLK_PERIPH(CLK_ENVM, "clk_periph_envm", 0, CLK_IS_CRITICAL), - CLK_PERIPH(CLK_MAC0, "clk_periph_mac0", 1, 0), - CLK_PERIPH(CLK_MAC1, "clk_periph_mac1", 2, 0), - CLK_PERIPH(CLK_MMC, "clk_periph_mmc", 3, 0), - CLK_PERIPH(CLK_TIMER, "clk_periph_timer", 4, 0), - CLK_PERIPH(CLK_MMUART0, "clk_periph_mmuart0", 5, 0), - CLK_PERIPH(CLK_MMUART1, "clk_periph_mmuart1", 6, 0), - CLK_PERIPH(CLK_MMUART2, "clk_periph_mmuart2", 7, 0), - CLK_PERIPH(CLK_MMUART3, "clk_periph_mmuart3", 8, 0), - CLK_PERIPH(CLK_MMUART4, "clk_periph_mmuart4", 9, 0), - CLK_PERIPH(CLK_SPI0, "clk_periph_spi0", 10, 0), - CLK_PERIPH(CLK_SPI1, "clk_periph_spi1", 11, 0), - CLK_PERIPH(CLK_I2C0, "clk_periph_i2c0", 12, 0), - CLK_PERIPH(CLK_I2C1, "clk_periph_i2c1", 13, 0), - CLK_PERIPH(CLK_CAN0, "clk_periph_can0", 14, 0), - CLK_PERIPH(CLK_CAN1, "clk_periph_can1", 15, 0), - CLK_PERIPH(CLK_USB, "clk_periph_usb", 16, 0), - CLK_PERIPH(CLK_RTC, "clk_periph_rtc", 18, 0), - CLK_PERIPH(CLK_QSPI, "clk_periph_qspi", 19, 0), - CLK_PERIPH(CLK_GPIO0, "clk_periph_gpio0", 20, 0), - CLK_PERIPH(CLK_GPIO1, "clk_periph_gpio1", 21, 0), - CLK_PERIPH(CLK_GPIO2, "clk_periph_gpio2", 22, 0), - CLK_PERIPH(CLK_DDRC, "clk_periph_ddrc", 23, CLK_IS_CRITICAL), - CLK_PERIPH(CLK_FIC0, "clk_periph_fic0", 24, 0), - CLK_PERIPH(CLK_FIC1, "clk_periph_fic1", 25, 0), - CLK_PERIPH(CLK_FIC2, "clk_periph_fic2", 26, 0), - CLK_PERIPH(CLK_FIC3, "clk_periph_fic3", 27, 0), - CLK_PERIPH(CLK_ATHENA, "clk_periph_athena", 28, 0), - CLK_PERIPH(CLK_CFM, "clk_periph_cfm", 29, 0), + CLK_PERIPH(CLK_ENVM, "clk_periph_envm", CLK_AHB, 0, CLK_IS_CRITICAL), + CLK_PERIPH(CLK_MAC0, "clk_periph_mac0", CLK_AHB, 1, 0), + CLK_PERIPH(CLK_MAC1, "clk_periph_mac1", CLK_AHB, 2, 0), + CLK_PERIPH(CLK_MMC, "clk_periph_mmc", CLK_AHB, 3, 0), + CLK_PERIPH(CLK_TIMER, "clk_periph_timer", CLK_RTCREF, 4, 0), + CLK_PERIPH(CLK_MMUART0, "clk_periph_mmuart0", CLK_AHB, 5, 0), + CLK_PERIPH(CLK_MMUART1, "clk_periph_mmuart1", CLK_AHB, 6, 0), + CLK_PERIPH(CLK_MMUART2, "clk_periph_mmuart2", CLK_AHB, 7, 0), + CLK_PERIPH(CLK_MMUART3, "clk_periph_mmuart3", CLK_AHB, 8, 0), + CLK_PERIPH(CLK_MMUART4, "clk_periph_mmuart4", CLK_AHB, 9, 0), + CLK_PERIPH(CLK_SPI0, "clk_periph_spi0", CLK_AHB, 10, 0), + CLK_PERIPH(CLK_SPI1, "clk_periph_spi1", CLK_AHB, 11, 0), + CLK_PERIPH(CLK_I2C0, "clk_periph_i2c0", CLK_AHB, 12, 0), + CLK_PERIPH(CLK_I2C1, "clk_periph_i2c1", CLK_AHB, 13, 0), + CLK_PERIPH(CLK_CAN0, "clk_periph_can0", CLK_AHB, 14, 0), + CLK_PERIPH(CLK_CAN1, "clk_periph_can1", CLK_AHB, 15, 0), + CLK_PERIPH(CLK_USB, "clk_periph_usb", CLK_AHB, 16, 0), + CLK_PERIPH(CLK_RTC, "clk_periph_rtc", CLK_AHB, 18, 0), + CLK_PERIPH(CLK_QSPI, "clk_periph_qspi", CLK_AHB, 19, 0), + CLK_PERIPH(CLK_GPIO0, "clk_periph_gpio0", CLK_AHB, 20, 0), + CLK_PERIPH(CLK_GPIO1, "clk_periph_gpio1", CLK_AHB, 21, 0), + CLK_PERIPH(CLK_GPIO2, "clk_periph_gpio2", CLK_AHB, 22, 0), + CLK_PERIPH(CLK_DDRC, "clk_periph_ddrc", CLK_AHB, 23, CLK_IS_CRITICAL), + CLK_PERIPH(CLK_FIC0, "clk_periph_fic0", CLK_AXI, 24, 0), + CLK_PERIPH(CLK_FIC1, "clk_periph_fic1", CLK_AXI, 25, 0), + CLK_PERIPH(CLK_FIC2, "clk_periph_fic2", CLK_AXI, 26, 0), + CLK_PERIPH(CLK_FIC3, "clk_periph_fic3", CLK_AXI, 27, 0), + CLK_PERIPH(CLK_ATHENA, "clk_periph_athena", CLK_AXI, 28, 0), + CLK_PERIPH(CLK_CFM, "clk_periph_cfm", CLK_AHB, 29, 0), }; -int mpfs_clk_register_periphs(void __iomem *base, struct clk *parent) +int mpfs_clk_register_periphs(void __iomem *base, struct udevice *dev) { int ret; int i, id, num_clks; @@ -152,11 +155,14 @@ int mpfs_clk_register_periphs(void __iomem *base, struct clk *parent) num_clks = ARRAY_SIZE(mpfs_periph_clks); for (i = 0; i < num_clks; i++) { + struct clk parent = { .id = mpfs_periph_clks[i].periph.parent_id }; + + clk_request(dev, &parent); hw = &mpfs_periph_clks[i].hw; mpfs_periph_clks[i].sys_base = base; - mpfs_periph_clks[i].prate = clk_get_rate(parent); + mpfs_periph_clks[i].prate = clk_get_rate(&parent); name = mpfs_periph_clks[i].periph.name; - ret = clk_register(hw, MPFS_PERIPH_CLOCK, name, parent->dev->name); + ret = clk_register(hw, MPFS_PERIPH_CLOCK, name, parent.dev->name); if (ret) ERR_PTR(ret); id = mpfs_periph_clks[i].periph.id; From 4e405c68fbf53e52fdb36631caa090c081c59bd0 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Tue, 25 Oct 2022 08:58:48 +0100 Subject: [PATCH 5/9] clk: microchip: mpfs: fix criticality of peripheral clocks Sync the critical clocks in the U-Boot driver with those marked as critical in Linux. The Linux driver has an explanation of why each clock is considered to be critical, so import that too. Fixes: 2f27c9219e ("clk: Add Microchip PolarFire SoC clock driver") Signed-off-by: Conor Dooley Reviewed-by: Leo Yu-Chi Liang Reviewed-by: Padmarao Begari --- drivers/clk/microchip/mpfs_clk_periph.c | 28 ++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/clk/microchip/mpfs_clk_periph.c b/drivers/clk/microchip/mpfs_clk_periph.c index e23eb552c36..ddeccb91457 100644 --- a/drivers/clk/microchip/mpfs_clk_periph.c +++ b/drivers/clk/microchip/mpfs_clk_periph.c @@ -114,13 +114,27 @@ static ulong mpfs_periph_clk_recalc_rate(struct clk *hw) .periph.flags = _flags, \ } +/* + * Critical clocks: + * - CLK_ENVM: reserved by hart software services (hss) superloop monitor/m mode interrupt + * trap handler + * - CLK_MMUART0: reserved by the hss + * - CLK_DDRC: provides clock to the ddr subsystem + * - CLK_RTC: the onboard RTC's AHB bus clock must be kept running as the rtc will stop + * if the AHB interface clock is disabled + * - CLK_FICx: these provide the processor side clocks to the "FIC" (Fabric InterConnect) + * clock domain crossers which provide the interface to the FPGA fabric. Disabling them + * causes the FPGA fabric to go into reset. + * - CLK_ATHENA: The athena clock is FIC4, which is reserved for the Athena TeraFire. + */ + static struct mpfs_periph_hw_clock mpfs_periph_clks[] = { CLK_PERIPH(CLK_ENVM, "clk_periph_envm", CLK_AHB, 0, CLK_IS_CRITICAL), CLK_PERIPH(CLK_MAC0, "clk_periph_mac0", CLK_AHB, 1, 0), CLK_PERIPH(CLK_MAC1, "clk_periph_mac1", CLK_AHB, 2, 0), CLK_PERIPH(CLK_MMC, "clk_periph_mmc", CLK_AHB, 3, 0), CLK_PERIPH(CLK_TIMER, "clk_periph_timer", CLK_RTCREF, 4, 0), - CLK_PERIPH(CLK_MMUART0, "clk_periph_mmuart0", CLK_AHB, 5, 0), + CLK_PERIPH(CLK_MMUART0, "clk_periph_mmuart0", CLK_AHB, 5, CLK_IS_CRITICAL), CLK_PERIPH(CLK_MMUART1, "clk_periph_mmuart1", CLK_AHB, 6, 0), CLK_PERIPH(CLK_MMUART2, "clk_periph_mmuart2", CLK_AHB, 7, 0), CLK_PERIPH(CLK_MMUART3, "clk_periph_mmuart3", CLK_AHB, 8, 0), @@ -132,17 +146,17 @@ static struct mpfs_periph_hw_clock mpfs_periph_clks[] = { CLK_PERIPH(CLK_CAN0, "clk_periph_can0", CLK_AHB, 14, 0), CLK_PERIPH(CLK_CAN1, "clk_periph_can1", CLK_AHB, 15, 0), CLK_PERIPH(CLK_USB, "clk_periph_usb", CLK_AHB, 16, 0), - CLK_PERIPH(CLK_RTC, "clk_periph_rtc", CLK_AHB, 18, 0), + CLK_PERIPH(CLK_RTC, "clk_periph_rtc", CLK_AHB, 18, CLK_IS_CRITICAL), CLK_PERIPH(CLK_QSPI, "clk_periph_qspi", CLK_AHB, 19, 0), CLK_PERIPH(CLK_GPIO0, "clk_periph_gpio0", CLK_AHB, 20, 0), CLK_PERIPH(CLK_GPIO1, "clk_periph_gpio1", CLK_AHB, 21, 0), CLK_PERIPH(CLK_GPIO2, "clk_periph_gpio2", CLK_AHB, 22, 0), CLK_PERIPH(CLK_DDRC, "clk_periph_ddrc", CLK_AHB, 23, CLK_IS_CRITICAL), - CLK_PERIPH(CLK_FIC0, "clk_periph_fic0", CLK_AXI, 24, 0), - CLK_PERIPH(CLK_FIC1, "clk_periph_fic1", CLK_AXI, 25, 0), - CLK_PERIPH(CLK_FIC2, "clk_periph_fic2", CLK_AXI, 26, 0), - CLK_PERIPH(CLK_FIC3, "clk_periph_fic3", CLK_AXI, 27, 0), - CLK_PERIPH(CLK_ATHENA, "clk_periph_athena", CLK_AXI, 28, 0), + CLK_PERIPH(CLK_FIC0, "clk_periph_fic0", CLK_AXI, 24, CLK_IS_CRITICAL), + CLK_PERIPH(CLK_FIC1, "clk_periph_fic1", CLK_AXI, 25, CLK_IS_CRITICAL), + CLK_PERIPH(CLK_FIC2, "clk_periph_fic2", CLK_AXI, 26, CLK_IS_CRITICAL), + CLK_PERIPH(CLK_FIC3, "clk_periph_fic3", CLK_AXI, 27, CLK_IS_CRITICAL), + CLK_PERIPH(CLK_ATHENA, "clk_periph_athena", CLK_AXI, 28, CLK_IS_CRITICAL), CLK_PERIPH(CLK_CFM, "clk_periph_cfm", CLK_AHB, 29, 0), }; From 3f3527044d7460543b69931c3385925119dcf945 Mon Sep 17 00:00:00 2001 From: Conor Dooley Date: Tue, 25 Oct 2022 08:58:49 +0100 Subject: [PATCH 6/9] riscv: dts: fix the mpfs's reference clock frequency The initial devicetree for PolarFire SoC incorrectly created a fixed frequency clock in the devicetree to represent the msspll, but the msspll is not a fixed frequency clock. The actual reference clock on a board is either 125 or 100 MHz, 125 MHz in the case of the icicle kit. Swap the incorrect representation of the msspll out for the actual reference clock. Fixes: dd4ee416a6 ("riscv: dts: Add device tree for Microchip Icicle Kit") Signed-off-by: Conor Dooley Reviewed-by: Leo Yu-Chi Liang Reviewed-by: Padmarao Begari --- arch/riscv/dts/microchip-mpfs-icicle-kit.dts | 4 ++++ arch/riscv/dts/microchip-mpfs.dtsi | 14 ++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/arch/riscv/dts/microchip-mpfs-icicle-kit.dts b/arch/riscv/dts/microchip-mpfs-icicle-kit.dts index 762dcfc6944..c3f58e2d56f 100644 --- a/arch/riscv/dts/microchip-mpfs-icicle-kit.dts +++ b/arch/riscv/dts/microchip-mpfs-icicle-kit.dts @@ -54,6 +54,10 @@ }; }; +&refclk { + clock-frequency = <125000000>; +}; + &uart1 { status = "okay"; }; diff --git a/arch/riscv/dts/microchip-mpfs.dtsi b/arch/riscv/dts/microchip-mpfs.dtsi index 4f449a3a934..891dd0918b2 100644 --- a/arch/riscv/dts/microchip-mpfs.dtsi +++ b/arch/riscv/dts/microchip-mpfs.dtsi @@ -170,6 +170,11 @@ }; }; + refclk: refclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + }; + soc { #address-cells = <2>; #size-cells = <2>; @@ -225,16 +230,9 @@ &cpu4_intc HART_INT_M_EXT &cpu4_intc HART_INT_S_EXT>; }; - refclk: refclk { - compatible = "fixed-clock"; - #clock-cells = <0>; - clock-frequency = <600000000>; - clock-output-names = "msspllclk"; - }; - clkcfg: clkcfg@20002000 { compatible = "microchip,mpfs-clkcfg"; - reg = <0x0 0x20002000 0x0 0x1000>; + reg = <0x0 0x20002000 0x0 0x1000>, <0x0 0x3E001000 0x0 0x1000>; reg-names = "mss_sysreg"; clocks = <&refclk>; #clock-cells = <1>; From c277c787a09254ebdf919c7cfc94631fe854677d Mon Sep 17 00:00:00 2001 From: Yu Chien Peter Lin Date: Sat, 5 Nov 2022 14:02:14 +0800 Subject: [PATCH 7/9] riscv: Fix detecting FPU support in standard extension We should check the string until it hits underscore, in case it searches multi-letter extensions. For example, "rv64imac_xandes" will be treated as D extension support since there is a "d" in "andes", resulting illegal instruction caused by initializing FCSR. Signed-off-by: Yu Chien Peter Lin Reviewed-by: Rick Chen Reviewed-by: Padmarao Begari Reviewed-by: Samuel Holland --- arch/riscv/cpu/cpu.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c index 52ab02519f8..d34c8efce09 100644 --- a/arch/riscv/cpu/cpu.c +++ b/arch/riscv/cpu/cpu.c @@ -36,6 +36,7 @@ static inline bool supports_extension(char ext) #ifdef CONFIG_CPU struct udevice *dev; char desc[32]; + int i; uclass_find_first_device(UCLASS_CPU, &dev); if (!dev) { @@ -43,9 +44,16 @@ static inline bool supports_extension(char ext) return false; } if (!cpu_get_desc(dev, desc, sizeof(desc))) { - /* skip the first 4 characters (rv32|rv64) */ - if (strchr(desc + 4, ext)) - return true; + /* + * skip the first 4 characters (rv32|rv64) and + * check until underscore + */ + for (i = 4; i < sizeof(desc); i++) { + if (desc[i] == '_' || desc[i] == '\0') + break; + if (desc[i] == ext) + return true; + } } return false; From 5c89467262f1bad0fe089a8d2c3b1560a1f7a3db Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 8 Nov 2022 15:53:12 +0100 Subject: [PATCH 8/9] riscv: clarify meaning of CONFIG_SBI_V02 Describe that CONFIG_SBI_V02=y does not mean SBI specification v0.2 but v0.2 or later. Signed-off-by: Heinrich Schuchardt Reviewed-by: Rick Chen --- arch/riscv/Kconfig | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 4d64e9be3f2..ebc4bef220e 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -257,16 +257,16 @@ config SBI_V01 deprecated in future once legacy M-mode software are no longer in use. config SBI_V02 - bool "SBI v0.2 support" + bool "SBI v0.2 or later support" depends on SBI help - This config allows kernel to use SBI v0.2 APIs. SBI v0.2 is more - scalable and extendable to handle future needs for RISC-V supervisor - interfaces. For example, with SBI v0.2 HSM extension, only a single - hart need to boot and enter operating system. The booting hart can - bring up secondary harts one by one afterwards. + The SBI specification introduced the concept of extensions in version + v0.2. With this configuration option U-Boot can detect and use SBI + extensions. With the HSM extension introduced in SBI 0.2, only a + single hart needs to boot and enter the operating system. The booting + hart can bring up secondary harts one by one afterwards. - Choose this option if OpenSBI v0.7 or above release is used together + Choose this option if OpenSBI release v0.7 or above is used together with U-Boot. endchoice From 591e0f878083925e7afff82e1774ba295a7767aa Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 7 Nov 2022 10:55:46 +0100 Subject: [PATCH 9/9] riscv: enable reset via SBI on PolarFire Icicle Kit HSS 2022.10 provides support for resetting the board. Signed-off-by: Heinrich Schuchardt Reviewed-by: Padmarao Begari Tested-by: Padmarao Begari Reviewed-by: Conor Dooley --- configs/microchip_mpfs_icicle_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configs/microchip_mpfs_icicle_defconfig b/configs/microchip_mpfs_icicle_defconfig index 19947ea90b6..887a58e70a0 100644 --- a/configs/microchip_mpfs_icicle_defconfig +++ b/configs/microchip_mpfs_icicle_defconfig @@ -21,3 +21,5 @@ CONFIG_SYS_BOOTM_LEN=0x4000000 CONFIG_SYS_RELOC_GD_ENV_ADDR=y CONFIG_BOOTP_SEND_HOSTNAME=y CONFIG_DM_MTD=y +CONFIG_SYSRESET=y +CONFIG_SYSRESET_SBI=y