diff options
author | 2025-03-08 22:04:20 +0800 | |
---|---|---|
committer | 2025-03-08 22:04:20 +0800 | |
commit | a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch) | |
tree | 84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/lantiq | |
download | ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.tar.gz ohosKernel-a07bb8fd1299070229f0e8f3dcb57ffd5ef9870a.zip |
Initial commit: OpenHarmony-v4.0-ReleaseOpenHarmony-v4.0-Release
Diffstat (limited to 'arch/mips/lantiq')
-rw-r--r-- | arch/mips/lantiq/Kconfig | 55 | ||||
-rw-r--r-- | arch/mips/lantiq/Makefile | 10 | ||||
-rw-r--r-- | arch/mips/lantiq/Platform | 8 | ||||
-rw-r--r-- | arch/mips/lantiq/clk.c | 201 | ||||
-rw-r--r-- | arch/mips/lantiq/clk.h | 94 | ||||
-rw-r--r-- | arch/mips/lantiq/early_printk.c | 31 | ||||
-rw-r--r-- | arch/mips/lantiq/falcon/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/lantiq/falcon/prom.c | 90 | ||||
-rw-r--r-- | arch/mips/lantiq/falcon/reset.c | 75 | ||||
-rw-r--r-- | arch/mips/lantiq/falcon/sysctrl.c | 265 | ||||
-rw-r--r-- | arch/mips/lantiq/irq.c | 433 | ||||
-rw-r--r-- | arch/mips/lantiq/prom.c | 113 | ||||
-rw-r--r-- | arch/mips/lantiq/prom.h | 27 | ||||
-rw-r--r-- | arch/mips/lantiq/xway/Makefile | 4 | ||||
-rw-r--r-- | arch/mips/lantiq/xway/clk.c | 351 | ||||
-rw-r--r-- | arch/mips/lantiq/xway/dcdc.c | 60 | ||||
-rw-r--r-- | arch/mips/lantiq/xway/dma.c | 271 | ||||
-rw-r--r-- | arch/mips/lantiq/xway/gptu.c | 208 | ||||
-rw-r--r-- | arch/mips/lantiq/xway/prom.c | 144 | ||||
-rw-r--r-- | arch/mips/lantiq/xway/sysctrl.c | 588 | ||||
-rw-r--r-- | arch/mips/lantiq/xway/vmmc.c | 64 |
21 files changed, 3094 insertions, 0 deletions
diff --git a/arch/mips/lantiq/Kconfig b/arch/mips/lantiq/Kconfig new file mode 100644 index 000000000..6c6802e48 --- /dev/null +++ b/arch/mips/lantiq/Kconfig | |||
@@ -0,0 +1,55 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | if LANTIQ | ||
3 | |||
4 | config SOC_TYPE_XWAY | ||
5 | bool | ||
6 | select PINCTRL_XWAY | ||
7 | default n | ||
8 | |||
9 | choice | ||
10 | prompt "SoC Type" | ||
11 | default SOC_XWAY | ||
12 | |||
13 | config SOC_AMAZON_SE | ||
14 | bool "Amazon SE" | ||
15 | select SOC_TYPE_XWAY | ||
16 | select MFD_SYSCON | ||
17 | select MFD_CORE | ||
18 | |||
19 | config SOC_XWAY | ||
20 | bool "XWAY" | ||
21 | select SOC_TYPE_XWAY | ||
22 | select HAVE_PCI | ||
23 | select MFD_SYSCON | ||
24 | select MFD_CORE | ||
25 | |||
26 | config SOC_FALCON | ||
27 | bool "FALCON" | ||
28 | select PINCTRL_FALCON | ||
29 | |||
30 | endchoice | ||
31 | |||
32 | choice | ||
33 | prompt "Built-in device tree" | ||
34 | help | ||
35 | Legacy bootloaders do not pass a DTB pointer to the kernel, so | ||
36 | if a "wrapper" is not being used, the kernel will need to include | ||
37 | a device tree that matches the target board. | ||
38 | |||
39 | The builtin DTB will only be used if the firmware does not supply | ||
40 | a valid DTB. | ||
41 | |||
42 | config LANTIQ_DT_NONE | ||
43 | bool "None" | ||
44 | |||
45 | config DT_EASY50712 | ||
46 | bool "Easy50712" | ||
47 | depends on SOC_XWAY | ||
48 | select BUILTIN_DTB | ||
49 | endchoice | ||
50 | |||
51 | config PCI_LANTIQ | ||
52 | bool "PCI Support" | ||
53 | depends on SOC_XWAY && PCI | ||
54 | |||
55 | endif | ||
diff --git a/arch/mips/lantiq/Makefile b/arch/mips/lantiq/Makefile new file mode 100644 index 000000000..e7234ca09 --- /dev/null +++ b/arch/mips/lantiq/Makefile | |||
@@ -0,0 +1,10 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | # Copyright (C) 2010 John Crispin <john@phrozen.org> | ||
3 | # | ||
4 | |||
5 | obj-y := irq.o clk.o prom.o | ||
6 | |||
7 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | ||
8 | |||
9 | obj-$(CONFIG_SOC_TYPE_XWAY) += xway/ | ||
10 | obj-$(CONFIG_SOC_FALCON) += falcon/ | ||
diff --git a/arch/mips/lantiq/Platform b/arch/mips/lantiq/Platform new file mode 100644 index 000000000..0bc9c0fbd --- /dev/null +++ b/arch/mips/lantiq/Platform | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Lantiq | ||
3 | # | ||
4 | |||
5 | cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq | ||
6 | load-$(CONFIG_LANTIQ) = 0xffffffff80002000 | ||
7 | cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway | ||
8 | cflags-$(CONFIG_SOC_FALCON) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/falcon | ||
diff --git a/arch/mips/lantiq/clk.c b/arch/mips/lantiq/clk.c new file mode 100644 index 000000000..2d5a0bcb0 --- /dev/null +++ b/arch/mips/lantiq/clk.c | |||
@@ -0,0 +1,201 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> | ||
5 | * Copyright (C) 2010 John Crispin <john@phrozen.org> | ||
6 | */ | ||
7 | #include <linux/io.h> | ||
8 | #include <linux/export.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/clk.h> | ||
13 | #include <linux/clkdev.h> | ||
14 | #include <linux/err.h> | ||
15 | #include <linux/list.h> | ||
16 | |||
17 | #include <asm/time.h> | ||
18 | #include <asm/irq.h> | ||
19 | #include <asm/div64.h> | ||
20 | |||
21 | #include <lantiq_soc.h> | ||
22 | |||
23 | #include "clk.h" | ||
24 | #include "prom.h" | ||
25 | |||
26 | /* lantiq socs have 3 static clocks */ | ||
27 | static struct clk cpu_clk_generic[4]; | ||
28 | |||
29 | void clkdev_add_static(unsigned long cpu, unsigned long fpi, | ||
30 | unsigned long io, unsigned long ppe) | ||
31 | { | ||
32 | cpu_clk_generic[0].rate = cpu; | ||
33 | cpu_clk_generic[1].rate = fpi; | ||
34 | cpu_clk_generic[2].rate = io; | ||
35 | cpu_clk_generic[3].rate = ppe; | ||
36 | } | ||
37 | |||
38 | struct clk *clk_get_cpu(void) | ||
39 | { | ||
40 | return &cpu_clk_generic[0]; | ||
41 | } | ||
42 | |||
43 | struct clk *clk_get_fpi(void) | ||
44 | { | ||
45 | return &cpu_clk_generic[1]; | ||
46 | } | ||
47 | EXPORT_SYMBOL_GPL(clk_get_fpi); | ||
48 | |||
49 | struct clk *clk_get_io(void) | ||
50 | { | ||
51 | return &cpu_clk_generic[2]; | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(clk_get_io); | ||
54 | |||
55 | struct clk *clk_get_ppe(void) | ||
56 | { | ||
57 | return &cpu_clk_generic[3]; | ||
58 | } | ||
59 | EXPORT_SYMBOL_GPL(clk_get_ppe); | ||
60 | |||
61 | static inline int clk_good(struct clk *clk) | ||
62 | { | ||
63 | return clk && !IS_ERR(clk); | ||
64 | } | ||
65 | |||
66 | unsigned long clk_get_rate(struct clk *clk) | ||
67 | { | ||
68 | if (unlikely(!clk_good(clk))) | ||
69 | return 0; | ||
70 | |||
71 | if (clk->rate != 0) | ||
72 | return clk->rate; | ||
73 | |||
74 | if (clk->get_rate != NULL) | ||
75 | return clk->get_rate(); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | EXPORT_SYMBOL(clk_get_rate); | ||
80 | |||
81 | int clk_set_rate(struct clk *clk, unsigned long rate) | ||
82 | { | ||
83 | if (unlikely(!clk_good(clk))) | ||
84 | return 0; | ||
85 | if (clk->rates && *clk->rates) { | ||
86 | unsigned long *r = clk->rates; | ||
87 | |||
88 | while (*r && (*r != rate)) | ||
89 | r++; | ||
90 | if (!*r) { | ||
91 | pr_err("clk %s.%s: trying to set invalid rate %ld\n", | ||
92 | clk->cl.dev_id, clk->cl.con_id, rate); | ||
93 | return -1; | ||
94 | } | ||
95 | } | ||
96 | clk->rate = rate; | ||
97 | return 0; | ||
98 | } | ||
99 | EXPORT_SYMBOL(clk_set_rate); | ||
100 | |||
101 | long clk_round_rate(struct clk *clk, unsigned long rate) | ||
102 | { | ||
103 | if (unlikely(!clk_good(clk))) | ||
104 | return 0; | ||
105 | if (clk->rates && *clk->rates) { | ||
106 | unsigned long *r = clk->rates; | ||
107 | |||
108 | while (*r && (*r != rate)) | ||
109 | r++; | ||
110 | if (!*r) { | ||
111 | return clk->rate; | ||
112 | } | ||
113 | } | ||
114 | return rate; | ||
115 | } | ||
116 | EXPORT_SYMBOL(clk_round_rate); | ||
117 | |||
118 | int clk_enable(struct clk *clk) | ||
119 | { | ||
120 | if (unlikely(!clk_good(clk))) | ||
121 | return -1; | ||
122 | |||
123 | if (clk->enable) | ||
124 | return clk->enable(clk); | ||
125 | |||
126 | return -1; | ||
127 | } | ||
128 | EXPORT_SYMBOL(clk_enable); | ||
129 | |||
130 | void clk_disable(struct clk *clk) | ||
131 | { | ||
132 | if (unlikely(!clk_good(clk))) | ||
133 | return; | ||
134 | |||
135 | if (clk->disable) | ||
136 | clk->disable(clk); | ||
137 | } | ||
138 | EXPORT_SYMBOL(clk_disable); | ||
139 | |||
140 | int clk_activate(struct clk *clk) | ||
141 | { | ||
142 | if (unlikely(!clk_good(clk))) | ||
143 | return -1; | ||
144 | |||
145 | if (clk->activate) | ||
146 | return clk->activate(clk); | ||
147 | |||
148 | return -1; | ||
149 | } | ||
150 | EXPORT_SYMBOL(clk_activate); | ||
151 | |||
152 | void clk_deactivate(struct clk *clk) | ||
153 | { | ||
154 | if (unlikely(!clk_good(clk))) | ||
155 | return; | ||
156 | |||
157 | if (clk->deactivate) | ||
158 | clk->deactivate(clk); | ||
159 | } | ||
160 | EXPORT_SYMBOL(clk_deactivate); | ||
161 | |||
162 | struct clk *clk_get_parent(struct clk *clk) | ||
163 | { | ||
164 | return NULL; | ||
165 | } | ||
166 | EXPORT_SYMBOL(clk_get_parent); | ||
167 | |||
168 | int clk_set_parent(struct clk *clk, struct clk *parent) | ||
169 | { | ||
170 | return 0; | ||
171 | } | ||
172 | EXPORT_SYMBOL(clk_set_parent); | ||
173 | |||
174 | static inline u32 get_counter_resolution(void) | ||
175 | { | ||
176 | u32 res; | ||
177 | |||
178 | __asm__ __volatile__( | ||
179 | ".set push\n" | ||
180 | ".set mips32r2\n" | ||
181 | "rdhwr %0, $3\n" | ||
182 | ".set pop\n" | ||
183 | : "=&r" (res) | ||
184 | : /* no input */ | ||
185 | : "memory"); | ||
186 | |||
187 | return res; | ||
188 | } | ||
189 | |||
190 | void __init plat_time_init(void) | ||
191 | { | ||
192 | struct clk *clk; | ||
193 | |||
194 | ltq_soc_init(); | ||
195 | |||
196 | clk = clk_get_cpu(); | ||
197 | mips_hpt_frequency = clk_get_rate(clk) / get_counter_resolution(); | ||
198 | write_c0_compare(read_c0_count()); | ||
199 | pr_info("CPU Clock: %ldMHz\n", clk_get_rate(clk) / 1000000); | ||
200 | clk_put(clk); | ||
201 | } | ||
diff --git a/arch/mips/lantiq/clk.h b/arch/mips/lantiq/clk.h new file mode 100644 index 000000000..f135e3035 --- /dev/null +++ b/arch/mips/lantiq/clk.h | |||
@@ -0,0 +1,94 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0-only */ | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2010 John Crispin <john@phrozen.org> | ||
5 | */ | ||
6 | |||
7 | #ifndef _LTQ_CLK_H__ | ||
8 | #define _LTQ_CLK_H__ | ||
9 | |||
10 | #include <linux/clkdev.h> | ||
11 | |||
12 | /* clock speeds */ | ||
13 | #define CLOCK_33M 33333333 | ||
14 | #define CLOCK_60M 60000000 | ||
15 | #define CLOCK_62_5M 62500000 | ||
16 | #define CLOCK_83M 83333333 | ||
17 | #define CLOCK_83_5M 83500000 | ||
18 | #define CLOCK_98_304M 98304000 | ||
19 | #define CLOCK_100M 100000000 | ||
20 | #define CLOCK_111M 111111111 | ||
21 | #define CLOCK_125M 125000000 | ||
22 | #define CLOCK_133M 133333333 | ||
23 | #define CLOCK_150M 150000000 | ||
24 | #define CLOCK_166M 166666666 | ||
25 | #define CLOCK_167M 166666667 | ||
26 | #define CLOCK_196_608M 196608000 | ||
27 | #define CLOCK_200M 200000000 | ||
28 | #define CLOCK_222M 222000000 | ||
29 | #define CLOCK_240M 240000000 | ||
30 | #define CLOCK_250M 250000000 | ||
31 | #define CLOCK_266M 266666666 | ||
32 | #define CLOCK_288M 288888888 | ||
33 | #define CLOCK_300M 300000000 | ||
34 | #define CLOCK_333M 333333333 | ||
35 | #define CLOCK_360M 360000000 | ||
36 | #define CLOCK_393M 393215332 | ||
37 | #define CLOCK_400M 400000000 | ||
38 | #define CLOCK_432M 432000000 | ||
39 | #define CLOCK_450M 450000000 | ||
40 | #define CLOCK_500M 500000000 | ||
41 | #define CLOCK_600M 600000000 | ||
42 | #define CLOCK_666M 666666666 | ||
43 | #define CLOCK_720M 720000000 | ||
44 | |||
45 | /* clock out speeds */ | ||
46 | #define CLOCK_32_768K 32768 | ||
47 | #define CLOCK_1_536M 1536000 | ||
48 | #define CLOCK_2_5M 2500000 | ||
49 | #define CLOCK_12M 12000000 | ||
50 | #define CLOCK_24M 24000000 | ||
51 | #define CLOCK_25M 25000000 | ||
52 | #define CLOCK_30M 30000000 | ||
53 | #define CLOCK_40M 40000000 | ||
54 | #define CLOCK_48M 48000000 | ||
55 | #define CLOCK_50M 50000000 | ||
56 | #define CLOCK_60M 60000000 | ||
57 | |||
58 | struct clk { | ||
59 | struct clk_lookup cl; | ||
60 | unsigned long rate; | ||
61 | unsigned long *rates; | ||
62 | unsigned int module; | ||
63 | unsigned int bits; | ||
64 | unsigned long (*get_rate) (void); | ||
65 | int (*enable) (struct clk *clk); | ||
66 | void (*disable) (struct clk *clk); | ||
67 | int (*activate) (struct clk *clk); | ||
68 | void (*deactivate) (struct clk *clk); | ||
69 | void (*reboot) (struct clk *clk); | ||
70 | }; | ||
71 | |||
72 | extern void clkdev_add_static(unsigned long cpu, unsigned long fpi, | ||
73 | unsigned long io, unsigned long ppe); | ||
74 | |||
75 | extern unsigned long ltq_danube_cpu_hz(void); | ||
76 | extern unsigned long ltq_danube_fpi_hz(void); | ||
77 | extern unsigned long ltq_danube_pp32_hz(void); | ||
78 | |||
79 | extern unsigned long ltq_ar9_cpu_hz(void); | ||
80 | extern unsigned long ltq_ar9_fpi_hz(void); | ||
81 | |||
82 | extern unsigned long ltq_vr9_cpu_hz(void); | ||
83 | extern unsigned long ltq_vr9_fpi_hz(void); | ||
84 | extern unsigned long ltq_vr9_pp32_hz(void); | ||
85 | |||
86 | extern unsigned long ltq_ar10_cpu_hz(void); | ||
87 | extern unsigned long ltq_ar10_fpi_hz(void); | ||
88 | extern unsigned long ltq_ar10_pp32_hz(void); | ||
89 | |||
90 | extern unsigned long ltq_grx390_cpu_hz(void); | ||
91 | extern unsigned long ltq_grx390_fpi_hz(void); | ||
92 | extern unsigned long ltq_grx390_pp32_hz(void); | ||
93 | |||
94 | #endif | ||
diff --git a/arch/mips/lantiq/early_printk.c b/arch/mips/lantiq/early_printk.c new file mode 100644 index 000000000..4e4a28be1 --- /dev/null +++ b/arch/mips/lantiq/early_printk.c | |||
@@ -0,0 +1,31 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2010 John Crispin <john@phrozen.org> | ||
5 | */ | ||
6 | |||
7 | #include <linux/cpu.h> | ||
8 | #include <lantiq_soc.h> | ||
9 | #include <asm/setup.h> | ||
10 | |||
11 | #define ASC_BUF 1024 | ||
12 | #define LTQ_ASC_FSTAT ((u32 *)(LTQ_EARLY_ASC + 0x0048)) | ||
13 | #ifdef __BIG_ENDIAN | ||
14 | #define LTQ_ASC_TBUF ((u32 *)(LTQ_EARLY_ASC + 0x0020 + 3)) | ||
15 | #else | ||
16 | #define LTQ_ASC_TBUF ((u32 *)(LTQ_EARLY_ASC + 0x0020)) | ||
17 | #endif | ||
18 | #define TXMASK 0x3F00 | ||
19 | #define TXOFFSET 8 | ||
20 | |||
21 | void prom_putchar(char c) | ||
22 | { | ||
23 | unsigned long flags; | ||
24 | |||
25 | local_irq_save(flags); | ||
26 | do { } while ((ltq_r32(LTQ_ASC_FSTAT) & TXMASK) >> TXOFFSET); | ||
27 | if (c == '\n') | ||
28 | ltq_w8('\r', LTQ_ASC_TBUF); | ||
29 | ltq_w8(c, LTQ_ASC_TBUF); | ||
30 | local_irq_restore(flags); | ||
31 | } | ||
diff --git a/arch/mips/lantiq/falcon/Makefile b/arch/mips/lantiq/falcon/Makefile new file mode 100644 index 000000000..98da1e031 --- /dev/null +++ b/arch/mips/lantiq/falcon/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | obj-y := prom.o reset.o sysctrl.o | ||
diff --git a/arch/mips/lantiq/falcon/prom.c b/arch/mips/lantiq/falcon/prom.c new file mode 100644 index 000000000..7b98def10 --- /dev/null +++ b/arch/mips/lantiq/falcon/prom.c | |||
@@ -0,0 +1,90 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com> | ||
5 | * Copyright (C) 2012 John Crispin <john@phrozen.org> | ||
6 | */ | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | #include <asm/cacheflush.h> | ||
10 | #include <asm/traps.h> | ||
11 | #include <asm/io.h> | ||
12 | |||
13 | #include <lantiq_soc.h> | ||
14 | |||
15 | #include "../prom.h" | ||
16 | |||
17 | #define SOC_FALCON "Falcon" | ||
18 | #define SOC_FALCON_D "Falcon-D" | ||
19 | #define SOC_FALCON_V "Falcon-V" | ||
20 | #define SOC_FALCON_M "Falcon-M" | ||
21 | |||
22 | #define COMP_FALCON "lantiq,falcon" | ||
23 | |||
24 | #define PART_SHIFT 12 | ||
25 | #define PART_MASK 0x0FFFF000 | ||
26 | #define REV_SHIFT 28 | ||
27 | #define REV_MASK 0xF0000000 | ||
28 | #define SREV_SHIFT 22 | ||
29 | #define SREV_MASK 0x03C00000 | ||
30 | #define TYPE_SHIFT 26 | ||
31 | #define TYPE_MASK 0x3C000000 | ||
32 | |||
33 | /* reset, nmi and ejtag exception vectors */ | ||
34 | #define BOOT_REG_BASE (KSEG1 | 0x1F200000) | ||
35 | #define BOOT_RVEC (BOOT_REG_BASE | 0x00) | ||
36 | #define BOOT_NVEC (BOOT_REG_BASE | 0x04) | ||
37 | #define BOOT_EVEC (BOOT_REG_BASE | 0x08) | ||
38 | |||
39 | void __init ltq_soc_nmi_setup(void) | ||
40 | { | ||
41 | extern void (*nmi_handler)(void); | ||
42 | |||
43 | ltq_w32((unsigned long)&nmi_handler, (void *)BOOT_NVEC); | ||
44 | } | ||
45 | |||
46 | void __init ltq_soc_ejtag_setup(void) | ||
47 | { | ||
48 | extern void (*ejtag_debug_handler)(void); | ||
49 | |||
50 | ltq_w32((unsigned long)&ejtag_debug_handler, (void *)BOOT_EVEC); | ||
51 | } | ||
52 | |||
53 | void __init ltq_soc_detect(struct ltq_soc_info *i) | ||
54 | { | ||
55 | u32 type; | ||
56 | i->partnum = (ltq_r32(FALCON_CHIPID) & PART_MASK) >> PART_SHIFT; | ||
57 | i->rev = (ltq_r32(FALCON_CHIPID) & REV_MASK) >> REV_SHIFT; | ||
58 | i->srev = ((ltq_r32(FALCON_CHIPCONF) & SREV_MASK) >> SREV_SHIFT); | ||
59 | i->compatible = COMP_FALCON; | ||
60 | i->type = SOC_TYPE_FALCON; | ||
61 | sprintf(i->rev_type, "%c%d%d", (i->srev & 0x4) ? ('B') : ('A'), | ||
62 | i->rev & 0x7, (i->srev & 0x3) + 1); | ||
63 | |||
64 | switch (i->partnum) { | ||
65 | case SOC_ID_FALCON: | ||
66 | type = (ltq_r32(FALCON_CHIPTYPE) & TYPE_MASK) >> TYPE_SHIFT; | ||
67 | switch (type) { | ||
68 | case 0: | ||
69 | i->name = SOC_FALCON_D; | ||
70 | break; | ||
71 | case 1: | ||
72 | i->name = SOC_FALCON_V; | ||
73 | break; | ||
74 | case 2: | ||
75 | i->name = SOC_FALCON_M; | ||
76 | break; | ||
77 | default: | ||
78 | i->name = SOC_FALCON; | ||
79 | break; | ||
80 | } | ||
81 | break; | ||
82 | |||
83 | default: | ||
84 | unreachable(); | ||
85 | break; | ||
86 | } | ||
87 | |||
88 | board_nmi_handler_setup = ltq_soc_nmi_setup; | ||
89 | board_ejtag_handler_setup = ltq_soc_ejtag_setup; | ||
90 | } | ||
diff --git a/arch/mips/lantiq/falcon/reset.c b/arch/mips/lantiq/falcon/reset.c new file mode 100644 index 000000000..261996c23 --- /dev/null +++ b/arch/mips/lantiq/falcon/reset.c | |||
@@ -0,0 +1,75 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com> | ||
5 | * Copyright (C) 2012 John Crispin <john@phrozen.org> | ||
6 | */ | ||
7 | |||
8 | #include <linux/init.h> | ||
9 | #include <linux/io.h> | ||
10 | #include <linux/pm.h> | ||
11 | #include <asm/reboot.h> | ||
12 | #include <linux/export.h> | ||
13 | |||
14 | #include <lantiq_soc.h> | ||
15 | |||
16 | /* | ||
17 | * Dummy implementation. Used to allow platform code to find out what | ||
18 | * source was booted from | ||
19 | */ | ||
20 | unsigned char ltq_boot_select(void) | ||
21 | { | ||
22 | return BS_SPI; | ||
23 | } | ||
24 | |||
25 | #define BOOT_REG_BASE (KSEG1 | 0x1F200000) | ||
26 | #define BOOT_PW1_REG (BOOT_REG_BASE | 0x20) | ||
27 | #define BOOT_PW2_REG (BOOT_REG_BASE | 0x24) | ||
28 | #define BOOT_PW1 0x4C545100 | ||
29 | #define BOOT_PW2 0x0051544C | ||
30 | |||
31 | #define WDT_REG_BASE (KSEG1 | 0x1F8803F0) | ||
32 | #define WDT_PW1 0x00BE0000 | ||
33 | #define WDT_PW2 0x00DC0000 | ||
34 | |||
35 | static void machine_restart(char *command) | ||
36 | { | ||
37 | local_irq_disable(); | ||
38 | |||
39 | /* reboot magic */ | ||
40 | ltq_w32(BOOT_PW1, (void *)BOOT_PW1_REG); /* 'LTQ\0' */ | ||
41 | ltq_w32(BOOT_PW2, (void *)BOOT_PW2_REG); /* '\0QTL' */ | ||
42 | ltq_w32(0, (void *)BOOT_REG_BASE); /* reset Bootreg RVEC */ | ||
43 | |||
44 | /* watchdog magic */ | ||
45 | ltq_w32(WDT_PW1, (void *)WDT_REG_BASE); | ||
46 | ltq_w32(WDT_PW2 | | ||
47 | (0x3 << 26) | /* PWL */ | ||
48 | (0x2 << 24) | /* CLKDIV */ | ||
49 | (0x1 << 31) | /* enable */ | ||
50 | (1), /* reload */ | ||
51 | (void *)WDT_REG_BASE); | ||
52 | unreachable(); | ||
53 | } | ||
54 | |||
55 | static void machine_halt(void) | ||
56 | { | ||
57 | local_irq_disable(); | ||
58 | unreachable(); | ||
59 | } | ||
60 | |||
61 | static void machine_power_off(void) | ||
62 | { | ||
63 | local_irq_disable(); | ||
64 | unreachable(); | ||
65 | } | ||
66 | |||
67 | static int __init mips_reboot_setup(void) | ||
68 | { | ||
69 | _machine_restart = machine_restart; | ||
70 | _machine_halt = machine_halt; | ||
71 | pm_power_off = machine_power_off; | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | arch_initcall(mips_reboot_setup); | ||
diff --git a/arch/mips/lantiq/falcon/sysctrl.c b/arch/mips/lantiq/falcon/sysctrl.c new file mode 100644 index 000000000..446a25369 --- /dev/null +++ b/arch/mips/lantiq/falcon/sysctrl.c | |||
@@ -0,0 +1,265 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2011 Thomas Langer <thomas.langer@lantiq.com> | ||
5 | * Copyright (C) 2011 John Crispin <john@phrozen.org> | ||
6 | */ | ||
7 | |||
8 | #include <linux/ioport.h> | ||
9 | #include <linux/export.h> | ||
10 | #include <linux/clkdev.h> | ||
11 | #include <linux/of_address.h> | ||
12 | #include <asm/delay.h> | ||
13 | |||
14 | #include <lantiq_soc.h> | ||
15 | |||
16 | #include "../clk.h" | ||
17 | |||
18 | /* infrastructure control register */ | ||
19 | #define SYS1_INFRAC 0x00bc | ||
20 | /* Configuration fuses for drivers and pll */ | ||
21 | #define STATUS_CONFIG 0x0040 | ||
22 | |||
23 | /* GPE frequency selection */ | ||
24 | #define GPPC_OFFSET 24 | ||
25 | #define GPEFREQ_MASK 0x0000C00 | ||
26 | #define GPEFREQ_OFFSET 10 | ||
27 | /* Clock status register */ | ||
28 | #define SYSCTL_CLKS 0x0000 | ||
29 | /* Clock enable register */ | ||
30 | #define SYSCTL_CLKEN 0x0004 | ||
31 | /* Clock clear register */ | ||
32 | #define SYSCTL_CLKCLR 0x0008 | ||
33 | /* Activation Status Register */ | ||
34 | #define SYSCTL_ACTS 0x0020 | ||
35 | /* Activation Register */ | ||
36 | #define SYSCTL_ACT 0x0024 | ||
37 | /* Deactivation Register */ | ||
38 | #define SYSCTL_DEACT 0x0028 | ||
39 | /* reboot Register */ | ||
40 | #define SYSCTL_RBT 0x002c | ||
41 | /* CPU0 Clock Control Register */ | ||
42 | #define SYS1_CPU0CC 0x0040 | ||
43 | /* HRST_OUT_N Control Register */ | ||
44 | #define SYS1_HRSTOUTC 0x00c0 | ||
45 | /* clock divider bit */ | ||
46 | #define CPU0CC_CPUDIV 0x0001 | ||
47 | |||
48 | /* Activation Status Register */ | ||
49 | #define ACTS_ASC0_ACT 0x00001000 | ||
50 | #define ACTS_SSC0 0x00002000 | ||
51 | #define ACTS_ASC1_ACT 0x00000800 | ||
52 | #define ACTS_I2C_ACT 0x00004000 | ||
53 | #define ACTS_P0 0x00010000 | ||
54 | #define ACTS_P1 0x00010000 | ||
55 | #define ACTS_P2 0x00020000 | ||
56 | #define ACTS_P3 0x00020000 | ||
57 | #define ACTS_P4 0x00040000 | ||
58 | #define ACTS_PADCTRL0 0x00100000 | ||
59 | #define ACTS_PADCTRL1 0x00100000 | ||
60 | #define ACTS_PADCTRL2 0x00200000 | ||
61 | #define ACTS_PADCTRL3 0x00200000 | ||
62 | #define ACTS_PADCTRL4 0x00400000 | ||
63 | |||
64 | #define sysctl_w32(m, x, y) ltq_w32((x), sysctl_membase[m] + (y)) | ||
65 | #define sysctl_r32(m, x) ltq_r32(sysctl_membase[m] + (x)) | ||
66 | #define sysctl_w32_mask(m, clear, set, reg) \ | ||
67 | sysctl_w32(m, (sysctl_r32(m, reg) & ~(clear)) | (set), reg) | ||
68 | |||
69 | #define status_w32(x, y) ltq_w32((x), status_membase + (y)) | ||
70 | #define status_r32(x) ltq_r32(status_membase + (x)) | ||
71 | |||
72 | static void __iomem *sysctl_membase[3], *status_membase; | ||
73 | void __iomem *ltq_sys1_membase, *ltq_ebu_membase; | ||
74 | |||
75 | void falcon_trigger_hrst(int level) | ||
76 | { | ||
77 | sysctl_w32(SYSCTL_SYS1, level & 1, SYS1_HRSTOUTC); | ||
78 | } | ||
79 | |||
80 | static inline void sysctl_wait(struct clk *clk, | ||
81 | unsigned int test, unsigned int reg) | ||
82 | { | ||
83 | int err = 1000000; | ||
84 | |||
85 | do {} while (--err && ((sysctl_r32(clk->module, reg) | ||
86 | & clk->bits) != test)); | ||
87 | if (!err) | ||
88 | pr_err("module de/activation failed %d %08X %08X %08X\n", | ||
89 | clk->module, clk->bits, test, | ||
90 | sysctl_r32(clk->module, reg) & clk->bits); | ||
91 | } | ||
92 | |||
93 | static int sysctl_activate(struct clk *clk) | ||
94 | { | ||
95 | sysctl_w32(clk->module, clk->bits, SYSCTL_CLKEN); | ||
96 | sysctl_w32(clk->module, clk->bits, SYSCTL_ACT); | ||
97 | sysctl_wait(clk, clk->bits, SYSCTL_ACTS); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static void sysctl_deactivate(struct clk *clk) | ||
102 | { | ||
103 | sysctl_w32(clk->module, clk->bits, SYSCTL_CLKCLR); | ||
104 | sysctl_w32(clk->module, clk->bits, SYSCTL_DEACT); | ||
105 | sysctl_wait(clk, 0, SYSCTL_ACTS); | ||
106 | } | ||
107 | |||
108 | static int sysctl_clken(struct clk *clk) | ||
109 | { | ||
110 | sysctl_w32(clk->module, clk->bits, SYSCTL_CLKEN); | ||
111 | sysctl_w32(clk->module, clk->bits, SYSCTL_ACT); | ||
112 | sysctl_wait(clk, clk->bits, SYSCTL_CLKS); | ||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static void sysctl_clkdis(struct clk *clk) | ||
117 | { | ||
118 | sysctl_w32(clk->module, clk->bits, SYSCTL_CLKCLR); | ||
119 | sysctl_wait(clk, 0, SYSCTL_CLKS); | ||
120 | } | ||
121 | |||
122 | static void sysctl_reboot(struct clk *clk) | ||
123 | { | ||
124 | unsigned int act; | ||
125 | unsigned int bits; | ||
126 | |||
127 | act = sysctl_r32(clk->module, SYSCTL_ACT); | ||
128 | bits = ~act & clk->bits; | ||
129 | if (bits != 0) { | ||
130 | sysctl_w32(clk->module, bits, SYSCTL_CLKEN); | ||
131 | sysctl_w32(clk->module, bits, SYSCTL_ACT); | ||
132 | sysctl_wait(clk, bits, SYSCTL_ACTS); | ||
133 | } | ||
134 | sysctl_w32(clk->module, act & clk->bits, SYSCTL_RBT); | ||
135 | sysctl_wait(clk, clk->bits, SYSCTL_ACTS); | ||
136 | } | ||
137 | |||
138 | /* enable the ONU core */ | ||
139 | static void falcon_gpe_enable(void) | ||
140 | { | ||
141 | unsigned int freq; | ||
142 | unsigned int status; | ||
143 | |||
144 | /* if if the clock is already enabled */ | ||
145 | status = sysctl_r32(SYSCTL_SYS1, SYS1_INFRAC); | ||
146 | if (status & (1 << (GPPC_OFFSET + 1))) | ||
147 | return; | ||
148 | |||
149 | freq = (status_r32(STATUS_CONFIG) & | ||
150 | GPEFREQ_MASK) >> | ||
151 | GPEFREQ_OFFSET; | ||
152 | if (freq == 0) | ||
153 | freq = 1; /* use 625MHz on unfused chip */ | ||
154 | |||
155 | /* apply new frequency */ | ||
156 | sysctl_w32_mask(SYSCTL_SYS1, 7 << (GPPC_OFFSET + 1), | ||
157 | freq << (GPPC_OFFSET + 2) , SYS1_INFRAC); | ||
158 | udelay(1); | ||
159 | |||
160 | /* enable new frequency */ | ||
161 | sysctl_w32_mask(SYSCTL_SYS1, 0, 1 << (GPPC_OFFSET + 1), SYS1_INFRAC); | ||
162 | udelay(1); | ||
163 | } | ||
164 | |||
165 | static inline void clkdev_add_sys(const char *dev, unsigned int module, | ||
166 | unsigned int bits) | ||
167 | { | ||
168 | struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | ||
169 | |||
170 | if (!clk) | ||
171 | return; | ||
172 | clk->cl.dev_id = dev; | ||
173 | clk->cl.con_id = NULL; | ||
174 | clk->cl.clk = clk; | ||
175 | clk->module = module; | ||
176 | clk->bits = bits; | ||
177 | clk->activate = sysctl_activate; | ||
178 | clk->deactivate = sysctl_deactivate; | ||
179 | clk->enable = sysctl_clken; | ||
180 | clk->disable = sysctl_clkdis; | ||
181 | clk->reboot = sysctl_reboot; | ||
182 | clkdev_add(&clk->cl); | ||
183 | } | ||
184 | |||
185 | void __init ltq_soc_init(void) | ||
186 | { | ||
187 | struct device_node *np_status = | ||
188 | of_find_compatible_node(NULL, NULL, "lantiq,status-falcon"); | ||
189 | struct device_node *np_ebu = | ||
190 | of_find_compatible_node(NULL, NULL, "lantiq,ebu-falcon"); | ||
191 | struct device_node *np_sys1 = | ||
192 | of_find_compatible_node(NULL, NULL, "lantiq,sys1-falcon"); | ||
193 | struct device_node *np_syseth = | ||
194 | of_find_compatible_node(NULL, NULL, "lantiq,syseth-falcon"); | ||
195 | struct device_node *np_sysgpe = | ||
196 | of_find_compatible_node(NULL, NULL, "lantiq,sysgpe-falcon"); | ||
197 | struct resource res_status, res_ebu, res_sys[3]; | ||
198 | int i; | ||
199 | |||
200 | /* check if all the core register ranges are available */ | ||
201 | if (!np_status || !np_ebu || !np_sys1 || !np_syseth || !np_sysgpe) | ||
202 | panic("Failed to load core nodes from devicetree"); | ||
203 | |||
204 | if (of_address_to_resource(np_status, 0, &res_status) || | ||
205 | of_address_to_resource(np_ebu, 0, &res_ebu) || | ||
206 | of_address_to_resource(np_sys1, 0, &res_sys[0]) || | ||
207 | of_address_to_resource(np_syseth, 0, &res_sys[1]) || | ||
208 | of_address_to_resource(np_sysgpe, 0, &res_sys[2])) | ||
209 | panic("Failed to get core resources"); | ||
210 | |||
211 | if ((request_mem_region(res_status.start, resource_size(&res_status), | ||
212 | res_status.name) < 0) || | ||
213 | (request_mem_region(res_ebu.start, resource_size(&res_ebu), | ||
214 | res_ebu.name) < 0) || | ||
215 | (request_mem_region(res_sys[0].start, | ||
216 | resource_size(&res_sys[0]), | ||
217 | res_sys[0].name) < 0) || | ||
218 | (request_mem_region(res_sys[1].start, | ||
219 | resource_size(&res_sys[1]), | ||
220 | res_sys[1].name) < 0) || | ||
221 | (request_mem_region(res_sys[2].start, | ||
222 | resource_size(&res_sys[2]), | ||
223 | res_sys[2].name) < 0)) | ||
224 | pr_err("Failed to request core resources"); | ||
225 | |||
226 | status_membase = ioremap(res_status.start, | ||
227 | resource_size(&res_status)); | ||
228 | ltq_ebu_membase = ioremap(res_ebu.start, | ||
229 | resource_size(&res_ebu)); | ||
230 | |||
231 | if (!status_membase || !ltq_ebu_membase) | ||
232 | panic("Failed to remap core resources"); | ||
233 | |||
234 | for (i = 0; i < 3; i++) { | ||
235 | sysctl_membase[i] = ioremap(res_sys[i].start, | ||
236 | resource_size(&res_sys[i])); | ||
237 | if (!sysctl_membase[i]) | ||
238 | panic("Failed to remap sysctrl resources"); | ||
239 | } | ||
240 | ltq_sys1_membase = sysctl_membase[0]; | ||
241 | |||
242 | falcon_gpe_enable(); | ||
243 | |||
244 | /* get our 3 static rates for cpu, fpi and io clocks */ | ||
245 | if (ltq_sys1_r32(SYS1_CPU0CC) & CPU0CC_CPUDIV) | ||
246 | clkdev_add_static(CLOCK_200M, CLOCK_100M, CLOCK_200M, 0); | ||
247 | else | ||
248 | clkdev_add_static(CLOCK_400M, CLOCK_100M, CLOCK_200M, 0); | ||
249 | |||
250 | /* add our clock domains */ | ||
251 | clkdev_add_sys("1d810000.gpio", SYSCTL_SYSETH, ACTS_P0); | ||
252 | clkdev_add_sys("1d810100.gpio", SYSCTL_SYSETH, ACTS_P2); | ||
253 | clkdev_add_sys("1e800100.gpio", SYSCTL_SYS1, ACTS_P1); | ||
254 | clkdev_add_sys("1e800200.gpio", SYSCTL_SYS1, ACTS_P3); | ||
255 | clkdev_add_sys("1e800300.gpio", SYSCTL_SYS1, ACTS_P4); | ||
256 | clkdev_add_sys("1db01000.pad", SYSCTL_SYSETH, ACTS_PADCTRL0); | ||
257 | clkdev_add_sys("1db02000.pad", SYSCTL_SYSETH, ACTS_PADCTRL2); | ||
258 | clkdev_add_sys("1e800400.pad", SYSCTL_SYS1, ACTS_PADCTRL1); | ||
259 | clkdev_add_sys("1e800500.pad", SYSCTL_SYS1, ACTS_PADCTRL3); | ||
260 | clkdev_add_sys("1e800600.pad", SYSCTL_SYS1, ACTS_PADCTRL4); | ||
261 | clkdev_add_sys("1e100b00.serial", SYSCTL_SYS1, ACTS_ASC1_ACT); | ||
262 | clkdev_add_sys("1e100c00.serial", SYSCTL_SYS1, ACTS_ASC0_ACT); | ||
263 | clkdev_add_sys("1e100d00.spi", SYSCTL_SYS1, ACTS_SSC0); | ||
264 | clkdev_add_sys("1e200000.i2c", SYSCTL_SYS1, ACTS_I2C_ACT); | ||
265 | } | ||
diff --git a/arch/mips/lantiq/irq.c b/arch/mips/lantiq/irq.c new file mode 100644 index 000000000..43c2f271e --- /dev/null +++ b/arch/mips/lantiq/irq.c | |||
@@ -0,0 +1,433 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2010 John Crispin <john@phrozen.org> | ||
5 | * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/interrupt.h> | ||
9 | #include <linux/ioport.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/irqdomain.h> | ||
12 | #include <linux/of_platform.h> | ||
13 | #include <linux/of_address.h> | ||
14 | #include <linux/of_irq.h> | ||
15 | |||
16 | #include <asm/bootinfo.h> | ||
17 | #include <asm/irq_cpu.h> | ||
18 | |||
19 | #include <lantiq_soc.h> | ||
20 | #include <irq.h> | ||
21 | |||
22 | /* register definitions - internal irqs */ | ||
23 | #define LTQ_ICU_ISR 0x0000 | ||
24 | #define LTQ_ICU_IER 0x0008 | ||
25 | #define LTQ_ICU_IOSR 0x0010 | ||
26 | #define LTQ_ICU_IRSR 0x0018 | ||
27 | #define LTQ_ICU_IMR 0x0020 | ||
28 | |||
29 | #define LTQ_ICU_IM_SIZE 0x28 | ||
30 | |||
31 | /* register definitions - external irqs */ | ||
32 | #define LTQ_EIU_EXIN_C 0x0000 | ||
33 | #define LTQ_EIU_EXIN_INIC 0x0004 | ||
34 | #define LTQ_EIU_EXIN_INC 0x0008 | ||
35 | #define LTQ_EIU_EXIN_INEN 0x000C | ||
36 | |||
37 | /* number of external interrupts */ | ||
38 | #define MAX_EIU 6 | ||
39 | |||
40 | /* the performance counter */ | ||
41 | #define LTQ_PERF_IRQ (INT_NUM_IM4_IRL0 + 31) | ||
42 | |||
43 | /* | ||
44 | * irqs generated by devices attached to the EBU need to be acked in | ||
45 | * a special manner | ||
46 | */ | ||
47 | #define LTQ_ICU_EBU_IRQ 22 | ||
48 | |||
49 | #define ltq_icu_w32(vpe, m, x, y) \ | ||
50 | ltq_w32((x), ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (y)) | ||
51 | |||
52 | #define ltq_icu_r32(vpe, m, x) \ | ||
53 | ltq_r32(ltq_icu_membase[vpe] + m*LTQ_ICU_IM_SIZE + (x)) | ||
54 | |||
55 | #define ltq_eiu_w32(x, y) ltq_w32((x), ltq_eiu_membase + (y)) | ||
56 | #define ltq_eiu_r32(x) ltq_r32(ltq_eiu_membase + (x)) | ||
57 | |||
58 | /* we have a cascade of 8 irqs */ | ||
59 | #define MIPS_CPU_IRQ_CASCADE 8 | ||
60 | |||
61 | static int exin_avail; | ||
62 | static u32 ltq_eiu_irq[MAX_EIU]; | ||
63 | static void __iomem *ltq_icu_membase[NR_CPUS]; | ||
64 | static void __iomem *ltq_eiu_membase; | ||
65 | static struct irq_domain *ltq_domain; | ||
66 | static DEFINE_SPINLOCK(ltq_eiu_lock); | ||
67 | static DEFINE_RAW_SPINLOCK(ltq_icu_lock); | ||
68 | static int ltq_perfcount_irq; | ||
69 | |||
70 | int ltq_eiu_get_irq(int exin) | ||
71 | { | ||
72 | if (exin < exin_avail) | ||
73 | return ltq_eiu_irq[exin]; | ||
74 | return -1; | ||
75 | } | ||
76 | |||
77 | void ltq_disable_irq(struct irq_data *d) | ||
78 | { | ||
79 | unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; | ||
80 | unsigned long im = offset / INT_NUM_IM_OFFSET; | ||
81 | unsigned long flags; | ||
82 | int vpe; | ||
83 | |||
84 | offset %= INT_NUM_IM_OFFSET; | ||
85 | |||
86 | raw_spin_lock_irqsave(<q_icu_lock, flags); | ||
87 | for_each_present_cpu(vpe) { | ||
88 | ltq_icu_w32(vpe, im, | ||
89 | ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset), | ||
90 | LTQ_ICU_IER); | ||
91 | } | ||
92 | raw_spin_unlock_irqrestore(<q_icu_lock, flags); | ||
93 | } | ||
94 | |||
95 | void ltq_mask_and_ack_irq(struct irq_data *d) | ||
96 | { | ||
97 | unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; | ||
98 | unsigned long im = offset / INT_NUM_IM_OFFSET; | ||
99 | unsigned long flags; | ||
100 | int vpe; | ||
101 | |||
102 | offset %= INT_NUM_IM_OFFSET; | ||
103 | |||
104 | raw_spin_lock_irqsave(<q_icu_lock, flags); | ||
105 | for_each_present_cpu(vpe) { | ||
106 | ltq_icu_w32(vpe, im, | ||
107 | ltq_icu_r32(vpe, im, LTQ_ICU_IER) & ~BIT(offset), | ||
108 | LTQ_ICU_IER); | ||
109 | ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR); | ||
110 | } | ||
111 | raw_spin_unlock_irqrestore(<q_icu_lock, flags); | ||
112 | } | ||
113 | |||
114 | static void ltq_ack_irq(struct irq_data *d) | ||
115 | { | ||
116 | unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; | ||
117 | unsigned long im = offset / INT_NUM_IM_OFFSET; | ||
118 | unsigned long flags; | ||
119 | int vpe; | ||
120 | |||
121 | offset %= INT_NUM_IM_OFFSET; | ||
122 | |||
123 | raw_spin_lock_irqsave(<q_icu_lock, flags); | ||
124 | for_each_present_cpu(vpe) { | ||
125 | ltq_icu_w32(vpe, im, BIT(offset), LTQ_ICU_ISR); | ||
126 | } | ||
127 | raw_spin_unlock_irqrestore(<q_icu_lock, flags); | ||
128 | } | ||
129 | |||
130 | void ltq_enable_irq(struct irq_data *d) | ||
131 | { | ||
132 | unsigned long offset = d->hwirq - MIPS_CPU_IRQ_CASCADE; | ||
133 | unsigned long im = offset / INT_NUM_IM_OFFSET; | ||
134 | unsigned long flags; | ||
135 | int vpe; | ||
136 | |||
137 | offset %= INT_NUM_IM_OFFSET; | ||
138 | |||
139 | vpe = cpumask_first(irq_data_get_effective_affinity_mask(d)); | ||
140 | |||
141 | /* This shouldn't be even possible, maybe during CPU hotplug spam */ | ||
142 | if (unlikely(vpe >= nr_cpu_ids)) | ||
143 | vpe = smp_processor_id(); | ||
144 | |||
145 | raw_spin_lock_irqsave(<q_icu_lock, flags); | ||
146 | |||
147 | ltq_icu_w32(vpe, im, ltq_icu_r32(vpe, im, LTQ_ICU_IER) | BIT(offset), | ||
148 | LTQ_ICU_IER); | ||
149 | |||
150 | raw_spin_unlock_irqrestore(<q_icu_lock, flags); | ||
151 | } | ||
152 | |||
153 | static int ltq_eiu_settype(struct irq_data *d, unsigned int type) | ||
154 | { | ||
155 | int i; | ||
156 | unsigned long flags; | ||
157 | |||
158 | for (i = 0; i < exin_avail; i++) { | ||
159 | if (d->hwirq == ltq_eiu_irq[i]) { | ||
160 | int val = 0; | ||
161 | int edge = 0; | ||
162 | |||
163 | switch (type) { | ||
164 | case IRQF_TRIGGER_NONE: | ||
165 | break; | ||
166 | case IRQF_TRIGGER_RISING: | ||
167 | val = 1; | ||
168 | edge = 1; | ||
169 | break; | ||
170 | case IRQF_TRIGGER_FALLING: | ||
171 | val = 2; | ||
172 | edge = 1; | ||
173 | break; | ||
174 | case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING: | ||
175 | val = 3; | ||
176 | edge = 1; | ||
177 | break; | ||
178 | case IRQF_TRIGGER_HIGH: | ||
179 | val = 5; | ||
180 | break; | ||
181 | case IRQF_TRIGGER_LOW: | ||
182 | val = 6; | ||
183 | break; | ||
184 | default: | ||
185 | pr_err("invalid type %d for irq %ld\n", | ||
186 | type, d->hwirq); | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | |||
190 | if (edge) | ||
191 | irq_set_handler(d->hwirq, handle_edge_irq); | ||
192 | |||
193 | spin_lock_irqsave(<q_eiu_lock, flags); | ||
194 | ltq_eiu_w32((ltq_eiu_r32(LTQ_EIU_EXIN_C) & | ||
195 | (~(7 << (i * 4)))) | (val << (i * 4)), | ||
196 | LTQ_EIU_EXIN_C); | ||
197 | spin_unlock_irqrestore(<q_eiu_lock, flags); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static unsigned int ltq_startup_eiu_irq(struct irq_data *d) | ||
205 | { | ||
206 | int i; | ||
207 | |||
208 | ltq_enable_irq(d); | ||
209 | for (i = 0; i < exin_avail; i++) { | ||
210 | if (d->hwirq == ltq_eiu_irq[i]) { | ||
211 | /* by default we are low level triggered */ | ||
212 | ltq_eiu_settype(d, IRQF_TRIGGER_LOW); | ||
213 | /* clear all pending */ | ||
214 | ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INC) & ~BIT(i), | ||
215 | LTQ_EIU_EXIN_INC); | ||
216 | /* enable */ | ||
217 | ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) | BIT(i), | ||
218 | LTQ_EIU_EXIN_INEN); | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static void ltq_shutdown_eiu_irq(struct irq_data *d) | ||
227 | { | ||
228 | int i; | ||
229 | |||
230 | ltq_disable_irq(d); | ||
231 | for (i = 0; i < exin_avail; i++) { | ||
232 | if (d->hwirq == ltq_eiu_irq[i]) { | ||
233 | /* disable */ | ||
234 | ltq_eiu_w32(ltq_eiu_r32(LTQ_EIU_EXIN_INEN) & ~BIT(i), | ||
235 | LTQ_EIU_EXIN_INEN); | ||
236 | break; | ||
237 | } | ||
238 | } | ||
239 | } | ||
240 | |||
241 | #if defined(CONFIG_SMP) | ||
242 | static int ltq_icu_irq_set_affinity(struct irq_data *d, | ||
243 | const struct cpumask *cpumask, bool force) | ||
244 | { | ||
245 | struct cpumask tmask; | ||
246 | |||
247 | if (!cpumask_and(&tmask, cpumask, cpu_online_mask)) | ||
248 | return -EINVAL; | ||
249 | |||
250 | irq_data_update_effective_affinity(d, &tmask); | ||
251 | |||
252 | return IRQ_SET_MASK_OK; | ||
253 | } | ||
254 | #endif | ||
255 | |||
256 | static struct irq_chip ltq_irq_type = { | ||
257 | .name = "icu", | ||
258 | .irq_enable = ltq_enable_irq, | ||
259 | .irq_disable = ltq_disable_irq, | ||
260 | .irq_unmask = ltq_enable_irq, | ||
261 | .irq_ack = ltq_ack_irq, | ||
262 | .irq_mask = ltq_disable_irq, | ||
263 | .irq_mask_ack = ltq_mask_and_ack_irq, | ||
264 | #if defined(CONFIG_SMP) | ||
265 | .irq_set_affinity = ltq_icu_irq_set_affinity, | ||
266 | #endif | ||
267 | }; | ||
268 | |||
269 | static struct irq_chip ltq_eiu_type = { | ||
270 | .name = "eiu", | ||
271 | .irq_startup = ltq_startup_eiu_irq, | ||
272 | .irq_shutdown = ltq_shutdown_eiu_irq, | ||
273 | .irq_enable = ltq_enable_irq, | ||
274 | .irq_disable = ltq_disable_irq, | ||
275 | .irq_unmask = ltq_enable_irq, | ||
276 | .irq_ack = ltq_ack_irq, | ||
277 | .irq_mask = ltq_disable_irq, | ||
278 | .irq_mask_ack = ltq_mask_and_ack_irq, | ||
279 | .irq_set_type = ltq_eiu_settype, | ||
280 | #if defined(CONFIG_SMP) | ||
281 | .irq_set_affinity = ltq_icu_irq_set_affinity, | ||
282 | #endif | ||
283 | }; | ||
284 | |||
285 | static void ltq_hw_irq_handler(struct irq_desc *desc) | ||
286 | { | ||
287 | unsigned int module = irq_desc_get_irq(desc) - 2; | ||
288 | u32 irq; | ||
289 | irq_hw_number_t hwirq; | ||
290 | int vpe = smp_processor_id(); | ||
291 | |||
292 | irq = ltq_icu_r32(vpe, module, LTQ_ICU_IOSR); | ||
293 | if (irq == 0) | ||
294 | return; | ||
295 | |||
296 | /* | ||
297 | * silicon bug causes only the msb set to 1 to be valid. all | ||
298 | * other bits might be bogus | ||
299 | */ | ||
300 | irq = __fls(irq); | ||
301 | hwirq = irq + MIPS_CPU_IRQ_CASCADE + (INT_NUM_IM_OFFSET * module); | ||
302 | generic_handle_irq(irq_linear_revmap(ltq_domain, hwirq)); | ||
303 | |||
304 | /* if this is a EBU irq, we need to ack it or get a deadlock */ | ||
305 | if (irq == LTQ_ICU_EBU_IRQ && !module && LTQ_EBU_PCC_ISTAT != 0) | ||
306 | ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_PCC_ISTAT) | 0x10, | ||
307 | LTQ_EBU_PCC_ISTAT); | ||
308 | } | ||
309 | |||
310 | static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) | ||
311 | { | ||
312 | struct irq_chip *chip = <q_irq_type; | ||
313 | struct irq_data *data; | ||
314 | int i; | ||
315 | |||
316 | if (hw < MIPS_CPU_IRQ_CASCADE) | ||
317 | return 0; | ||
318 | |||
319 | for (i = 0; i < exin_avail; i++) | ||
320 | if (hw == ltq_eiu_irq[i]) | ||
321 | chip = <q_eiu_type; | ||
322 | |||
323 | data = irq_get_irq_data(irq); | ||
324 | |||
325 | irq_data_update_effective_affinity(data, cpumask_of(0)); | ||
326 | |||
327 | irq_set_chip_and_handler(irq, chip, handle_level_irq); | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static const struct irq_domain_ops irq_domain_ops = { | ||
333 | .xlate = irq_domain_xlate_onetwocell, | ||
334 | .map = icu_map, | ||
335 | }; | ||
336 | |||
337 | int __init icu_of_init(struct device_node *node, struct device_node *parent) | ||
338 | { | ||
339 | struct device_node *eiu_node; | ||
340 | struct resource res; | ||
341 | int i, ret, vpe; | ||
342 | |||
343 | /* load register regions of available ICUs */ | ||
344 | for_each_possible_cpu(vpe) { | ||
345 | if (of_address_to_resource(node, vpe, &res)) | ||
346 | panic("Failed to get icu%i memory range", vpe); | ||
347 | |||
348 | if (!request_mem_region(res.start, resource_size(&res), | ||
349 | res.name)) | ||
350 | pr_err("Failed to request icu%i memory\n", vpe); | ||
351 | |||
352 | ltq_icu_membase[vpe] = ioremap(res.start, | ||
353 | resource_size(&res)); | ||
354 | |||
355 | if (!ltq_icu_membase[vpe]) | ||
356 | panic("Failed to remap icu%i memory", vpe); | ||
357 | } | ||
358 | |||
359 | /* turn off all irqs by default */ | ||
360 | for_each_possible_cpu(vpe) { | ||
361 | for (i = 0; i < MAX_IM; i++) { | ||
362 | /* make sure all irqs are turned off by default */ | ||
363 | ltq_icu_w32(vpe, i, 0, LTQ_ICU_IER); | ||
364 | |||
365 | /* clear all possibly pending interrupts */ | ||
366 | ltq_icu_w32(vpe, i, ~0, LTQ_ICU_ISR); | ||
367 | ltq_icu_w32(vpe, i, ~0, LTQ_ICU_IMR); | ||
368 | |||
369 | /* clear resend */ | ||
370 | ltq_icu_w32(vpe, i, 0, LTQ_ICU_IRSR); | ||
371 | } | ||
372 | } | ||
373 | |||
374 | mips_cpu_irq_init(); | ||
375 | |||
376 | for (i = 0; i < MAX_IM; i++) | ||
377 | irq_set_chained_handler(i + 2, ltq_hw_irq_handler); | ||
378 | |||
379 | ltq_domain = irq_domain_add_linear(node, | ||
380 | (MAX_IM * INT_NUM_IM_OFFSET) + MIPS_CPU_IRQ_CASCADE, | ||
381 | &irq_domain_ops, 0); | ||
382 | |||
383 | /* tell oprofile which irq to use */ | ||
384 | ltq_perfcount_irq = irq_create_mapping(ltq_domain, LTQ_PERF_IRQ); | ||
385 | |||
386 | /* the external interrupts are optional and xway only */ | ||
387 | eiu_node = of_find_compatible_node(NULL, NULL, "lantiq,eiu-xway"); | ||
388 | if (eiu_node && !of_address_to_resource(eiu_node, 0, &res)) { | ||
389 | /* find out how many external irq sources we have */ | ||
390 | exin_avail = of_property_count_u32_elems(eiu_node, | ||
391 | "lantiq,eiu-irqs"); | ||
392 | |||
393 | if (exin_avail > MAX_EIU) | ||
394 | exin_avail = MAX_EIU; | ||
395 | |||
396 | ret = of_property_read_u32_array(eiu_node, "lantiq,eiu-irqs", | ||
397 | ltq_eiu_irq, exin_avail); | ||
398 | if (ret) | ||
399 | panic("failed to load external irq resources"); | ||
400 | |||
401 | if (!request_mem_region(res.start, resource_size(&res), | ||
402 | res.name)) | ||
403 | pr_err("Failed to request eiu memory"); | ||
404 | |||
405 | ltq_eiu_membase = ioremap(res.start, | ||
406 | resource_size(&res)); | ||
407 | if (!ltq_eiu_membase) | ||
408 | panic("Failed to remap eiu memory"); | ||
409 | } | ||
410 | |||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | int get_c0_perfcount_int(void) | ||
415 | { | ||
416 | return ltq_perfcount_irq; | ||
417 | } | ||
418 | EXPORT_SYMBOL_GPL(get_c0_perfcount_int); | ||
419 | |||
420 | unsigned int get_c0_compare_int(void) | ||
421 | { | ||
422 | return CP0_LEGACY_COMPARE_IRQ; | ||
423 | } | ||
424 | |||
425 | static const struct of_device_id of_irq_ids[] __initconst = { | ||
426 | { .compatible = "lantiq,icu", .data = icu_of_init }, | ||
427 | {}, | ||
428 | }; | ||
429 | |||
430 | void __init arch_init_irq(void) | ||
431 | { | ||
432 | of_irq_init(of_irq_ids); | ||
433 | } | ||
diff --git a/arch/mips/lantiq/prom.c b/arch/mips/lantiq/prom.c new file mode 100644 index 000000000..3f568f5aa --- /dev/null +++ b/arch/mips/lantiq/prom.c | |||
@@ -0,0 +1,113 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2010 John Crispin <john@phrozen.org> | ||
5 | */ | ||
6 | |||
7 | #include <linux/export.h> | ||
8 | #include <linux/clk.h> | ||
9 | #include <linux/memblock.h> | ||
10 | #include <linux/of_fdt.h> | ||
11 | |||
12 | #include <asm/bootinfo.h> | ||
13 | #include <asm/time.h> | ||
14 | #include <asm/prom.h> | ||
15 | |||
16 | #include <lantiq.h> | ||
17 | |||
18 | #include "prom.h" | ||
19 | #include "clk.h" | ||
20 | |||
21 | /* access to the ebu needs to be locked between different drivers */ | ||
22 | DEFINE_SPINLOCK(ebu_lock); | ||
23 | EXPORT_SYMBOL_GPL(ebu_lock); | ||
24 | |||
25 | /* | ||
26 | * This is needed by the VPE loader code, just set it to 0 and assume | ||
27 | * that the firmware hardcodes this value to something useful. | ||
28 | */ | ||
29 | unsigned long physical_memsize = 0L; | ||
30 | |||
31 | /* | ||
32 | * this struct is filled by the soc specific detection code and holds | ||
33 | * information about the specific soc type, revision and name | ||
34 | */ | ||
35 | static struct ltq_soc_info soc_info; | ||
36 | |||
37 | const char *get_system_type(void) | ||
38 | { | ||
39 | return soc_info.sys_type; | ||
40 | } | ||
41 | |||
42 | int ltq_soc_type(void) | ||
43 | { | ||
44 | return soc_info.type; | ||
45 | } | ||
46 | |||
47 | void __init prom_free_prom_memory(void) | ||
48 | { | ||
49 | } | ||
50 | |||
51 | static void __init prom_init_cmdline(void) | ||
52 | { | ||
53 | int argc = fw_arg0; | ||
54 | char **argv = (char **) KSEG1ADDR(fw_arg1); | ||
55 | int i; | ||
56 | |||
57 | arcs_cmdline[0] = '\0'; | ||
58 | |||
59 | for (i = 0; i < argc; i++) { | ||
60 | char *p = (char *) KSEG1ADDR(argv[i]); | ||
61 | |||
62 | if (CPHYSADDR(p) && *p) { | ||
63 | strlcat(arcs_cmdline, p, sizeof(arcs_cmdline)); | ||
64 | strlcat(arcs_cmdline, " ", sizeof(arcs_cmdline)); | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | void __init plat_mem_setup(void) | ||
70 | { | ||
71 | void *dtb; | ||
72 | |||
73 | ioport_resource.start = IOPORT_RESOURCE_START; | ||
74 | ioport_resource.end = IOPORT_RESOURCE_END; | ||
75 | iomem_resource.start = IOMEM_RESOURCE_START; | ||
76 | iomem_resource.end = IOMEM_RESOURCE_END; | ||
77 | |||
78 | set_io_port_base((unsigned long) KSEG1); | ||
79 | |||
80 | if (fw_passed_dtb) /* UHI interface */ | ||
81 | dtb = (void *)fw_passed_dtb; | ||
82 | else if (&__dtb_start != &__dtb_end) | ||
83 | dtb = (void *)__dtb_start; | ||
84 | else | ||
85 | panic("no dtb found"); | ||
86 | |||
87 | /* | ||
88 | * Load the devicetree. This causes the chosen node to be | ||
89 | * parsed resulting in our memory appearing | ||
90 | */ | ||
91 | __dt_setup_arch(dtb); | ||
92 | } | ||
93 | |||
94 | void __init device_tree_init(void) | ||
95 | { | ||
96 | unflatten_and_copy_device_tree(); | ||
97 | } | ||
98 | |||
99 | void __init prom_init(void) | ||
100 | { | ||
101 | /* call the soc specific detetcion code and get it to fill soc_info */ | ||
102 | ltq_soc_detect(&soc_info); | ||
103 | snprintf(soc_info.sys_type, LTQ_SYS_TYPE_LEN - 1, "%s rev %s", | ||
104 | soc_info.name, soc_info.rev_type); | ||
105 | soc_info.sys_type[LTQ_SYS_TYPE_LEN - 1] = '\0'; | ||
106 | pr_info("SoC: %s\n", soc_info.sys_type); | ||
107 | prom_init_cmdline(); | ||
108 | |||
109 | #if defined(CONFIG_MIPS_MT_SMP) | ||
110 | if (register_vsmp_smp_ops()) | ||
111 | panic("failed to register_vsmp_smp_ops()"); | ||
112 | #endif | ||
113 | } | ||
diff --git a/arch/mips/lantiq/prom.h b/arch/mips/lantiq/prom.h new file mode 100644 index 000000000..5cd29c6b3 --- /dev/null +++ b/arch/mips/lantiq/prom.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0-only */ | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2010 John Crispin <john@phrozen.org> | ||
5 | */ | ||
6 | |||
7 | #ifndef _LTQ_PROM_H__ | ||
8 | #define _LTQ_PROM_H__ | ||
9 | |||
10 | #define LTQ_SYS_TYPE_LEN 0x100 | ||
11 | #define LTQ_SYS_REV_LEN 0x10 | ||
12 | |||
13 | struct ltq_soc_info { | ||
14 | unsigned char *name; | ||
15 | unsigned int rev; | ||
16 | unsigned char rev_type[LTQ_SYS_REV_LEN]; | ||
17 | unsigned int srev; | ||
18 | unsigned int partnum; | ||
19 | unsigned int type; | ||
20 | unsigned char sys_type[LTQ_SYS_TYPE_LEN]; | ||
21 | unsigned char *compatible; | ||
22 | }; | ||
23 | |||
24 | extern void ltq_soc_detect(struct ltq_soc_info *i); | ||
25 | extern void ltq_soc_init(void); | ||
26 | |||
27 | #endif | ||
diff --git a/arch/mips/lantiq/xway/Makefile b/arch/mips/lantiq/xway/Makefile new file mode 100644 index 000000000..c0f02dab7 --- /dev/null +++ b/arch/mips/lantiq/xway/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0-only | ||
2 | obj-y := prom.o sysctrl.o clk.o dma.o gptu.o dcdc.o | ||
3 | |||
4 | obj-y += vmmc.o | ||
diff --git a/arch/mips/lantiq/xway/clk.c b/arch/mips/lantiq/xway/clk.c new file mode 100644 index 000000000..47ad21430 --- /dev/null +++ b/arch/mips/lantiq/xway/clk.c | |||
@@ -0,0 +1,351 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2010 John Crispin <john@phrozen.org> | ||
5 | * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG | ||
6 | */ | ||
7 | |||
8 | #include <linux/io.h> | ||
9 | #include <linux/export.h> | ||
10 | #include <linux/clk.h> | ||
11 | |||
12 | #include <asm/time.h> | ||
13 | #include <asm/irq.h> | ||
14 | #include <asm/div64.h> | ||
15 | |||
16 | #include <lantiq_soc.h> | ||
17 | |||
18 | #include "../clk.h" | ||
19 | |||
20 | static unsigned int ram_clocks[] = { | ||
21 | CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M }; | ||
22 | #define DDR_HZ ram_clocks[ltq_cgu_r32(CGU_SYS) & 0x3] | ||
23 | |||
24 | /* legacy xway clock */ | ||
25 | #define CGU_SYS 0x10 | ||
26 | |||
27 | /* vr9, ar10/grx390 clock */ | ||
28 | #define CGU_SYS_XRX 0x0c | ||
29 | #define CGU_IF_CLK_AR10 0x24 | ||
30 | |||
31 | unsigned long ltq_danube_fpi_hz(void) | ||
32 | { | ||
33 | unsigned long ddr_clock = DDR_HZ; | ||
34 | |||
35 | if (ltq_cgu_r32(CGU_SYS) & 0x40) | ||
36 | return ddr_clock >> 1; | ||
37 | return ddr_clock; | ||
38 | } | ||
39 | |||
40 | unsigned long ltq_danube_cpu_hz(void) | ||
41 | { | ||
42 | switch (ltq_cgu_r32(CGU_SYS) & 0xc) { | ||
43 | case 0: | ||
44 | return CLOCK_333M; | ||
45 | case 4: | ||
46 | return DDR_HZ; | ||
47 | case 8: | ||
48 | return DDR_HZ << 1; | ||
49 | default: | ||
50 | return DDR_HZ >> 1; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | unsigned long ltq_danube_pp32_hz(void) | ||
55 | { | ||
56 | unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 7) & 3; | ||
57 | unsigned long clk; | ||
58 | |||
59 | switch (clksys) { | ||
60 | case 1: | ||
61 | clk = CLOCK_240M; | ||
62 | break; | ||
63 | case 2: | ||
64 | clk = CLOCK_222M; | ||
65 | break; | ||
66 | case 3: | ||
67 | clk = CLOCK_133M; | ||
68 | break; | ||
69 | default: | ||
70 | clk = CLOCK_266M; | ||
71 | break; | ||
72 | } | ||
73 | |||
74 | return clk; | ||
75 | } | ||
76 | |||
77 | unsigned long ltq_ar9_sys_hz(void) | ||
78 | { | ||
79 | if (((ltq_cgu_r32(CGU_SYS) >> 3) & 0x3) == 0x2) | ||
80 | return CLOCK_393M; | ||
81 | return CLOCK_333M; | ||
82 | } | ||
83 | |||
84 | unsigned long ltq_ar9_fpi_hz(void) | ||
85 | { | ||
86 | unsigned long sys = ltq_ar9_sys_hz(); | ||
87 | |||
88 | if (ltq_cgu_r32(CGU_SYS) & BIT(0)) | ||
89 | return sys / 3; | ||
90 | else | ||
91 | return sys / 2; | ||
92 | } | ||
93 | |||
94 | unsigned long ltq_ar9_cpu_hz(void) | ||
95 | { | ||
96 | if (ltq_cgu_r32(CGU_SYS) & BIT(2)) | ||
97 | return ltq_ar9_fpi_hz(); | ||
98 | else | ||
99 | return ltq_ar9_sys_hz(); | ||
100 | } | ||
101 | |||
102 | unsigned long ltq_vr9_cpu_hz(void) | ||
103 | { | ||
104 | unsigned int cpu_sel; | ||
105 | unsigned long clk; | ||
106 | |||
107 | cpu_sel = (ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0xf; | ||
108 | |||
109 | switch (cpu_sel) { | ||
110 | case 0: | ||
111 | clk = CLOCK_600M; | ||
112 | break; | ||
113 | case 1: | ||
114 | clk = CLOCK_500M; | ||
115 | break; | ||
116 | case 2: | ||
117 | clk = CLOCK_393M; | ||
118 | break; | ||
119 | case 3: | ||
120 | clk = CLOCK_333M; | ||
121 | break; | ||
122 | case 5: | ||
123 | case 6: | ||
124 | clk = CLOCK_196_608M; | ||
125 | break; | ||
126 | case 7: | ||
127 | clk = CLOCK_167M; | ||
128 | break; | ||
129 | case 4: | ||
130 | case 8: | ||
131 | case 9: | ||
132 | clk = CLOCK_125M; | ||
133 | break; | ||
134 | default: | ||
135 | clk = 0; | ||
136 | break; | ||
137 | } | ||
138 | |||
139 | return clk; | ||
140 | } | ||
141 | |||
142 | unsigned long ltq_vr9_fpi_hz(void) | ||
143 | { | ||
144 | unsigned int ocp_sel, cpu_clk; | ||
145 | unsigned long clk; | ||
146 | |||
147 | cpu_clk = ltq_vr9_cpu_hz(); | ||
148 | ocp_sel = ltq_cgu_r32(CGU_SYS_XRX) & 0x3; | ||
149 | |||
150 | switch (ocp_sel) { | ||
151 | case 0: | ||
152 | /* OCP ratio 1 */ | ||
153 | clk = cpu_clk; | ||
154 | break; | ||
155 | case 2: | ||
156 | /* OCP ratio 2 */ | ||
157 | clk = cpu_clk / 2; | ||
158 | break; | ||
159 | case 3: | ||
160 | /* OCP ratio 2.5 */ | ||
161 | clk = (cpu_clk * 2) / 5; | ||
162 | break; | ||
163 | case 4: | ||
164 | /* OCP ratio 3 */ | ||
165 | clk = cpu_clk / 3; | ||
166 | break; | ||
167 | default: | ||
168 | clk = 0; | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | return clk; | ||
173 | } | ||
174 | |||
175 | unsigned long ltq_vr9_pp32_hz(void) | ||
176 | { | ||
177 | unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7; | ||
178 | unsigned long clk; | ||
179 | |||
180 | switch (clksys) { | ||
181 | case 0: | ||
182 | clk = CLOCK_500M; | ||
183 | break; | ||
184 | case 1: | ||
185 | clk = CLOCK_432M; | ||
186 | break; | ||
187 | case 2: | ||
188 | clk = CLOCK_288M; | ||
189 | break; | ||
190 | default: | ||
191 | clk = CLOCK_500M; | ||
192 | break; | ||
193 | } | ||
194 | |||
195 | return clk; | ||
196 | } | ||
197 | |||
198 | unsigned long ltq_ar10_cpu_hz(void) | ||
199 | { | ||
200 | unsigned int clksys; | ||
201 | int cpu_fs = (ltq_cgu_r32(CGU_SYS_XRX) >> 8) & 0x1; | ||
202 | int freq_div = (ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0x7; | ||
203 | |||
204 | switch (cpu_fs) { | ||
205 | case 0: | ||
206 | clksys = CLOCK_500M; | ||
207 | break; | ||
208 | case 1: | ||
209 | clksys = CLOCK_600M; | ||
210 | break; | ||
211 | default: | ||
212 | clksys = CLOCK_500M; | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | switch (freq_div) { | ||
217 | case 0: | ||
218 | return clksys; | ||
219 | case 1: | ||
220 | return clksys >> 1; | ||
221 | case 2: | ||
222 | return clksys >> 2; | ||
223 | default: | ||
224 | return clksys; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | unsigned long ltq_ar10_fpi_hz(void) | ||
229 | { | ||
230 | int freq_fpi = (ltq_cgu_r32(CGU_IF_CLK_AR10) >> 25) & 0xf; | ||
231 | |||
232 | switch (freq_fpi) { | ||
233 | case 1: | ||
234 | return CLOCK_300M; | ||
235 | case 5: | ||
236 | return CLOCK_250M; | ||
237 | case 2: | ||
238 | return CLOCK_150M; | ||
239 | case 6: | ||
240 | return CLOCK_125M; | ||
241 | |||
242 | default: | ||
243 | return CLOCK_125M; | ||
244 | } | ||
245 | } | ||
246 | |||
247 | unsigned long ltq_ar10_pp32_hz(void) | ||
248 | { | ||
249 | unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7; | ||
250 | unsigned long clk; | ||
251 | |||
252 | switch (clksys) { | ||
253 | case 1: | ||
254 | clk = CLOCK_250M; | ||
255 | break; | ||
256 | case 4: | ||
257 | clk = CLOCK_400M; | ||
258 | break; | ||
259 | default: | ||
260 | clk = CLOCK_250M; | ||
261 | break; | ||
262 | } | ||
263 | |||
264 | return clk; | ||
265 | } | ||
266 | |||
267 | unsigned long ltq_grx390_cpu_hz(void) | ||
268 | { | ||
269 | unsigned int clksys; | ||
270 | int cpu_fs = ((ltq_cgu_r32(CGU_SYS_XRX) >> 9) & 0x3); | ||
271 | int freq_div = ((ltq_cgu_r32(CGU_SYS_XRX) >> 4) & 0x7); | ||
272 | |||
273 | switch (cpu_fs) { | ||
274 | case 0: | ||
275 | clksys = CLOCK_600M; | ||
276 | break; | ||
277 | case 1: | ||
278 | clksys = CLOCK_666M; | ||
279 | break; | ||
280 | case 2: | ||
281 | clksys = CLOCK_720M; | ||
282 | break; | ||
283 | default: | ||
284 | clksys = CLOCK_600M; | ||
285 | break; | ||
286 | } | ||
287 | |||
288 | switch (freq_div) { | ||
289 | case 0: | ||
290 | return clksys; | ||
291 | case 1: | ||
292 | return clksys >> 1; | ||
293 | case 2: | ||
294 | return clksys >> 2; | ||
295 | default: | ||
296 | return clksys; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | unsigned long ltq_grx390_fpi_hz(void) | ||
301 | { | ||
302 | /* fpi clock is derived from ddr_clk */ | ||
303 | unsigned int clksys; | ||
304 | int cpu_fs = ((ltq_cgu_r32(CGU_SYS_XRX) >> 9) & 0x3); | ||
305 | int freq_div = ((ltq_cgu_r32(CGU_SYS_XRX)) & 0x7); | ||
306 | switch (cpu_fs) { | ||
307 | case 0: | ||
308 | clksys = CLOCK_600M; | ||
309 | break; | ||
310 | case 1: | ||
311 | clksys = CLOCK_666M; | ||
312 | break; | ||
313 | case 2: | ||
314 | clksys = CLOCK_720M; | ||
315 | break; | ||
316 | default: | ||
317 | clksys = CLOCK_600M; | ||
318 | break; | ||
319 | } | ||
320 | |||
321 | switch (freq_div) { | ||
322 | case 1: | ||
323 | return clksys >> 1; | ||
324 | case 2: | ||
325 | return clksys >> 2; | ||
326 | default: | ||
327 | return clksys >> 1; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | unsigned long ltq_grx390_pp32_hz(void) | ||
332 | { | ||
333 | unsigned int clksys = (ltq_cgu_r32(CGU_SYS) >> 16) & 0x7; | ||
334 | unsigned long clk; | ||
335 | |||
336 | switch (clksys) { | ||
337 | case 1: | ||
338 | clk = CLOCK_250M; | ||
339 | break; | ||
340 | case 2: | ||
341 | clk = CLOCK_432M; | ||
342 | break; | ||
343 | case 4: | ||
344 | clk = CLOCK_400M; | ||
345 | break; | ||
346 | default: | ||
347 | clk = CLOCK_250M; | ||
348 | break; | ||
349 | } | ||
350 | return clk; | ||
351 | } | ||
diff --git a/arch/mips/lantiq/xway/dcdc.c b/arch/mips/lantiq/xway/dcdc.c new file mode 100644 index 000000000..4960bee0a --- /dev/null +++ b/arch/mips/lantiq/xway/dcdc.c | |||
@@ -0,0 +1,60 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2012 John Crispin <john@phrozen.org> | ||
5 | * Copyright (C) 2010 Sameer Ahmad, Lantiq GmbH | ||
6 | */ | ||
7 | |||
8 | #include <linux/ioport.h> | ||
9 | #include <linux/of_platform.h> | ||
10 | |||
11 | #include <lantiq_soc.h> | ||
12 | |||
13 | /* Bias and regulator Setup Register */ | ||
14 | #define DCDC_BIAS_VREG0 0xa | ||
15 | /* Bias and regulator Setup Register */ | ||
16 | #define DCDC_BIAS_VREG1 0xb | ||
17 | |||
18 | #define dcdc_w8(x, y) ltq_w8((x), dcdc_membase + (y)) | ||
19 | #define dcdc_r8(x) ltq_r8(dcdc_membase + (x)) | ||
20 | |||
21 | static void __iomem *dcdc_membase; | ||
22 | |||
23 | static int dcdc_probe(struct platform_device *pdev) | ||
24 | { | ||
25 | struct resource *res; | ||
26 | |||
27 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
28 | dcdc_membase = devm_ioremap_resource(&pdev->dev, res); | ||
29 | if (IS_ERR(dcdc_membase)) | ||
30 | return PTR_ERR(dcdc_membase); | ||
31 | |||
32 | dev_info(&pdev->dev, "Core Voltage : %d mV\n", | ||
33 | dcdc_r8(DCDC_BIAS_VREG1) * 8); | ||
34 | |||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static const struct of_device_id dcdc_match[] = { | ||
39 | { .compatible = "lantiq,dcdc-xrx200" }, | ||
40 | {}, | ||
41 | }; | ||
42 | |||
43 | static struct platform_driver dcdc_driver = { | ||
44 | .probe = dcdc_probe, | ||
45 | .driver = { | ||
46 | .name = "dcdc-xrx200", | ||
47 | .of_match_table = dcdc_match, | ||
48 | }, | ||
49 | }; | ||
50 | |||
51 | int __init dcdc_init(void) | ||
52 | { | ||
53 | int ret = platform_driver_register(&dcdc_driver); | ||
54 | |||
55 | if (ret) | ||
56 | pr_info("dcdc: Error registering platform driver\n"); | ||
57 | return ret; | ||
58 | } | ||
59 | |||
60 | arch_initcall(dcdc_init); | ||
diff --git a/arch/mips/lantiq/xway/dma.c b/arch/mips/lantiq/xway/dma.c new file mode 100644 index 000000000..ab13e2571 --- /dev/null +++ b/arch/mips/lantiq/xway/dma.c | |||
@@ -0,0 +1,271 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2011 John Crispin <john@phrozen.org> | ||
5 | */ | ||
6 | |||
7 | #include <linux/init.h> | ||
8 | #include <linux/platform_device.h> | ||
9 | #include <linux/io.h> | ||
10 | #include <linux/dma-mapping.h> | ||
11 | #include <linux/export.h> | ||
12 | #include <linux/spinlock.h> | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/err.h> | ||
16 | |||
17 | #include <lantiq_soc.h> | ||
18 | #include <xway_dma.h> | ||
19 | |||
20 | #define LTQ_DMA_ID 0x08 | ||
21 | #define LTQ_DMA_CTRL 0x10 | ||
22 | #define LTQ_DMA_CPOLL 0x14 | ||
23 | #define LTQ_DMA_CS 0x18 | ||
24 | #define LTQ_DMA_CCTRL 0x1C | ||
25 | #define LTQ_DMA_CDBA 0x20 | ||
26 | #define LTQ_DMA_CDLEN 0x24 | ||
27 | #define LTQ_DMA_CIS 0x28 | ||
28 | #define LTQ_DMA_CIE 0x2C | ||
29 | #define LTQ_DMA_PS 0x40 | ||
30 | #define LTQ_DMA_PCTRL 0x44 | ||
31 | #define LTQ_DMA_IRNEN 0xf4 | ||
32 | |||
33 | #define DMA_ID_CHNR GENMASK(26, 20) /* channel number */ | ||
34 | #define DMA_DESCPT BIT(3) /* descriptor complete irq */ | ||
35 | #define DMA_TX BIT(8) /* TX channel direction */ | ||
36 | #define DMA_CHAN_ON BIT(0) /* channel on / off bit */ | ||
37 | #define DMA_PDEN BIT(6) /* enable packet drop */ | ||
38 | #define DMA_CHAN_RST BIT(1) /* channel on / off bit */ | ||
39 | #define DMA_RESET BIT(0) /* channel on / off bit */ | ||
40 | #define DMA_IRQ_ACK 0x7e /* IRQ status register */ | ||
41 | #define DMA_POLL BIT(31) /* turn on channel polling */ | ||
42 | #define DMA_CLK_DIV4 BIT(6) /* polling clock divider */ | ||
43 | #define DMA_PCTRL_2W_BURST 0x1 /* 2 word burst length */ | ||
44 | #define DMA_PCTRL_4W_BURST 0x2 /* 4 word burst length */ | ||
45 | #define DMA_PCTRL_8W_BURST 0x3 /* 8 word burst length */ | ||
46 | #define DMA_TX_BURST_SHIFT 4 /* tx burst shift */ | ||
47 | #define DMA_RX_BURST_SHIFT 2 /* rx burst shift */ | ||
48 | #define DMA_ETOP_ENDIANNESS (0xf << 8) /* endianness swap etop channels */ | ||
49 | #define DMA_WEIGHT (BIT(17) | BIT(16)) /* default channel wheight */ | ||
50 | |||
51 | #define ltq_dma_r32(x) ltq_r32(ltq_dma_membase + (x)) | ||
52 | #define ltq_dma_w32(x, y) ltq_w32(x, ltq_dma_membase + (y)) | ||
53 | #define ltq_dma_w32_mask(x, y, z) ltq_w32_mask(x, y, \ | ||
54 | ltq_dma_membase + (z)) | ||
55 | |||
56 | static void __iomem *ltq_dma_membase; | ||
57 | static DEFINE_SPINLOCK(ltq_dma_lock); | ||
58 | |||
59 | void | ||
60 | ltq_dma_enable_irq(struct ltq_dma_channel *ch) | ||
61 | { | ||
62 | unsigned long flags; | ||
63 | |||
64 | spin_lock_irqsave(<q_dma_lock, flags); | ||
65 | ltq_dma_w32(ch->nr, LTQ_DMA_CS); | ||
66 | ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); | ||
67 | spin_unlock_irqrestore(<q_dma_lock, flags); | ||
68 | } | ||
69 | EXPORT_SYMBOL_GPL(ltq_dma_enable_irq); | ||
70 | |||
71 | void | ||
72 | ltq_dma_disable_irq(struct ltq_dma_channel *ch) | ||
73 | { | ||
74 | unsigned long flags; | ||
75 | |||
76 | spin_lock_irqsave(<q_dma_lock, flags); | ||
77 | ltq_dma_w32(ch->nr, LTQ_DMA_CS); | ||
78 | ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN); | ||
79 | spin_unlock_irqrestore(<q_dma_lock, flags); | ||
80 | } | ||
81 | EXPORT_SYMBOL_GPL(ltq_dma_disable_irq); | ||
82 | |||
83 | void | ||
84 | ltq_dma_ack_irq(struct ltq_dma_channel *ch) | ||
85 | { | ||
86 | unsigned long flags; | ||
87 | |||
88 | spin_lock_irqsave(<q_dma_lock, flags); | ||
89 | ltq_dma_w32(ch->nr, LTQ_DMA_CS); | ||
90 | ltq_dma_w32(DMA_IRQ_ACK, LTQ_DMA_CIS); | ||
91 | spin_unlock_irqrestore(<q_dma_lock, flags); | ||
92 | } | ||
93 | EXPORT_SYMBOL_GPL(ltq_dma_ack_irq); | ||
94 | |||
95 | void | ||
96 | ltq_dma_open(struct ltq_dma_channel *ch) | ||
97 | { | ||
98 | unsigned long flag; | ||
99 | |||
100 | spin_lock_irqsave(<q_dma_lock, flag); | ||
101 | ltq_dma_w32(ch->nr, LTQ_DMA_CS); | ||
102 | ltq_dma_w32_mask(0, DMA_CHAN_ON, LTQ_DMA_CCTRL); | ||
103 | spin_unlock_irqrestore(<q_dma_lock, flag); | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(ltq_dma_open); | ||
106 | |||
107 | void | ||
108 | ltq_dma_close(struct ltq_dma_channel *ch) | ||
109 | { | ||
110 | unsigned long flag; | ||
111 | |||
112 | spin_lock_irqsave(<q_dma_lock, flag); | ||
113 | ltq_dma_w32(ch->nr, LTQ_DMA_CS); | ||
114 | ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); | ||
115 | ltq_dma_w32_mask(1 << ch->nr, 0, LTQ_DMA_IRNEN); | ||
116 | spin_unlock_irqrestore(<q_dma_lock, flag); | ||
117 | } | ||
118 | EXPORT_SYMBOL_GPL(ltq_dma_close); | ||
119 | |||
120 | static void | ||
121 | ltq_dma_alloc(struct ltq_dma_channel *ch) | ||
122 | { | ||
123 | unsigned long flags; | ||
124 | |||
125 | ch->desc = 0; | ||
126 | ch->desc_base = dma_alloc_coherent(ch->dev, | ||
127 | LTQ_DESC_NUM * LTQ_DESC_SIZE, | ||
128 | &ch->phys, GFP_ATOMIC); | ||
129 | |||
130 | spin_lock_irqsave(<q_dma_lock, flags); | ||
131 | ltq_dma_w32(ch->nr, LTQ_DMA_CS); | ||
132 | ltq_dma_w32(ch->phys, LTQ_DMA_CDBA); | ||
133 | ltq_dma_w32(LTQ_DESC_NUM, LTQ_DMA_CDLEN); | ||
134 | ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); | ||
135 | wmb(); | ||
136 | ltq_dma_w32_mask(0, DMA_CHAN_RST, LTQ_DMA_CCTRL); | ||
137 | while (ltq_dma_r32(LTQ_DMA_CCTRL) & DMA_CHAN_RST) | ||
138 | ; | ||
139 | spin_unlock_irqrestore(<q_dma_lock, flags); | ||
140 | } | ||
141 | |||
142 | void | ||
143 | ltq_dma_alloc_tx(struct ltq_dma_channel *ch) | ||
144 | { | ||
145 | unsigned long flags; | ||
146 | |||
147 | ltq_dma_alloc(ch); | ||
148 | |||
149 | spin_lock_irqsave(<q_dma_lock, flags); | ||
150 | ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); | ||
151 | ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); | ||
152 | ltq_dma_w32(DMA_WEIGHT | DMA_TX, LTQ_DMA_CCTRL); | ||
153 | spin_unlock_irqrestore(<q_dma_lock, flags); | ||
154 | } | ||
155 | EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx); | ||
156 | |||
157 | void | ||
158 | ltq_dma_alloc_rx(struct ltq_dma_channel *ch) | ||
159 | { | ||
160 | unsigned long flags; | ||
161 | |||
162 | ltq_dma_alloc(ch); | ||
163 | |||
164 | spin_lock_irqsave(<q_dma_lock, flags); | ||
165 | ltq_dma_w32(DMA_DESCPT, LTQ_DMA_CIE); | ||
166 | ltq_dma_w32_mask(0, 1 << ch->nr, LTQ_DMA_IRNEN); | ||
167 | ltq_dma_w32(DMA_WEIGHT, LTQ_DMA_CCTRL); | ||
168 | spin_unlock_irqrestore(<q_dma_lock, flags); | ||
169 | } | ||
170 | EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx); | ||
171 | |||
172 | void | ||
173 | ltq_dma_free(struct ltq_dma_channel *ch) | ||
174 | { | ||
175 | if (!ch->desc_base) | ||
176 | return; | ||
177 | ltq_dma_close(ch); | ||
178 | dma_free_coherent(ch->dev, LTQ_DESC_NUM * LTQ_DESC_SIZE, | ||
179 | ch->desc_base, ch->phys); | ||
180 | } | ||
181 | EXPORT_SYMBOL_GPL(ltq_dma_free); | ||
182 | |||
183 | void | ||
184 | ltq_dma_init_port(int p) | ||
185 | { | ||
186 | ltq_dma_w32(p, LTQ_DMA_PS); | ||
187 | switch (p) { | ||
188 | case DMA_PORT_ETOP: | ||
189 | /* | ||
190 | * Tell the DMA engine to swap the endianness of data frames and | ||
191 | * drop packets if the channel arbitration fails. | ||
192 | */ | ||
193 | ltq_dma_w32_mask(0, DMA_ETOP_ENDIANNESS | DMA_PDEN, | ||
194 | LTQ_DMA_PCTRL); | ||
195 | break; | ||
196 | |||
197 | case DMA_PORT_DEU: | ||
198 | ltq_dma_w32((DMA_PCTRL_2W_BURST << DMA_TX_BURST_SHIFT) | | ||
199 | (DMA_PCTRL_2W_BURST << DMA_RX_BURST_SHIFT), | ||
200 | LTQ_DMA_PCTRL); | ||
201 | break; | ||
202 | |||
203 | default: | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | EXPORT_SYMBOL_GPL(ltq_dma_init_port); | ||
208 | |||
209 | static int | ||
210 | ltq_dma_init(struct platform_device *pdev) | ||
211 | { | ||
212 | struct clk *clk; | ||
213 | struct resource *res; | ||
214 | unsigned int id, nchannels; | ||
215 | int i; | ||
216 | |||
217 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
218 | ltq_dma_membase = devm_ioremap_resource(&pdev->dev, res); | ||
219 | if (IS_ERR(ltq_dma_membase)) | ||
220 | panic("Failed to remap dma resource"); | ||
221 | |||
222 | /* power up and reset the dma engine */ | ||
223 | clk = clk_get(&pdev->dev, NULL); | ||
224 | if (IS_ERR(clk)) | ||
225 | panic("Failed to get dma clock"); | ||
226 | |||
227 | clk_enable(clk); | ||
228 | ltq_dma_w32_mask(0, DMA_RESET, LTQ_DMA_CTRL); | ||
229 | |||
230 | usleep_range(1, 10); | ||
231 | |||
232 | /* disable all interrupts */ | ||
233 | ltq_dma_w32(0, LTQ_DMA_IRNEN); | ||
234 | |||
235 | /* reset/configure each channel */ | ||
236 | id = ltq_dma_r32(LTQ_DMA_ID); | ||
237 | nchannels = ((id & DMA_ID_CHNR) >> 20); | ||
238 | for (i = 0; i < nchannels; i++) { | ||
239 | ltq_dma_w32(i, LTQ_DMA_CS); | ||
240 | ltq_dma_w32(DMA_CHAN_RST, LTQ_DMA_CCTRL); | ||
241 | ltq_dma_w32(DMA_POLL | DMA_CLK_DIV4, LTQ_DMA_CPOLL); | ||
242 | ltq_dma_w32_mask(DMA_CHAN_ON, 0, LTQ_DMA_CCTRL); | ||
243 | } | ||
244 | |||
245 | dev_info(&pdev->dev, | ||
246 | "Init done - hw rev: %X, ports: %d, channels: %d\n", | ||
247 | id & 0x1f, (id >> 16) & 0xf, nchannels); | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static const struct of_device_id dma_match[] = { | ||
253 | { .compatible = "lantiq,dma-xway" }, | ||
254 | {}, | ||
255 | }; | ||
256 | |||
257 | static struct platform_driver dma_driver = { | ||
258 | .probe = ltq_dma_init, | ||
259 | .driver = { | ||
260 | .name = "dma-xway", | ||
261 | .of_match_table = dma_match, | ||
262 | }, | ||
263 | }; | ||
264 | |||
265 | int __init | ||
266 | dma_init(void) | ||
267 | { | ||
268 | return platform_driver_register(&dma_driver); | ||
269 | } | ||
270 | |||
271 | postcore_initcall(dma_init); | ||
diff --git a/arch/mips/lantiq/xway/gptu.c b/arch/mips/lantiq/xway/gptu.c new file mode 100644 index 000000000..200fe9ff6 --- /dev/null +++ b/arch/mips/lantiq/xway/gptu.c | |||
@@ -0,0 +1,208 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2012 John Crispin <john@phrozen.org> | ||
5 | * Copyright (C) 2012 Lantiq GmbH | ||
6 | */ | ||
7 | |||
8 | #include <linux/interrupt.h> | ||
9 | #include <linux/ioport.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/of_platform.h> | ||
12 | #include <linux/of_irq.h> | ||
13 | |||
14 | #include <lantiq_soc.h> | ||
15 | #include "../clk.h" | ||
16 | |||
17 | /* the magic ID byte of the core */ | ||
18 | #define GPTU_MAGIC 0x59 | ||
19 | /* clock control register */ | ||
20 | #define GPTU_CLC 0x00 | ||
21 | /* id register */ | ||
22 | #define GPTU_ID 0x08 | ||
23 | /* interrupt node enable */ | ||
24 | #define GPTU_IRNEN 0xf4 | ||
25 | /* interrupt control register */ | ||
26 | #define GPTU_IRCR 0xf8 | ||
27 | /* interrupt capture register */ | ||
28 | #define GPTU_IRNCR 0xfc | ||
29 | /* there are 3 identical blocks of 2 timers. calculate register offsets */ | ||
30 | #define GPTU_SHIFT(x) (x % 2 ? 4 : 0) | ||
31 | #define GPTU_BASE(x) (((x >> 1) * 0x20) + 0x10) | ||
32 | /* timer control register */ | ||
33 | #define GPTU_CON(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x00) | ||
34 | /* timer auto reload register */ | ||
35 | #define GPTU_RUN(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x08) | ||
36 | /* timer manual reload register */ | ||
37 | #define GPTU_RLD(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x10) | ||
38 | /* timer count register */ | ||
39 | #define GPTU_CNT(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x18) | ||
40 | |||
41 | /* GPTU_CON(x) */ | ||
42 | #define CON_CNT BIT(2) | ||
43 | #define CON_EDGE_ANY (BIT(7) | BIT(6)) | ||
44 | #define CON_SYNC BIT(8) | ||
45 | #define CON_CLK_INT BIT(10) | ||
46 | |||
47 | /* GPTU_RUN(x) */ | ||
48 | #define RUN_SEN BIT(0) | ||
49 | #define RUN_RL BIT(2) | ||
50 | |||
51 | /* set clock to runmode */ | ||
52 | #define CLC_RMC BIT(8) | ||
53 | /* bring core out of suspend */ | ||
54 | #define CLC_SUSPEND BIT(4) | ||
55 | /* the disable bit */ | ||
56 | #define CLC_DISABLE BIT(0) | ||
57 | |||
58 | #define gptu_w32(x, y) ltq_w32((x), gptu_membase + (y)) | ||
59 | #define gptu_r32(x) ltq_r32(gptu_membase + (x)) | ||
60 | |||
61 | enum gptu_timer { | ||
62 | TIMER1A = 0, | ||
63 | TIMER1B, | ||
64 | TIMER2A, | ||
65 | TIMER2B, | ||
66 | TIMER3A, | ||
67 | TIMER3B | ||
68 | }; | ||
69 | |||
70 | static void __iomem *gptu_membase; | ||
71 | static struct resource irqres[6]; | ||
72 | |||
73 | static irqreturn_t timer_irq_handler(int irq, void *priv) | ||
74 | { | ||
75 | int timer = irq - irqres[0].start; | ||
76 | gptu_w32(1 << timer, GPTU_IRNCR); | ||
77 | return IRQ_HANDLED; | ||
78 | } | ||
79 | |||
80 | static void gptu_hwinit(void) | ||
81 | { | ||
82 | gptu_w32(0x00, GPTU_IRNEN); | ||
83 | gptu_w32(0xff, GPTU_IRNCR); | ||
84 | gptu_w32(CLC_RMC | CLC_SUSPEND, GPTU_CLC); | ||
85 | } | ||
86 | |||
87 | static void gptu_hwexit(void) | ||
88 | { | ||
89 | gptu_w32(0x00, GPTU_IRNEN); | ||
90 | gptu_w32(0xff, GPTU_IRNCR); | ||
91 | gptu_w32(CLC_DISABLE, GPTU_CLC); | ||
92 | } | ||
93 | |||
94 | static int gptu_enable(struct clk *clk) | ||
95 | { | ||
96 | int ret = request_irq(irqres[clk->bits].start, timer_irq_handler, | ||
97 | IRQF_TIMER, "gtpu", NULL); | ||
98 | if (ret) { | ||
99 | pr_err("gptu: failed to request irq\n"); | ||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | gptu_w32(CON_CNT | CON_EDGE_ANY | CON_SYNC | CON_CLK_INT, | ||
104 | GPTU_CON(clk->bits)); | ||
105 | gptu_w32(1, GPTU_RLD(clk->bits)); | ||
106 | gptu_w32(gptu_r32(GPTU_IRNEN) | BIT(clk->bits), GPTU_IRNEN); | ||
107 | gptu_w32(RUN_SEN | RUN_RL, GPTU_RUN(clk->bits)); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static void gptu_disable(struct clk *clk) | ||
112 | { | ||
113 | gptu_w32(0, GPTU_RUN(clk->bits)); | ||
114 | gptu_w32(0, GPTU_CON(clk->bits)); | ||
115 | gptu_w32(0, GPTU_RLD(clk->bits)); | ||
116 | gptu_w32(gptu_r32(GPTU_IRNEN) & ~BIT(clk->bits), GPTU_IRNEN); | ||
117 | free_irq(irqres[clk->bits].start, NULL); | ||
118 | } | ||
119 | |||
120 | static inline void clkdev_add_gptu(struct device *dev, const char *con, | ||
121 | unsigned int timer) | ||
122 | { | ||
123 | struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | ||
124 | |||
125 | if (!clk) | ||
126 | return; | ||
127 | clk->cl.dev_id = dev_name(dev); | ||
128 | clk->cl.con_id = con; | ||
129 | clk->cl.clk = clk; | ||
130 | clk->enable = gptu_enable; | ||
131 | clk->disable = gptu_disable; | ||
132 | clk->bits = timer; | ||
133 | clkdev_add(&clk->cl); | ||
134 | } | ||
135 | |||
136 | static int gptu_probe(struct platform_device *pdev) | ||
137 | { | ||
138 | struct clk *clk; | ||
139 | struct resource *res; | ||
140 | |||
141 | if (of_irq_to_resource_table(pdev->dev.of_node, irqres, 6) != 6) { | ||
142 | dev_err(&pdev->dev, "Failed to get IRQ list\n"); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | |||
146 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
147 | |||
148 | /* remap gptu register range */ | ||
149 | gptu_membase = devm_ioremap_resource(&pdev->dev, res); | ||
150 | if (IS_ERR(gptu_membase)) | ||
151 | return PTR_ERR(gptu_membase); | ||
152 | |||
153 | /* enable our clock */ | ||
154 | clk = clk_get(&pdev->dev, NULL); | ||
155 | if (IS_ERR(clk)) { | ||
156 | dev_err(&pdev->dev, "Failed to get clock\n"); | ||
157 | return -ENOENT; | ||
158 | } | ||
159 | clk_enable(clk); | ||
160 | |||
161 | /* power up the core */ | ||
162 | gptu_hwinit(); | ||
163 | |||
164 | /* the gptu has a ID register */ | ||
165 | if (((gptu_r32(GPTU_ID) >> 8) & 0xff) != GPTU_MAGIC) { | ||
166 | dev_err(&pdev->dev, "Failed to find magic\n"); | ||
167 | gptu_hwexit(); | ||
168 | clk_disable(clk); | ||
169 | clk_put(clk); | ||
170 | return -ENAVAIL; | ||
171 | } | ||
172 | |||
173 | /* register the clocks */ | ||
174 | clkdev_add_gptu(&pdev->dev, "timer1a", TIMER1A); | ||
175 | clkdev_add_gptu(&pdev->dev, "timer1b", TIMER1B); | ||
176 | clkdev_add_gptu(&pdev->dev, "timer2a", TIMER2A); | ||
177 | clkdev_add_gptu(&pdev->dev, "timer2b", TIMER2B); | ||
178 | clkdev_add_gptu(&pdev->dev, "timer3a", TIMER3A); | ||
179 | clkdev_add_gptu(&pdev->dev, "timer3b", TIMER3B); | ||
180 | |||
181 | dev_info(&pdev->dev, "gptu: 6 timers loaded\n"); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static const struct of_device_id gptu_match[] = { | ||
187 | { .compatible = "lantiq,gptu-xway" }, | ||
188 | {}, | ||
189 | }; | ||
190 | |||
191 | static struct platform_driver dma_driver = { | ||
192 | .probe = gptu_probe, | ||
193 | .driver = { | ||
194 | .name = "gptu-xway", | ||
195 | .of_match_table = gptu_match, | ||
196 | }, | ||
197 | }; | ||
198 | |||
199 | int __init gptu_init(void) | ||
200 | { | ||
201 | int ret = platform_driver_register(&dma_driver); | ||
202 | |||
203 | if (ret) | ||
204 | pr_info("gptu: Error registering platform driver\n"); | ||
205 | return ret; | ||
206 | } | ||
207 | |||
208 | arch_initcall(gptu_init); | ||
diff --git a/arch/mips/lantiq/xway/prom.c b/arch/mips/lantiq/xway/prom.c new file mode 100644 index 000000000..544619754 --- /dev/null +++ b/arch/mips/lantiq/xway/prom.c | |||
@@ -0,0 +1,144 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2010 John Crispin <john@phrozen.org> | ||
5 | * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG | ||
6 | */ | ||
7 | |||
8 | #include <linux/export.h> | ||
9 | #include <linux/clk.h> | ||
10 | #include <asm/bootinfo.h> | ||
11 | #include <asm/time.h> | ||
12 | |||
13 | #include <lantiq_soc.h> | ||
14 | |||
15 | #include "../prom.h" | ||
16 | |||
17 | #define SOC_DANUBE "Danube" | ||
18 | #define SOC_TWINPASS "Twinpass" | ||
19 | #define SOC_AMAZON_SE "Amazon_SE" | ||
20 | #define SOC_AR9 "AR9" | ||
21 | #define SOC_GR9 "GRX200" | ||
22 | #define SOC_VR9 "xRX200" | ||
23 | #define SOC_VRX220 "xRX220" | ||
24 | #define SOC_AR10 "xRX300" | ||
25 | #define SOC_GRX390 "xRX330" | ||
26 | |||
27 | #define COMP_DANUBE "lantiq,danube" | ||
28 | #define COMP_TWINPASS "lantiq,twinpass" | ||
29 | #define COMP_AMAZON_SE "lantiq,ase" | ||
30 | #define COMP_AR9 "lantiq,ar9" | ||
31 | #define COMP_GR9 "lantiq,gr9" | ||
32 | #define COMP_VR9 "lantiq,vr9" | ||
33 | #define COMP_AR10 "lantiq,ar10" | ||
34 | #define COMP_GRX390 "lantiq,grx390" | ||
35 | |||
36 | #define PART_SHIFT 12 | ||
37 | #define PART_MASK 0x0FFFFFFF | ||
38 | #define REV_SHIFT 28 | ||
39 | #define REV_MASK 0xF0000000 | ||
40 | |||
41 | void __init ltq_soc_detect(struct ltq_soc_info *i) | ||
42 | { | ||
43 | i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT; | ||
44 | i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT; | ||
45 | sprintf(i->rev_type, "1.%d", i->rev); | ||
46 | switch (i->partnum) { | ||
47 | case SOC_ID_DANUBE1: | ||
48 | case SOC_ID_DANUBE2: | ||
49 | i->name = SOC_DANUBE; | ||
50 | i->type = SOC_TYPE_DANUBE; | ||
51 | i->compatible = COMP_DANUBE; | ||
52 | break; | ||
53 | |||
54 | case SOC_ID_TWINPASS: | ||
55 | i->name = SOC_TWINPASS; | ||
56 | i->type = SOC_TYPE_DANUBE; | ||
57 | i->compatible = COMP_TWINPASS; | ||
58 | break; | ||
59 | |||
60 | case SOC_ID_ARX188: | ||
61 | case SOC_ID_ARX168_1: | ||
62 | case SOC_ID_ARX168_2: | ||
63 | case SOC_ID_ARX182: | ||
64 | i->name = SOC_AR9; | ||
65 | i->type = SOC_TYPE_AR9; | ||
66 | i->compatible = COMP_AR9; | ||
67 | break; | ||
68 | |||
69 | case SOC_ID_GRX188: | ||
70 | case SOC_ID_GRX168: | ||
71 | i->name = SOC_GR9; | ||
72 | i->type = SOC_TYPE_AR9; | ||
73 | i->compatible = COMP_GR9; | ||
74 | break; | ||
75 | |||
76 | case SOC_ID_AMAZON_SE_1: | ||
77 | case SOC_ID_AMAZON_SE_2: | ||
78 | #ifdef CONFIG_PCI | ||
79 | panic("ase is only supported for non pci kernels"); | ||
80 | #endif | ||
81 | i->name = SOC_AMAZON_SE; | ||
82 | i->type = SOC_TYPE_AMAZON_SE; | ||
83 | i->compatible = COMP_AMAZON_SE; | ||
84 | break; | ||
85 | |||
86 | case SOC_ID_VRX282: | ||
87 | case SOC_ID_VRX268: | ||
88 | case SOC_ID_VRX288: | ||
89 | i->name = SOC_VR9; | ||
90 | i->type = SOC_TYPE_VR9; | ||
91 | i->compatible = COMP_VR9; | ||
92 | break; | ||
93 | |||
94 | case SOC_ID_GRX268: | ||
95 | case SOC_ID_GRX288: | ||
96 | i->name = SOC_GR9; | ||
97 | i->type = SOC_TYPE_VR9; | ||
98 | i->compatible = COMP_GR9; | ||
99 | break; | ||
100 | |||
101 | case SOC_ID_VRX268_2: | ||
102 | case SOC_ID_VRX288_2: | ||
103 | i->name = SOC_VR9; | ||
104 | i->type = SOC_TYPE_VR9_2; | ||
105 | i->compatible = COMP_VR9; | ||
106 | break; | ||
107 | |||
108 | case SOC_ID_VRX220: | ||
109 | i->name = SOC_VRX220; | ||
110 | i->type = SOC_TYPE_VRX220; | ||
111 | i->compatible = COMP_VR9; | ||
112 | break; | ||
113 | |||
114 | case SOC_ID_GRX282_2: | ||
115 | case SOC_ID_GRX288_2: | ||
116 | i->name = SOC_GR9; | ||
117 | i->type = SOC_TYPE_VR9_2; | ||
118 | i->compatible = COMP_GR9; | ||
119 | break; | ||
120 | |||
121 | case SOC_ID_ARX362: | ||
122 | case SOC_ID_ARX368: | ||
123 | case SOC_ID_ARX382: | ||
124 | case SOC_ID_ARX388: | ||
125 | case SOC_ID_URX388: | ||
126 | i->name = SOC_AR10; | ||
127 | i->type = SOC_TYPE_AR10; | ||
128 | i->compatible = COMP_AR10; | ||
129 | break; | ||
130 | |||
131 | case SOC_ID_GRX383: | ||
132 | case SOC_ID_GRX369: | ||
133 | case SOC_ID_GRX387: | ||
134 | case SOC_ID_GRX389: | ||
135 | i->name = SOC_GRX390; | ||
136 | i->type = SOC_TYPE_GRX390; | ||
137 | i->compatible = COMP_GRX390; | ||
138 | break; | ||
139 | |||
140 | default: | ||
141 | unreachable(); | ||
142 | break; | ||
143 | } | ||
144 | } | ||
diff --git a/arch/mips/lantiq/xway/sysctrl.c b/arch/mips/lantiq/xway/sysctrl.c new file mode 100644 index 000000000..084f6caba --- /dev/null +++ b/arch/mips/lantiq/xway/sysctrl.c | |||
@@ -0,0 +1,588 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2011-2012 John Crispin <john@phrozen.org> | ||
5 | * Copyright (C) 2013-2015 Lantiq Beteiligungs-GmbH & Co.KG | ||
6 | */ | ||
7 | |||
8 | #include <linux/ioport.h> | ||
9 | #include <linux/export.h> | ||
10 | #include <linux/clkdev.h> | ||
11 | #include <linux/spinlock.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 for legacy */ | ||
22 | #define CGU_IFCCR 0x0018 | ||
23 | #define CGU_IFCCR_VR9 0x0024 | ||
24 | /* system clock register for legacy */ | ||
25 | #define CGU_SYS 0x0010 | ||
26 | /* pci control register */ | ||
27 | #define CGU_PCICR 0x0034 | ||
28 | #define CGU_PCICR_VR9 0x0038 | ||
29 | /* ephy configuration register */ | ||
30 | #define CGU_EPHY 0x10 | ||
31 | |||
32 | /* Legacy PMU register for ar9, ase, danube */ | ||
33 | /* power control register */ | ||
34 | #define PMU_PWDCR 0x1C | ||
35 | /* power status register */ | ||
36 | #define PMU_PWDSR 0x20 | ||
37 | /* power control register */ | ||
38 | #define PMU_PWDCR1 0x24 | ||
39 | /* power status register */ | ||
40 | #define PMU_PWDSR1 0x28 | ||
41 | /* power control register */ | ||
42 | #define PWDCR(x) ((x) ? (PMU_PWDCR1) : (PMU_PWDCR)) | ||
43 | /* power status register */ | ||
44 | #define PWDSR(x) ((x) ? (PMU_PWDSR1) : (PMU_PWDSR)) | ||
45 | |||
46 | |||
47 | /* PMU register for ar10 and grx390 */ | ||
48 | |||
49 | /* First register set */ | ||
50 | #define PMU_CLK_SR 0x20 /* status */ | ||
51 | #define PMU_CLK_CR_A 0x24 /* Enable */ | ||
52 | #define PMU_CLK_CR_B 0x28 /* Disable */ | ||
53 | /* Second register set */ | ||
54 | #define PMU_CLK_SR1 0x30 /* status */ | ||
55 | #define PMU_CLK_CR1_A 0x34 /* Enable */ | ||
56 | #define PMU_CLK_CR1_B 0x38 /* Disable */ | ||
57 | /* Third register set */ | ||
58 | #define PMU_ANA_SR 0x40 /* status */ | ||
59 | #define PMU_ANA_CR_A 0x44 /* Enable */ | ||
60 | #define PMU_ANA_CR_B 0x48 /* Disable */ | ||
61 | |||
62 | /* Status */ | ||
63 | static u32 pmu_clk_sr[] = { | ||
64 | PMU_CLK_SR, | ||
65 | PMU_CLK_SR1, | ||
66 | PMU_ANA_SR, | ||
67 | }; | ||
68 | |||
69 | /* Enable */ | ||
70 | static u32 pmu_clk_cr_a[] = { | ||
71 | PMU_CLK_CR_A, | ||
72 | PMU_CLK_CR1_A, | ||
73 | PMU_ANA_CR_A, | ||
74 | }; | ||
75 | |||
76 | /* Disable */ | ||
77 | static u32 pmu_clk_cr_b[] = { | ||
78 | PMU_CLK_CR_B, | ||
79 | PMU_CLK_CR1_B, | ||
80 | PMU_ANA_CR_B, | ||
81 | }; | ||
82 | |||
83 | #define PWDCR_EN_XRX(x) (pmu_clk_cr_a[(x)]) | ||
84 | #define PWDCR_DIS_XRX(x) (pmu_clk_cr_b[(x)]) | ||
85 | #define PWDSR_XRX(x) (pmu_clk_sr[(x)]) | ||
86 | |||
87 | /* clock gates that we can en/disable */ | ||
88 | #define PMU_USB0_P BIT(0) | ||
89 | #define PMU_ASE_SDIO BIT(2) /* ASE special */ | ||
90 | #define PMU_PCI BIT(4) | ||
91 | #define PMU_DMA BIT(5) | ||
92 | #define PMU_USB0 BIT(6) | ||
93 | #define PMU_ASC0 BIT(7) | ||
94 | #define PMU_EPHY BIT(7) /* ase */ | ||
95 | #define PMU_USIF BIT(7) /* from vr9 until grx390 */ | ||
96 | #define PMU_SPI BIT(8) | ||
97 | #define PMU_DFE BIT(9) | ||
98 | #define PMU_EBU BIT(10) | ||
99 | #define PMU_STP BIT(11) | ||
100 | #define PMU_GPT BIT(12) | ||
101 | #define PMU_AHBS BIT(13) /* vr9 */ | ||
102 | #define PMU_FPI BIT(14) | ||
103 | #define PMU_AHBM BIT(15) | ||
104 | #define PMU_SDIO BIT(16) /* danube, ar9, vr9 */ | ||
105 | #define PMU_ASC1 BIT(17) | ||
106 | #define PMU_PPE_QSB BIT(18) | ||
107 | #define PMU_PPE_SLL01 BIT(19) | ||
108 | #define PMU_DEU BIT(20) | ||
109 | #define PMU_PPE_TC BIT(21) | ||
110 | #define PMU_PPE_EMA BIT(22) | ||
111 | #define PMU_PPE_DPLUM BIT(23) | ||
112 | #define PMU_PPE_DP BIT(23) | ||
113 | #define PMU_PPE_DPLUS BIT(24) | ||
114 | #define PMU_USB1_P BIT(26) | ||
115 | #define PMU_GPHY3 BIT(26) /* grx390 */ | ||
116 | #define PMU_USB1 BIT(27) | ||
117 | #define PMU_SWITCH BIT(28) | ||
118 | #define PMU_PPE_TOP BIT(29) | ||
119 | #define PMU_GPHY0 BIT(29) /* ar10, xrx390 */ | ||
120 | #define PMU_GPHY BIT(30) | ||
121 | #define PMU_GPHY1 BIT(30) /* ar10, xrx390 */ | ||
122 | #define PMU_PCIE_CLK BIT(31) | ||
123 | #define PMU_GPHY2 BIT(31) /* ar10, xrx390 */ | ||
124 | |||
125 | #define PMU1_PCIE_PHY BIT(0) /* vr9-specific,moved in ar10/grx390 */ | ||
126 | #define PMU1_PCIE_CTL BIT(1) | ||
127 | #define PMU1_PCIE_PDI BIT(4) | ||
128 | #define PMU1_PCIE_MSI BIT(5) | ||
129 | #define PMU1_CKE BIT(6) | ||
130 | #define PMU1_PCIE1_CTL BIT(17) | ||
131 | #define PMU1_PCIE1_PDI BIT(20) | ||
132 | #define PMU1_PCIE1_MSI BIT(21) | ||
133 | #define PMU1_PCIE2_CTL BIT(25) | ||
134 | #define PMU1_PCIE2_PDI BIT(26) | ||
135 | #define PMU1_PCIE2_MSI BIT(27) | ||
136 | |||
137 | #define PMU_ANALOG_USB0_P BIT(0) | ||
138 | #define PMU_ANALOG_USB1_P BIT(1) | ||
139 | #define PMU_ANALOG_PCIE0_P BIT(8) | ||
140 | #define PMU_ANALOG_PCIE1_P BIT(9) | ||
141 | #define PMU_ANALOG_PCIE2_P BIT(10) | ||
142 | #define PMU_ANALOG_DSL_AFE BIT(16) | ||
143 | #define PMU_ANALOG_DCDC_2V5 BIT(17) | ||
144 | #define PMU_ANALOG_DCDC_1VX BIT(18) | ||
145 | #define PMU_ANALOG_DCDC_1V0 BIT(19) | ||
146 | |||
147 | #define pmu_w32(x, y) ltq_w32((x), pmu_membase + (y)) | ||
148 | #define pmu_r32(x) ltq_r32(pmu_membase + (x)) | ||
149 | |||
150 | static void __iomem *pmu_membase; | ||
151 | void __iomem *ltq_cgu_membase; | ||
152 | void __iomem *ltq_ebu_membase; | ||
153 | |||
154 | static u32 ifccr = CGU_IFCCR; | ||
155 | static u32 pcicr = CGU_PCICR; | ||
156 | |||
157 | static DEFINE_SPINLOCK(g_pmu_lock); | ||
158 | |||
159 | /* legacy function kept alive to ease clkdev transition */ | ||
160 | void ltq_pmu_enable(unsigned int module) | ||
161 | { | ||
162 | int retry = 1000000; | ||
163 | |||
164 | spin_lock(&g_pmu_lock); | ||
165 | pmu_w32(pmu_r32(PMU_PWDCR) & ~module, PMU_PWDCR); | ||
166 | do {} while (--retry && (pmu_r32(PMU_PWDSR) & module)); | ||
167 | spin_unlock(&g_pmu_lock); | ||
168 | |||
169 | if (!retry) | ||
170 | panic("activating PMU module failed!"); | ||
171 | } | ||
172 | EXPORT_SYMBOL(ltq_pmu_enable); | ||
173 | |||
174 | /* legacy function kept alive to ease clkdev transition */ | ||
175 | void ltq_pmu_disable(unsigned int module) | ||
176 | { | ||
177 | int retry = 1000000; | ||
178 | |||
179 | spin_lock(&g_pmu_lock); | ||
180 | pmu_w32(pmu_r32(PMU_PWDCR) | module, PMU_PWDCR); | ||
181 | do {} while (--retry && (!(pmu_r32(PMU_PWDSR) & module))); | ||
182 | spin_unlock(&g_pmu_lock); | ||
183 | |||
184 | if (!retry) | ||
185 | pr_warn("deactivating PMU module failed!"); | ||
186 | } | ||
187 | EXPORT_SYMBOL(ltq_pmu_disable); | ||
188 | |||
189 | /* enable a hw clock */ | ||
190 | static int cgu_enable(struct clk *clk) | ||
191 | { | ||
192 | ltq_cgu_w32(ltq_cgu_r32(ifccr) | clk->bits, ifccr); | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | /* disable a hw clock */ | ||
197 | static void cgu_disable(struct clk *clk) | ||
198 | { | ||
199 | ltq_cgu_w32(ltq_cgu_r32(ifccr) & ~clk->bits, ifccr); | ||
200 | } | ||
201 | |||
202 | /* enable a clock gate */ | ||
203 | static int pmu_enable(struct clk *clk) | ||
204 | { | ||
205 | int retry = 1000000; | ||
206 | |||
207 | if (of_machine_is_compatible("lantiq,ar10") | ||
208 | || of_machine_is_compatible("lantiq,grx390")) { | ||
209 | pmu_w32(clk->bits, PWDCR_EN_XRX(clk->module)); | ||
210 | do {} while (--retry && | ||
211 | (!(pmu_r32(PWDSR_XRX(clk->module)) & clk->bits))); | ||
212 | |||
213 | } else { | ||
214 | spin_lock(&g_pmu_lock); | ||
215 | pmu_w32(pmu_r32(PWDCR(clk->module)) & ~clk->bits, | ||
216 | PWDCR(clk->module)); | ||
217 | do {} while (--retry && | ||
218 | (pmu_r32(PWDSR(clk->module)) & clk->bits)); | ||
219 | spin_unlock(&g_pmu_lock); | ||
220 | } | ||
221 | |||
222 | if (!retry) | ||
223 | panic("activating PMU module failed!"); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | /* disable a clock gate */ | ||
229 | static void pmu_disable(struct clk *clk) | ||
230 | { | ||
231 | int retry = 1000000; | ||
232 | |||
233 | if (of_machine_is_compatible("lantiq,ar10") | ||
234 | || of_machine_is_compatible("lantiq,grx390")) { | ||
235 | pmu_w32(clk->bits, PWDCR_DIS_XRX(clk->module)); | ||
236 | do {} while (--retry && | ||
237 | (pmu_r32(PWDSR_XRX(clk->module)) & clk->bits)); | ||
238 | } else { | ||
239 | spin_lock(&g_pmu_lock); | ||
240 | pmu_w32(pmu_r32(PWDCR(clk->module)) | clk->bits, | ||
241 | PWDCR(clk->module)); | ||
242 | do {} while (--retry && | ||
243 | (!(pmu_r32(PWDSR(clk->module)) & clk->bits))); | ||
244 | spin_unlock(&g_pmu_lock); | ||
245 | } | ||
246 | |||
247 | if (!retry) | ||
248 | pr_warn("deactivating PMU module failed!"); | ||
249 | } | ||
250 | |||
251 | /* the pci enable helper */ | ||
252 | static int pci_enable(struct clk *clk) | ||
253 | { | ||
254 | unsigned int val = ltq_cgu_r32(ifccr); | ||
255 | /* set bus clock speed */ | ||
256 | if (of_machine_is_compatible("lantiq,ar9") || | ||
257 | of_machine_is_compatible("lantiq,vr9")) { | ||
258 | val &= ~0x1f00000; | ||
259 | if (clk->rate == CLOCK_33M) | ||
260 | val |= 0xe00000; | ||
261 | else | ||
262 | val |= 0x700000; /* 62.5M */ | ||
263 | } else { | ||
264 | val &= ~0xf00000; | ||
265 | if (clk->rate == CLOCK_33M) | ||
266 | val |= 0x800000; | ||
267 | else | ||
268 | val |= 0x400000; /* 62.5M */ | ||
269 | } | ||
270 | ltq_cgu_w32(val, ifccr); | ||
271 | pmu_enable(clk); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | /* enable the external clock as a source */ | ||
276 | static int pci_ext_enable(struct clk *clk) | ||
277 | { | ||
278 | ltq_cgu_w32(ltq_cgu_r32(ifccr) & ~(1 << 16), ifccr); | ||
279 | ltq_cgu_w32((1 << 30), pcicr); | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | /* disable the external clock as a source */ | ||
284 | static void pci_ext_disable(struct clk *clk) | ||
285 | { | ||
286 | ltq_cgu_w32(ltq_cgu_r32(ifccr) | (1 << 16), ifccr); | ||
287 | ltq_cgu_w32((1 << 31) | (1 << 30), pcicr); | ||
288 | } | ||
289 | |||
290 | /* enable a clockout source */ | ||
291 | static int clkout_enable(struct clk *clk) | ||
292 | { | ||
293 | int i; | ||
294 | |||
295 | /* get the correct rate */ | ||
296 | for (i = 0; i < 4; i++) { | ||
297 | if (clk->rates[i] == clk->rate) { | ||
298 | int shift = 14 - (2 * clk->module); | ||
299 | int enable = 7 - clk->module; | ||
300 | unsigned int val = ltq_cgu_r32(ifccr); | ||
301 | |||
302 | val &= ~(3 << shift); | ||
303 | val |= i << shift; | ||
304 | val |= enable; | ||
305 | ltq_cgu_w32(val, ifccr); | ||
306 | return 0; | ||
307 | } | ||
308 | } | ||
309 | return -1; | ||
310 | } | ||
311 | |||
312 | /* manage the clock gates via PMU */ | ||
313 | static void clkdev_add_pmu(const char *dev, const char *con, bool deactivate, | ||
314 | unsigned int module, unsigned int bits) | ||
315 | { | ||
316 | struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | ||
317 | |||
318 | if (!clk) | ||
319 | return; | ||
320 | clk->cl.dev_id = dev; | ||
321 | clk->cl.con_id = con; | ||
322 | clk->cl.clk = clk; | ||
323 | clk->enable = pmu_enable; | ||
324 | clk->disable = pmu_disable; | ||
325 | clk->module = module; | ||
326 | clk->bits = bits; | ||
327 | if (deactivate) { | ||
328 | /* | ||
329 | * Disable it during the initialization. Module should enable | ||
330 | * when used | ||
331 | */ | ||
332 | pmu_disable(clk); | ||
333 | } | ||
334 | clkdev_add(&clk->cl); | ||
335 | } | ||
336 | |||
337 | /* manage the clock generator */ | ||
338 | static void clkdev_add_cgu(const char *dev, const char *con, | ||
339 | unsigned int bits) | ||
340 | { | ||
341 | struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | ||
342 | |||
343 | if (!clk) | ||
344 | return; | ||
345 | clk->cl.dev_id = dev; | ||
346 | clk->cl.con_id = con; | ||
347 | clk->cl.clk = clk; | ||
348 | clk->enable = cgu_enable; | ||
349 | clk->disable = cgu_disable; | ||
350 | clk->bits = bits; | ||
351 | clkdev_add(&clk->cl); | ||
352 | } | ||
353 | |||
354 | /* pci needs its own enable function as the setup is a bit more complex */ | ||
355 | static unsigned long valid_pci_rates[] = {CLOCK_33M, CLOCK_62_5M, 0}; | ||
356 | |||
357 | static void clkdev_add_pci(void) | ||
358 | { | ||
359 | struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | ||
360 | struct clk *clk_ext = kzalloc(sizeof(struct clk), GFP_KERNEL); | ||
361 | |||
362 | /* main pci clock */ | ||
363 | if (clk) { | ||
364 | clk->cl.dev_id = "17000000.pci"; | ||
365 | clk->cl.con_id = NULL; | ||
366 | clk->cl.clk = clk; | ||
367 | clk->rate = CLOCK_33M; | ||
368 | clk->rates = valid_pci_rates; | ||
369 | clk->enable = pci_enable; | ||
370 | clk->disable = pmu_disable; | ||
371 | clk->module = 0; | ||
372 | clk->bits = PMU_PCI; | ||
373 | clkdev_add(&clk->cl); | ||
374 | } | ||
375 | |||
376 | /* use internal/external bus clock */ | ||
377 | if (clk_ext) { | ||
378 | clk_ext->cl.dev_id = "17000000.pci"; | ||
379 | clk_ext->cl.con_id = "external"; | ||
380 | clk_ext->cl.clk = clk_ext; | ||
381 | clk_ext->enable = pci_ext_enable; | ||
382 | clk_ext->disable = pci_ext_disable; | ||
383 | clkdev_add(&clk_ext->cl); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | /* xway socs can generate clocks on gpio pins */ | ||
388 | static unsigned long valid_clkout_rates[4][5] = { | ||
389 | {CLOCK_32_768K, CLOCK_1_536M, CLOCK_2_5M, CLOCK_12M, 0}, | ||
390 | {CLOCK_40M, CLOCK_12M, CLOCK_24M, CLOCK_48M, 0}, | ||
391 | {CLOCK_25M, CLOCK_40M, CLOCK_30M, CLOCK_60M, 0}, | ||
392 | {CLOCK_12M, CLOCK_50M, CLOCK_32_768K, CLOCK_25M, 0}, | ||
393 | }; | ||
394 | |||
395 | static void clkdev_add_clkout(void) | ||
396 | { | ||
397 | int i; | ||
398 | |||
399 | for (i = 0; i < 4; i++) { | ||
400 | struct clk *clk; | ||
401 | char *name; | ||
402 | |||
403 | name = kzalloc(sizeof("clkout0"), GFP_KERNEL); | ||
404 | if (!name) | ||
405 | continue; | ||
406 | sprintf(name, "clkout%d", i); | ||
407 | |||
408 | clk = kzalloc(sizeof(struct clk), GFP_KERNEL); | ||
409 | if (!clk) { | ||
410 | kfree(name); | ||
411 | continue; | ||
412 | } | ||
413 | clk->cl.dev_id = "1f103000.cgu"; | ||
414 | clk->cl.con_id = name; | ||
415 | clk->cl.clk = clk; | ||
416 | clk->rate = 0; | ||
417 | clk->rates = valid_clkout_rates[i]; | ||
418 | clk->enable = clkout_enable; | ||
419 | clk->module = i; | ||
420 | clkdev_add(&clk->cl); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | /* bring up all register ranges that we need for basic system control */ | ||
425 | void __init ltq_soc_init(void) | ||
426 | { | ||
427 | struct resource res_pmu, res_cgu, res_ebu; | ||
428 | struct device_node *np_pmu = | ||
429 | of_find_compatible_node(NULL, NULL, "lantiq,pmu-xway"); | ||
430 | struct device_node *np_cgu = | ||
431 | of_find_compatible_node(NULL, NULL, "lantiq,cgu-xway"); | ||
432 | struct device_node *np_ebu = | ||
433 | of_find_compatible_node(NULL, NULL, "lantiq,ebu-xway"); | ||
434 | |||
435 | /* check if all the core register ranges are available */ | ||
436 | if (!np_pmu || !np_cgu || !np_ebu) | ||
437 | panic("Failed to load core nodes from devicetree"); | ||
438 | |||
439 | if (of_address_to_resource(np_pmu, 0, &res_pmu) || | ||
440 | of_address_to_resource(np_cgu, 0, &res_cgu) || | ||
441 | of_address_to_resource(np_ebu, 0, &res_ebu)) | ||
442 | panic("Failed to get core resources"); | ||
443 | |||
444 | if (!request_mem_region(res_pmu.start, resource_size(&res_pmu), | ||
445 | res_pmu.name) || | ||
446 | !request_mem_region(res_cgu.start, resource_size(&res_cgu), | ||
447 | res_cgu.name) || | ||
448 | !request_mem_region(res_ebu.start, resource_size(&res_ebu), | ||
449 | res_ebu.name)) | ||
450 | pr_err("Failed to request core resources"); | ||
451 | |||
452 | pmu_membase = ioremap(res_pmu.start, resource_size(&res_pmu)); | ||
453 | ltq_cgu_membase = ioremap(res_cgu.start, | ||
454 | resource_size(&res_cgu)); | ||
455 | ltq_ebu_membase = ioremap(res_ebu.start, | ||
456 | resource_size(&res_ebu)); | ||
457 | if (!pmu_membase || !ltq_cgu_membase || !ltq_ebu_membase) | ||
458 | panic("Failed to remap core resources"); | ||
459 | |||
460 | /* make sure to unprotect the memory region where flash is located */ | ||
461 | ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0); | ||
462 | |||
463 | /* add our generic xway clocks */ | ||
464 | clkdev_add_pmu("10000000.fpi", NULL, 0, 0, PMU_FPI); | ||
465 | clkdev_add_pmu("1e100a00.gptu", NULL, 1, 0, PMU_GPT); | ||
466 | clkdev_add_pmu("1e100bb0.stp", NULL, 1, 0, PMU_STP); | ||
467 | clkdev_add_pmu("1e100c00.serial", NULL, 0, 0, PMU_ASC1); | ||
468 | clkdev_add_pmu("1e104100.dma", NULL, 1, 0, PMU_DMA); | ||
469 | clkdev_add_pmu("1e100800.spi", NULL, 1, 0, PMU_SPI); | ||
470 | clkdev_add_pmu("1e105300.ebu", NULL, 0, 0, PMU_EBU); | ||
471 | clkdev_add_clkout(); | ||
472 | |||
473 | /* add the soc dependent clocks */ | ||
474 | if (of_machine_is_compatible("lantiq,vr9")) { | ||
475 | ifccr = CGU_IFCCR_VR9; | ||
476 | pcicr = CGU_PCICR_VR9; | ||
477 | } else { | ||
478 | clkdev_add_pmu("1e180000.etop", NULL, 1, 0, PMU_PPE); | ||
479 | } | ||
480 | |||
481 | if (!of_machine_is_compatible("lantiq,ase")) | ||
482 | clkdev_add_pci(); | ||
483 | |||
484 | if (of_machine_is_compatible("lantiq,grx390") || | ||
485 | of_machine_is_compatible("lantiq,ar10")) { | ||
486 | clkdev_add_pmu("1e108000.switch", "gphy0", 0, 0, PMU_GPHY0); | ||
487 | clkdev_add_pmu("1e108000.switch", "gphy1", 0, 0, PMU_GPHY1); | ||
488 | clkdev_add_pmu("1e108000.switch", "gphy2", 0, 0, PMU_GPHY2); | ||
489 | clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 2, PMU_ANALOG_USB0_P); | ||
490 | clkdev_add_pmu("1f203034.usb2-phy", "phy", 1, 2, PMU_ANALOG_USB1_P); | ||
491 | /* rc 0 */ | ||
492 | clkdev_add_pmu("1f106800.phy", "phy", 1, 2, PMU_ANALOG_PCIE0_P); | ||
493 | clkdev_add_pmu("1d900000.pcie", "msi", 1, 1, PMU1_PCIE_MSI); | ||
494 | clkdev_add_pmu("1f106800.phy", "pdi", 1, 1, PMU1_PCIE_PDI); | ||
495 | clkdev_add_pmu("1d900000.pcie", "ctl", 1, 1, PMU1_PCIE_CTL); | ||
496 | /* rc 1 */ | ||
497 | clkdev_add_pmu("1f700400.phy", "phy", 1, 2, PMU_ANALOG_PCIE1_P); | ||
498 | clkdev_add_pmu("19000000.pcie", "msi", 1, 1, PMU1_PCIE1_MSI); | ||
499 | clkdev_add_pmu("1f700400.phy", "pdi", 1, 1, PMU1_PCIE1_PDI); | ||
500 | clkdev_add_pmu("19000000.pcie", "ctl", 1, 1, PMU1_PCIE1_CTL); | ||
501 | } | ||
502 | |||
503 | if (of_machine_is_compatible("lantiq,ase")) { | ||
504 | if (ltq_cgu_r32(CGU_SYS) & (1 << 5)) | ||
505 | clkdev_add_static(CLOCK_266M, CLOCK_133M, | ||
506 | CLOCK_133M, CLOCK_266M); | ||
507 | else | ||
508 | clkdev_add_static(CLOCK_133M, CLOCK_133M, | ||
509 | CLOCK_133M, CLOCK_133M); | ||
510 | clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0); | ||
511 | clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 0, PMU_USB0_P); | ||
512 | clkdev_add_pmu("1e180000.etop", "ppe", 1, 0, PMU_PPE); | ||
513 | clkdev_add_cgu("1e180000.etop", "ephycgu", CGU_EPHY); | ||
514 | clkdev_add_pmu("1e180000.etop", "ephy", 1, 0, PMU_EPHY); | ||
515 | clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_ASE_SDIO); | ||
516 | clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); | ||
517 | } else if (of_machine_is_compatible("lantiq,grx390")) { | ||
518 | clkdev_add_static(ltq_grx390_cpu_hz(), ltq_grx390_fpi_hz(), | ||
519 | ltq_grx390_fpi_hz(), ltq_grx390_pp32_hz()); | ||
520 | clkdev_add_pmu("1e108000.switch", "gphy3", 0, 0, PMU_GPHY3); | ||
521 | clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0); | ||
522 | clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1); | ||
523 | /* rc 2 */ | ||
524 | clkdev_add_pmu("1f106a00.pcie", "phy", 1, 2, PMU_ANALOG_PCIE2_P); | ||
525 | clkdev_add_pmu("1a800000.pcie", "msi", 1, 1, PMU1_PCIE2_MSI); | ||
526 | clkdev_add_pmu("1f106a00.pcie", "pdi", 1, 1, PMU1_PCIE2_PDI); | ||
527 | clkdev_add_pmu("1a800000.pcie", "ctl", 1, 1, PMU1_PCIE2_CTL); | ||
528 | clkdev_add_pmu("1e10b308.eth", NULL, 0, 0, PMU_SWITCH | PMU_PPE_DP); | ||
529 | clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); | ||
530 | clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); | ||
531 | } else if (of_machine_is_compatible("lantiq,ar10")) { | ||
532 | clkdev_add_static(ltq_ar10_cpu_hz(), ltq_ar10_fpi_hz(), | ||
533 | ltq_ar10_fpi_hz(), ltq_ar10_pp32_hz()); | ||
534 | clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0); | ||
535 | clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1); | ||
536 | clkdev_add_pmu("1e10b308.eth", NULL, 0, 0, PMU_SWITCH | | ||
537 | PMU_PPE_DP | PMU_PPE_TC); | ||
538 | clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); | ||
539 | clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); | ||
540 | clkdev_add_pmu("1e116000.mei", "afe", 1, 2, PMU_ANALOG_DSL_AFE); | ||
541 | clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); | ||
542 | } else if (of_machine_is_compatible("lantiq,vr9")) { | ||
543 | clkdev_add_static(ltq_vr9_cpu_hz(), ltq_vr9_fpi_hz(), | ||
544 | ltq_vr9_fpi_hz(), ltq_vr9_pp32_hz()); | ||
545 | clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 0, PMU_USB0_P); | ||
546 | clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0 | PMU_AHBM); | ||
547 | clkdev_add_pmu("1f203034.usb2-phy", "phy", 1, 0, PMU_USB1_P); | ||
548 | clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1 | PMU_AHBM); | ||
549 | clkdev_add_pmu("1f106800.phy", "phy", 1, 1, PMU1_PCIE_PHY); | ||
550 | clkdev_add_pmu("1d900000.pcie", "bus", 1, 0, PMU_PCIE_CLK); | ||
551 | clkdev_add_pmu("1d900000.pcie", "msi", 1, 1, PMU1_PCIE_MSI); | ||
552 | clkdev_add_pmu("1f106800.phy", "pdi", 1, 1, PMU1_PCIE_PDI); | ||
553 | clkdev_add_pmu("1d900000.pcie", "ctl", 1, 1, PMU1_PCIE_CTL); | ||
554 | clkdev_add_pmu(NULL, "ahb", 1, 0, PMU_AHBM | PMU_AHBS); | ||
555 | |||
556 | clkdev_add_pmu("1da00000.usif", "NULL", 1, 0, PMU_USIF); | ||
557 | clkdev_add_pmu("1e10b308.eth", NULL, 0, 0, | ||
558 | PMU_SWITCH | PMU_PPE_DPLUS | PMU_PPE_DPLUM | | ||
559 | PMU_PPE_EMA | PMU_PPE_TC | PMU_PPE_SLL01 | | ||
560 | PMU_PPE_QSB | PMU_PPE_TOP); | ||
561 | clkdev_add_pmu("1e108000.switch", "gphy0", 0, 0, PMU_GPHY); | ||
562 | clkdev_add_pmu("1e108000.switch", "gphy1", 0, 0, PMU_GPHY); | ||
563 | clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO); | ||
564 | clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); | ||
565 | clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); | ||
566 | } else if (of_machine_is_compatible("lantiq,ar9")) { | ||
567 | clkdev_add_static(ltq_ar9_cpu_hz(), ltq_ar9_fpi_hz(), | ||
568 | ltq_ar9_fpi_hz(), CLOCK_250M); | ||
569 | clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 0, PMU_USB0_P); | ||
570 | clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0 | PMU_AHBM); | ||
571 | clkdev_add_pmu("1f203034.usb2-phy", "phy", 1, 0, PMU_USB1_P); | ||
572 | clkdev_add_pmu("1e106000.usb", "otg", 1, 0, PMU_USB1 | PMU_AHBM); | ||
573 | clkdev_add_pmu("1e180000.etop", "switch", 1, 0, PMU_SWITCH); | ||
574 | clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO); | ||
575 | clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); | ||
576 | clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); | ||
577 | clkdev_add_pmu("1e100400.serial", NULL, 1, 0, PMU_ASC0); | ||
578 | } else { | ||
579 | clkdev_add_static(ltq_danube_cpu_hz(), ltq_danube_fpi_hz(), | ||
580 | ltq_danube_fpi_hz(), ltq_danube_pp32_hz()); | ||
581 | clkdev_add_pmu("1e101000.usb", "otg", 1, 0, PMU_USB0 | PMU_AHBM); | ||
582 | clkdev_add_pmu("1f203018.usb2-phy", "phy", 1, 0, PMU_USB0_P); | ||
583 | clkdev_add_pmu("1e103000.sdio", NULL, 1, 0, PMU_SDIO); | ||
584 | clkdev_add_pmu("1e103100.deu", NULL, 1, 0, PMU_DEU); | ||
585 | clkdev_add_pmu("1e116000.mei", "dfe", 1, 0, PMU_DFE); | ||
586 | clkdev_add_pmu("1e100400.serial", NULL, 1, 0, PMU_ASC0); | ||
587 | } | ||
588 | } | ||
diff --git a/arch/mips/lantiq/xway/vmmc.c b/arch/mips/lantiq/xway/vmmc.c new file mode 100644 index 000000000..7a14da8d9 --- /dev/null +++ b/arch/mips/lantiq/xway/vmmc.c | |||
@@ -0,0 +1,64 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0-only | ||
2 | /* | ||
3 | * | ||
4 | * Copyright (C) 2012 John Crispin <john@phrozen.org> | ||
5 | */ | ||
6 | |||
7 | #include <linux/export.h> | ||
8 | #include <linux/of_platform.h> | ||
9 | #include <linux/of_gpio.h> | ||
10 | #include <linux/dma-mapping.h> | ||
11 | |||
12 | #include <lantiq_soc.h> | ||
13 | |||
14 | static unsigned int *cp1_base; | ||
15 | |||
16 | unsigned int *ltq_get_cp1_base(void) | ||
17 | { | ||
18 | if (!cp1_base) | ||
19 | panic("no cp1 base was set\n"); | ||
20 | |||
21 | return cp1_base; | ||
22 | } | ||
23 | EXPORT_SYMBOL(ltq_get_cp1_base); | ||
24 | |||
25 | static int vmmc_probe(struct platform_device *pdev) | ||
26 | { | ||
27 | #define CP1_SIZE (1 << 20) | ||
28 | int gpio_count; | ||
29 | dma_addr_t dma; | ||
30 | |||
31 | cp1_base = | ||
32 | (void *) CPHYSADDR(dma_alloc_coherent(&pdev->dev, CP1_SIZE, | ||
33 | &dma, GFP_KERNEL)); | ||
34 | |||
35 | gpio_count = of_gpio_count(pdev->dev.of_node); | ||
36 | while (gpio_count > 0) { | ||
37 | enum of_gpio_flags flags; | ||
38 | int gpio = of_get_gpio_flags(pdev->dev.of_node, | ||
39 | --gpio_count, &flags); | ||
40 | if (gpio_request(gpio, "vmmc-relay")) | ||
41 | continue; | ||
42 | dev_info(&pdev->dev, "requested GPIO %d\n", gpio); | ||
43 | gpio_direction_output(gpio, | ||
44 | (flags & OF_GPIO_ACTIVE_LOW) ? (0) : (1)); | ||
45 | } | ||
46 | |||
47 | dev_info(&pdev->dev, "reserved %dMB at 0x%p", CP1_SIZE >> 20, cp1_base); | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static const struct of_device_id vmmc_match[] = { | ||
53 | { .compatible = "lantiq,vmmc-xway" }, | ||
54 | {}, | ||
55 | }; | ||
56 | |||
57 | static struct platform_driver vmmc_driver = { | ||
58 | .probe = vmmc_probe, | ||
59 | .driver = { | ||
60 | .name = "lantiq,vmmc", | ||
61 | .of_match_table = vmmc_match, | ||
62 | }, | ||
63 | }; | ||
64 | builtin_platform_driver(vmmc_driver); | ||