Here's a first pass at better modeling of clocks and PLLs.  The longer
term goal being the ability model the clock tree well enough to do
DVFS on parts that support it.

- generalize PLLs
- add concept of clock parents
- drop 'div_by_*' in favor of 'fixed_divider' attribute of clock
- misc. other minor cleanups

TODO:
- add PLL2 which can have programmable dividers.

Known problems:
- doesn't boot on dm646x, and can't see why because DEBUG_LL doesn't work either

Basic boot testing on dm6446 and dm355.
---
 arch/arm/mach-davinci/clock.c |  273 +++++++++++++++++++++++++++++------------
 arch/arm/mach-davinci/clock.h |   17 +++-
 2 files changed, 211 insertions(+), 79 deletions(-)

diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 67ab35d..aeee633 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -25,22 +25,31 @@
 #include <mach/cpu.h>
 #include "clock.h"
 
-#define DAVINCI_PLL_CNTRL0_BASE 0x01C40800
+#define DAVINCI_PLL1_BASE 0x01c40800
+#define DAVINCI_PLL2_BASE 0x01c40c00
+#define MAX_PLL 2
 
 /* PLL/Reset register offsets */
+#define PLLCTL          0x100
+#define PLLCTL_PLLEN    BIT(0)
+#define PLLCTL_CLKMODE  BIT(8)
+
 #define PLLM           0x110
+#define PLLM_PLLM_MASK  0x1f
+
+#define PREDIV          0x114
+#define PLLDIV1         0x118
+#define PLLDIV2         0x11c
+#define PLLDIV3         0x120
+#define POSTDIV         0x128
+#define BPDIV           0x12c
+#define PLLDIV_EN       BIT(15)
+#define PLLDIV_RATIO_MASK 0xf
 
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
 static DEFINE_SPINLOCK(clockfw_lock);
 
