diff mbox series

[U-Boot,4/4] arm: mxs: implement mxs_set_gpmiclk

Message ID 20190912091656.14301-5-rasmus.villemoes@prevas.dk
State Changes Requested
Delegated to: Stefano Babic
Headers show
Series arm: mxs: mxs_set_gpmiclk | expand

Commit Message

Rasmus Villemoes Sept. 12, 2019, 9:17 a.m. UTC
This allows a board file to set the gpmiclk to something other than
the default 24 MHz based on ref_xtal.

I don't have an mx23-based board, but I believe there's a bug in the
current mxs_get_gpmiclk: According to the data sheet, the gpmiclk can
be derived from ref_io, not ref_cpu. Since other clocks are also
derived from ref_io, it seems most sensible to require the board file
to set that appropriately first, then derive the divider from its
current setting.

For mx28 boards, OTOH, there's a separate ref_gpmi only used for
clk_gpmi. For simplicity, if !xtal, simply enable that at its maximum
frequency.

Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
---
 arch/arm/cpu/arm926ejs/mxs/clock.c    | 41 +++++++++++++++++++++++++++
 arch/arm/include/asm/arch-mxs/clock.h |  1 +
 2 files changed, 42 insertions(+)
diff mbox series

Patch

diff --git a/arch/arm/cpu/arm926ejs/mxs/clock.c b/arch/arm/cpu/arm926ejs/mxs/clock.c
index 43d044d917..d247da56fe 100644
--- a/arch/arm/cpu/arm926ejs/mxs/clock.c
+++ b/arch/arm/cpu/arm926ejs/mxs/clock.c
@@ -138,6 +138,47 @@  static uint32_t mxs_get_gpmiclk(void)
 	return (PLL_FREQ_MHZ * PLL_FREQ_COEF / frac) / div;
 }
 
+void mxs_set_gpmiclk(uint32_t freq, int xtal)
+{
+	struct mxs_clkctrl_regs *clkctrl_regs =
+		(struct mxs_clkctrl_regs *)MXS_CLKCTRL_BASE;
+	uint32_t clk, div;
+
+	if (xtal) {
+		clk = XTAL_FREQ_KHZ;
+	} else {
+#if defined(CONFIG_MX23)
+		clk = mxs_get_ioclk(MXC_IOCLK0);
+#elif defined(CONFIG_MX28)
+		/* enable ref_gpmi at 480 MHz. */
+		writeb(CLKCTRL_FRAC_CLKGATE,
+			&clkctrl_regs->hw_clkctrl_frac1_set[CLKCTRL_FRAC1_GPMI]);
+		writeb(CLKCTRL_FRAC_CLKGATE | PLL_FREQ_COEF,
+			&clkctrl_regs->hw_clkctrl_frac1[CLKCTRL_FRAC1_GPMI]);
+		writeb(CLKCTRL_FRAC_CLKGATE,
+			&clkctrl_regs->hw_clkctrl_frac1_clr[CLKCTRL_FRAC1_GPMI]);
+		clk = PLL_FREQ_KHZ;
+#endif
+	}
+	if (freq > clk)
+		return;
+	div = clk / freq;
+	if (div > CLKCTRL_GPMI_DIV_MASK)
+		div = CLKCTRL_GPMI_DIV_MASK;
+
+	clrbits_le32(&clkctrl_regs->hw_clkctrl_gpmi, CLKCTRL_GPMI_CLKGATE);
+	while (readl(&clkctrl_regs->hw_clkctrl_gpmi) & CLKCTRL_GPMI_CLKGATE)
+		;
+	clrsetbits_le32(&clkctrl_regs->hw_clkctrl_gpmi, CLKCTRL_GPMI_DIV_MASK, div);
+	while (readl(&clkctrl_regs->hw_clkctrl_gpmi) & CLKCTRL_GPMI_BUSY)
+		;
+
+	if (xtal)
+		writel(CLKCTRL_CLKSEQ_BYPASS_GPMI, &clkctrl_regs->hw_clkctrl_clkseq_set);
+	else
+		writel(CLKCTRL_CLKSEQ_BYPASS_GPMI, &clkctrl_regs->hw_clkctrl_clkseq_clr);
+}
+
 /*
  * Set IO clock frequency, in kHz
  */
diff --git a/arch/arm/include/asm/arch-mxs/clock.h b/arch/arm/include/asm/arch-mxs/clock.h
index ee56d10fec..0a6625eb90 100644
--- a/arch/arm/include/asm/arch-mxs/clock.h
+++ b/arch/arm/include/asm/arch-mxs/clock.h
@@ -44,6 +44,7 @@  uint32_t mxc_get_clock(enum mxc_clock clk);
 
 void mxs_set_ioclk(enum mxs_ioclock io, uint32_t freq);
 void mxs_set_sspclk(enum mxs_sspclock ssp, uint32_t freq, int xtal);
+void mxs_set_gpmiclk(uint32_t freq, int xtal);
 void mxs_set_ssp_busclock(unsigned int bus, uint32_t freq);
 void mxs_set_lcdclk(uint32_t __maybe_unused lcd_base, uint32_t freq);