diff options
Diffstat (limited to 'target/linux/xburst/patches-3.3/0011-MIPS-JZ4740-Added-setting-of-PLL-rate-and-main-divid.patch')
-rw-r--r-- | target/linux/xburst/patches-3.3/0011-MIPS-JZ4740-Added-setting-of-PLL-rate-and-main-divid.patch | 351 |
1 files changed, 0 insertions, 351 deletions
diff --git a/target/linux/xburst/patches-3.3/0011-MIPS-JZ4740-Added-setting-of-PLL-rate-and-main-divid.patch b/target/linux/xburst/patches-3.3/0011-MIPS-JZ4740-Added-setting-of-PLL-rate-and-main-divid.patch deleted file mode 100644 index 01c211ba77..0000000000 --- a/target/linux/xburst/patches-3.3/0011-MIPS-JZ4740-Added-setting-of-PLL-rate-and-main-divid.patch +++ /dev/null @@ -1,351 +0,0 @@ -From 27ff621cd9a5347efda4be502abbef13a99146ce Mon Sep 17 00:00:00 2001 -From: Maarten ter Huurne <maarten@treewalker.org> -Date: Sun, 29 Aug 2010 08:11:00 +0200 -Subject: [PATCH 11/21] MIPS: JZ4740: Added setting of PLL rate and main - dividers. - -This functionality makes a cpufreq driver possible. -Squashed version of the development done in the jz-2.6.39 branch. ---- - arch/mips/jz4740/clock.c | 230 ++++++++++++++++++++++++++++++++++++++++++++-- - arch/mips/jz4740/clock.h | 4 + - 2 files changed, 224 insertions(+), 10 deletions(-) - ---- a/arch/mips/jz4740/clock.c -+++ b/arch/mips/jz4740/clock.c -@@ -1,5 +1,8 @@ - /* -+ * Copyright (c) 2006-2007, Ingenic Semiconductor Inc. - * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> -+ * Copyright (c) 2010, Ulrich Hecht <ulrich.hecht@gmail.com> -+ * Copyright (c) 2010, Maarten ter Huurne <maarten@treewalker.org> - * JZ4740 SoC clock support - * - * This program is free software; you can redistribute it and/or modify it -@@ -41,16 +44,20 @@ - #define JZ_CLOCK_CTRL_I2S_SRC_PLL BIT(31) - #define JZ_CLOCK_CTRL_KO_ENABLE BIT(30) - #define JZ_CLOCK_CTRL_UDC_SRC_PLL BIT(29) --#define JZ_CLOCK_CTRL_UDIV_MASK 0x1f800000 - #define JZ_CLOCK_CTRL_CHANGE_ENABLE BIT(22) - #define JZ_CLOCK_CTRL_PLL_HALF BIT(21) --#define JZ_CLOCK_CTRL_LDIV_MASK 0x001f0000 - #define JZ_CLOCK_CTRL_UDIV_OFFSET 23 - #define JZ_CLOCK_CTRL_LDIV_OFFSET 16 - #define JZ_CLOCK_CTRL_MDIV_OFFSET 12 - #define JZ_CLOCK_CTRL_PDIV_OFFSET 8 - #define JZ_CLOCK_CTRL_HDIV_OFFSET 4 - #define JZ_CLOCK_CTRL_CDIV_OFFSET 0 -+#define JZ_CLOCK_CTRL_UDIV_MASK (0x3f << JZ_CLOCK_CTRL_UDIV_OFFSET) -+#define JZ_CLOCK_CTRL_LDIV_MASK (0x1f << JZ_CLOCK_CTRL_LDIV_OFFSET) -+#define JZ_CLOCK_CTRL_MDIV_MASK (0x0f << JZ_CLOCK_CTRL_MDIV_OFFSET) -+#define JZ_CLOCK_CTRL_PDIV_MASK (0x0f << JZ_CLOCK_CTRL_PDIV_OFFSET) -+#define JZ_CLOCK_CTRL_HDIV_MASK (0x0f << JZ_CLOCK_CTRL_HDIV_OFFSET) -+#define JZ_CLOCK_CTRL_CDIV_MASK (0x0f << JZ_CLOCK_CTRL_CDIV_OFFSET) - - #define JZ_CLOCK_GATE_UART0 BIT(0) - #define JZ_CLOCK_GATE_TCU BIT(1) -@@ -90,6 +97,7 @@ - #define JZ_CLOCK_PLL_M_OFFSET 23 - #define JZ_CLOCK_PLL_N_OFFSET 18 - #define JZ_CLOCK_PLL_OD_OFFSET 16 -+#define JZ_CLOCK_PLL_STABILIZE_OFFSET 0 - - #define JZ_CLOCK_LOW_POWER_MODE_DOZE BIT(2) - #define JZ_CLOCK_LOW_POWER_MODE_SLEEP BIT(0) -@@ -97,10 +105,15 @@ - #define JZ_CLOCK_SLEEP_CTRL_SUSPEND_UHC BIT(7) - #define JZ_CLOCK_SLEEP_CTRL_ENABLE_UDC BIT(6) - -+#define JZ_REG_EMC_RTCNT 0x88 -+#define JZ_REG_EMC_RTCOR 0x8C -+ - static void __iomem *jz_clock_base; - static spinlock_t jz_clock_lock; - static LIST_HEAD(jz_clocks); - -+static void __iomem *jz_emc_base; -+ - struct main_clk { - struct clk clk; - uint32_t div_offset; -@@ -204,25 +217,88 @@ static int jz_clk_ko_is_enabled(struct c - return !!(jz_clk_reg_read(JZ_REG_CLOCK_CTRL) & JZ_CLOCK_CTRL_KO_ENABLE); - } - -+static struct static_clk jz_clk_ext; -+ -+static unsigned long jz_clk_pll_calc_rate( -+ unsigned int in_div, unsigned int feedback, unsigned int out_div) -+{ -+ return ((jz_clk_ext.rate / in_div) * feedback) / out_div; -+} -+ -+static void jz_clk_pll_calc_dividers(unsigned long rate, -+ unsigned int *in_div, unsigned int *feedback, unsigned int *out_div) -+{ -+ unsigned int target; -+ -+ /* The frequency after the input divider must be between 1 and 15 MHz. -+ The highest divider yields the best resolution. */ -+ *in_div = jz_clk_ext.rate / 1000000; -+ if (*in_div >= 34) -+ *in_div = 33; -+ -+ /* The frequency before the output divider must be between 100 and -+ 500 MHz. The lowest target rate is more energy efficient. */ -+ if (rate < 25000000) { -+ *out_div = 4; -+ target = 25000000 * 4; -+ } else if (rate <= 50000000) { -+ *out_div = 4; -+ target = rate * 4; -+ } else if (rate <= 100000000) { -+ *out_div = 2; -+ target = rate * 2; -+ } else if (rate <= 500000000) { -+ *out_div = 1; -+ target = rate; -+ } else { -+ *out_div = 1; -+ target = 500000000; -+ } -+ -+ /* Compute the feedback divider. -+ Since the divided input is at least 1 MHz and the target frequency -+ at most 500 MHz, the feedback will be at most 500 and will therefore -+ always fit in the 9-bit register. -+ Similarly, the divided input is at most 15 MHz and the target -+ frequency at least 100 MHz, so the feedback will be at least 6 -+ where the minimum supported value is 2. */ -+ *feedback = ((target / 1000) * *in_div) / (jz_clk_ext.rate / 1000); -+} -+ -+static unsigned long jz_clk_pll_round_rate(struct clk *clk, unsigned long rate) -+{ -+ unsigned int in_div, feedback, out_div; -+ /* The PLL frequency must be a multiple of 24 MHz, since the LCD pixel -+ * clock must be exactly 12 MHz for the TV-out to work. -+ * TODO: A multiple of 12 MHz for the PLL would work if the PLL would -+ * not be divided by 2 before being passed to the set of derived -+ * clocks that includes the LCD pixel clock. -+ * TODO: Systemwide decisions like this should be made by the board -+ * support code, so add some kind of hook for that. -+ */ -+ unsigned long rate24 = (rate / 24000000) * 24000000; -+ -+ jz_clk_pll_calc_dividers(rate24, &in_div, &feedback, &out_div); -+ return jz_clk_pll_calc_rate(in_div, feedback, out_div); -+} -+ - static const int pllno[] = {1, 2, 2, 4}; - - static unsigned long jz_clk_pll_get_rate(struct clk *clk) - { - uint32_t val; -- int m; -- int n; -- int od; -+ unsigned int in_div, feedback, out_div; - - val = jz_clk_reg_read(JZ_REG_CLOCK_PLL); - - if (val & JZ_CLOCK_PLL_BYPASS) - return clk_get_rate(clk->parent); - -- m = ((val >> 23) & 0x1ff) + 2; -- n = ((val >> 18) & 0x1f) + 2; -- od = (val >> 16) & 0x3; -+ feedback = ((val >> 23) & 0x1ff) + 2; -+ in_div = ((val >> 18) & 0x1f) + 2; -+ out_div = pllno[(val >> 16) & 0x3]; - -- return ((clk_get_rate(clk->parent) / n) * m) / pllno[od]; -+ return jz_clk_pll_calc_rate(in_div, feedback, out_div); - } - - static unsigned long jz_clk_pll_half_get_rate(struct clk *clk) -@@ -235,7 +311,77 @@ static unsigned long jz_clk_pll_half_get - return jz_clk_pll_get_rate(clk->parent) >> 1; - } - --static const int jz_clk_main_divs[] = {1, 2, 3, 4, 6, 8, 12, 16, 24, 32}; -+#define SDRAM_TREF 15625 /* Refresh period: 4096 refresh cycles/64ms */ -+ -+static void sdram_set_pll(unsigned int pllin) -+{ -+ unsigned int ns, sdramclock; -+ -+ ns = 1000000000 / pllin; -+ sdramclock = (SDRAM_TREF / ns) / 64 + 1; -+ if (sdramclock > 0xff) sdramclock = 0xff; -+ /* Set refresh registers */ -+ writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCOR); -+ writew(sdramclock, jz_emc_base + JZ_REG_EMC_RTCNT); -+} -+ -+static int jz_clk_pll_set_rate(struct clk *clk, unsigned long rate) -+{ -+ unsigned int ctrl, plcr1; -+ unsigned int feedback, in_div, out_div, pllout, pllout2; -+ -+ jz_clk_pll_calc_dividers(rate, &in_div, &feedback, &out_div); -+ -+ ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); -+ pllout = jz_clk_pll_calc_rate(in_div, feedback, out_div); -+ pllout2 = (ctrl & JZ_CLOCK_CTRL_PLL_HALF) ? pllout : (pllout / 2); -+ -+ /* Init UHC clock */ -+ writel(pllout2 / 48000000 - 1, jz_clock_base + JZ_REG_CLOCK_UHC); -+ -+ plcr1 = ((feedback - 2) << JZ_CLOCK_PLL_M_OFFSET) | -+ ((in_div - 2) << JZ_CLOCK_PLL_N_OFFSET) | -+ ((out_div - 1) << JZ_CLOCK_PLL_OD_OFFSET) | -+ (0x20 << JZ_CLOCK_PLL_STABILIZE_OFFSET) | -+ JZ_CLOCK_PLL_ENABLED; -+ -+ sdram_set_pll(pllout); -+ -+ /* LCD pixclock */ -+ writel(pllout2 / 12000000 - 1, jz_clock_base + JZ_REG_CLOCK_LCD); -+ -+ /* configure PLL */ -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %1,0(%0)\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : -+ : "r" (jz_clock_base + JZ_REG_CLOCK_PLL), "r" (plcr1)); -+ -+ /* MtH: For some reason the MSC will have problems if this flag is not -+ restored, even though the MSC is supposedly the only divider -+ that is not affected by this flag. */ -+ jz_clk_reg_set_bits(JZ_REG_CLOCK_CTRL, JZ_CLOCK_CTRL_CHANGE_ENABLE); -+ -+ return 0; -+} -+ -+static const unsigned int jz_clk_main_divs[] = { -+ 1, 2, 3, 4, 6, 8, 12, 16, 24, 32 -+}; -+static const unsigned int jz_clk_main_divs_inv[] = { -+ -1, 0, 1, 2, 3, -1, 4, -1, 5, -1, -1, -1, 6, -1, -1, -1, -+ 7, -1, -1, -1, -1, -1, -1, -1, 8, -1, -1, -1, -1, -1, -1, -1, -+ 9 -+}; - - static unsigned long jz_clk_main_round_rate(struct clk *clk, unsigned long rate) - { -@@ -290,6 +436,64 @@ static int jz_clk_main_set_rate(struct c - return 0; - } - -+static struct main_clk jz_clk_cpu; -+ -+int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv, -+ unsigned int mdiv, unsigned int pdiv) -+{ -+ unsigned int cdiv_enc, hdiv_enc, mdiv_enc, pdiv_enc; -+ unsigned int ctrl; -+ unsigned int tmp, wait; -+ -+ if (cdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) || -+ hdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) || -+ mdiv >= ARRAY_SIZE(jz_clk_main_divs_inv) || -+ pdiv >= ARRAY_SIZE(jz_clk_main_divs_inv)) -+ return -EINVAL; -+ cdiv_enc = jz_clk_main_divs_inv[cdiv]; -+ hdiv_enc = jz_clk_main_divs_inv[hdiv]; -+ mdiv_enc = jz_clk_main_divs_inv[mdiv]; -+ pdiv_enc = jz_clk_main_divs_inv[pdiv]; -+ if (cdiv_enc == (unsigned int)-1 || -+ hdiv_enc == (unsigned int)-1 || -+ mdiv_enc == (unsigned int)-1 || -+ pdiv_enc == (unsigned int)-1) -+ return -EINVAL; -+ -+ ctrl = jz_clk_reg_read(JZ_REG_CLOCK_CTRL); -+ ctrl &= ~(JZ_CLOCK_CTRL_CHANGE_ENABLE | -+ JZ_CLOCK_CTRL_CDIV_MASK | JZ_CLOCK_CTRL_HDIV_MASK | -+ JZ_CLOCK_CTRL_MDIV_MASK | JZ_CLOCK_CTRL_PDIV_MASK); -+ if (immediate) ctrl |= JZ_CLOCK_CTRL_CHANGE_ENABLE; -+ ctrl |= (cdiv_enc << JZ_CLOCK_CTRL_CDIV_OFFSET) | -+ (hdiv_enc << JZ_CLOCK_CTRL_HDIV_OFFSET) | -+ (mdiv_enc << JZ_CLOCK_CTRL_MDIV_OFFSET) | -+ (pdiv_enc << JZ_CLOCK_CTRL_PDIV_OFFSET); -+ -+ /* set dividers */ -+ /* delay loops lifted from the old Ingenic cpufreq driver */ -+ wait = ((clk_get_rate(&jz_clk_cpu.clk) / 1000000) * 500) / 1000; -+ __asm__ __volatile__( -+ ".set noreorder\n\t" -+ ".align 5\n" -+ "sw %2,0(%1)\n\t" -+ "li %0,0\n\t" -+ "1:\n\t" -+ "bne %0,%3,1b\n\t" -+ "addi %0, 1\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ "nop\n\t" -+ ".set reorder\n\t" -+ : "=r" (tmp) -+ : "r" (jz_clock_base + JZ_REG_CLOCK_CTRL), "r" (ctrl), -+ "r" (wait)); -+ -+ return 0; -+} -+EXPORT_SYMBOL_GPL(clk_main_set_dividers); -+ - static struct clk_ops jz_clk_static_ops = { - .get_rate = jz_clk_static_get_rate, - .enable = jz_clk_enable_gating, -@@ -307,6 +511,8 @@ static struct static_clk jz_clk_ext = { - - static struct clk_ops jz_clk_pll_ops = { - .get_rate = jz_clk_pll_get_rate, -+ .set_rate = jz_clk_pll_set_rate, -+ .round_rate = jz_clk_pll_round_rate, - }; - - static struct clk jz_clk_pll = { -@@ -897,6 +1103,10 @@ static int jz4740_clock_init(void) - if (!jz_clock_base) - return -EBUSY; - -+ jz_emc_base = ioremap(JZ4740_EMC_BASE_ADDR, 0x100); -+ if (!jz_emc_base) -+ return -EBUSY; -+ - spin_lock_init(&jz_clock_lock); - - jz_clk_ext.rate = jz4740_clock_bdata.ext_rate; ---- a/arch/mips/jz4740/clock.h -+++ b/arch/mips/jz4740/clock.h -@@ -17,6 +17,7 @@ - #define __MIPS_JZ4740_CLOCK_H__ - - #include <linux/list.h> -+#include <linux/types.h> - - struct jz4740_clock_board_data { - unsigned long ext_rate; -@@ -63,6 +64,9 @@ struct clk { - - int clk_is_enabled(struct clk *clk); - -+int clk_main_set_dividers(bool immediate, unsigned int cdiv, unsigned int hdiv, -+ unsigned int mdiv, unsigned int pdiv); -+ - #ifdef CONFIG_DEBUG_FS - void jz4740_clock_debugfs_init(void); - void jz4740_clock_debugfs_add_clk(struct clk *clk); |