-static unsigned int commonrate;
-static unsigned int div_by_four;
-static unsigned int div_by_six;
-static unsigned int div_by_eight;
-static unsigned int armrate;
-static unsigned int fixedrate = 27000000;      /* 27 MHZ */
-
 extern void davinci_psc_config(unsigned int domain, unsigned int id, char 
enable);
 
 /*
@@ -213,7 +222,7 @@ unsigned long clk_get_rate(struct clk *clk)
        if (clk == NULL || IS_ERR(clk))
                return -EINVAL;
 
-       return *(clk->rate);
+       return clk->rate;
 }
 EXPORT_SYMBOL(clk_get_rate);
 
@@ -222,7 +231,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
        if (clk == NULL || IS_ERR(clk))
                return -EINVAL;
 
-       return *(clk->rate);
+       return clk->rate;
 }
 EXPORT_SYMBOL(clk_round_rate);
 
@@ -241,6 +250,12 @@ int clk_register(struct clk *clk)
        if (clk == NULL || IS_ERR(clk))
                return -EINVAL;
 
+       if (clk->fixed_divisor) {
+               BUG_ON(!clk->parent);
+               BUG_ON(!clk->parent->rate);
+               clk->rate = clk->parent->rate / clk->fixed_divisor;
+       }
+
        mutex_lock(&clocks_mutex);
        list_add(&clk->node, &clocks);
        mutex_unlock(&clocks_mutex);
@@ -260,223 +275,287 @@ void clk_unregister(struct clk *clk)
 }
 EXPORT_SYMBOL(clk_unregister);
 
+static struct pll_data pll1_data = {
+       .phys_base = DAVINCI_PLL1_BASE,
+};
+
+static struct clk osc_clk = {
+       .name = "osc_clk",
+       .flags = ALWAYS_ENABLED,
+};
+
+static struct clk aux_clk = {
+       .name = "aux_clk",
+       .flags = ALWAYS_ENABLED,
+};
+
+static struct clk pll1_clk = {
+       .name = "pll1",
+       .parent = &osc_clk,
+       .pll_data = &pll1_data,
+};
+
+static struct clk *pll_list[] = {
+       &pll1_clk,
+       NULL,
+};
+
 static struct clk davinci_clks[] = {
        {
                .name = "ARMCLK",
-               .rate = &armrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 2,
                .lpsc = -1,
                .flags = ALWAYS_ENABLED,
        },
        {
                .name = "UART0",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_UART0,
        },
        {
                .name = "UART1",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_UART1,
        },
        {
                .name = "UART2",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_UART2,
        },
        {
                .name = "EMACCLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_EMAC_WRAPPER,
        },
        {
                .name = "I2CCLK",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_I2C,
        },
        {
                .name = "IDECLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_ATA,
        },
        {
                .name = "McBSPCLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_McBSP,
        },
        {
                .name = "MMCSDCLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_MMC_SD,
        },
        {
                .name = "SPICLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_SPI,
        },
        {
                .name = "gpio",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_GPIO,
        },
        {
                .name = "USBCLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_USB,
        },
        {
                .name = "VLYNQCLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_VLYNQ,
        },
        {
                .name = "AEMIFCLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_AEMIF,
                .usecount = 1,
        }
 };
+
 static struct clk davinci_dm646x_clks[] = {
        {
                .name = "ARMCLK",
-               .rate = &armrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 2,
                .lpsc = -1,
                .flags = ALWAYS_ENABLED,
        },
        {
                .name = "UART0",
-               .rate = &fixedrate,
+               .parent = &aux_clk,
+               .fixed_divisor = 1,
                .lpsc = DM646X_LPSC_UART0,
        },
        {
                .name = "UART1",
-               .rate = &fixedrate,
+               .parent = &aux_clk,
+               .fixed_divisor = 1,
                .lpsc = DM646X_LPSC_UART1,
        },
        {
                .name = "UART2",
-               .rate = &fixedrate,
+               .parent = &aux_clk,
+               .fixed_divisor = 1,
                .lpsc = DM646X_LPSC_UART2,
        },
        {
                .name = "I2CCLK",
-               .rate = &div_by_four,
+               .parent = &pll1_clk,
+               .fixed_divisor = 4,
                .lpsc = DM646X_LPSC_I2C,
        },
        {
                .name = "gpio",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 4,
                .lpsc = DM646X_LPSC_GPIO,
        },
        {
                .name = "AEMIFCLK",
-               .rate = &div_by_four,
+               .parent = &pll1_clk,
+               .fixed_divisor = 4,
                .lpsc = DM646X_LPSC_AEMIF,
                .usecount = 1,
        },
        {
                .name = "EMACCLK",
-               .rate = &div_by_four,
+               .parent = &pll1_clk,
+               .fixed_divisor = 4,
                .lpsc = DM646X_LPSC_EMAC,
        },
 };
 static struct clk davinci_dm355_clks[] = {
        {
                .name = "ARMCLK",
-               .rate = &armrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 2,
                .lpsc = -1,
                .flags = ALWAYS_ENABLED,
        },
        {
                .name = "UART0",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_UART0,
-               .usecount = 1,
        },
        {
                .name = "UART1",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_UART1,
-               .usecount = 1,
        },
        {
                .name = "UART2",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_UART2,
-               .usecount = 1,
        },
        {
                .name = "I2CCLK",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_I2C,
        },
        {
                .name = "McBSPCLK0",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_McBSP,
        },
        {
                .name = "McBSPCLK1",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DM355_LPSC_McBSP1,
        },
        {
                .name = "MMCSDCLK0",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_MMC_SD,
        },
        {
                .name = "MMCSDCLK1",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DM355_LPSC_MMC_SD1,
        },
        {
                .name = "SPICLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_SPI,
        },
        {
                .name = "SPICLK1",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DM355_LPSC_SPI1,
        },
        {
                .name = "SPICLK2",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DM355_LPSC_SPI2,
        },
        {
                .name = "gpio",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_GPIO,
        },
        {
                .name = "AEMIFCLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_AEMIF,
                .usecount = 1,
        },
        {
                .name = "PWM0_CLK",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_PWM0,
        },
        {
                .name = "PWM1_CLK",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_PWM1,
        },
        {
                .name = "PWM2_CLK",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DAVINCI_LPSC_PWM2,
        },
        {
                .name = "PWM3_CLK",
-               .rate = &fixedrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 1,
                .lpsc = DM355_LPSC_PWM3,
        },
        {
                .name = "USBCLK",
-               .rate = &commonrate,
+               .parent = &pll1_clk,
+               .fixed_divisor = 6,
                .lpsc = DAVINCI_LPSC_USB,
        },
 };
@@ -505,42 +584,82 @@ static int __init clk_disable_unused(void)
 late_initcall(clk_disable_unused);
 #endif
 
+static void __init davinci_pll_init(void)
+{
+       int i;
+
+       if (cpu_is_davinci_dm646x()) {
+               osc_clk.rate = DM646X_OSC_FREQ;
+               aux_clk.rate = DM646X_AUX_OSC_FREQ;
+       } else if (cpu_is_davinci_dm355())
+               osc_clk.rate = DM355_OSC_FREQ;
+       else
+               osc_clk.rate = DM644X_OSC_FREQ;
+       clk_register(&osc_clk);
+       clk_register(&aux_clk);
+
+       for(i = 0; i < MAX_PLL; i++) {
+               u32 ctrl, mult, prediv = 1, postdiv = 1;
+               u8 bypass;
+               void __iomem *base;
+               struct clk *pll_clk = pll_list[i];
+
+               if (!pll_clk)
+                       continue;
+
+               base = IO_ADDRESS(pll_clk->pll_data->phys_base);
+               ctrl = __raw_readl(base + PLLCTL);
+               bypass = !(ctrl & PLLCTL_PLLEN);
+               pll_clk->rate = pll_clk->parent->rate;
+
+               mult = __raw_readl(base + PLLM) & PLLM_PLLM_MASK;
+               mult += 1;
+
+               postdiv = __raw_readl(base + POSTDIV);
+               if (postdiv & PLLDIV_EN)
+                       postdiv = (postdiv & PLLDIV_RATIO_MASK) + 1;
+
+               if (!cpu_is_davinci_dm644x()) {
+                       prediv = __raw_readl(base + PREDIV);
+                       if (prediv & PLLDIV_EN)
+                               prediv = (prediv & PLLDIV_RATIO_MASK) + 1;
+               }
+
+               if (!bypass) {
+                       pll_clk->rate /= prediv;
+                       pll_clk->rate *= mult;
+                       pll_clk->rate /= postdiv;
+               }
+
+               printk(KERN_INFO "PLL%d: input = %lu MHz [ ",
+                      i + 1, pll_clk->parent->rate / 1000000);
+               if (bypass)
+                       printk("bypass ");
+               if (prediv > 1)
+                       printk("/ %d ", prediv);
+               if (mult > 1)
+                       printk("* %d ", mult);
+               if (postdiv > 1)
+                       printk("/ %d ", postdiv);
+               printk("] --> %lu MHz output.\n", pll_clk->rate / 1000000);
+       }
+}
+
 int __init davinci_clk_init(void)
 {
        struct clk *clkp;
        static struct clk *board_clks;
        int count = 0, num_clks;
-       u32 pll_mult;
 
-       pll_mult = davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLM);
-       commonrate = ((pll_mult + 1) * DM646X_OSC_FREQ) / 6;
-       armrate = ((pll_mult + 1) * DM646X_OSC_FREQ) / 2;
+       davinci_pll_init();
 
        if (cpu_is_davinci_dm646x()) {
-               fixedrate = 24000000;
-               div_by_four = ((pll_mult + 1) * DM646X_OSC_FREQ) / 4;
-               div_by_six = ((pll_mult + 1) * DM646X_OSC_FREQ) / 6;
-               div_by_eight = ((pll_mult + 1) * DM646X_OSC_FREQ) / 8;
-               armrate = ((pll_mult + 1) * DM646X_OSC_FREQ) / 2;
-
                board_clks = davinci_dm646x_clks;
                num_clks = ARRAY_SIZE(davinci_dm646x_clks);
        } else if (cpu_is_davinci_dm355()) {
-               unsigned long postdiv;
-
-               postdiv = (davinci_readl(DAVINCI_PLL_CNTRL0_BASE + 0x128)
-                          & 0x1f) + 1;
-
-               fixedrate = 24000000;
-               armrate = (pll_mult + 1) * (fixedrate / (16 * postdiv));
-               commonrate = armrate / 2;
                board_clks = davinci_dm355_clks;
                num_clks = ARRAY_SIZE(davinci_dm355_clks);
        } else {
-               fixedrate = DM646X_OSC_FREQ;
-               armrate = (pll_mult + 1) * (fixedrate / 2);
-               commonrate = armrate / 3;
-
                board_clks = davinci_clks;
                num_clks = ARRAY_SIZE(davinci_clks);
        }
@@ -581,7 +700,7 @@ static int davinci_ck_show(struct seq_file *m, void *v)
        struct clk *cp;
 
        list_for_each_entry(cp, &clocks, node)
-               seq_printf(m,"%s %d %d\n", cp->name, *(cp->rate), cp->usecount);
+               seq_printf(m,"%s %lu %d\n", cp->name, cp->rate, cp->usecount);
 
        return 0;
 }
diff --git a/arch/arm/mach-davinci/clock.h b/arch/arm/mach-davinci/clock.h
index b7f111d..b5d2be1 100644
--- a/arch/arm/mach-davinci/clock.h
+++ b/arch/arm/mach-davinci/clock.h
@@ -11,15 +11,24 @@
 #ifndef __ARCH_ARM_DAVINCI_CLOCK_H
 #define __ARCH_ARM_DAVINCI_CLOCK_H
 
+#define MAX_PLL_DIVISORS 8
+
+struct pll_data {
+       u32 phys_base;
+};
+
 struct clk {
        struct list_head        node;
        struct module           *owner;
        const char              *name;
-       unsigned int            *rate;
+       unsigned long           rate;
        int                     id;
        __s8                    usecount;
        __u8                    flags;
        __u8                    lpsc;
+       __u8                    fixed_divisor;
+       struct clk              *parent;
+       struct pll_data         *pll_data;
 };
 
 /* Clock flags */
@@ -31,10 +40,14 @@ struct clk {
 #define ENABLE_REG_32BIT       32
 
 /* various clock frequencies */
+#define DM644X_OSC_FREQ        27000000
+
 #define DM646X_OSC_FREQ        27000000
 #define DM646X_AUX_OSC_FREQ    24000000
 #define DM646X_CLOCK_TICK_RATE 148500000
-#define DM355_CLOCK_TICK_RATE  24000000
+
+#define DM355_OSC_FREQ         24000000
+#define DM355_CLOCK_TICK_RATE  DM355_OSC_FREQ
 
 int davinci_clk_associate(struct device *dev, const char *logical_clockname,
                const char *physical_clockname);
-- 
1.6.0.3


_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to