aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/lantiq/xway
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/lantiq/xway
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/lantiq/xway')
-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
7 files changed, 519 insertions, 392 deletions
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}