config CLK_MPFS
bool "Clock support for Microchip PolarFire SoC"
depends on CLK && CLK_CCF
+ depends on SYSCON
+ depends on REGMAP
help
This enables support clock driver for Microchip PolarFire SoC platform.
#include <log.h>
#include <dm/device.h>
#include <dm/devres.h>
+#include <dm/ofnode.h>
#include <dm/uclass.h>
+#include <regmap.h>
+#include <syscon.h>
#include <dt-bindings/clock/microchip-mpfs-clock.h>
#include <linux/err.h>
#include "mpfs_clk.h"
-static int mpfs_clk_probe(struct udevice *dev)
+static int mpfs_clk_syscon_probe(struct udevice *dev, void __iomem **msspll_base,
+ struct regmap **regmap)
{
- struct clk *parent_clk = dev_get_priv(dev);
- struct clk clk_msspll = { .id = CLK_MSSPLL };
- void __iomem *base;
- void __iomem *msspll_base;
- int ret;
+ ofnode node;
- base = dev_read_addr_index_ptr(dev, 0);
- if (!base)
- return -EINVAL;
+ node = ofnode_by_compatible(ofnode_null(), "microchip,mpfs-mss-top-sysreg");
+ if (!ofnode_valid(node))
+ return -ENODEV;
- ret = clk_get_by_index(dev, 0, parent_clk);
+ *regmap = syscon_node_to_regmap(node);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ *msspll_base = dev_read_addr_index_ptr(dev, 0);
+
+ return 0;
+}
+
+static int mpfs_clk_old_format_probe(struct udevice *dev, void __iomem **msspll_base,
+ struct regmap **regmap)
+{
+ int ret;
+
+ ret = regmap_init_mem_index(dev_ofnode(dev), regmap, 0);
if (ret)
return ret;
* Otherwise, skip registering it & pass the reference clock directly
* to the cfg clock registration function.
*/
- msspll_base = dev_read_addr_index_ptr(dev, 1);
+ *msspll_base = dev_read_addr_index_ptr(dev, 1);
+
+ return 0;
+}
+
+static int mpfs_clk_probe(struct udevice *dev)
+{
+ struct clk *parent_clk = dev_get_priv(dev);
+ struct clk clk_msspll = { .id = CLK_MSSPLL };
+ struct regmap *regmap;
+ void __iomem *msspll_base;
+ int ret;
+
+ ret = clk_get_by_index(dev, 0, parent_clk);
+ if (ret)
+ return ret;
+
+ ret = mpfs_clk_syscon_probe(dev, &msspll_base, ®map);
+ if (ret) {
+ ret = mpfs_clk_old_format_probe(dev, &msspll_base, ®map);
+ if (ret)
+ return ret;
+ }
+
if (msspll_base) {
ret = mpfs_clk_register_msspll(msspll_base, parent_clk);
if (ret)
parent_clk = &clk_msspll;
}
- ret = mpfs_clk_register_cfgs(base, parent_clk);
+ ret = mpfs_clk_register_cfgs(parent_clk, regmap);
if (ret)
return ret;
- ret = mpfs_clk_register_periphs(base, dev);
+ ret = mpfs_clk_register_periphs(dev, regmap);
return ret;
}
#define __MICROCHIP_MPFS_CLK_H
#include <linux/clk-provider.h>
+#include <regmap.h>
/**
* mpfs_clk_register_cfgs() - register configuration clocks
*
* @parent: a pointer to parent clock.
* Return: zero on success, or a negative error code.
*/
-int mpfs_clk_register_cfgs(void __iomem *base, struct clk *parent);
+int mpfs_clk_register_cfgs(struct clk *parent, struct regmap *regmap);
/**
* mpfs_clk_register_msspll() - register the mss pll
*
* @dev: udevice representing the clock controller.
* Return: zero on success, or a negative error code.
*/
-int mpfs_clk_register_periphs(void __iomem *base, struct udevice *dev);
+int mpfs_clk_register_periphs(struct udevice *dev, struct regmap *regmap);
/**
* divider_get_val() - get the clock divider value
*
#include <dm/device.h>
#include <dm/devres.h>
#include <dm/uclass.h>
+#include <regmap.h>
#include <dt-bindings/clock/microchip-mpfs-clock.h>
#include <linux/err.h>
*/
struct mpfs_cfg_hw_clock {
struct mpfs_cfg_clock cfg;
- void __iomem *sys_base;
+ struct regmap *regmap;
u32 prate;
struct clk hw;
};
{
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 rate;
u32 val;
- val = readl(base_addr + REG_CLOCK_CONFIG_CR) >> cfg->shift;
+ regmap_read(cfg_hw->regmap, REG_CLOCK_CONFIG_CR, &val);
+ val >>= cfg->shift;
val &= clk_div_mask(cfg->width);
rate = cfg_hw->prate / (1u << val);
hw->rate = rate;
{
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;
int divider_setting;
if (divider_setting < 0)
return divider_setting;
- val = readl(base_addr + REG_CLOCK_CONFIG_CR);
+ regmap_read(cfg_hw->regmap, REG_CLOCK_CONFIG_CR, &val);
val &= ~(clk_div_mask(cfg->width) << cfg_hw->cfg.shift);
val |= divider_setting << cfg->shift;
- writel(val, base_addr + REG_CLOCK_CONFIG_CR);
+ regmap_write(cfg_hw->regmap, REG_CLOCK_CONFIG_CR, val);
return clk_get_rate(hw);
}
CLK_CFG(CLK_AHB, "clk_ahb", 4, 2, mpfs_div_ahb_table, 0),
};
-int mpfs_clk_register_cfgs(void __iomem *base, struct clk *parent)
+int mpfs_clk_register_cfgs(struct clk *parent, struct regmap *regmap)
{
int ret;
int i, id, num_clks;
num_clks = ARRAY_SIZE(mpfs_cfg_clks);
for (i = 0; i < num_clks; i++) {
hw = &mpfs_cfg_clks[i].hw;
- mpfs_cfg_clks[i].sys_base = base;
+ mpfs_cfg_clks[i].regmap = regmap;
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->dev->name);
#include <dm/device.h>
#include <dm/devres.h>
#include <dm/uclass.h>
+#include <regmap.h>
#include <dt-bindings/clock/microchip-mpfs-clock.h>
#include <linux/err.h>
*/
struct mpfs_periph_hw_clock {
struct mpfs_periph_clock periph;
- void __iomem *sys_base;
+ struct regmap *regmap;
u32 prate;
struct clk 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;
+ u32 reg;
if (periph->flags != CLK_IS_CRITICAL) {
- reg = readl(base_addr + REG_SUBBLK_RESET_CR);
- val = reg & ~(1u << periph->shift);
- writel(val, base_addr + REG_SUBBLK_RESET_CR);
+ regmap_read(periph_hw->regmap, REG_SUBBLK_RESET_CR, ®);
+ reg &= ~(1u << periph->shift);
+ regmap_write(periph_hw->regmap, REG_SUBBLK_RESET_CR, reg);
- reg = readl(base_addr + REG_SUBBLK_CLOCK_CR);
- val = reg | (1u << periph->shift);
- writel(val, base_addr + REG_SUBBLK_CLOCK_CR);
+ regmap_read(periph_hw->regmap, REG_SUBBLK_CLOCK_CR, ®);
+ reg |= (1u << periph->shift);
+ regmap_write(periph_hw->regmap, REG_SUBBLK_CLOCK_CR, reg);
}
return 0;
{
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;
+ u32 reg;
if (periph->flags != CLK_IS_CRITICAL) {
- reg = readl(base_addr + REG_SUBBLK_RESET_CR);
- val = reg | (1u << periph->shift);
- writel(val, base_addr + REG_SUBBLK_RESET_CR);
+ regmap_read(periph_hw->regmap, REG_SUBBLK_RESET_CR, ®);
+ reg |= (1u << periph->shift);
+ regmap_write(periph_hw->regmap, REG_SUBBLK_RESET_CR, reg);
- reg = readl(base_addr + REG_SUBBLK_CLOCK_CR);
- val = reg & ~(1u << periph->shift);
- writel(val, base_addr + REG_SUBBLK_CLOCK_CR);
+ regmap_read(periph_hw->regmap, REG_SUBBLK_CLOCK_CR, ®);
+ reg &= ~(1u << periph->shift);
+ regmap_write(periph_hw->regmap, REG_SUBBLK_CLOCK_CR, reg);
}
return 0;
CLK_PERIPH(CLK_CFM, "clk_periph_cfm", CLK_AHB, 29, 0),
};
-int mpfs_clk_register_periphs(void __iomem *base, struct udevice *dev)
+int mpfs_clk_register_periphs(struct udevice *dev, struct regmap *regmap)
{
int ret;
int i, id, num_clks;
clk_request(dev, &parent);
hw = &mpfs_periph_clks[i].hw;
- mpfs_periph_clks[i].sys_base = base;
+ mpfs_periph_clks[i].regmap = regmap;
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);