@@ -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
*/
@@ -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);
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(+)