Commit cb4f4949 authored by Alexandre Belloni's avatar Alexandre Belloni Committed by Stephen Boyd
Browse files

clk: at91: allow configuring peripheral PCR layout



The PCR register actually changed layout for each SoC. By chance, this
didn't have impact on sama5d[2-4] support but since sama5d3, PID is seven
bits wide and sama5d4 and sama5d2 don't have DIV.

For the DT backward compatibility, keep the layout as is.

Signed-off-by: default avatarAlexandre Belloni <alexandre.belloni@bootlin.com>
Signed-off-by: default avatarStephen Boyd <sboyd@kernel.org>
parent 5c16ffa7
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -49,6 +49,13 @@ static const struct {
	{ .n = "pck1",  .p = "prog1",    .id = 9 },
};

static const struct clk_pcr_layout at91sam9x5_pcr_layout = {
	.offset = 0x10c,
	.cmd = BIT(12),
	.pid_mask = GENMASK(5, 0),
	.div_mask = GENMASK(17, 16),
};

struct pck {
	char *n;
	u8 id;
@@ -242,6 +249,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,

	for (i = 0; i < ARRAY_SIZE(at91sam9x5_periphck); i++) {
		hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
							 &at91sam9x5_pcr_layout,
							 at91sam9x5_periphck[i].n,
							 "masterck",
							 at91sam9x5_periphck[i].id,
@@ -254,6 +262,7 @@ static void __init at91sam9x5_pmc_setup(struct device_node *np,

	for (i = 0; extra_pcks[i].id; i++) {
		hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
							 &at91sam9x5_pcr_layout,
							 extra_pcks[i].n,
							 "masterck",
							 extra_pcks[i].id,
+24 −22
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 *
 */

#include <linux/bitops.h>
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/clk/at91_pmc.h>
@@ -23,9 +24,6 @@ DEFINE_SPINLOCK(pmc_pcr_lock);
#define PERIPHERAL_ID_MAX	31
#define PERIPHERAL_MASK(id)	(1 << ((id) & PERIPHERAL_ID_MAX))

#define PERIPHERAL_RSHIFT_MASK	0x3
#define PERIPHERAL_RSHIFT(val)	(((val) >> 16) & PERIPHERAL_RSHIFT_MASK)

#define PERIPHERAL_MAX_SHIFT	3

struct clk_peripheral {
@@ -43,6 +41,7 @@ struct clk_sam9x5_peripheral {
	spinlock_t *lock;
	u32 id;
	u32 div;
	const struct clk_pcr_layout *layout;
	bool auto_div;
};

@@ -169,13 +168,13 @@ static int clk_sam9x5_peripheral_enable(struct clk_hw *hw)
		return 0;

	spin_lock_irqsave(periph->lock, flags);
	regmap_write(periph->regmap, AT91_PMC_PCR,
		     (periph->id & AT91_PMC_PCR_PID_MASK));
	regmap_update_bits(periph->regmap, AT91_PMC_PCR,
			   AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
	regmap_write(periph->regmap, periph->layout->offset,
		     (periph->id & periph->layout->pid_mask));
	regmap_update_bits(periph->regmap, periph->layout->offset,
			   periph->layout->div_mask | periph->layout->cmd |
			   AT91_PMC_PCR_EN,
			   AT91_PMC_PCR_DIV(periph->div) |
			   AT91_PMC_PCR_CMD |
			   field_prep(periph->layout->div_mask, periph->div) |
			   periph->layout->cmd |
			   AT91_PMC_PCR_EN);
	spin_unlock_irqrestore(periph->lock, flags);

@@ -191,11 +190,11 @@ static void clk_sam9x5_peripheral_disable(struct clk_hw *hw)
		return;

	spin_lock_irqsave(periph->lock, flags);
	regmap_write(periph->regmap, AT91_PMC_PCR,
		     (periph->id & AT91_PMC_PCR_PID_MASK));
	regmap_update_bits(periph->regmap, AT91_PMC_PCR,
			   AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,
			   AT91_PMC_PCR_CMD);
	regmap_write(periph->regmap, periph->layout->offset,
		     (periph->id & periph->layout->pid_mask));
	regmap_update_bits(periph->regmap, periph->layout->offset,
			   AT91_PMC_PCR_EN | periph->layout->cmd,
			   periph->layout->cmd);
	spin_unlock_irqrestore(periph->lock, flags);
}

@@ -209,9 +208,9 @@ static int clk_sam9x5_peripheral_is_enabled(struct clk_hw *hw)
		return 1;

	spin_lock_irqsave(periph->lock, flags);
	regmap_write(periph->regmap, AT91_PMC_PCR,
		     (periph->id & AT91_PMC_PCR_PID_MASK));
	regmap_read(periph->regmap, AT91_PMC_PCR, &status);
	regmap_write(periph->regmap, periph->layout->offset,
		     (periph->id & periph->layout->pid_mask));
	regmap_read(periph->regmap, periph->layout->offset, &status);
	spin_unlock_irqrestore(periph->lock, flags);

	return status & AT91_PMC_PCR_EN ? 1 : 0;
@@ -229,13 +228,13 @@ clk_sam9x5_peripheral_recalc_rate(struct clk_hw *hw,
		return parent_rate;

	spin_lock_irqsave(periph->lock, flags);
	regmap_write(periph->regmap, AT91_PMC_PCR,
		     (periph->id & AT91_PMC_PCR_PID_MASK));
	regmap_read(periph->regmap, AT91_PMC_PCR, &status);
	regmap_write(periph->regmap, periph->layout->offset,
		     (periph->id & periph->layout->pid_mask));
	regmap_read(periph->regmap, periph->layout->offset, &status);
	spin_unlock_irqrestore(periph->lock, flags);

	if (status & AT91_PMC_PCR_EN) {
		periph->div = PERIPHERAL_RSHIFT(status);
		periph->div = field_get(periph->layout->div_mask, status);
		periph->auto_div = false;
	} else {
		clk_sam9x5_peripheral_autodiv(periph);
@@ -328,6 +327,7 @@ static const struct clk_ops sam9x5_peripheral_ops = {

struct clk_hw * __init
at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
				    const struct clk_pcr_layout *layout,
				    const char *name, const char *parent_name,
				    u32 id, const struct clk_range *range)
{
@@ -354,7 +354,9 @@ at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
	periph->div = 0;
	periph->regmap = regmap;
	periph->lock = lock;
	if (layout->div_mask)
		periph->auto_div = true;
	periph->layout = layout;
	periph->range = *range;

	hw = &periph->hw;
+9 −0
Original line number Diff line number Diff line
@@ -93,6 +93,14 @@ CLK_OF_DECLARE(of_sama5d2_clk_audio_pll_pmc_setup,
	       of_sama5d2_clk_audio_pll_pmc_setup);
#endif /* CONFIG_HAVE_AT91_AUDIO_PLL */

static const struct clk_pcr_layout dt_pcr_layout = {
	.offset = 0x10c,
	.cmd = BIT(12),
	.pid_mask = GENMASK(5, 0),
	.div_mask = GENMASK(17, 16),
	.gckcss_mask = GENMASK(10, 8),
};

#ifdef CONFIG_HAVE_AT91_GENERATED_CLK
#define GENERATED_SOURCE_MAX	6

@@ -448,6 +456,7 @@ of_at91_clk_periph_setup(struct device_node *np, u8 type)

			hw = at91_clk_register_sam9x5_peripheral(regmap,
								 &pmc_pcr_lock,
								 &dt_pcr_layout,
								 name,
								 parent_name,
								 id, &range);
+12 −0
Original line number Diff line number Diff line
@@ -80,6 +80,17 @@ extern const struct clk_programmable_layout at91rm9200_programmable_layout;
extern const struct clk_programmable_layout at91sam9g45_programmable_layout;
extern const struct clk_programmable_layout at91sam9x5_programmable_layout;

struct clk_pcr_layout {
	u32 offset;
	u32 cmd;
	u32 div_mask;
	u32 gckcss_mask;
	u32 pid_mask;
};

#define field_get(_mask, _reg) (((_reg) & (_mask)) >> (ffs(_mask) - 1))
#define field_prep(_mask, _val) (((_val) << (ffs(_mask) - 1)) & (_mask))

#define ndck(a, s) (a[s - 1].id + 1)
#define nck(a) (a[ARRAY_SIZE(a) - 1].id + 1)
struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
@@ -143,6 +154,7 @@ at91_clk_register_peripheral(struct regmap *regmap, const char *name,
			     const char *parent_name, u32 id);
struct clk_hw * __init
at91_clk_register_sam9x5_peripheral(struct regmap *regmap, spinlock_t *lock,
				    const struct clk_pcr_layout *layout,
				    const char *name, const char *parent_name,
				    u32 id, const struct clk_range *range);

+9 −0
Original line number Diff line number Diff line
@@ -28,6 +28,13 @@ static const struct clk_pll_characteristics plla_characteristics = {
	.out = plla_out,
};

static const struct clk_pcr_layout sama5d2_pcr_layout = {
	.offset = 0x10c,
	.cmd = BIT(12),
	.gckcss_mask = GENMASK(10, 8),
	.pid_mask = GENMASK(6, 0),
};

static const struct {
	char *n;
	char *p;
@@ -266,6 +273,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)

	for (i = 0; i < ARRAY_SIZE(sama5d2_periphck); i++) {
		hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
							 &sama5d2_pcr_layout,
							 sama5d2_periphck[i].n,
							 "masterck",
							 sama5d2_periphck[i].id,
@@ -278,6 +286,7 @@ static void __init sama5d2_pmc_setup(struct device_node *np)

	for (i = 0; i < ARRAY_SIZE(sama5d2_periph32ck); i++) {
		hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
							 &sama5d2_pcr_layout,
							 sama5d2_periph32ck[i].n,
							 "h32mxck",
							 sama5d2_periph32ck[i].id,
Loading