aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorJohn Crispin <blogic@openwrt.org>2012-04-17 09:53:19 -0400
committerRalf Baechle <ralf@linux-mips.org>2012-05-21 09:31:51 -0400
commit287e3f3f4e68ca881e3faa413e7aa114fee609d3 (patch)
treef33d5e8b76c50306eee6540570b39d5bcd92210f /arch/mips
parentbd51db7f3bf2ba23ff55f6d5fdcec04c74df13e4 (diff)
MIPS: lantiq: implement support for clkdev api
This patch unifies all clock generation and gating code into one file. All drivers will now be able to request their clocks via their device. This patch also adds support for the clockout feature, which allows clock generation on external pins. Support for COMMON_CLK will be provided in the next series. Signed-off-by: John Crispin <blogic@openwrt.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/3804/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/Kconfig3
-rw-r--r--arch/mips/include/asm/mach-lantiq/lantiq.h27
-rw-r--r--arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h5
-rw-r--r--arch/mips/lantiq/clk.c146
-rw-r--r--arch/mips/lantiq/clk.h68
-rw-r--r--arch/mips/lantiq/xway/Makefile5
-rw-r--r--arch/mips/lantiq/xway/clk-ase.c48
-rw-r--r--arch/mips/lantiq/xway/clk-xway.c223
-rw-r--r--arch/mips/lantiq/xway/clk.c151
-rw-r--r--arch/mips/lantiq/xway/ebu.c48
-rw-r--r--arch/mips/lantiq/xway/pmu.c69
-rw-r--r--arch/mips/lantiq/xway/sysctrl.c367
12 files changed, 681 insertions, 479 deletions
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index fbb56394c675..22058dc59a53 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -228,7 +228,8 @@ config LANTIQ
228 select ARCH_REQUIRE_GPIOLIB 228 select ARCH_REQUIRE_GPIOLIB
229 select SWAP_IO_SPACE 229 select SWAP_IO_SPACE
230 select BOOT_RAW 230 select BOOT_RAW
231 select HAVE_CLK 231 select HAVE_MACH_CLKDEV
232 select CLKDEV_LOOKUP
232 select USE_OF 233 select USE_OF
233 234
234config LASAT 235config LASAT
diff --git a/arch/mips/include/asm/mach-lantiq/lantiq.h b/arch/mips/include/asm/mach-lantiq/lantiq.h
index 7a90190bc387..6775d2402cd0 100644
--- a/arch/mips/include/asm/mach-lantiq/lantiq.h
+++ b/arch/mips/include/asm/mach-lantiq/lantiq.h
@@ -9,6 +9,8 @@
9#define _LANTIQ_H__ 9#define _LANTIQ_H__
10 10
11#include <linux/irq.h> 11#include <linux/irq.h>
12#include <linux/device.h>
13#include <linux/clk.h>
12 14
13/* generic reg access functions */ 15/* generic reg access functions */
14#define ltq_r32(reg) __raw_readl(reg) 16#define ltq_r32(reg) __raw_readl(reg)
@@ -21,26 +23,13 @@
21/* register access macros for EBU and CGU */ 23/* register access macros for EBU and CGU */
22#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y)) 24#define ltq_ebu_w32(x, y) ltq_w32((x), ltq_ebu_membase + (y))
23#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x)) 25#define ltq_ebu_r32(x) ltq_r32(ltq_ebu_membase + (x))
24#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y)) 26#define ltq_ebu_w32_mask(x, y, z) \
25#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x)) 27 ltq_w32_mask(x, y, ltq_ebu_membase + (z))
26
27extern __iomem void *ltq_ebu_membase; 28extern __iomem void *ltq_ebu_membase;
28extern __iomem void *ltq_cgu_membase;
29 29
30extern unsigned int ltq_get_cpu_ver(void); 30extern unsigned int ltq_get_cpu_ver(void);
31extern unsigned int ltq_get_soc_type(void); 31extern unsigned int ltq_get_soc_type(void);
32 32
33/* clock speeds */
34#define CLOCK_60M 60000000
35#define CLOCK_83M 83333333
36#define CLOCK_111M 111111111
37#define CLOCK_133M 133333333
38#define CLOCK_167M 166666667
39#define CLOCK_200M 200000000
40#define CLOCK_266M 266666666
41#define CLOCK_333M 333333333
42#define CLOCK_400M 400000000
43
44/* spinlock all ebu i/o */ 33/* spinlock all ebu i/o */
45extern spinlock_t ebu_lock; 34extern spinlock_t ebu_lock;
46 35
@@ -48,6 +37,14 @@ extern spinlock_t ebu_lock;
48extern void ltq_disable_irq(struct irq_data *data); 37extern void ltq_disable_irq(struct irq_data *data);
49extern void ltq_mask_and_ack_irq(struct irq_data *data); 38extern void ltq_mask_and_ack_irq(struct irq_data *data);
50extern void ltq_enable_irq(struct irq_data *data); 39extern void ltq_enable_irq(struct irq_data *data);
40
41/* clock handling */
42extern int clk_activate(struct clk *clk);
43extern void clk_deactivate(struct clk *clk);
44extern struct clk *clk_get_cpu(void);
45extern struct clk *clk_get_fpi(void);
46extern struct clk *clk_get_io(void);
47
51/* find out what bootsource we have */ 48/* find out what bootsource we have */
52extern unsigned char ltq_boot_select(void); 49extern unsigned char ltq_boot_select(void);
53/* find out what caused the last cpu reset */ 50/* find out what caused the last cpu reset */
diff --git a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
index 150c7bef5a14..b5a2acf9156f 100644
--- a/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
+++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
@@ -59,6 +59,11 @@
59#define BS_NAND 0x6 59#define BS_NAND 0x6
60#define BS_RMII0 0x7 60#define BS_RMII0 0x7
61 61
62/* helpers used to access the cgu */
63#define ltq_cgu_w32(x, y) ltq_w32((x), ltq_cgu_membase + (y))
64#define ltq_cgu_r32(x) ltq_r32(ltq_cgu_membase + (x))
65extern __iomem void *ltq_cgu_membase;
66
62/* 67/*
63 * during early_printk no ioremap is possible 68 * during early_printk no ioremap is possible
64 * lets use KSEG1 instead 69 * lets use KSEG1 instead
diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c
index 412814fdd3ee..d3bcc33f4699 100644
--- a/arch/mips/lantiq/clk.c
+++ b/arch/mips/lantiq/clk.c
@@ -12,6 +12,7 @@
12#include <linux/kernel.h> 12#include <linux/kernel.h>
13#include <linux/types.h> 13#include <linux/types.h>
14#include <linux/clk.h> 14#include <linux/clk.h>
15#include <linux/clkdev.h>
15#include <linux/err.h> 16#include <linux/err.h>
16#include <linux/list.h> 17#include <linux/list.h>
17 18
@@ -22,44 +23,32 @@
22#include <lantiq_soc.h> 23#include <lantiq_soc.h>
23 24
24#include "clk.h" 25#include "clk.h"
26#include "prom.h"
25 27
26struct clk { 28/* lantiq socs have 3 static clocks */
27 const char *name; 29static struct clk cpu_clk_generic[3];
28 unsigned long rate;
29 unsigned long (*get_rate) (void);
30};
31 30
32static struct clk *cpu_clk; 31void clkdev_add_static(unsigned long cpu, unsigned long fpi, unsigned long io)
33static int cpu_clk_cnt; 32{
33 cpu_clk_generic[0].rate = cpu;
34 cpu_clk_generic[1].rate = fpi;
35 cpu_clk_generic[2].rate = io;
36}
34 37
35/* lantiq socs have 3 static clocks */ 38struct clk *clk_get_cpu(void)
36static struct clk cpu_clk_generic[] = { 39{
37 { 40 return &cpu_clk_generic[0];
38 .name = "cpu", 41}
39 .get_rate = ltq_get_cpu_hz, 42
40 }, { 43struct clk *clk_get_fpi(void)
41 .name = "fpi", 44{
42 .get_rate = ltq_get_fpi_hz, 45 return &cpu_clk_generic[1];
43 }, { 46}
44 .name = "io", 47EXPORT_SYMBOL_GPL(clk_get_fpi);
45 .get_rate = ltq_get_io_region_clock, 48
46 }, 49struct clk *clk_get_io(void)
47};
48
49static struct resource ltq_cgu_resource = {
50 .name = "cgu",
51 .start = LTQ_CGU_BASE_ADDR,
52 .end = LTQ_CGU_BASE_ADDR + LTQ_CGU_SIZE - 1,
53 .flags = IORESOURCE_MEM,
54};
55
56/* remapped clock register range */
57void __iomem *ltq_cgu_membase;
58
59void clk_init(void)
60{ 50{
61 cpu_clk = cpu_clk_generic; 51 return &cpu_clk_generic[2];
62 cpu_clk_cnt = ARRAY_SIZE(cpu_clk_generic);
63} 52}
64 53
65static inline int clk_good(struct clk *clk) 54static inline int clk_good(struct clk *clk)
@@ -82,38 +71,71 @@ unsigned long clk_get_rate(struct clk *clk)
82} 71}
83EXPORT_SYMBOL(clk_get_rate); 72EXPORT_SYMBOL(clk_get_rate);
84 73
85struct clk *clk_get(struct device *dev, const char *id) 74int clk_set_rate(struct clk *clk, unsigned long rate)
86{ 75{
87 int i; 76 if (unlikely(!clk_good(clk)))
88 77 return 0;
89 for (i = 0; i < cpu_clk_cnt; i++) 78 if (clk->rates && *clk->rates) {
90 if (!strcmp(id, cpu_clk[i].name)) 79 unsigned long *r = clk->rates;
91 return &cpu_clk[i]; 80
92 BUG(); 81 while (*r && (*r != rate))
93 return ERR_PTR(-ENOENT); 82 r++;
94} 83 if (!*r) {
95EXPORT_SYMBOL(clk_get); 84 pr_err("clk %s.%s: trying to set invalid rate %ld\n",
96 85 clk->cl.dev_id, clk->cl.con_id, rate);
97void clk_put(struct clk *clk) 86 return -1;
98{ 87 }
99 /* not used */ 88 }
89 clk->rate = rate;
90 return 0;
100} 91}
101EXPORT_SYMBOL(clk_put); 92EXPORT_SYMBOL(clk_set_rate);
102 93
103int clk_enable(struct clk *clk) 94int clk_enable(struct clk *clk)
104{ 95{
105 /* not used */ 96 if (unlikely(!clk_good(clk)))
106 return 0; 97 return -1;
98
99 if (clk->enable)
100 return clk->enable(clk);
101
102 return -1;
107} 103}
108EXPORT_SYMBOL(clk_enable); 104EXPORT_SYMBOL(clk_enable);
109 105
110void clk_disable(struct clk *clk) 106void clk_disable(struct clk *clk)
111{ 107{
112 /* not used */ 108 if (unlikely(!clk_good(clk)))
109 return;
110
111 if (clk->disable)
112 clk->disable(clk);
113} 113}
114EXPORT_SYMBOL(clk_disable); 114EXPORT_SYMBOL(clk_disable);
115 115
116static inline u32 ltq_get_counter_resolution(void) 116int clk_activate(struct clk *clk)
117{
118 if (unlikely(!clk_good(clk)))
119 return -1;
120
121 if (clk->activate)
122 return clk->activate(clk);
123
124 return -1;
125}
126EXPORT_SYMBOL(clk_activate);
127
128void clk_deactivate(struct clk *clk)
129{
130 if (unlikely(!clk_good(clk)))
131 return;
132
133 if (clk->deactivate)
134 clk->deactivate(clk);
135}
136EXPORT_SYMBOL(clk_deactivate);
137
138static inline u32 get_counter_resolution(void)
117{ 139{
118 u32 res; 140 u32 res;
119 141
@@ -133,21 +155,11 @@ void __init plat_time_init(void)
133{ 155{
134 struct clk *clk; 156 struct clk *clk;
135 157
136 if (insert_resource(&iomem_resource, &ltq_cgu_resource) < 0) 158 ltq_soc_init();
137 panic("Failed to insert cgu memory");
138 159
139 if (request_mem_region(ltq_cgu_resource.start, 160 clk = clk_get_cpu();
140 resource_size(&ltq_cgu_resource), "cgu") < 0) 161 mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution();
141 panic("Failed to request cgu memory");
142
143 ltq_cgu_membase = ioremap_nocache(ltq_cgu_resource.start,
144 resource_size(&ltq_cgu_resource));
145 if (!ltq_cgu_membase) {
146 pr_err("Failed to remap cgu memory\n");
147 unreachable();
148 }
149 clk = clk_get(0, "cpu");
150 mips_hpt_frequency = clk_get_rate(clk) / ltq_get_counter_resolution();
151 write_c0_compare(read_c0_count()); 162 write_c0_compare(read_c0_count());
163 pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000);
152 clk_put(clk); 164 clk_put(clk);
153} 165}
diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h
index 3328925f2c3f..fa670602b91b 100644
--- a/arch/mips/lantiq/clk.h
+++ b/arch/mips/lantiq/clk.h
@@ -9,10 +9,70 @@
9#ifndef _LTQ_CLK_H__ 9#ifndef _LTQ_CLK_H__
10#define _LTQ_CLK_H__ 10#define _LTQ_CLK_H__
11 11
12extern void clk_init(void); 12#include <linux/clkdev.h>
13 13
14extern unsigned long ltq_get_cpu_hz(void); 14/* clock speeds */
15extern unsigned long ltq_get_fpi_hz(void); 15#define CLOCK_33M 33333333
16extern unsigned long ltq_get_io_region_clock(void); 16#define CLOCK_60M 60000000
17#define CLOCK_62_5M 62500000
18#define CLOCK_83M 83333333
19#define CLOCK_83_5M 83500000
20#define CLOCK_98_304M 98304000
21#define CLOCK_100M 100000000
22#define CLOCK_111M 111111111
23#define CLOCK_125M 125000000
24#define CLOCK_133M 133333333
25#define CLOCK_150M 150000000
26#define CLOCK_166M 166666666
27#define CLOCK_167M 166666667
28#define CLOCK_196_608M 196608000
29#define CLOCK_200M 200000000
30#define CLOCK_250M 250000000
31#define CLOCK_266M 266666666
32#define CLOCK_300M 300000000
33#define CLOCK_333M 333333333
34#define CLOCK_393M 393215332
35#define CLOCK_400M 400000000
36#define CLOCK_500M 500000000
37#define CLOCK_600M 600000000
38
39/* clock out speeds */
40#define CLOCK_32_768K 32768
41#define CLOCK_1_536M 1536000
42#define CLOCK_2_5M 2500000
43#define CLOCK_12M 12000000
44#define CLOCK_24M 24000000
45#define CLOCK_25M 25000000
46#define CLOCK_30M 30000000
47#define CLOCK_40M 40000000
48#define CLOCK_48M 48000000
49#define CLOCK_50M 50000000
50#define CLOCK_60M 60000000
51
52struct clk {
53 struct clk_lookup cl;
54 unsigned long rate;
55 unsigned long *rates;
56 unsigned int module;
57 unsigned int bits;
58 unsigned long (*get_rate) (void);
59 int (*enable) (struct clk *clk);
60 void (*disable) (struct clk *clk);
61 int (*activate) (struct clk *clk);
62 void (*deactivate) (struct clk *clk);
63 void (*reboot) (struct clk *clk);
64};
65
66extern void clkdev_add_static(unsigned long cpu, unsigned long fpi,
67 unsigned long io);
68
69extern unsigned long ltq_danube_cpu_hz(void);
70extern unsigned long ltq_danube_fpi_hz(void);
71
72extern unsigned long ltq_ar9_cpu_hz(void);
73extern unsigned long ltq_ar9_fpi_hz(void);
74
75extern unsigned long ltq_vr9_cpu_hz(void);
76extern unsigned long ltq_vr9_fpi_hz(void);
17 77
18#endif 78#endif
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile
index 7a6c30f672f4..edef6c582fce 100644
--- a/arch/mips/lantiq/xway/Makefile
+++ b/arch/mips/lantiq/xway/Makefile
@@ -1,4 +1 @@
1obj-y := prom.o pmu.o ebu.o reset.o gpio.o gpio_stp.o gpio_ebu.o dma.o obj-y := prom.o sysctrl.o clk.o reset.o gpio.o gpio_stp.o gpio_ebu.o dma.o
2
3obj-$(CONFIG_SOC_XWAY) += clk-xway.o
4obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o
diff --git a/arch/mips/lantiq/xway/clk-ase.c b/arch/mips/lantiq/xway/clk-ase.c
deleted file mode 100644
index 652258309c9c..000000000000
--- a/arch/mips/lantiq/xway/clk-ase.c
+++ /dev/null
@@ -1,48 +0,0 @@
1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License version 2 as published
4 * by the Free Software Foundation.
5 *
6 * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
7 */
8
9#include <linux/io.h>
10#include <linux/export.h>
11#include <linux/init.h>
12#include <linux/clk.h>
13
14#include <asm/time.h>
15#include <asm/irq.h>
16#include <asm/div64.h>
17
18#include <lantiq_soc.h>
19
20/* cgu registers */
21#define LTQ_CGU_SYS 0x0010
22
23unsigned int ltq_get_io_region_clock(void)
24{
25 return CLOCK_133M;
26}
27EXPORT_SYMBOL(ltq_get_io_region_clock);
28
29unsigned int ltq_get_fpi_bus_clock(int fpi)
30{
31 return CLOCK_133M;
32}
33EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
34
35unsigned int ltq_get_cpu_hz(void)
36{
37 if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5))
38 return CLOCK_266M;
39 else
40 return CLOCK_133M;
41}
42EXPORT_SYMBOL(ltq_get_cpu_hz);
43
44unsigned int ltq_get_fpi_hz(void)
45{
46 return CLOCK_133M;
47}
48EXPORT_SYMBOL(ltq_get_fpi_hz);
diff --git a/arch/mips/lantiq/xway/clk-xway.c b/arch/mips/lantiq/xway/clk-xway.c
deleted file mode 100644
index 696b1a3e0642..000000000000
--- a/arch/mips/lantiq/xway/clk-xway.c
+++ /dev/null
@@ -1,223 +0,0 @@
1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License version 2 as published
4 * by the Free Software Foundation.
5 *
6 * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
7 */
8
9#include <linux/io.h>
10#include <linux/export.h>
11#include <linux/init.h>
12#include <linux/clk.h>
13
14#include <asm/time.h>
15#include <asm/irq.h>
16#include <asm/div64.h>
17
18#include <lantiq_soc.h>
19
20static unsigned int ltq_ram_clocks[] = {
21 CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };
22#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3]
23
24#define BASIC_FREQUENCY_1 35328000
25#define BASIC_FREQUENCY_2 36000000
26#define BASIS_REQUENCY_USB 12000000
27
28#define GET_BITS(x, msb, lsb) \
29 (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
30
31#define LTQ_CGU_PLL0_CFG 0x0004
32#define LTQ_CGU_PLL1_CFG 0x0008
33#define LTQ_CGU_PLL2_CFG 0x000C
34#define LTQ_CGU_SYS 0x0010
35#define LTQ_CGU_UPDATE 0x0014
36#define LTQ_CGU_IF_CLK 0x0018
37#define LTQ_CGU_OSC_CON 0x001C
38#define LTQ_CGU_SMD 0x0020
39#define LTQ_CGU_CT1SR 0x0028
40#define LTQ_CGU_CT2SR 0x002C
41#define LTQ_CGU_PCMCR 0x0030
42#define LTQ_CGU_PCI_CR 0x0034
43#define LTQ_CGU_PD_PC 0x0038
44#define LTQ_CGU_FMR 0x003C
45
46#define CGU_PLL0_PHASE_DIVIDER_ENABLE \
47 (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31))
48#define CGU_PLL0_BYPASS \
49 (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30))
50#define CGU_PLL0_CFG_DSMSEL \
51 (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28))
52#define CGU_PLL0_CFG_FRAC_EN \
53 (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27))
54#define CGU_PLL1_SRC \
55 (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31))
56#define CGU_PLL2_PHASE_DIVIDER_ENABLE \
57 (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20))
58#define CGU_SYS_FPI_SEL (1 << 6)
59#define CGU_SYS_DDR_SEL 0x3
60#define CGU_PLL0_SRC (1 << 29)
61
62#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17)
63#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6)
64#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2)
65#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17)
66#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13)
67
68static unsigned int ltq_get_pll0_fdiv(void);
69
70static inline unsigned int get_input_clock(int pll)
71{
72 switch (pll) {
73 case 0:
74 if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC)
75 return BASIS_REQUENCY_USB;
76 else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
77 return BASIC_FREQUENCY_1;
78 else
79 return BASIC_FREQUENCY_2;
80 case 1:
81 if (CGU_PLL1_SRC)
82 return BASIS_REQUENCY_USB;
83 else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
84 return BASIC_FREQUENCY_1;
85 else
86 return BASIC_FREQUENCY_2;
87 case 2:
88 switch (CGU_PLL2_SRC) {
89 case 0:
90 return ltq_get_pll0_fdiv();
91 case 1:
92 return CGU_PLL2_PHASE_DIVIDER_ENABLE ?
93 BASIC_FREQUENCY_1 :
94 BASIC_FREQUENCY_2;
95 case 2:
96 return BASIS_REQUENCY_USB;
97 }
98 default:
99 return 0;
100 }
101}
102
103static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den)
104{
105 u64 res, clock = get_input_clock(pll);
106
107 res = num * clock;
108 do_div(res, den);
109 return res;
110}
111
112static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N,
113 unsigned int K)
114{
115 unsigned int num = ((N + 1) << 10) + K;
116 unsigned int den = (M + 1) << 10;
117
118 return cal_dsm(pll, num, den);
119}
120
121static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N,
122 unsigned int K)
123{
124 unsigned int num = ((N + 1) << 11) + K + 512;
125 unsigned int den = (M + 1) << 11;
126
127 return cal_dsm(pll, num, den);
128}
129
130static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N,
131 unsigned int K)
132{
133 unsigned int num = K >= 512 ?
134 ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;
135 unsigned int den = (M + 1) << 12;
136
137 return cal_dsm(pll, num, den);
138}
139
140static inline unsigned int dsm(int pll, unsigned int M, unsigned int N,
141 unsigned int K, unsigned int dsmsel, unsigned int phase_div_en)
142{
143 if (!dsmsel)
144 return mash_dsm(pll, M, N, K);
145 else if (!phase_div_en)
146 return mash_dsm(pll, M, N, K);
147 else
148 return ssff_dsm_2(pll, M, N, K);
149}
150
151static inline unsigned int ltq_get_pll0_fosc(void)
152{
153 if (CGU_PLL0_BYPASS)
154 return get_input_clock(0);
155 else
156 return !CGU_PLL0_CFG_FRAC_EN
157 ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0,
158 CGU_PLL0_CFG_DSMSEL,
159 CGU_PLL0_PHASE_DIVIDER_ENABLE)
160 : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN,
161 CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL,
162 CGU_PLL0_PHASE_DIVIDER_ENABLE);
163}
164
165static unsigned int ltq_get_pll0_fdiv(void)
166{
167 unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1;
168
169 return (ltq_get_pll0_fosc() + (div >> 1)) / div;
170}
171
172unsigned int ltq_get_io_region_clock(void)
173{
174 unsigned int ret = ltq_get_pll0_fosc();
175
176 switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) {
177 default:
178 case 0:
179 return (ret + 1) / 2;
180 case 1:
181 return (ret * 2 + 2) / 5;
182 case 2:
183 return (ret + 1) / 3;
184 case 3:
185 return (ret + 2) / 4;
186 }
187}
188EXPORT_SYMBOL(ltq_get_io_region_clock);
189
190unsigned int ltq_get_fpi_bus_clock(int fpi)
191{
192 unsigned int ret = ltq_get_io_region_clock();
193
194 if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL))
195 ret >>= 1;
196 return ret;
197}
198EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
199
200unsigned int ltq_get_cpu_hz(void)
201{
202 switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) {
203 case 0:
204 return CLOCK_333M;
205 case 4:
206 return DDR_HZ;
207 case 8:
208 return DDR_HZ << 1;
209 default:
210 return DDR_HZ >> 1;
211 }
212}
213EXPORT_SYMBOL(ltq_get_cpu_hz);
214
215unsigned int ltq_get_fpi_hz(void)
216{
217 unsigned int ddr_clock = DDR_HZ;
218
219 if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40)
220 return ddr_clock >> 1;
221 return ddr_clock;
222}
223EXPORT_SYMBOL(ltq_get_fpi_hz);
diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c
new file mode 100644
index 000000000000..9aa17f79a742
--- /dev/null
+++ b/arch/mips/lantiq/xway/clk.c
@@ -0,0 +1,151 @@
1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License version 2 as published
4 * by the Free Software Foundation.
5 *
6 * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
7 */
8
9#include <linux/io.h>
10#include <linux/export.h>
11#include <linux/init.h>
12#include <linux/clk.h>
13
14#include <asm/time.h>
15#include <asm/irq.h>
16#include <asm/div64.h>
17
18#include <lantiq_soc.h>
19
20#include "../clk.h"
21
22static unsigned int ram_clocks[] = {
23 CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };
24#define DDR_HZ ram_clocks[ltq_cgu_r32(CGU_SYS) & 0x3]
25
26/* legacy xway clock */
27#define CGU_SYS 0x10
28
29/* vr9 clock */
30#define CGU_SYS_VR9 0x0c
31#define CGU_IF_CLK_VR9 0x24
32
33unsigned long ltq_danube_fpi_hz(void)
34{
35 unsigned long ddr_clock = DDR_HZ;
36
37 if (ltq_cgu_r32(CGU_SYS) & 0x40)
38 return ddr_clock >> 1;
39 return ddr_clock;
40}
41
42unsigned long ltq_danube_cpu_hz(void)
43{
44 switch (ltq_cgu_r32(CGU_SYS) & 0xc) {
45 case 0:
46 return CLOCK_333M;
47 case 4:
48 return DDR_HZ;
49 case 8:
50 return DDR_HZ << 1;
51 default:
52 return DDR_HZ >> 1;
53 }
54}
55
56unsigned long ltq_ar9_sys_hz(void)
57{
58 if (((ltq_cgu_r32(CGU_SYS) >> 3) & 0x3) == 0x2)
59 return CLOCK_393M;
60 return CLOCK_333M;
61}
62
63unsigned long ltq_ar9_fpi_hz(void)
64{
65 unsigned long sys = ltq_ar9_sys_hz();
66
67 if (ltq_cgu_r32(CGU_SYS) & BIT(0))
68 return sys;
69 return sys >> 1;
70}
71
72unsigned long ltq_ar9_cpu_hz(void)
73{
74 if (ltq_cgu_r32(CGU_SYS) & BIT(2))
75 return ltq_ar9_fpi_hz();
76 else
77 return ltq_ar9_sys_hz();
78}
79
80unsigned long ltq_vr9_cpu_hz(void)
81{
82 unsigned int cpu_sel;
83 unsigned long clk;
84
85 cpu_sel = (ltq_cgu_r32(CGU_SYS_VR9) >> 4) & 0xf;
86
87 switch (cpu_sel) {
88 case 0:
89 clk = CLOCK_600M;
90 break;
91 case 1:
92 clk = CLOCK_500M;
93 break;
94 case 2:
95 clk = CLOCK_393M;
96 break;
97 case 3:
98 clk = CLOCK_333M;
99 break;
100 case 5:
101 case 6:
102 clk = CLOCK_196_608M;
103 break;
104 case 7:
105 clk = CLOCK_167M;
106 break;
107 case 4:
108 case 8:
109 case 9:
110 clk = CLOCK_125M;
111 break;
112 default:
113 clk = 0;
114 break;
115 }
116
117 return clk;
118}
119
120unsigned long ltq_vr9_fpi_hz(void)
121{
122 unsigned int ocp_sel, cpu_clk;
123 unsigned long clk;
124
125 cpu_clk = ltq_vr9_cpu_hz();
126 ocp_sel = ltq_cgu_r32(CGU_SYS_VR9) & 0x3;
127
128 switch (ocp_sel) {
129 case 0:
130 /* OCP ratio 1 */
131 clk = cpu_clk;
132 break;
133 case 2:
134 /* OCP ratio 2 */
135 clk = cpu_clk / 2;
136 break;
137 case 3:
138 /* OCP ratio 2.5 */
139 clk = (cpu_clk * 2) / 5;
140 break;
141 case 4:
142 /* OCP ratio 3 */
143 clk = cpu_clk / 3;
144 break;
145 default:
146 clk = 0;
147 break;
148 }
149
150 return clk;
151}
diff --git a/arch/mips/lantiq/xway/ebu.c b/arch/mips/lantiq/xway/ebu.c
deleted file mode 100644
index 419b47b70f32..000000000000
--- a/arch/mips/lantiq/xway/ebu.c
+++ /dev/null
@@ -1,48 +0,0 @@
1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License version 2 as published
4 * by the Free Software Foundation.
5 *
6 * EBU - the external bus unit attaches PCI, NOR and NAND
7 *
8 * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/ioport.h>
14
15#include <lantiq_soc.h>
16
17static struct resource ltq_ebu_resource = {
18 .name = "ebu",
19 .start = LTQ_EBU_BASE_ADDR,
20 .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1,
21 .flags = IORESOURCE_MEM,
22};
23
24/* remapped base addr of the clock unit and external bus unit */
25void __iomem *ltq_ebu_membase;
26
27static int __init lantiq_ebu_init(void)
28{
29 /* insert and request the memory region */
30 if (insert_resource(&iomem_resource, &ltq_ebu_resource) < 0)
31 panic("Failed to insert ebu memory");
32
33 if (request_mem_region(ltq_ebu_resource.start,
34 resource_size(&ltq_ebu_resource), "ebu") < 0)
35 panic("Failed to request ebu memory");
36
37 /* remap ebu register range */
38 ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start,
39 resource_size(&ltq_ebu_resource));
40 if (!ltq_ebu_membase)
41 panic("Failed to remap ebu memory");
42
43 /* make sure to unprotect the memory region where flash is located */
44 ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
45 return 0;
46}
47
48postcore_initcall(lantiq_ebu_init);
diff --git a/arch/mips/lantiq/xway/pmu.c b/arch/mips/lantiq/xway/pmu.c
deleted file mode 100644
index fe85361e032e..000000000000
--- a/arch/mips/lantiq/xway/pmu.c
+++ /dev/null
@@ -1,69 +0,0 @@
1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License version 2 as published
4 * by the Free Software Foundation.
5 *
6 * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
7 */
8
9#include <linux/kernel.h>
10#include <linux/module.h>
11#include <linux/ioport.h>
12
13#include <lantiq_soc.h>
14
15/* PMU - the power management unit allows us to turn part of the core
16 * on and off
17 */
18
19/* the enable / disable registers */
20#define LTQ_PMU_PWDCR 0x1C
21#define LTQ_PMU_PWDSR 0x20
22
23#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y))
24#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x))
25
26static struct resource ltq_pmu_resource = {
27 .name = "pmu",
28 .start = LTQ_PMU_BASE_ADDR,
29 .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1,
30 .flags = IORESOURCE_MEM,
31};
32
33static void __iomem *ltq_pmu_membase;
34
35void ltq_pmu_enable(unsigned int module)
36{
37 int err = 1000000;
38
39 ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR);
40 do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module));
41
42 if (!err)
43 panic("activating PMU module failed!");
44}
45EXPORT_SYMBOL(ltq_pmu_enable);
46
47void ltq_pmu_disable(unsigned int module)
48{
49 ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR);
50}
51EXPORT_SYMBOL(ltq_pmu_disable);
52
53int __init ltq_pmu_init(void)
54{
55 if (insert_resource(&iomem_resource, &ltq_pmu_resource) < 0)
56 panic("Failed to insert pmu memory");
57
58 if (request_mem_region(ltq_pmu_resource.start,
59 resource_size(&ltq_pmu_resource), "pmu") < 0)
60 panic("Failed to request pmu memory");
61
62 ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start,
63 resource_size(&ltq_pmu_resource));
64 if (!ltq_pmu_membase)
65 panic("Failed to remap pmu memory");
66 return 0;
67}
68
69core_initcall(ltq_pmu_init);
diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c
new file mode 100644
index 000000000000..4d6aac693535
--- /dev/null
+++ b/arch/mips/lantiq/xway/sysctrl.c
@@ -0,0 +1,367 @@
1/*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU General Public License version 2 as published
4 * by the Free Software Foundation.
5 *
6 * Copyright (C) 2011-2012 John Crispin <blogic@openwrt.org>
7 */
8
9#include <linux/ioport.h>
10#include <linux/export.h>
11#include <linux/clkdev.h>
12#include <linux/of.h>
13#include <linux/of_platform.h>
14#include <linux/of_address.h>
15
16#include <lantiq_soc.h>
17
18#include "../clk.h"
19#include "../prom.h"
20
21/* clock control register */
22#define CGU_IFCCR 0x0018
23/* system clock register */
24#define CGU_SYS 0x0010
25/* pci control register */
26#define CGU_PCICR 0x0034
27/* ephy configuration register */
28#define CGU_EPHY 0x10
29/* power control register */
30#define PMU_PWDCR 0x1C
31/* power status register */
32#define PMU_PWDSR 0x20
33/* power control register */
34#define PMU_PWDCR1 0x24
35/* power status register */
36#define PMU_PWDSR1 0x28
37/* power control register */
38#define PWDCR(x) ((x) ? (PMU_PWDCR1) : (PMU_PWDCR))
39/* power status register */
40#define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR))
41
42/* clock gates that we can en/disable */
43#define PMU_USB0_P BIT(0)
44#define PMU_PCI BIT(4)
45#define PMU_USB0 BIT(6)
46#define PMU_ASC0 BIT(7)
47#define PMU_EPHY BIT(7) /* ase */
48#define PMU_SPI BIT(8)
49#define PMU_DFE BIT(9)
50#define PMU_EBU BIT(10)
51#define PMU_STP BIT(11)
52#define PMU_AHBS BIT(13) /* vr9 */
53#define PMU_AHBM BIT(15)
54#define PMU_ASC1 BIT(17)
55#define PMU_PPE_QSB BIT(18)
56#define PMU_PPE_SLL01 BIT(19)
57#define PMU_PPE_TC BIT(21)
58#define PMU_PPE_EMA BIT(22)
59#define PMU_PPE_DPLUM BIT(23)
60#define PMU_PPE_DPLUS BIT(24)
61#define PMU_USB1_P BIT(26)
62#define PMU_USB1 BIT(27)
63#define PMU_PPE_TOP BIT(29)
64#define PMU_GPHY BIT(30)
65#define PMU_PCIE_CLK BIT(31)
66
67#define PMU1_PCIE_PHY BIT(0)
68#define PMU1_PCIE_CTL BIT(1)
69#define PMU1_PCIE_PDI BIT(4)
70#define PMU1_PCIE_MSI BIT(5)
71
72#define pmu_w32(x, y) ltq_w32((x), pmu_membase + (y))
73#define pmu_r32(x) ltq_r32(pmu_membase + (x))
74
75static void __iomem *pmu_membase;
76void __iomem *ltq_cgu_membase;
77void __iomem *ltq_ebu_membase;
78
79/* legacy function kept alive to ease clkdev transition */
80void ltq_pmu_enable(unsigned int module)
81{
82 int err = 1000000;
83
84 pmu_w32(pmu_r32(PMU_PWDCR) & ~module, PMU_PWDCR);
85 do {} while (--err && (pmu_r32(PMU_PWDSR) & module));
86
87 if (!err)
88 panic("activating PMU module failed!");
89}
90EXPORT_SYMBOL(ltq_pmu_enable);
91
92/* legacy function kept alive to ease clkdev transition */
93void ltq_pmu_disable(unsigned int module)
94{
95 pmu_w32(pmu_r32(PMU_PWDCR) | module, PMU_PWDCR);
96}
97EXPORT_SYMBOL(ltq_pmu_disable);
98
99/* enable a hw clock */
100static int cgu_enable(struct clk *clk)
101{
102 ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | clk->bits, CGU_IFCCR);
103 return 0;
104}
105
106/* disable a hw clock */
107static void cgu_disable(struct clk *clk)
108{
109 ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~clk->bits, CGU_IFCCR);
110}
111
112/* enable a clock gate */
113static int pmu_enable(struct clk *clk)
114{
115 int retry = 1000000;
116
117 pmu_w32(pmu_r32(PWDCR(clk->module)) & ~clk->bits,
118 PWDCR(clk->module));
119 do {} while (--retry && (pmu_r32(PWDSR(clk->module)) & clk->bits));
120
121 if (!retry)
122 panic("activating PMU module failed!\n");
123
124 return 0;
125}
126
127/* disable a clock gate */
128static void pmu_disable(struct clk *clk)
129{
130 pmu_w32(pmu_r32(PWDCR(clk->module)) | clk->bits,
131 PWDCR(clk->module));
132}
133
134/* the pci enable helper */
135static int pci_enable(struct clk *clk)
136{
137 unsigned int ifccr = ltq_cgu_r32(CGU_IFCCR);
138 /* set bus clock speed */
139 if (of_machine_is_compatible("lantiq,ar9")) {
140 ifccr &= ~0x1f00000;
141 if (clk->rate == CLOCK_33M)
142 ifccr |= 0xe00000;
143 else
144 ifccr |= 0x700000; /* 62.5M */
145 } else {
146 ifccr &= ~0xf00000;
147 if (clk->rate == CLOCK_33M)
148 ifccr |= 0x800000;
149 else
150 ifccr |= 0x400000; /* 62.5M */
151 }
152 ltq_cgu_w32(ifccr, CGU_IFCCR);
153 pmu_enable(clk);
154 return 0;
155}
156
157/* enable the external clock as a source */
158static int pci_ext_enable(struct clk *clk)
159{
160 ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) & ~(1 << 16),
161 CGU_IFCCR);
162 ltq_cgu_w32((1 << 30), CGU_PCICR);
163 return 0;
164}
165
166/* disable the external clock as a source */
167static void pci_ext_disable(struct clk *clk)
168{
169 ltq_cgu_w32(ltq_cgu_r32(CGU_IFCCR) | (1 << 16),
170 CGU_IFCCR);
171 ltq_cgu_w32((1 << 31) | (1 << 30), CGU_PCICR);
172}
173
174/* enable a clockout source */
175static int clkout_enable(struct clk *clk)
176{
177 int i;
178
179 /* get the correct rate */
180 for (i = 0; i < 4; i++) {
181 if (clk->rates[i] == clk->rate) {
182 int shift = 14 - (2 * clk->module);
183 unsigned int ifccr = ltq_cgu_r32(CGU_IFCCR);
184
185 ifccr &= ~(3 << shift);
186 ifccr |= i << shift;
187 ltq_cgu_w32(ifccr, CGU_IFCCR);
188 return 0;
189 }
190 }
191 return -1;
192}
193
194/* manage the clock gates via PMU */
195static void clkdev_add_pmu(const char *dev, const char *con,
196 unsigned int module, unsigned int bits)
197{
198 struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
199
200 clk->cl.dev_id = dev;
201 clk->cl.con_id = con;
202 clk->cl.clk = clk;
203 clk->enable = pmu_enable;
204 clk->disable = pmu_disable;
205 clk->module = module;
206 clk->bits = bits;
207 clkdev_add(&clk->cl);
208}
209
210/* manage the clock generator */
211static void clkdev_add_cgu(const char *dev, const char *con,
212 unsigned int bits)
213{
214 struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
215
216 clk->cl.dev_id = dev;
217 clk->cl.con_id = con;
218 clk->cl.clk = clk;
219 clk->enable = cgu_enable;
220 clk->disable = cgu_disable;
221 clk->bits = bits;
222 clkdev_add(&clk->cl);
223}
224
225/* pci needs its own enable function as the setup is a bit more complex */
226static unsigned long valid_pci_rates[] = {CLOCK_33M, CLOCK_62_5M, 0};
227
228static void clkdev_add_pci(void)
229{
230 struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
231 struct clk *clk_ext = kzalloc(sizeof(struct clk), GFP_KERNEL);
232
233 /* main pci clock */
234 clk->cl.dev_id = "17000000.pci";
235 clk->cl.con_id = NULL;
236 clk->cl.clk = clk;
237 clk->rate = CLOCK_33M;
238 clk->rates = valid_pci_rates;
239 clk->enable = pci_enable;
240 clk->disable = pmu_disable;
241 clk->module = 0;
242 clk->bits = PMU_PCI;
243 clkdev_add(&clk->cl);
244
245 /* use internal/external bus clock */
246 clk_ext->cl.dev_id = "17000000.pci";
247 clk_ext->cl.con_id = "external";
248 clk_ext->cl.clk = clk_ext;
249 clk_ext->enable = pci_ext_enable;
250 clk_ext->disable = pci_ext_disable;
251 clkdev_add(&clk_ext->cl);
252}
253
254/* xway socs can generate clocks on gpio pins */
255static unsigned long valid_clkout_rates[4][5] = {
256 {CLOCK_32_768K, CLOCK_1_536M, CLOCK_2_5M, CLOCK_12M, 0},
257 {CLOCK_40M, CLOCK_12M, CLOCK_24M, CLOCK_48M, 0},
258 {CLOCK_25M, CLOCK_40M, CLOCK_30M, CLOCK_60M, 0},
259 {CLOCK_12M, CLOCK_50M, CLOCK_32_768K, CLOCK_25M, 0},
260};
261
262static void clkdev_add_clkout(void)
263{
264 int i;
265
266 for (i = 0; i < 4; i++) {
267 struct clk *clk;
268 char *name;
269
270 name = kzalloc(sizeof("clkout0"), GFP_KERNEL);
271 sprintf(name, "clkout%d", i);
272
273 clk = kzalloc(sizeof(struct clk), GFP_KERNEL);
274 clk->cl.dev_id = "1f103000.cgu";
275 clk->cl.con_id = name;
276 clk->cl.clk = clk;
277 clk->rate = 0;
278 clk->rates = valid_clkout_rates[i];
279 clk->enable = clkout_enable;
280 clk->module = i;
281 clkdev_add(&clk->cl);
282 }
283}
284
285/* bring up all register ranges that we need for basic system control */
286void __init ltq_soc_init(void)
287{
288 struct resource res_pmu, res_cgu, res_ebu;
289 struct device_node *np_pmu =
290 of_find_compatible_node(NULL, NULL, "lantiq,pmu-xway");
291 struct device_node *np_cgu =
292 of_find_compatible_node(NULL, NULL, "lantiq,cgu-xway");
293 struct device_node *np_ebu =
294 of_find_compatible_node(NULL, NULL, "lantiq,ebu-xway");
295
296 /* check if all the core register ranges are available */
297 if (!np_pmu || !np_cgu || !np_ebu)
298 panic("Failed to load core nodess from devicetree");
299
300 if (of_address_to_resource(np_pmu, 0, &res_pmu) ||
301 of_address_to_resource(np_cgu, 0, &res_cgu) ||
302 of_address_to_resource(np_ebu, 0, &res_ebu))
303 panic("Failed to get core resources");
304
305 if ((request_mem_region(res_pmu.start, resource_size(&res_pmu),
306 res_pmu.name) < 0) ||
307 (request_mem_region(res_cgu.start, resource_size(&res_cgu),
308 res_cgu.name) < 0) ||
309 (request_mem_region(res_ebu.start, resource_size(&res_ebu),
310 res_ebu.name) < 0))
311 pr_err("Failed to request core reources");
312
313 pmu_membase = ioremap_nocache(res_pmu.start, resource_size(&res_pmu));
314 ltq_cgu_membase = ioremap_nocache(res_cgu.start,
315 resource_size(&res_cgu));
316 ltq_ebu_membase = ioremap_nocache(res_ebu.start,
317 resource_size(&res_ebu));
318 if (!pmu_membase || !ltq_cgu_membase || !ltq_ebu_membase)
319 panic("Failed to remap core resources");
320
321 /* make sure to unprotect the memory region where flash is located */
322 ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
323
324 /* add our generic xway clocks */
325 clkdev_add_pmu("10000000.fpi", NULL, 0, PMU_FPI);
326 clkdev_add_pmu("1e100400.serial", NULL, 0, PMU_ASC0);
327 clkdev_add_pmu("1e100a00.gptu", NULL, 0, PMU_GPT);
328 clkdev_add_pmu("1e100bb0.stp", NULL, 0, PMU_STP);
329 clkdev_add_pmu("1e104100.dma", NULL, 0, PMU_DMA);
330 clkdev_add_pmu("1e100800.spi", NULL, 0, PMU_SPI);
331 clkdev_add_pmu("1e105300.ebu", NULL, 0, PMU_EBU);
332 clkdev_add_clkout();
333
334 /* add the soc dependent clocks */
335 if (!of_machine_is_compatible("lantiq,vr9"))
336 clkdev_add_pmu("1e180000.etop", NULL, 0, PMU_PPE);
337
338 if (!of_machine_is_compatible("lantiq,ase")) {
339 clkdev_add_pmu("1e100c00.serial", NULL, 0, PMU_ASC1);
340 clkdev_add_pci();
341 }
342
343 if (of_machine_is_compatible("lantiq,ase")) {
344 if (ltq_cgu_r32(CGU_SYS) & (1 << 5))
345 clkdev_add_static(CLOCK_266M, CLOCK_133M, CLOCK_133M);
346 else
347 clkdev_add_static(CLOCK_133M, CLOCK_133M, CLOCK_133M);
348 clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY),
349 clkdev_add_pmu("1e180000.etop", "ephy", 0, PMU_EPHY);
350 } else if (of_machine_is_compatible("lantiq,vr9")) {
351 clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(),
352 ltq_vr9_fpi_hz());
353 clkdev_add_pmu("1d900000.pcie", "phy", 1, PMU1_PCIE_PHY);
354 clkdev_add_pmu("1d900000.pcie", "bus", 0, PMU_PCIE_CLK);
355 clkdev_add_pmu("1d900000.pcie", "msi", 1, PMU1_PCIE_MSI);
356 clkdev_add_pmu("1d900000.pcie", "pdi", 1, PMU1_PCIE_PDI);
357 clkdev_add_pmu("1d900000.pcie", "ctl", 1, PMU1_PCIE_CTL);
358 clkdev_add_pmu("1d900000.pcie", "ahb", 0, PMU_AHBM | PMU_AHBS);
359 } else if (of_machine_is_compatible("lantiq,ar9")) {
360 clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(),
361 ltq_ar9_fpi_hz());
362 clkdev_add_pmu("1e180000.etop", "switch", 0, PMU_SWITCH);
363 } else {
364 clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(),
365 ltq_danube_fpi_hz());
366 }
367}