Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] sh: Simplistic clock framework

This adds a relatively simplistic clock framework for sh. The initial goal
behind this is to clean up the arch/sh/kernel/time.c mess and to get the CPU
subtype-specific frequency setting and calculation code moved somewhere more
sensible.

This only deals with the core clocks at the moment, though it's trivial for
other drivers to define their own clocks as desired.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Cc: john stultz <johnstul@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Paul Mundt and committed by
Linus Torvalds
36ddf31b b66c1a39

+1287 -623
+1 -1
arch/sh/boards/overdrive/Makefile
··· 2 2 # Makefile for the STMicroelectronics Overdrive specific parts of the kernel 3 3 # 4 4 5 - obj-y := mach.o setup.o io.o irq.o led.o time.o 5 + obj-y := mach.o setup.o io.o irq.o led.o 6 6 7 7 obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o 8 8
+1 -5
arch/sh/boards/overdrive/setup.c
··· 17 17 #include <asm/overdrive/overdrive.h> 18 18 #include <asm/overdrive/fpga.h> 19 19 20 - extern void od_time_init(void); 21 - 22 20 const char *get_system_type(void) 23 21 { 24 22 return "SH7750 Overdrive"; ··· 29 31 { 30 32 #ifdef CONFIG_PCI 31 33 init_overdrive_fpga(); 32 - galileo_init(); 34 + galileo_init(); 33 35 #endif 34 - 35 - board_time_init = od_time_init; 36 36 37 37 /* Enable RS232 receive buffers */ 38 38 writel(0x1e, OVERDRIVE_CTRL);
-119
arch/sh/boards/overdrive/time.c
··· 1 - /* 2 - * arch/sh/boards/overdrive/time.c 3 - * 4 - * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com) 5 - * Copyright (C) 2002 Paul Mundt (lethal@chaoticdreams.org) 6 - * 7 - * May be copied or modified under the terms of the GNU General Public 8 - * License. See linux/COPYING for more information. 9 - * 10 - * STMicroelectronics Overdrive Support. 11 - */ 12 - 13 - void od_time_init(void) 14 - { 15 - struct frqcr_data { 16 - unsigned short frqcr; 17 - struct { 18 - unsigned char multiplier; 19 - unsigned char divisor; 20 - } factor[3]; 21 - }; 22 - 23 - static struct frqcr_data st40_frqcr_table[] = { 24 - { 0x000, {{1,1}, {1,1}, {1,2}}}, 25 - { 0x002, {{1,1}, {1,1}, {1,4}}}, 26 - { 0x004, {{1,1}, {1,1}, {1,8}}}, 27 - { 0x008, {{1,1}, {1,2}, {1,2}}}, 28 - { 0x00A, {{1,1}, {1,2}, {1,4}}}, 29 - { 0x00C, {{1,1}, {1,2}, {1,8}}}, 30 - { 0x011, {{1,1}, {2,3}, {1,6}}}, 31 - { 0x013, {{1,1}, {2,3}, {1,3}}}, 32 - { 0x01A, {{1,1}, {1,2}, {1,4}}}, 33 - { 0x01C, {{1,1}, {1,2}, {1,8}}}, 34 - { 0x023, {{1,1}, {2,3}, {1,3}}}, 35 - { 0x02C, {{1,1}, {1,2}, {1,8}}}, 36 - { 0x048, {{1,2}, {1,2}, {1,4}}}, 37 - { 0x04A, {{1,2}, {1,2}, {1,6}}}, 38 - { 0x04C, {{1,2}, {1,2}, {1,8}}}, 39 - { 0x05A, {{1,2}, {1,3}, {1,6}}}, 40 - { 0x05C, {{1,2}, {1,3}, {1,6}}}, 41 - { 0x063, {{1,2}, {1,4}, {1,4}}}, 42 - { 0x06C, {{1,2}, {1,4}, {1,8}}}, 43 - { 0x091, {{1,3}, {1,3}, {1,6}}}, 44 - { 0x093, {{1,3}, {1,3}, {1,6}}}, 45 - { 0x0A3, {{1,3}, {1,6}, {1,6}}}, 46 - { 0x0DA, {{1,4}, {1,4}, {1,8}}}, 47 - { 0x0DC, {{1,4}, {1,4}, {1,8}}}, 48 - { 0x0EC, {{1,4}, {1,8}, {1,8}}}, 49 - { 0x123, {{1,4}, {1,4}, {1,8}}}, 50 - { 0x16C, {{1,4}, {1,8}, {1,8}}}, 51 - }; 52 - 53 - struct memclk_data { 54 - unsigned char multiplier; 55 - unsigned char divisor; 56 - }; 57 - static struct memclk_data st40_memclk_table[8] = { 58 - {1,1}, // 000 59 - {1,2}, // 001 60 - {1,3}, // 010 61 - {2,3}, // 011 62 - {1,4}, // 100 63 - {1,6}, // 101 64 - {1,8}, // 110 65 - {1,8} // 111 66 - }; 67 - 68 - unsigned long pvr; 69 - 70 - /* 71 - * This should probably be moved into the SH3 probing code, and then 72 - * use the processor structure to determine which CPU we are running 73 - * on. 74 - */ 75 - pvr = ctrl_inl(CCN_PVR); 76 - printk("PVR %08x\n", pvr); 77 - 78 - if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) { 79 - /* 80 - * Unfortunatly the STB1 FRQCR values are different from the 81 - * 7750 ones. 82 - */ 83 - struct frqcr_data *d; 84 - int a; 85 - unsigned long memclkcr; 86 - struct memclk_data *e; 87 - 88 - for (a=0; a<ARRAY_SIZE(st40_frqcr_table); a++) { 89 - d = &st40_frqcr_table[a]; 90 - if (d->frqcr == (frqcr & 0x1ff)) 91 - break; 92 - } 93 - if (a == ARRAY_SIZE(st40_frqcr_table)) { 94 - d = st40_frqcr_table; 95 - printk("ERROR: Unrecognised FRQCR value, using default multipliers\n"); 96 - } 97 - 98 - memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR); 99 - e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK]; 100 - 101 - printk("Clock multipliers: CPU: %d/%d Bus: %d/%d Mem: %d/%d Periph: %d/%d\n", 102 - d->factor[0].multiplier, d->factor[0].divisor, 103 - d->factor[1].multiplier, d->factor[1].divisor, 104 - e->multiplier, e->divisor, 105 - d->factor[2].multiplier, d->factor[2].divisor); 106 - 107 - current_cpu_data.master_clock = current_cpu_data.module_clock * 108 - d->factor[2].divisor / 109 - d->factor[2].multiplier; 110 - current_cpu_data.bus_clock = current_cpu_data.master_clock * 111 - d->factor[1].multiplier / 112 - d->factor[1].divisor; 113 - current_cpu_data.memory_clock = current_cpu_data.master_clock * 114 - e->multiplier / e->divisor; 115 - current_cpu_data.cpu_clock = current_cpu_data.master_clock * 116 - d->factor[0].multiplier / 117 - d->factor[0].divisor; 118 - } 119 -
+287
arch/sh/kernel/cpu/clock.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/clock.c - SuperH clock framework 3 + * 4 + * Copyright (C) 2005 Paul Mundt 5 + * 6 + * This clock framework is derived from the OMAP version by: 7 + * 8 + * Copyright (C) 2004 Nokia Corporation 9 + * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> 10 + * 11 + * This file is subject to the terms and conditions of the GNU General Public 12 + * License. See the file "COPYING" in the main directory of this archive 13 + * for more details. 14 + */ 15 + #include <linux/kernel.h> 16 + #include <linux/init.h> 17 + #include <linux/module.h> 18 + #include <linux/list.h> 19 + #include <linux/kref.h> 20 + #include <linux/seq_file.h> 21 + #include <linux/err.h> 22 + #include <asm/clock.h> 23 + #include <asm/timer.h> 24 + 25 + static LIST_HEAD(clock_list); 26 + static DEFINE_SPINLOCK(clock_lock); 27 + static DECLARE_MUTEX(clock_list_sem); 28 + 29 + /* 30 + * Each subtype is expected to define the init routines for these clocks, 31 + * as each subtype (or processor family) will have these clocks at the 32 + * very least. These are all provided through the CPG, which even some of 33 + * the more quirky parts (such as ST40, SH4-202, etc.) still have. 34 + * 35 + * The processor-specific code is expected to register any additional 36 + * clock sources that are of interest. 37 + */ 38 + static struct clk master_clk = { 39 + .name = "master_clk", 40 + .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, 41 + #ifdef CONFIG_SH_PCLK_FREQ_BOOL 42 + .rate = CONFIG_SH_PCLK_FREQ, 43 + #endif 44 + }; 45 + 46 + static struct clk module_clk = { 47 + .name = "module_clk", 48 + .parent = &master_clk, 49 + .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, 50 + }; 51 + 52 + static struct clk bus_clk = { 53 + .name = "bus_clk", 54 + .parent = &master_clk, 55 + .flags = CLK_ALWAYS_ENABLED | CLK_RATE_PROPAGATES, 56 + }; 57 + 58 + static struct clk cpu_clk = { 59 + .name = "cpu_clk", 60 + .parent = &master_clk, 61 + .flags = CLK_ALWAYS_ENABLED, 62 + }; 63 + 64 + /* 65 + * The ordering of these clocks matters, do not change it. 66 + */ 67 + static struct clk *onchip_clocks[] = { 68 + &master_clk, 69 + &module_clk, 70 + &bus_clk, 71 + &cpu_clk, 72 + }; 73 + 74 + static void propagate_rate(struct clk *clk) 75 + { 76 + struct clk *clkp; 77 + 78 + list_for_each_entry(clkp, &clock_list, node) { 79 + if (likely(clkp->parent != clk)) 80 + continue; 81 + if (likely(clkp->ops && clkp->ops->recalc)) 82 + clkp->ops->recalc(clkp); 83 + } 84 + } 85 + 86 + int __clk_enable(struct clk *clk) 87 + { 88 + /* 89 + * See if this is the first time we're enabling the clock, some 90 + * clocks that are always enabled still require "special" 91 + * initialization. This is especially true if the clock mode 92 + * changes and the clock needs to hunt for the proper set of 93 + * divisors to use before it can effectively recalc. 94 + */ 95 + if (unlikely(atomic_read(&clk->kref.refcount) == 1)) 96 + if (clk->ops && clk->ops->init) 97 + clk->ops->init(clk); 98 + 99 + if (clk->flags & CLK_ALWAYS_ENABLED) 100 + return 0; 101 + 102 + if (likely(clk->ops && clk->ops->enable)) 103 + clk->ops->enable(clk); 104 + 105 + kref_get(&clk->kref); 106 + return 0; 107 + } 108 + 109 + int clk_enable(struct clk *clk) 110 + { 111 + unsigned long flags; 112 + int ret; 113 + 114 + spin_lock_irqsave(&clock_lock, flags); 115 + ret = __clk_enable(clk); 116 + spin_unlock_irqrestore(&clock_lock, flags); 117 + 118 + return ret; 119 + } 120 + 121 + static void clk_kref_release(struct kref *kref) 122 + { 123 + /* Nothing to do */ 124 + } 125 + 126 + void __clk_disable(struct clk *clk) 127 + { 128 + if (clk->flags & CLK_ALWAYS_ENABLED) 129 + return; 130 + 131 + kref_put(&clk->kref, clk_kref_release); 132 + } 133 + 134 + void clk_disable(struct clk *clk) 135 + { 136 + unsigned long flags; 137 + 138 + spin_lock_irqsave(&clock_lock, flags); 139 + __clk_disable(clk); 140 + spin_unlock_irqrestore(&clock_lock, flags); 141 + } 142 + 143 + int clk_register(struct clk *clk) 144 + { 145 + down(&clock_list_sem); 146 + 147 + list_add(&clk->node, &clock_list); 148 + kref_init(&clk->kref); 149 + 150 + up(&clock_list_sem); 151 + 152 + return 0; 153 + } 154 + 155 + void clk_unregister(struct clk *clk) 156 + { 157 + down(&clock_list_sem); 158 + list_del(&clk->node); 159 + up(&clock_list_sem); 160 + } 161 + 162 + inline unsigned long clk_get_rate(struct clk *clk) 163 + { 164 + return clk->rate; 165 + } 166 + 167 + int clk_set_rate(struct clk *clk, unsigned long rate) 168 + { 169 + int ret = -EOPNOTSUPP; 170 + 171 + if (likely(clk->ops && clk->ops->set_rate)) { 172 + unsigned long flags; 173 + 174 + spin_lock_irqsave(&clock_lock, flags); 175 + ret = clk->ops->set_rate(clk, rate); 176 + spin_unlock_irqrestore(&clock_lock, flags); 177 + } 178 + 179 + if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) 180 + propagate_rate(clk); 181 + 182 + return ret; 183 + } 184 + 185 + void clk_recalc_rate(struct clk *clk) 186 + { 187 + if (likely(clk->ops && clk->ops->recalc)) { 188 + unsigned long flags; 189 + 190 + spin_lock_irqsave(&clock_lock, flags); 191 + clk->ops->recalc(clk); 192 + spin_unlock_irqrestore(&clock_lock, flags); 193 + } 194 + 195 + if (unlikely(clk->flags & CLK_RATE_PROPAGATES)) 196 + propagate_rate(clk); 197 + } 198 + 199 + struct clk *clk_get(const char *id) 200 + { 201 + struct clk *p, *clk = ERR_PTR(-ENOENT); 202 + 203 + down(&clock_list_sem); 204 + list_for_each_entry(p, &clock_list, node) { 205 + if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) { 206 + clk = p; 207 + break; 208 + } 209 + } 210 + up(&clock_list_sem); 211 + 212 + return clk; 213 + } 214 + 215 + void clk_put(struct clk *clk) 216 + { 217 + if (clk && !IS_ERR(clk)) 218 + module_put(clk->owner); 219 + } 220 + 221 + void __init __attribute__ ((weak)) 222 + arch_init_clk_ops(struct clk_ops **ops, int type) 223 + { 224 + } 225 + 226 + int __init clk_init(void) 227 + { 228 + int i, ret = 0; 229 + 230 + if (unlikely(!master_clk.rate)) 231 + /* 232 + * NOTE: This will break if the default divisor has been 233 + * changed. 234 + * 235 + * No one should be changing the default on us however, 236 + * expect that a sane value for CONFIG_SH_PCLK_FREQ will 237 + * be defined in the event of a different divisor. 238 + */ 239 + master_clk.rate = get_timer_frequency() * 4; 240 + 241 + for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) { 242 + struct clk *clk = onchip_clocks[i]; 243 + 244 + arch_init_clk_ops(&clk->ops, i); 245 + ret |= clk_register(clk); 246 + clk_enable(clk); 247 + } 248 + 249 + /* Kick the child clocks.. */ 250 + propagate_rate(&master_clk); 251 + propagate_rate(&bus_clk); 252 + 253 + return ret; 254 + } 255 + 256 + int show_clocks(struct seq_file *m) 257 + { 258 + struct clk *clk; 259 + 260 + list_for_each_entry_reverse(clk, &clock_list, node) { 261 + unsigned long rate = clk_get_rate(clk); 262 + 263 + /* 264 + * Don't bother listing dummy clocks with no ancestry 265 + * that only support enable and disable ops. 266 + */ 267 + if (unlikely(!rate && !clk->parent)) 268 + continue; 269 + 270 + seq_printf(m, "%-12s\t: %ld.%02ldMHz\n", clk->name, 271 + rate / 1000000, (rate % 1000000) / 10000); 272 + } 273 + 274 + return 0; 275 + } 276 + 277 + EXPORT_SYMBOL_GPL(clk_register); 278 + EXPORT_SYMBOL_GPL(clk_unregister); 279 + EXPORT_SYMBOL_GPL(clk_get); 280 + EXPORT_SYMBOL_GPL(clk_put); 281 + EXPORT_SYMBOL_GPL(clk_enable); 282 + EXPORT_SYMBOL_GPL(clk_disable); 283 + EXPORT_SYMBOL_GPL(__clk_enable); 284 + EXPORT_SYMBOL_GPL(__clk_disable); 285 + EXPORT_SYMBOL_GPL(clk_get_rate); 286 + EXPORT_SYMBOL_GPL(clk_set_rate); 287 + EXPORT_SYMBOL_GPL(clk_recalc_rate);
+7
arch/sh/kernel/cpu/sh3/Makefile
··· 4 4 5 5 obj-y := ex.o probe.o 6 6 7 + clock-$(CONFIG_CPU_SH3) := clock-sh3.o 8 + clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o 9 + clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o 10 + clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o 11 + 12 + obj-y += $(clock-y) 13 +
+89
arch/sh/kernel/cpu/sh3/clock-sh3.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh3/clock-sh3.c 3 + * 4 + * Generic SH-3 support for the clock framework 5 + * 6 + * Copyright (C) 2005 Paul Mundt 7 + * 8 + * FRQCR parsing hacked out of arch/sh/kernel/time.c 9 + * 10 + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka 11 + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 12 + * Copyright (C) 2002, 2003, 2004 Paul Mundt 13 + * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> 14 + * 15 + * This file is subject to the terms and conditions of the GNU General Public 16 + * License. See the file "COPYING" in the main directory of this archive 17 + * for more details. 18 + */ 19 + #include <linux/init.h> 20 + #include <linux/kernel.h> 21 + #include <asm/clock.h> 22 + #include <asm/freq.h> 23 + #include <asm/io.h> 24 + 25 + static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; 26 + static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 }; 27 + static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; 28 + 29 + static void master_clk_init(struct clk *clk) 30 + { 31 + int frqcr = ctrl_inw(FRQCR); 32 + int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); 33 + 34 + clk->rate *= pfc_divisors[idx]; 35 + } 36 + 37 + static struct clk_ops sh3_master_clk_ops = { 38 + .init = master_clk_init, 39 + }; 40 + 41 + static void module_clk_recalc(struct clk *clk) 42 + { 43 + int frqcr = ctrl_inw(FRQCR); 44 + int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); 45 + 46 + clk->rate = clk->parent->rate / pfc_divisors[idx]; 47 + } 48 + 49 + static struct clk_ops sh3_module_clk_ops = { 50 + .recalc = module_clk_recalc, 51 + }; 52 + 53 + static void bus_clk_recalc(struct clk *clk) 54 + { 55 + int frqcr = ctrl_inw(FRQCR); 56 + int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4); 57 + 58 + clk->rate = clk->parent->rate / stc_multipliers[idx]; 59 + } 60 + 61 + static struct clk_ops sh3_bus_clk_ops = { 62 + .recalc = bus_clk_recalc, 63 + }; 64 + 65 + static void cpu_clk_recalc(struct clk *clk) 66 + { 67 + int frqcr = ctrl_inw(FRQCR); 68 + int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2); 69 + 70 + clk->rate = clk->parent->rate / ifc_divisors[idx]; 71 + } 72 + 73 + static struct clk_ops sh3_cpu_clk_ops = { 74 + .recalc = cpu_clk_recalc, 75 + }; 76 + 77 + static struct clk_ops *sh3_clk_ops[] = { 78 + &sh3_master_clk_ops, 79 + &sh3_module_clk_ops, 80 + &sh3_bus_clk_ops, 81 + &sh3_cpu_clk_ops, 82 + }; 83 + 84 + void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 85 + { 86 + if (idx < ARRAY_SIZE(sh3_clk_ops)) 87 + *ops = sh3_clk_ops[idx]; 88 + } 89 +
+78
arch/sh/kernel/cpu/sh3/clock-sh7300.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh3/clock-sh7300.c 3 + * 4 + * SH7300 support for the clock framework 5 + * 6 + * Copyright (C) 2005 Paul Mundt 7 + * 8 + * FRQCR parsing hacked out of arch/sh/kernel/time.c 9 + * 10 + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka 11 + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 12 + * Copyright (C) 2002, 2003, 2004 Paul Mundt 13 + * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> 14 + * 15 + * This file is subject to the terms and conditions of the GNU General Public 16 + * License. See the file "COPYING" in the main directory of this archive 17 + * for more details. 18 + */ 19 + #include <linux/init.h> 20 + #include <linux/kernel.h> 21 + #include <asm/clock.h> 22 + #include <asm/freq.h> 23 + #include <asm/io.h> 24 + 25 + static int md_table[] = { 1, 2, 3, 4, 6, 8, 12 }; 26 + 27 + static void master_clk_init(struct clk *clk) 28 + { 29 + clk->rate *= md_table[ctrl_inw(FRQCR) & 0x0007]; 30 + } 31 + 32 + static struct clk_ops sh7300_master_clk_ops = { 33 + .init = master_clk_init, 34 + }; 35 + 36 + static void module_clk_recalc(struct clk *clk) 37 + { 38 + int idx = (ctrl_inw(FRQCR) & 0x0007); 39 + clk->rate = clk->parent->rate / md_table[idx]; 40 + } 41 + 42 + static struct clk_ops sh7300_module_clk_ops = { 43 + .recalc = module_clk_recalc, 44 + }; 45 + 46 + static void bus_clk_recalc(struct clk *clk) 47 + { 48 + int idx = (ctrl_inw(FRQCR) & 0x0700) >> 8; 49 + clk->rate = clk->parent->rate / md_table[idx]; 50 + } 51 + 52 + static struct clk_ops sh7300_bus_clk_ops = { 53 + .recalc = bus_clk_recalc, 54 + }; 55 + 56 + static void cpu_clk_recalc(struct clk *clk) 57 + { 58 + int idx = (ctrl_inw(FRQCR) & 0x0070) >> 4; 59 + clk->rate = clk->parent->rate / md_table[idx]; 60 + } 61 + 62 + static struct clk_ops sh7300_cpu_clk_ops = { 63 + .recalc = cpu_clk_recalc, 64 + }; 65 + 66 + static struct clk_ops *sh7300_clk_ops[] = { 67 + &sh7300_master_clk_ops, 68 + &sh7300_module_clk_ops, 69 + &sh7300_bus_clk_ops, 70 + &sh7300_cpu_clk_ops, 71 + }; 72 + 73 + void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 74 + { 75 + if (idx < ARRAY_SIZE(sh7300_clk_ops)) 76 + *ops = sh7300_clk_ops[idx]; 77 + } 78 +
+84
arch/sh/kernel/cpu/sh3/clock-sh7705.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh3/clock-sh7705.c 3 + * 4 + * SH7705 support for the clock framework 5 + * 6 + * Copyright (C) 2005 Paul Mundt 7 + * 8 + * FRQCR parsing hacked out of arch/sh/kernel/time.c 9 + * 10 + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka 11 + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 12 + * Copyright (C) 2002, 2003, 2004 Paul Mundt 13 + * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> 14 + * 15 + * This file is subject to the terms and conditions of the GNU General Public 16 + * License. See the file "COPYING" in the main directory of this archive 17 + * for more details. 18 + */ 19 + #include <linux/init.h> 20 + #include <linux/kernel.h> 21 + #include <asm/clock.h> 22 + #include <asm/freq.h> 23 + #include <asm/io.h> 24 + 25 + /* 26 + * SH7705 uses the same divisors as the generic SH-3 case, it's just the 27 + * FRQCR layout that is a bit different.. 28 + */ 29 + static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; 30 + static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 }; 31 + static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; 32 + 33 + static void master_clk_init(struct clk *clk) 34 + { 35 + clk->rate *= pfc_divisors[ctrl_inw(FRQCR) & 0x0003]; 36 + } 37 + 38 + static struct clk_ops sh7705_master_clk_ops = { 39 + .init = master_clk_init, 40 + }; 41 + 42 + static void module_clk_recalc(struct clk *clk) 43 + { 44 + int idx = ctrl_inw(FRQCR) & 0x0003; 45 + clk->rate = clk->parent->rate / pfc_divisors[idx]; 46 + } 47 + 48 + static struct clk_ops sh7705_module_clk_ops = { 49 + .recalc = module_clk_recalc, 50 + }; 51 + 52 + static void bus_clk_recalc(struct clk *clk) 53 + { 54 + int idx = (ctrl_inw(FRQCR) & 0x0300) >> 8; 55 + clk->rate = clk->parent->rate / stc_multipliers[idx]; 56 + } 57 + 58 + static struct clk_ops sh7705_bus_clk_ops = { 59 + .recalc = bus_clk_recalc, 60 + }; 61 + 62 + static void cpu_clk_recalc(struct clk *clk) 63 + { 64 + int idx = (ctrl_inw(FRQCR) & 0x0030) >> 4; 65 + clk->rate = clk->parent->rate / ifc_divisors[idx]; 66 + } 67 + 68 + static struct clk_ops sh7705_cpu_clk_ops = { 69 + .recalc = cpu_clk_recalc, 70 + }; 71 + 72 + static struct clk_ops *sh7705_clk_ops[] = { 73 + &sh7705_master_clk_ops, 74 + &sh7705_module_clk_ops, 75 + &sh7705_bus_clk_ops, 76 + &sh7705_cpu_clk_ops, 77 + }; 78 + 79 + void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 80 + { 81 + if (idx < ARRAY_SIZE(sh7705_clk_ops)) 82 + *ops = sh7705_clk_ops[idx]; 83 + } 84 +
+96
arch/sh/kernel/cpu/sh3/clock-sh7709.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh3/clock-sh7709.c 3 + * 4 + * SH7709 support for the clock framework 5 + * 6 + * Copyright (C) 2005 Andriy Skulysh 7 + * 8 + * Based on arch/sh/kernel/cpu/sh3/clock-sh7705.c 9 + * Copyright (C) 2005 Paul Mundt 10 + * 11 + * This file is subject to the terms and conditions of the GNU General Public 12 + * License. See the file "COPYING" in the main directory of this archive 13 + * for more details. 14 + */ 15 + #include <linux/init.h> 16 + #include <linux/kernel.h> 17 + #include <asm/clock.h> 18 + #include <asm/freq.h> 19 + #include <asm/io.h> 20 + 21 + static int stc_multipliers[] = { 1, 2, 4, 8, 3, 6, 1, 1 }; 22 + static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 }; 23 + static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 }; 24 + 25 + static void set_bus_parent(struct clk *clk) 26 + { 27 + struct clk *bus_clk = clk_get("bus_clk"); 28 + clk->parent = bus_clk; 29 + clk_put(bus_clk); 30 + } 31 + 32 + static void master_clk_init(struct clk *clk) 33 + { 34 + int frqcr = ctrl_inw(FRQCR); 35 + int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); 36 + 37 + clk->rate *= pfc_divisors[idx]; 38 + } 39 + 40 + static struct clk_ops sh7709_master_clk_ops = { 41 + .init = master_clk_init, 42 + }; 43 + 44 + static void module_clk_recalc(struct clk *clk) 45 + { 46 + int frqcr = ctrl_inw(FRQCR); 47 + int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003); 48 + 49 + clk->rate = clk->parent->rate / pfc_divisors[idx]; 50 + } 51 + 52 + static struct clk_ops sh7709_module_clk_ops = { 53 + #ifdef CLOCK_MODE_0_1_2_7 54 + .init = set_bus_parent, 55 + #endif 56 + .recalc = module_clk_recalc, 57 + }; 58 + 59 + static void bus_clk_recalc(struct clk *clk) 60 + { 61 + int frqcr = ctrl_inw(FRQCR); 62 + int idx = (frqcr & 0x0080) ? 63 + ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4) : 1; 64 + 65 + clk->rate = clk->parent->rate * stc_multipliers[idx]; 66 + } 67 + 68 + static struct clk_ops sh7709_bus_clk_ops = { 69 + .recalc = bus_clk_recalc, 70 + }; 71 + 72 + static void cpu_clk_recalc(struct clk *clk) 73 + { 74 + int frqcr = ctrl_inw(FRQCR); 75 + int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2); 76 + 77 + clk->rate = clk->parent->rate / ifc_divisors[idx]; 78 + } 79 + 80 + static struct clk_ops sh7709_cpu_clk_ops = { 81 + .init = set_bus_parent, 82 + .recalc = cpu_clk_recalc, 83 + }; 84 + 85 + static struct clk_ops *sh7709_clk_ops[] = { 86 + &sh7709_master_clk_ops, 87 + &sh7709_module_clk_ops, 88 + &sh7709_bus_clk_ops, 89 + &sh7709_cpu_clk_ops, 90 + }; 91 + 92 + void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 93 + { 94 + if (idx < ARRAY_SIZE(sh7709_clk_ops)) 95 + *ops = sh7709_clk_ops[idx]; 96 + }
+10 -1
arch/sh/kernel/cpu/sh4/Makefile
··· 5 5 obj-y := ex.o probe.o 6 6 7 7 obj-$(CONFIG_SH_FPU) += fpu.o 8 - obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) += irq_intc2.o 9 8 obj-$(CONFIG_SH_STORE_QUEUES) += sq.o 10 9 10 + # Primary on-chip clocks (common) 11 + clock-$(CONFIG_CPU_SH4) := clock-sh4.o 12 + clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o 13 + clock-$(CONFIG_CPU_SUBTYPE_SH7770) := clock-sh7770.o 14 + clock-$(CONFIG_CPU_SUBTYPE_SH7780) := clock-sh7780.o 15 + 16 + # Additional clocks by subtype 17 + clock-$(CONFIG_CPU_SUBTYPE_SH4_202) += clock-sh4-202.o 18 + 19 + obj-y += $(clock-y)
+179
arch/sh/kernel/cpu/sh4/clock-sh4-202.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh4/clock-sh4-202.c 3 + * 4 + * Additional SH4-202 support for the clock framework 5 + * 6 + * Copyright (C) 2005 Paul Mundt 7 + * 8 + * This file is subject to the terms and conditions of the GNU General Public 9 + * License. See the file "COPYING" in the main directory of this archive 10 + * for more details. 11 + */ 12 + #include <linux/init.h> 13 + #include <linux/kernel.h> 14 + #include <linux/err.h> 15 + #include <asm/clock.h> 16 + #include <asm/freq.h> 17 + #include <asm/io.h> 18 + 19 + #define CPG2_FRQCR3 0xfe0a0018 20 + 21 + static int frqcr3_divisors[] = { 1, 2, 3, 4, 6, 8, 16 }; 22 + static int frqcr3_values[] = { 0, 1, 2, 3, 4, 5, 6 }; 23 + 24 + static void emi_clk_recalc(struct clk *clk) 25 + { 26 + int idx = ctrl_inl(CPG2_FRQCR3) & 0x0007; 27 + clk->rate = clk->parent->rate / frqcr3_divisors[idx]; 28 + } 29 + 30 + static inline int frqcr3_lookup(struct clk *clk, unsigned long rate) 31 + { 32 + int divisor = clk->parent->rate / rate; 33 + int i; 34 + 35 + for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) 36 + if (frqcr3_divisors[i] == divisor) 37 + return frqcr3_values[i]; 38 + 39 + /* Safe fallback */ 40 + return 5; 41 + } 42 + 43 + static struct clk_ops sh4202_emi_clk_ops = { 44 + .recalc = emi_clk_recalc, 45 + }; 46 + 47 + static struct clk sh4202_emi_clk = { 48 + .name = "emi_clk", 49 + .flags = CLK_ALWAYS_ENABLED, 50 + .ops = &sh4202_emi_clk_ops, 51 + }; 52 + 53 + static void femi_clk_recalc(struct clk *clk) 54 + { 55 + int idx = (ctrl_inl(CPG2_FRQCR3) >> 3) & 0x0007; 56 + clk->rate = clk->parent->rate / frqcr3_divisors[idx]; 57 + } 58 + 59 + static struct clk_ops sh4202_femi_clk_ops = { 60 + .recalc = femi_clk_recalc, 61 + }; 62 + 63 + static struct clk sh4202_femi_clk = { 64 + .name = "femi_clk", 65 + .flags = CLK_ALWAYS_ENABLED, 66 + .ops = &sh4202_femi_clk_ops, 67 + }; 68 + 69 + static void shoc_clk_init(struct clk *clk) 70 + { 71 + int i; 72 + 73 + /* 74 + * For some reason, the shoc_clk seems to be set to some really 75 + * insane value at boot (values outside of the allowable frequency 76 + * range for instance). We deal with this by scaling it back down 77 + * to something sensible just in case. 78 + * 79 + * Start scaling from the high end down until we find something 80 + * that passes rate verification.. 81 + */ 82 + for (i = 0; i < ARRAY_SIZE(frqcr3_divisors); i++) { 83 + int divisor = frqcr3_divisors[i]; 84 + 85 + if (clk->ops->set_rate(clk, clk->parent->rate / divisor) == 0) 86 + break; 87 + } 88 + 89 + WARN_ON(i == ARRAY_SIZE(frqcr3_divisors)); /* Undefined clock */ 90 + } 91 + 92 + static void shoc_clk_recalc(struct clk *clk) 93 + { 94 + int idx = (ctrl_inl(CPG2_FRQCR3) >> 6) & 0x0007; 95 + clk->rate = clk->parent->rate / frqcr3_divisors[idx]; 96 + } 97 + 98 + static int shoc_clk_verify_rate(struct clk *clk, unsigned long rate) 99 + { 100 + struct clk *bclk = clk_get("bus_clk"); 101 + unsigned long bclk_rate = clk_get_rate(bclk); 102 + 103 + clk_put(bclk); 104 + 105 + if (rate > bclk_rate) 106 + return 1; 107 + if (rate > 66000000) 108 + return 1; 109 + 110 + return 0; 111 + } 112 + 113 + static int shoc_clk_set_rate(struct clk *clk, unsigned long rate) 114 + { 115 + unsigned long frqcr3; 116 + unsigned int tmp; 117 + 118 + /* Make sure we have something sensible to switch to */ 119 + if (shoc_clk_verify_rate(clk, rate) != 0) 120 + return -EINVAL; 121 + 122 + tmp = frqcr3_lookup(clk, rate); 123 + 124 + frqcr3 = ctrl_inl(CPG2_FRQCR3); 125 + frqcr3 &= ~(0x0007 << 6); 126 + frqcr3 |= tmp << 6; 127 + ctrl_outl(frqcr3, CPG2_FRQCR3); 128 + 129 + clk->rate = clk->parent->rate / frqcr3_divisors[tmp]; 130 + 131 + return 0; 132 + } 133 + 134 + static struct clk_ops sh4202_shoc_clk_ops = { 135 + .init = shoc_clk_init, 136 + .recalc = shoc_clk_recalc, 137 + .set_rate = shoc_clk_set_rate, 138 + }; 139 + 140 + static struct clk sh4202_shoc_clk = { 141 + .name = "shoc_clk", 142 + .flags = CLK_ALWAYS_ENABLED, 143 + .ops = &sh4202_shoc_clk_ops, 144 + }; 145 + 146 + static struct clk *sh4202_onchip_clocks[] = { 147 + &sh4202_emi_clk, 148 + &sh4202_femi_clk, 149 + &sh4202_shoc_clk, 150 + }; 151 + 152 + static int __init sh4202_clk_init(void) 153 + { 154 + struct clk *clk = clk_get("master_clk"); 155 + int i; 156 + 157 + for (i = 0; i < ARRAY_SIZE(sh4202_onchip_clocks); i++) { 158 + struct clk *clkp = sh4202_onchip_clocks[i]; 159 + 160 + clkp->parent = clk; 161 + clk_register(clkp); 162 + clk_enable(clkp); 163 + } 164 + 165 + /* 166 + * Now that we have the rest of the clocks registered, we need to 167 + * force the parent clock to propagate so that these clocks will 168 + * automatically figure out their rate. We cheat by handing the 169 + * parent clock its current rate and forcing child propagation. 170 + */ 171 + clk_set_rate(clk, clk_get_rate(clk)); 172 + 173 + clk_put(clk); 174 + 175 + return 0; 176 + } 177 + 178 + arch_initcall(sh4202_clk_init); 179 +
+80
arch/sh/kernel/cpu/sh4/clock-sh4.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh4/clock-sh4.c 3 + * 4 + * Generic SH-4 support for the clock framework 5 + * 6 + * Copyright (C) 2005 Paul Mundt 7 + * 8 + * FRQCR parsing hacked out of arch/sh/kernel/time.c 9 + * 10 + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka 11 + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 12 + * Copyright (C) 2002, 2003, 2004 Paul Mundt 13 + * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> 14 + * 15 + * This file is subject to the terms and conditions of the GNU General Public 16 + * License. See the file "COPYING" in the main directory of this archive 17 + * for more details. 18 + */ 19 + #include <linux/init.h> 20 + #include <linux/kernel.h> 21 + #include <asm/clock.h> 22 + #include <asm/freq.h> 23 + #include <asm/io.h> 24 + 25 + static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 1, 1 }; 26 + #define bfc_divisors ifc_divisors /* Same */ 27 + static int pfc_divisors[] = { 2, 3, 4, 6, 8, 2, 2, 2 }; 28 + 29 + static void master_clk_init(struct clk *clk) 30 + { 31 + clk->rate *= pfc_divisors[ctrl_inw(FRQCR) & 0x0007]; 32 + } 33 + 34 + static struct clk_ops sh4_master_clk_ops = { 35 + .init = master_clk_init, 36 + }; 37 + 38 + static void module_clk_recalc(struct clk *clk) 39 + { 40 + int idx = (ctrl_inw(FRQCR) & 0x0007); 41 + clk->rate = clk->parent->rate / pfc_divisors[idx]; 42 + } 43 + 44 + static struct clk_ops sh4_module_clk_ops = { 45 + .recalc = module_clk_recalc, 46 + }; 47 + 48 + static void bus_clk_recalc(struct clk *clk) 49 + { 50 + int idx = (ctrl_inw(FRQCR) >> 3) & 0x0007; 51 + clk->rate = clk->parent->rate / bfc_divisors[idx]; 52 + } 53 + 54 + static struct clk_ops sh4_bus_clk_ops = { 55 + .recalc = bus_clk_recalc, 56 + }; 57 + 58 + static void cpu_clk_recalc(struct clk *clk) 59 + { 60 + int idx = (ctrl_inw(FRQCR) >> 6) & 0x0007; 61 + clk->rate = clk->parent->rate / ifc_divisors[idx]; 62 + } 63 + 64 + static struct clk_ops sh4_cpu_clk_ops = { 65 + .recalc = cpu_clk_recalc, 66 + }; 67 + 68 + static struct clk_ops *sh4_clk_ops[] = { 69 + &sh4_master_clk_ops, 70 + &sh4_module_clk_ops, 71 + &sh4_bus_clk_ops, 72 + &sh4_cpu_clk_ops, 73 + }; 74 + 75 + void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 76 + { 77 + if (idx < ARRAY_SIZE(sh4_clk_ops)) 78 + *ops = sh4_clk_ops[idx]; 79 + } 80 +
+81
arch/sh/kernel/cpu/sh4/clock-sh73180.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh4/clock-sh73180.c 3 + * 4 + * SH73180 support for the clock framework 5 + * 6 + * Copyright (C) 2005 Paul Mundt 7 + * 8 + * FRQCR parsing hacked out of arch/sh/kernel/time.c 9 + * 10 + * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka 11 + * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 12 + * Copyright (C) 2002, 2003, 2004 Paul Mundt 13 + * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> 14 + * 15 + * This file is subject to the terms and conditions of the GNU General Public 16 + * License. See the file "COPYING" in the main directory of this archive 17 + * for more details. 18 + */ 19 + #include <linux/init.h> 20 + #include <linux/kernel.h> 21 + #include <asm/clock.h> 22 + #include <asm/freq.h> 23 + #include <asm/io.h> 24 + 25 + /* 26 + * SH73180 uses a common set of divisors, so this is quite simple.. 27 + */ 28 + static int divisors[] = { 1, 2, 3, 4, 6, 8, 12, 16 }; 29 + 30 + static void master_clk_init(struct clk *clk) 31 + { 32 + clk->rate *= divisors[ctrl_inl(FRQCR) & 0x0007]; 33 + } 34 + 35 + static struct clk_ops sh73180_master_clk_ops = { 36 + .init = master_clk_init, 37 + }; 38 + 39 + static void module_clk_recalc(struct clk *clk) 40 + { 41 + int idx = (ctrl_inl(FRQCR) & 0x0007); 42 + clk->rate = clk->parent->rate / divisors[idx]; 43 + } 44 + 45 + static struct clk_ops sh73180_module_clk_ops = { 46 + .recalc = module_clk_recalc, 47 + }; 48 + 49 + static void bus_clk_recalc(struct clk *clk) 50 + { 51 + int idx = (ctrl_inl(FRQCR) >> 12) & 0x0007; 52 + clk->rate = clk->parent->rate / divisors[idx]; 53 + } 54 + 55 + static struct clk_ops sh73180_bus_clk_ops = { 56 + .recalc = bus_clk_recalc, 57 + }; 58 + 59 + static void cpu_clk_recalc(struct clk *clk) 60 + { 61 + int idx = (ctrl_inl(FRQCR) >> 20) & 0x0007; 62 + clk->rate = clk->parent->rate / divisors[idx]; 63 + } 64 + 65 + static struct clk_ops sh73180_cpu_clk_ops = { 66 + .recalc = cpu_clk_recalc, 67 + }; 68 + 69 + static struct clk_ops *sh73180_clk_ops[] = { 70 + &sh73180_master_clk_ops, 71 + &sh73180_module_clk_ops, 72 + &sh73180_bus_clk_ops, 73 + &sh73180_cpu_clk_ops, 74 + }; 75 + 76 + void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 77 + { 78 + if (idx < ARRAY_SIZE(sh73180_clk_ops)) 79 + *ops = sh73180_clk_ops[idx]; 80 + } 81 +
+73
arch/sh/kernel/cpu/sh4/clock-sh7770.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh4/clock-sh7770.c 3 + * 4 + * SH7770 support for the clock framework 5 + * 6 + * Copyright (C) 2005 Paul Mundt 7 + * 8 + * This file is subject to the terms and conditions of the GNU General Public 9 + * License. See the file "COPYING" in the main directory of this archive 10 + * for more details. 11 + */ 12 + #include <linux/init.h> 13 + #include <linux/kernel.h> 14 + #include <asm/clock.h> 15 + #include <asm/freq.h> 16 + #include <asm/io.h> 17 + 18 + static int ifc_divisors[] = { 1, 1, 1, 1, 1, 1, 1, 1 }; 19 + static int bfc_divisors[] = { 1, 1, 1, 1, 1, 8,12, 1 }; 20 + static int pfc_divisors[] = { 1, 8, 1,10,12,16, 1, 1 }; 21 + 22 + static void master_clk_init(struct clk *clk) 23 + { 24 + clk->rate *= pfc_divisors[(ctrl_inl(FRQCR) >> 28) & 0x000f]; 25 + } 26 + 27 + static struct clk_ops sh7770_master_clk_ops = { 28 + .init = master_clk_init, 29 + }; 30 + 31 + static void module_clk_recalc(struct clk *clk) 32 + { 33 + int idx = ((ctrl_inl(FRQCR) >> 28) & 0x000f); 34 + clk->rate = clk->parent->rate / pfc_divisors[idx]; 35 + } 36 + 37 + static struct clk_ops sh7770_module_clk_ops = { 38 + .recalc = module_clk_recalc, 39 + }; 40 + 41 + static void bus_clk_recalc(struct clk *clk) 42 + { 43 + int idx = (ctrl_inl(FRQCR) & 0x000f); 44 + clk->rate = clk->parent->rate / bfc_divisors[idx]; 45 + } 46 + 47 + static struct clk_ops sh7770_bus_clk_ops = { 48 + .recalc = bus_clk_recalc, 49 + }; 50 + 51 + static void cpu_clk_recalc(struct clk *clk) 52 + { 53 + int idx = ((ctrl_inl(FRQCR) >> 24) & 0x000f); 54 + clk->rate = clk->parent->rate / ifc_divisors[idx]; 55 + } 56 + 57 + static struct clk_ops sh7770_cpu_clk_ops = { 58 + .recalc = cpu_clk_recalc, 59 + }; 60 + 61 + static struct clk_ops *sh7770_clk_ops[] = { 62 + &sh7770_master_clk_ops, 63 + &sh7770_module_clk_ops, 64 + &sh7770_bus_clk_ops, 65 + &sh7770_cpu_clk_ops, 66 + }; 67 + 68 + void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 69 + { 70 + if (idx < ARRAY_SIZE(sh7770_clk_ops)) 71 + *ops = sh7770_clk_ops[idx]; 72 + } 73 +
+126
arch/sh/kernel/cpu/sh4/clock-sh7780.c
··· 1 + /* 2 + * arch/sh/kernel/cpu/sh4/clock-sh7780.c 3 + * 4 + * SH7780 support for the clock framework 5 + * 6 + * Copyright (C) 2005 Paul Mundt 7 + * 8 + * This file is subject to the terms and conditions of the GNU General Public 9 + * License. See the file "COPYING" in the main directory of this archive 10 + * for more details. 11 + */ 12 + #include <linux/init.h> 13 + #include <linux/kernel.h> 14 + #include <asm/clock.h> 15 + #include <asm/freq.h> 16 + #include <asm/io.h> 17 + 18 + static int ifc_divisors[] = { 2, 4 }; 19 + static int bfc_divisors[] = { 1, 1, 1, 8, 12, 16, 24, 1 }; 20 + static int pfc_divisors[] = { 1, 24, 24, 1 }; 21 + static int cfc_divisors[] = { 1, 1, 4, 1, 6, 1, 1, 1 }; 22 + 23 + static void master_clk_init(struct clk *clk) 24 + { 25 + clk->rate *= pfc_divisors[ctrl_inl(FRQCR) & 0x0003]; 26 + } 27 + 28 + static struct clk_ops sh7780_master_clk_ops = { 29 + .init = master_clk_init, 30 + }; 31 + 32 + static void module_clk_recalc(struct clk *clk) 33 + { 34 + int idx = (ctrl_inl(FRQCR) & 0x0003); 35 + clk->rate = clk->parent->rate / pfc_divisors[idx]; 36 + } 37 + 38 + static struct clk_ops sh7780_module_clk_ops = { 39 + .recalc = module_clk_recalc, 40 + }; 41 + 42 + static void bus_clk_recalc(struct clk *clk) 43 + { 44 + int idx = ((ctrl_inl(FRQCR) >> 16) & 0x0007); 45 + clk->rate = clk->parent->rate / bfc_divisors[idx]; 46 + } 47 + 48 + static struct clk_ops sh7780_bus_clk_ops = { 49 + .recalc = bus_clk_recalc, 50 + }; 51 + 52 + static void cpu_clk_recalc(struct clk *clk) 53 + { 54 + int idx = ((ctrl_inl(FRQCR) >> 24) & 0x0001); 55 + clk->rate = clk->parent->rate / ifc_divisors[idx]; 56 + } 57 + 58 + static struct clk_ops sh7780_cpu_clk_ops = { 59 + .recalc = cpu_clk_recalc, 60 + }; 61 + 62 + static struct clk_ops *sh7780_clk_ops[] = { 63 + &sh7780_master_clk_ops, 64 + &sh7780_module_clk_ops, 65 + &sh7780_bus_clk_ops, 66 + &sh7780_cpu_clk_ops, 67 + }; 68 + 69 + void __init arch_init_clk_ops(struct clk_ops **ops, int idx) 70 + { 71 + if (idx < ARRAY_SIZE(sh7780_clk_ops)) 72 + *ops = sh7780_clk_ops[idx]; 73 + } 74 + 75 + static void shyway_clk_recalc(struct clk *clk) 76 + { 77 + int idx = ((ctrl_inl(FRQCR) >> 20) & 0x0007); 78 + clk->rate = clk->parent->rate / cfc_divisors[idx]; 79 + } 80 + 81 + static struct clk_ops sh7780_shyway_clk_ops = { 82 + .recalc = shyway_clk_recalc, 83 + }; 84 + 85 + static struct clk sh7780_shyway_clk = { 86 + .name = "shyway_clk", 87 + .flags = CLK_ALWAYS_ENABLED, 88 + .ops = &sh7780_shyway_clk_ops, 89 + }; 90 + 91 + /* 92 + * Additional SH7780-specific on-chip clocks that aren't already part of the 93 + * clock framework 94 + */ 95 + static struct clk *sh7780_onchip_clocks[] = { 96 + &sh7780_shyway_clk, 97 + }; 98 + 99 + static int __init sh7780_clk_init(void) 100 + { 101 + struct clk *clk = clk_get("master_clk"); 102 + int i; 103 + 104 + for (i = 0; i < ARRAY_SIZE(sh7780_onchip_clocks); i++) { 105 + struct clk *clkp = sh7780_onchip_clocks[i]; 106 + 107 + clkp->parent = clk; 108 + clk_register(clkp); 109 + clk_enable(clkp); 110 + } 111 + 112 + /* 113 + * Now that we have the rest of the clocks registered, we need to 114 + * force the parent clock to propagate so that these clocks will 115 + * automatically figure out their rate. We cheat by handing the 116 + * parent clock its current rate and forcing child propagation. 117 + */ 118 + clk_set_rate(clk, clk_get_rate(clk)); 119 + 120 + clk_put(clk); 121 + 122 + return 0; 123 + } 124 + 125 + arch_initcall(sh7780_clk_init); 126 +
+32 -486
arch/sh/kernel/time.c
··· 3 3 * 4 4 * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka 5 5 * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> 6 - * Copyright (C) 2002, 2003, 2004 Paul Mundt 6 + * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt 7 7 * Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org> 8 8 * 9 9 * Some code taken from i386 version. ··· 11 11 */ 12 12 13 13 #include <linux/config.h> 14 - #include <linux/errno.h> 15 - #include <linux/module.h> 16 - #include <linux/sched.h> 17 14 #include <linux/kernel.h> 18 - #include <linux/param.h> 19 - #include <linux/string.h> 20 - #include <linux/mm.h> 21 - #include <linux/interrupt.h> 22 - #include <linux/time.h> 23 - #include <linux/delay.h> 15 + #include <linux/module.h> 24 16 #include <linux/init.h> 25 - #include <linux/smp.h> 26 17 #include <linux/profile.h> 27 - 28 - #include <asm/processor.h> 29 - #include <asm/uaccess.h> 30 - #include <asm/io.h> 31 - #include <asm/irq.h> 32 - #include <asm/delay.h> 33 - #include <asm/machvec.h> 18 + #include <asm/clock.h> 34 19 #include <asm/rtc.h> 35 - #include <asm/freq.h> 36 - #include <asm/cpu/timer.h> 37 - #ifdef CONFIG_SH_KGDB 20 + #include <asm/timer.h> 38 21 #include <asm/kgdb.h> 39 - #endif 40 - 41 - #include <linux/timex.h> 42 - #include <linux/irq.h> 43 - 44 - #define TMU_TOCR_INIT 0x00 45 - #define TMU0_TCR_INIT 0x0020 46 - #define TMU_TSTR_INIT 1 47 - 48 - #define TMU0_TCR_CALIB 0x0000 49 - 50 - #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 51 - #define CLOCKGEN_MEMCLKCR 0xbb040038 52 - #define MEMCLKCR_RATIO_MASK 0x7 53 - #endif /* CONFIG_CPU_SUBTYPE_ST40STB1 */ 54 22 55 23 extern unsigned long wall_jiffies; 56 - #define TICK_SIZE (tick_nsec / 1000) 57 - DEFINE_SPINLOCK(tmu0_lock); 24 + struct sys_timer *sys_timer; 25 + 26 + /* Move this somewhere more sensible.. */ 27 + DEFINE_SPINLOCK(rtc_lock); 28 + EXPORT_SYMBOL(rtc_lock); 58 29 59 30 /* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want 60 31 * these routines anywhere... */ ··· 37 66 int (*rtc_set_time)(const time_t); 38 67 #endif 39 68 40 - #if defined(CONFIG_CPU_SUBTYPE_SH7300) 41 - static int md_table[] = { 1, 2, 3, 4, 6, 8, 12 }; 42 - #endif 43 - #if defined(CONFIG_CPU_SH3) 44 - static int stc_multipliers[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; 45 - static int stc_values[] = { 0, 1, 4, 2, 5, 0, 0, 0 }; 46 - #define bfc_divisors stc_multipliers 47 - #define bfc_values stc_values 48 - static int ifc_divisors[] = { 1, 2, 3, 4, 1, 1, 1, 1 }; 49 - static int ifc_values[] = { 0, 1, 4, 2, 0, 0, 0, 0 }; 50 - static int pfc_divisors[] = { 1, 2, 3, 4, 6, 1, 1, 1 }; 51 - static int pfc_values[] = { 0, 1, 4, 2, 5, 0, 0, 0 }; 52 - #elif defined(CONFIG_CPU_SH4) 53 - #if defined(CONFIG_CPU_SUBTYPE_SH73180) 54 - static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 12, 16 }; 55 - static int ifc_values[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; 56 - #define bfc_divisors ifc_divisors /* Same */ 57 - #define bfc_values ifc_values 58 - #define pfc_divisors ifc_divisors /* Same */ 59 - #define pfc_values ifc_values 60 - #else 61 - static int ifc_divisors[] = { 1, 2, 3, 4, 6, 8, 1, 1 }; 62 - static int ifc_values[] = { 0, 1, 2, 3, 0, 4, 0, 5 }; 63 - #define bfc_divisors ifc_divisors /* Same */ 64 - #define bfc_values ifc_values 65 - static int pfc_divisors[] = { 2, 3, 4, 6, 8, 2, 2, 2 }; 66 - static int pfc_values[] = { 0, 0, 1, 2, 0, 3, 0, 4 }; 67 - #endif 68 - #else 69 - #error "Unknown ifc/bfc/pfc/stc values for this processor" 70 - #endif 71 - 72 69 /* 73 70 * Scheduler clock - returns current time in nanosec units. 74 71 */ 75 - unsigned long long sched_clock(void) 72 + unsigned long long __attribute__ ((weak)) sched_clock(void) 76 73 { 77 74 return (unsigned long long)jiffies * (1000000000 / HZ); 78 - } 79 - 80 - static unsigned long do_gettimeoffset(void) 81 - { 82 - int count; 83 - unsigned long flags; 84 - 85 - static int count_p = 0x7fffffff; /* for the first call after boot */ 86 - static unsigned long jiffies_p = 0; 87 - 88 - /* 89 - * cache volatile jiffies temporarily; we have IRQs turned off. 90 - */ 91 - unsigned long jiffies_t; 92 - 93 - spin_lock_irqsave(&tmu0_lock, flags); 94 - /* timer count may underflow right here */ 95 - count = ctrl_inl(TMU0_TCNT); /* read the latched count */ 96 - 97 - jiffies_t = jiffies; 98 - 99 - /* 100 - * avoiding timer inconsistencies (they are rare, but they happen)... 101 - * there is one kind of problem that must be avoided here: 102 - * 1. the timer counter underflows 103 - */ 104 - 105 - if( jiffies_t == jiffies_p ) { 106 - if( count > count_p ) { 107 - /* the nutcase */ 108 - 109 - if(ctrl_inw(TMU0_TCR) & 0x100) { /* Check UNF bit */ 110 - /* 111 - * We cannot detect lost timer interrupts ... 112 - * well, that's why we call them lost, don't we? :) 113 - * [hmm, on the Pentium and Alpha we can ... sort of] 114 - */ 115 - count -= LATCH; 116 - } else { 117 - printk("do_slow_gettimeoffset(): hardware timer problem?\n"); 118 - } 119 - } 120 - } else 121 - jiffies_p = jiffies_t; 122 - 123 - count_p = count; 124 - spin_unlock_irqrestore(&tmu0_lock, flags); 125 - 126 - count = ((LATCH-1) - count) * TICK_SIZE; 127 - count = (count + LATCH/2) / LATCH; 128 - 129 - return count; 130 75 } 131 76 132 77 void do_gettimeofday(struct timeval *tv) ··· 53 166 54 167 do { 55 168 seq = read_seqbegin(&xtime_lock); 56 - usec = do_gettimeoffset(); 169 + usec = get_timer_offset(); 57 170 58 171 lost = jiffies - wall_jiffies; 59 172 if (lost) ··· 89 202 * wall time. Discover what correction gettimeofday() would have 90 203 * made, and then undo it! 91 204 */ 92 - nsec -= 1000 * (do_gettimeoffset() + 205 + nsec -= 1000 * (get_timer_offset() + 93 206 (jiffies - wall_jiffies) * (1000000 / HZ)); 94 207 95 208 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); ··· 111 224 static long last_rtc_update; 112 225 113 226 /* 114 - * timer_interrupt() needs to keep up the real-time clock, 227 + * handle_timer_tick() needs to keep up the real-time clock, 115 228 * as well as call the "do_timer()" routine every clocktick 116 229 */ 117 - static inline void do_timer_interrupt(int irq, struct pt_regs *regs) 230 + void handle_timer_tick(struct pt_regs *regs) 118 231 { 119 232 do_timer(regs); 120 233 #ifndef CONFIG_SMP ··· 139 252 if (rtc_set_time(xtime.tv_sec) == 0) 140 253 last_rtc_update = xtime.tv_sec; 141 254 else 142 - last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ 255 + /* do it again in 60s */ 256 + last_rtc_update = xtime.tv_sec - 600; 143 257 } 144 258 } 145 259 146 - /* 147 - * This is the same as the above, except we _also_ save the current 148 - * Time Stamp Counter value at the time of the timer interrupt, so that 149 - * we later on can estimate the time of day more exactly. 150 - */ 151 - static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 260 + static struct sysdev_class timer_sysclass = { 261 + set_kset_name("timer"), 262 + }; 263 + 264 + static int __init timer_init_sysfs(void) 152 265 { 153 - unsigned long timer_status; 266 + int ret = sysdev_class_register(&timer_sysclass); 267 + if (ret != 0) 268 + return ret; 154 269 155 - /* Clear UNF bit */ 156 - timer_status = ctrl_inw(TMU0_TCR); 157 - timer_status &= ~0x100; 158 - ctrl_outw(timer_status, TMU0_TCR); 159 - 160 - /* 161 - * Here we are in the timer irq handler. We just have irqs locally 162 - * disabled but we don't know if the timer_bh is running on the other 163 - * CPU. We need to avoid to SMP race with it. NOTE: we don' t need 164 - * the irq version of write_lock because as just said we have irq 165 - * locally disabled. -arca 166 - */ 167 - write_seqlock(&xtime_lock); 168 - do_timer_interrupt(irq, regs); 169 - write_sequnlock(&xtime_lock); 170 - 171 - return IRQ_HANDLED; 270 + sys_timer->dev.cls = &timer_sysclass; 271 + return sysdev_register(&sys_timer->dev); 172 272 } 173 273 174 - /* 175 - * Hah! We'll see if this works (switching from usecs to nsecs). 176 - */ 177 - static unsigned int __init get_timer_frequency(void) 178 - { 179 - u32 freq; 180 - struct timespec ts1, ts2; 181 - unsigned long diff_nsec; 182 - unsigned long factor; 183 - 184 - /* Setup the timer: We don't want to generate interrupts, just 185 - * have it count down at its natural rate. 186 - */ 187 - ctrl_outb(0, TMU_TSTR); 188 - #if !defined(CONFIG_CPU_SUBTYPE_SH7300) 189 - ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); 190 - #endif 191 - ctrl_outw(TMU0_TCR_CALIB, TMU0_TCR); 192 - ctrl_outl(0xffffffff, TMU0_TCOR); 193 - ctrl_outl(0xffffffff, TMU0_TCNT); 194 - 195 - rtc_get_time(&ts2); 196 - 197 - do { 198 - rtc_get_time(&ts1); 199 - } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); 200 - 201 - /* actually start the timer */ 202 - ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); 203 - 204 - do { 205 - rtc_get_time(&ts2); 206 - } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec); 207 - 208 - freq = 0xffffffff - ctrl_inl(TMU0_TCNT); 209 - if (ts2.tv_nsec < ts1.tv_nsec) { 210 - ts2.tv_nsec += 1000000000; 211 - ts2.tv_sec--; 212 - } 213 - 214 - diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec); 215 - 216 - /* this should work well if the RTC has a precision of n Hz, where 217 - * n is an integer. I don't think we have to worry about the other 218 - * cases. */ 219 - factor = (1000000000 + diff_nsec/2) / diff_nsec; 220 - 221 - if (factor * diff_nsec > 1100000000 || 222 - factor * diff_nsec < 900000000) 223 - panic("weird RTC (diff_nsec %ld)", diff_nsec); 224 - 225 - return freq * factor; 226 - } 274 + device_initcall(timer_init_sysfs); 227 275 228 276 void (*board_time_init)(void); 229 - void (*board_timer_setup)(struct irqaction *irq); 230 - 231 - static unsigned int sh_pclk_freq __initdata = CONFIG_SH_PCLK_FREQ; 232 - 233 - static int __init sh_pclk_setup(char *str) 234 - { 235 - unsigned int freq; 236 - 237 - if (get_option(&str, &freq)) 238 - sh_pclk_freq = freq; 239 - 240 - return 1; 241 - } 242 - __setup("sh_pclk=", sh_pclk_setup); 243 - 244 - static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer", NULL, NULL}; 245 - 246 - void get_current_frequency_divisors(unsigned int *ifc, unsigned int *bfc, unsigned int *pfc) 247 - { 248 - unsigned int frqcr = ctrl_inw(FRQCR); 249 - 250 - #if defined(CONFIG_CPU_SH3) 251 - #if defined(CONFIG_CPU_SUBTYPE_SH7300) 252 - *ifc = md_table[((frqcr & 0x0070) >> 4)]; 253 - *bfc = md_table[((frqcr & 0x0700) >> 8)]; 254 - *pfc = md_table[frqcr & 0x0007]; 255 - #elif defined(CONFIG_CPU_SUBTYPE_SH7705) 256 - *bfc = stc_multipliers[(frqcr & 0x0300) >> 8]; 257 - *ifc = ifc_divisors[(frqcr & 0x0030) >> 4]; 258 - *pfc = pfc_divisors[frqcr & 0x0003]; 259 - #else 260 - unsigned int tmp; 261 - 262 - tmp = (frqcr & 0x8000) >> 13; 263 - tmp |= (frqcr & 0x0030) >> 4; 264 - *bfc = stc_multipliers[tmp]; 265 - tmp = (frqcr & 0x4000) >> 12; 266 - tmp |= (frqcr & 0x000c) >> 2; 267 - *ifc = ifc_divisors[tmp]; 268 - tmp = (frqcr & 0x2000) >> 11; 269 - tmp |= frqcr & 0x0003; 270 - *pfc = pfc_divisors[tmp]; 271 - #endif 272 - #elif defined(CONFIG_CPU_SH4) 273 - #if defined(CONFIG_CPU_SUBTYPE_SH73180) 274 - *ifc = ifc_divisors[(frqcr>> 20) & 0x0007]; 275 - *bfc = bfc_divisors[(frqcr>> 12) & 0x0007]; 276 - *pfc = pfc_divisors[frqcr & 0x0007]; 277 - #else 278 - *ifc = ifc_divisors[(frqcr >> 6) & 0x0007]; 279 - *bfc = bfc_divisors[(frqcr >> 3) & 0x0007]; 280 - *pfc = pfc_divisors[frqcr & 0x0007]; 281 - #endif 282 - #endif 283 - } 284 - 285 - /* 286 - * This bit of ugliness builds up accessor routines to get at both 287 - * the divisors and the physical values. 288 - */ 289 - #define _FREQ_TABLE(x) \ 290 - unsigned int get_##x##_divisor(unsigned int value) \ 291 - { return x##_divisors[value]; } \ 292 - \ 293 - unsigned int get_##x##_value(unsigned int divisor) \ 294 - { return x##_values[(divisor - 1)]; } 295 - 296 - _FREQ_TABLE(ifc); 297 - _FREQ_TABLE(bfc); 298 - _FREQ_TABLE(pfc); 299 - 300 - #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 301 - 302 - /* 303 - * The ST40 divisors are totally different so we set the cpu data 304 - * clocks using a different algorithm 305 - * 306 - * I've just plugged this from the 2.4 code 307 - * - Alex Bennee <kernel-hacker@bennee.com> 308 - */ 309 - #define CCN_PVR_CHIP_SHIFT 24 310 - #define CCN_PVR_CHIP_MASK 0xff 311 - #define CCN_PVR_CHIP_ST40STB1 0x4 312 - 313 - 314 - struct frqcr_data { 315 - unsigned short frqcr; 316 - 317 - struct { 318 - unsigned char multiplier; 319 - unsigned char divisor; 320 - } factor[3]; 321 - }; 322 - 323 - static struct frqcr_data st40_frqcr_table[] = { 324 - { 0x000, {{1,1}, {1,1}, {1,2}}}, 325 - { 0x002, {{1,1}, {1,1}, {1,4}}}, 326 - { 0x004, {{1,1}, {1,1}, {1,8}}}, 327 - { 0x008, {{1,1}, {1,2}, {1,2}}}, 328 - { 0x00A, {{1,1}, {1,2}, {1,4}}}, 329 - { 0x00C, {{1,1}, {1,2}, {1,8}}}, 330 - { 0x011, {{1,1}, {2,3}, {1,6}}}, 331 - { 0x013, {{1,1}, {2,3}, {1,3}}}, 332 - { 0x01A, {{1,1}, {1,2}, {1,4}}}, 333 - { 0x01C, {{1,1}, {1,2}, {1,8}}}, 334 - { 0x023, {{1,1}, {2,3}, {1,3}}}, 335 - { 0x02C, {{1,1}, {1,2}, {1,8}}}, 336 - { 0x048, {{1,2}, {1,2}, {1,4}}}, 337 - { 0x04A, {{1,2}, {1,2}, {1,6}}}, 338 - { 0x04C, {{1,2}, {1,2}, {1,8}}}, 339 - { 0x05A, {{1,2}, {1,3}, {1,6}}}, 340 - { 0x05C, {{1,2}, {1,3}, {1,6}}}, 341 - { 0x063, {{1,2}, {1,4}, {1,4}}}, 342 - { 0x06C, {{1,2}, {1,4}, {1,8}}}, 343 - { 0x091, {{1,3}, {1,3}, {1,6}}}, 344 - { 0x093, {{1,3}, {1,3}, {1,6}}}, 345 - { 0x0A3, {{1,3}, {1,6}, {1,6}}}, 346 - { 0x0DA, {{1,4}, {1,4}, {1,8}}}, 347 - { 0x0DC, {{1,4}, {1,4}, {1,8}}}, 348 - { 0x0EC, {{1,4}, {1,8}, {1,8}}}, 349 - { 0x123, {{1,4}, {1,4}, {1,8}}}, 350 - { 0x16C, {{1,4}, {1,8}, {1,8}}}, 351 - }; 352 - 353 - struct memclk_data { 354 - unsigned char multiplier; 355 - unsigned char divisor; 356 - }; 357 - 358 - static struct memclk_data st40_memclk_table[8] = { 359 - {1,1}, // 000 360 - {1,2}, // 001 361 - {1,3}, // 010 362 - {2,3}, // 011 363 - {1,4}, // 100 364 - {1,6}, // 101 365 - {1,8}, // 110 366 - {1,8} // 111 367 - }; 368 - 369 - static void st40_specific_time_init(unsigned int module_clock, unsigned short frqcr) 370 - { 371 - unsigned int cpu_clock, master_clock, bus_clock, memory_clock; 372 - struct frqcr_data *d; 373 - int a; 374 - unsigned long memclkcr; 375 - struct memclk_data *e; 376 - 377 - for (a = 0; a < ARRAY_SIZE(st40_frqcr_table); a++) { 378 - d = &st40_frqcr_table[a]; 379 - 380 - if (d->frqcr == (frqcr & 0x1ff)) 381 - break; 382 - } 383 - 384 - if (a == ARRAY_SIZE(st40_frqcr_table)) { 385 - d = st40_frqcr_table; 386 - 387 - printk("ERROR: Unrecognised FRQCR value (0x%x), " 388 - "using default multipliers\n", frqcr); 389 - } 390 - 391 - memclkcr = ctrl_inl(CLOCKGEN_MEMCLKCR); 392 - e = &st40_memclk_table[memclkcr & MEMCLKCR_RATIO_MASK]; 393 - 394 - printk(KERN_INFO "Clock multipliers: CPU: %d/%d Bus: %d/%d " 395 - "Mem: %d/%d Periph: %d/%d\n", 396 - d->factor[0].multiplier, d->factor[0].divisor, 397 - d->factor[1].multiplier, d->factor[1].divisor, 398 - e->multiplier, e->divisor, 399 - d->factor[2].multiplier, d->factor[2].divisor); 400 - 401 - master_clock = module_clock * d->factor[2].divisor 402 - / d->factor[2].multiplier; 403 - bus_clock = master_clock * d->factor[1].multiplier 404 - / d->factor[1].divisor; 405 - memory_clock = master_clock * e->multiplier 406 - / e->divisor; 407 - cpu_clock = master_clock * d->factor[0].multiplier 408 - / d->factor[0].divisor; 409 - 410 - current_cpu_data.cpu_clock = cpu_clock; 411 - current_cpu_data.master_clock = master_clock; 412 - current_cpu_data.bus_clock = bus_clock; 413 - current_cpu_data.memory_clock = memory_clock; 414 - current_cpu_data.module_clock = module_clock; 415 - } 416 - #endif 417 277 418 278 void __init time_init(void) 419 279 { 420 - unsigned int timer_freq = 0; 421 - unsigned int ifc, pfc, bfc; 422 - unsigned long interval; 423 - #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 424 - unsigned long pvr; 425 - unsigned short frqcr; 426 - #endif 427 - 428 280 if (board_time_init) 429 281 board_time_init(); 430 282 431 - /* 432 - * If we don't have an RTC (such as with the SH7300), don't attempt to 433 - * probe the timer frequency. Rely on an either hardcoded peripheral 434 - * clock value, or on the sh_pclk command line option. Note that we 435 - * still need to have CONFIG_SH_PCLK_FREQ set in order for things like 436 - * CLOCK_TICK_RATE to be sane. 437 - */ 438 - current_cpu_data.module_clock = sh_pclk_freq; 439 - 440 - #ifdef CONFIG_SH_PCLK_CALC 441 - /* XXX: Switch this over to a more generic test. */ 442 - { 443 - unsigned int freq; 444 - 445 - /* 446 - * If we've specified a peripheral clock frequency, and we have 447 - * an RTC, compare it against the autodetected value. Complain 448 - * if there's a mismatch. 449 - */ 450 - timer_freq = get_timer_frequency(); 451 - freq = timer_freq * 4; 452 - 453 - if (sh_pclk_freq && (sh_pclk_freq/100*99 > freq || sh_pclk_freq/100*101 < freq)) { 454 - printk(KERN_NOTICE "Calculated peripheral clock value " 455 - "%d differs from sh_pclk value %d, fixing..\n", 456 - freq, sh_pclk_freq); 457 - current_cpu_data.module_clock = freq; 458 - } 459 - } 460 - #endif 461 - 462 - #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 463 - /* XXX: Update ST40 code to use board_time_init() */ 464 - pvr = ctrl_inl(CCN_PVR); 465 - frqcr = ctrl_inw(FRQCR); 466 - printk("time.c ST40 Probe: PVR %08lx, FRQCR %04hx\n", pvr, frqcr); 467 - 468 - if (((pvr >> CCN_PVR_CHIP_SHIFT) & CCN_PVR_CHIP_MASK) == CCN_PVR_CHIP_ST40STB1) 469 - st40_specific_time_init(current_cpu_data.module_clock, frqcr); 470 - else 471 - #endif 472 - get_current_frequency_divisors(&ifc, &bfc, &pfc); 283 + clk_init(); 473 284 474 285 if (rtc_get_time) { 475 286 rtc_get_time(&xtime); ··· 179 594 set_normalized_timespec(&wall_to_monotonic, 180 595 -xtime.tv_sec, -xtime.tv_nsec); 181 596 182 - if (board_timer_setup) { 183 - board_timer_setup(&irq0); 184 - } else { 185 - setup_irq(TIMER_IRQ, &irq0); 186 - } 187 - 188 597 /* 189 - * for ST40 chips the current_cpu_data should already be set 190 - * so not having valid pfc/bfc/ifc shouldn't be a problem 598 + * Find the timer to use as the system timer, it will be 599 + * initialized for us. 191 600 */ 192 - if (!current_cpu_data.master_clock) 193 - current_cpu_data.master_clock = current_cpu_data.module_clock * pfc; 194 - if (!current_cpu_data.bus_clock) 195 - current_cpu_data.bus_clock = current_cpu_data.master_clock / bfc; 196 - if (!current_cpu_data.cpu_clock) 197 - current_cpu_data.cpu_clock = current_cpu_data.master_clock / ifc; 198 - 199 - printk("CPU clock: %d.%02dMHz\n", 200 - (current_cpu_data.cpu_clock / 1000000), 201 - (current_cpu_data.cpu_clock % 1000000)/10000); 202 - printk("Bus clock: %d.%02dMHz\n", 203 - (current_cpu_data.bus_clock / 1000000), 204 - (current_cpu_data.bus_clock % 1000000)/10000); 205 - #ifdef CONFIG_CPU_SUBTYPE_ST40STB1 206 - printk("Memory clock: %d.%02dMHz\n", 207 - (current_cpu_data.memory_clock / 1000000), 208 - (current_cpu_data.memory_clock % 1000000)/10000); 209 - #endif 210 - printk("Module clock: %d.%02dMHz\n", 211 - (current_cpu_data.module_clock / 1000000), 212 - (current_cpu_data.module_clock % 1000000)/10000); 213 - 214 - interval = (current_cpu_data.module_clock/4 + HZ/2) / HZ; 215 - 216 - printk("Interval = %ld\n", interval); 217 - 218 - /* Start TMU0 */ 219 - ctrl_outb(0, TMU_TSTR); 220 - #if !defined(CONFIG_CPU_SUBTYPE_SH7300) 221 - ctrl_outb(TMU_TOCR_INIT, TMU_TOCR); 222 - #endif 223 - ctrl_outw(TMU0_TCR_INIT, TMU0_TCR); 224 - ctrl_outl(interval, TMU0_TCOR); 225 - ctrl_outl(interval, TMU0_TCNT); 226 - ctrl_outb(TMU_TSTR_INIT, TMU_TSTR); 601 + sys_timer = get_sys_timer(); 602 + printk(KERN_INFO "Using %s for system timer\n", sys_timer->name); 227 603 228 604 #if defined(CONFIG_SH_KGDB) 229 605 /*
+61
include/asm-sh/clock.h
··· 1 + #ifndef __ASM_SH_CLOCK_H 2 + #define __ASM_SH_CLOCK_H 3 + 4 + #include <linux/kref.h> 5 + #include <linux/list.h> 6 + #include <linux/seq_file.h> 7 + 8 + struct clk; 9 + 10 + struct clk_ops { 11 + void (*init)(struct clk *clk); 12 + void (*enable)(struct clk *clk); 13 + void (*disable)(struct clk *clk); 14 + void (*recalc)(struct clk *clk); 15 + int (*set_rate)(struct clk *clk, unsigned long rate); 16 + }; 17 + 18 + struct clk { 19 + struct list_head node; 20 + const char *name; 21 + 22 + struct module *owner; 23 + 24 + struct clk *parent; 25 + struct clk_ops *ops; 26 + 27 + struct kref kref; 28 + 29 + unsigned long rate; 30 + unsigned long flags; 31 + }; 32 + 33 + #define CLK_ALWAYS_ENABLED (1 << 0) 34 + #define CLK_RATE_PROPAGATES (1 << 1) 35 + 36 + /* Should be defined by processor-specific code */ 37 + void arch_init_clk_ops(struct clk_ops **, int type); 38 + 39 + /* arch/sh/kernel/cpu/clock.c */ 40 + int clk_init(void); 41 + 42 + int __clk_enable(struct clk *); 43 + int clk_enable(struct clk *); 44 + 45 + void __clk_disable(struct clk *); 46 + void clk_disable(struct clk *); 47 + 48 + int clk_set_rate(struct clk *, unsigned long rate); 49 + unsigned long clk_get_rate(struct clk *); 50 + void clk_recalc_rate(struct clk *); 51 + 52 + struct clk *clk_get(const char *id); 53 + void clk_put(struct clk *); 54 + 55 + int clk_register(struct clk *); 56 + void clk_unregister(struct clk *); 57 + 58 + int show_clocks(struct seq_file *m); 59 + 60 + #endif /* __ASM_SH_CLOCK_H */ 61 +
+2
include/asm-sh/cpu-sh4/freq.h
··· 12 12 13 13 #if defined(CONFIG_CPU_SUBTYPE_SH73180) 14 14 #define FRQCR 0xa4150000 15 + #elif defined(CONFIG_CPU_SUBTYPE_SH7780) 16 + #define FRQCR 0xffc80000 15 17 #else 16 18 #define FRQCR 0xffc00000 17 19 #endif
-11
include/asm-sh/freq.h
··· 14 14 15 15 #include <asm/cpu/freq.h> 16 16 17 - /* arch/sh/kernel/time.c */ 18 - extern void get_current_frequency_divisors(unsigned int *ifc, unsigned int *pfc, unsigned int *bfc); 19 - 20 - extern unsigned int get_ifc_divisor(unsigned int value); 21 - extern unsigned int get_ifc_divisor(unsigned int value); 22 - extern unsigned int get_ifc_divisor(unsigned int value); 23 - 24 - extern unsigned int get_ifc_value(unsigned int divisor); 25 - extern unsigned int get_pfc_value(unsigned int divisor); 26 - extern unsigned int get_bfc_value(unsigned int divisor); 27 - 28 17 #endif /* __KERNEL__ */ 29 18 #endif /* __ASM_SH_FREQ_H */