8f5f929128768750426f6de8455ff8bfa7ea9c3b
[openwrt/openwrt.git] / target / linux / lantiq / patches-2.6.39 / 0002-MIPS-Lantiq-add-SoC-specific-code-for-XWAY-family.patch
1 From 36cc26a362c6ad64ba3d176809847ec60cc40859 Mon Sep 17 00:00:00 2001
2 From: John Crispin <blogic@openwrt.org>
3 Date: Wed, 30 Mar 2011 09:27:48 +0200
4 Subject: [PATCH 02/13] MIPS: Lantiq: add SoC specific code for XWAY family
5
6 Add support for the Lantiq XWAY family of Mips24KEc SoCs.
7
8 * Danube (PSB50702)
9 * Twinpass (PSB4000)
10 * AR9 (PSB50802)
11 * Amazon SE (PSB5061)
12
13 The Amazon SE is a lightweight SoC and has no PCI as well as a different
14 clock. We split the code out into seperate files to handle this.
15
16 The GPIO pins on the SoCs are multi function and there are several bits
17 we can use to configure the pins. To be as compatible as possible to
18 GPIOLIB we add a function
19
20 int ltq_gpio_request(unsigned int pin, unsigned int alt0,
21 unsigned int alt1, unsigned int dir, const char *name);
22
23 which lets you configure the 2 "alternate function" bits. This way drivers like
24 PCI can make use of GPIOLIB without a cubersome wrapper.
25
26 The PLL code inside arch/mips/lantiq/xway/clk-xway.c is voodoo to me. It was
27 taken from a 2.4.20 source tree and was never really changed by me since then.
28
29 Signed-off-by: John Crispin <blogic@openwrt.org>
30 Signed-off-by: Ralph Hempel <ralph.hempel@lantiq.com>
31 Cc: linux-mips@linux-mips.org
32 Patchwork: https://patchwork.linux-mips.org/patch/2249/
33 Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
34 ---
35 arch/mips/Kconfig | 1 +
36 arch/mips/include/asm/mach-lantiq/xway/irq.h | 18 ++
37 .../mips/include/asm/mach-lantiq/xway/lantiq_irq.h | 66 ++++++
38 .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h | 140 ++++++++++++
39 arch/mips/lantiq/Kconfig | 21 ++
40 arch/mips/lantiq/Makefile | 2 +
41 arch/mips/lantiq/Platform | 1 +
42 arch/mips/lantiq/xway/Makefile | 4 +
43 arch/mips/lantiq/xway/clk-ase.c | 48 +++++
44 arch/mips/lantiq/xway/clk-xway.c | 223 ++++++++++++++++++++
45 arch/mips/lantiq/xway/ebu.c | 53 +++++
46 arch/mips/lantiq/xway/gpio.c | 195 +++++++++++++++++
47 arch/mips/lantiq/xway/pmu.c | 70 ++++++
48 arch/mips/lantiq/xway/prom-ase.c | 39 ++++
49 arch/mips/lantiq/xway/prom-xway.c | 54 +++++
50 arch/mips/lantiq/xway/reset.c | 91 ++++++++
51 16 files changed, 1026 insertions(+), 0 deletions(-)
52 create mode 100644 arch/mips/include/asm/mach-lantiq/xway/irq.h
53 create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
54 create mode 100644 arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
55 create mode 100644 arch/mips/lantiq/Kconfig
56 create mode 100644 arch/mips/lantiq/xway/Makefile
57 create mode 100644 arch/mips/lantiq/xway/clk-ase.c
58 create mode 100644 arch/mips/lantiq/xway/clk-xway.c
59 create mode 100644 arch/mips/lantiq/xway/ebu.c
60 create mode 100644 arch/mips/lantiq/xway/gpio.c
61 create mode 100644 arch/mips/lantiq/xway/pmu.c
62 create mode 100644 arch/mips/lantiq/xway/prom-ase.c
63 create mode 100644 arch/mips/lantiq/xway/prom-xway.c
64 create mode 100644 arch/mips/lantiq/xway/reset.c
65
66 --- a/arch/mips/Kconfig
67 +++ b/arch/mips/Kconfig
68 @@ -760,6 +760,7 @@ source "arch/mips/ath79/Kconfig"
69 source "arch/mips/bcm63xx/Kconfig"
70 source "arch/mips/jazz/Kconfig"
71 source "arch/mips/jz4740/Kconfig"
72 +source "arch/mips/lantiq/Kconfig"
73 source "arch/mips/lasat/Kconfig"
74 source "arch/mips/pmc-sierra/Kconfig"
75 source "arch/mips/powertv/Kconfig"
76 --- /dev/null
77 +++ b/arch/mips/include/asm/mach-lantiq/xway/irq.h
78 @@ -0,0 +1,18 @@
79 +/*
80 + * This program is free software; you can redistribute it and/or modify it
81 + * under the terms of the GNU General Public License version 2 as published
82 + * by the Free Software Foundation.
83 + *
84 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
85 + */
86 +
87 +#ifndef __LANTIQ_IRQ_H
88 +#define __LANTIQ_IRQ_H
89 +
90 +#include <lantiq_irq.h>
91 +
92 +#define NR_IRQS 256
93 +
94 +#include_next <irq.h>
95 +
96 +#endif
97 --- /dev/null
98 +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_irq.h
99 @@ -0,0 +1,66 @@
100 +/*
101 + * This program is free software; you can redistribute it and/or modify it
102 + * under the terms of the GNU General Public License version 2 as published
103 + * by the Free Software Foundation.
104 + *
105 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
106 + */
107 +
108 +#ifndef _LANTIQ_XWAY_IRQ_H__
109 +#define _LANTIQ_XWAY_IRQ_H__
110 +
111 +#define INT_NUM_IRQ0 8
112 +#define INT_NUM_IM0_IRL0 (INT_NUM_IRQ0 + 0)
113 +#define INT_NUM_IM1_IRL0 (INT_NUM_IRQ0 + 32)
114 +#define INT_NUM_IM2_IRL0 (INT_NUM_IRQ0 + 64)
115 +#define INT_NUM_IM3_IRL0 (INT_NUM_IRQ0 + 96)
116 +#define INT_NUM_IM4_IRL0 (INT_NUM_IRQ0 + 128)
117 +#define INT_NUM_IM_OFFSET (INT_NUM_IM1_IRL0 - INT_NUM_IM0_IRL0)
118 +
119 +#define LTQ_ASC_TIR(x) (INT_NUM_IM3_IRL0 + (x * 8))
120 +#define LTQ_ASC_RIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 1)
121 +#define LTQ_ASC_EIR(x) (INT_NUM_IM3_IRL0 + (x * 8) + 2)
122 +
123 +#define LTQ_ASC_ASE_TIR INT_NUM_IM2_IRL0
124 +#define LTQ_ASC_ASE_RIR (INT_NUM_IM2_IRL0 + 2)
125 +#define LTQ_ASC_ASE_EIR (INT_NUM_IM2_IRL0 + 3)
126 +
127 +#define LTQ_SSC_TIR (INT_NUM_IM0_IRL0 + 15)
128 +#define LTQ_SSC_RIR (INT_NUM_IM0_IRL0 + 14)
129 +#define LTQ_SSC_EIR (INT_NUM_IM0_IRL0 + 16)
130 +
131 +#define LTQ_MEI_DYING_GASP_INT (INT_NUM_IM1_IRL0 + 21)
132 +#define LTQ_MEI_INT (INT_NUM_IM1_IRL0 + 23)
133 +
134 +#define LTQ_TIMER6_INT (INT_NUM_IM1_IRL0 + 23)
135 +#define LTQ_USB_INT (INT_NUM_IM1_IRL0 + 22)
136 +#define LTQ_USB_OC_INT (INT_NUM_IM4_IRL0 + 23)
137 +
138 +#define MIPS_CPU_TIMER_IRQ 7
139 +
140 +#define LTQ_DMA_CH0_INT (INT_NUM_IM2_IRL0)
141 +#define LTQ_DMA_CH1_INT (INT_NUM_IM2_IRL0 + 1)
142 +#define LTQ_DMA_CH2_INT (INT_NUM_IM2_IRL0 + 2)
143 +#define LTQ_DMA_CH3_INT (INT_NUM_IM2_IRL0 + 3)
144 +#define LTQ_DMA_CH4_INT (INT_NUM_IM2_IRL0 + 4)
145 +#define LTQ_DMA_CH5_INT (INT_NUM_IM2_IRL0 + 5)
146 +#define LTQ_DMA_CH6_INT (INT_NUM_IM2_IRL0 + 6)
147 +#define LTQ_DMA_CH7_INT (INT_NUM_IM2_IRL0 + 7)
148 +#define LTQ_DMA_CH8_INT (INT_NUM_IM2_IRL0 + 8)
149 +#define LTQ_DMA_CH9_INT (INT_NUM_IM2_IRL0 + 9)
150 +#define LTQ_DMA_CH10_INT (INT_NUM_IM2_IRL0 + 10)
151 +#define LTQ_DMA_CH11_INT (INT_NUM_IM2_IRL0 + 11)
152 +#define LTQ_DMA_CH12_INT (INT_NUM_IM2_IRL0 + 25)
153 +#define LTQ_DMA_CH13_INT (INT_NUM_IM2_IRL0 + 26)
154 +#define LTQ_DMA_CH14_INT (INT_NUM_IM2_IRL0 + 27)
155 +#define LTQ_DMA_CH15_INT (INT_NUM_IM2_IRL0 + 28)
156 +#define LTQ_DMA_CH16_INT (INT_NUM_IM2_IRL0 + 29)
157 +#define LTQ_DMA_CH17_INT (INT_NUM_IM2_IRL0 + 30)
158 +#define LTQ_DMA_CH18_INT (INT_NUM_IM2_IRL0 + 16)
159 +#define LTQ_DMA_CH19_INT (INT_NUM_IM2_IRL0 + 21)
160 +
161 +#define LTQ_PPE_MBOX_INT (INT_NUM_IM2_IRL0 + 24)
162 +
163 +#define INT_NUM_IM4_IRL14 (INT_NUM_IM4_IRL0 + 14)
164 +
165 +#endif
166 --- /dev/null
167 +++ b/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
168 @@ -0,0 +1,140 @@
169 +/*
170 + * This program is free software; you can redistribute it and/or modify it
171 + * under the terms of the GNU General Public License version 2 as published
172 + * by the Free Software Foundation.
173 + *
174 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
175 + */
176 +
177 +#ifndef _LTQ_XWAY_H__
178 +#define _LTQ_XWAY_H__
179 +
180 +#ifdef CONFIG_SOC_TYPE_XWAY
181 +
182 +#include <lantiq.h>
183 +
184 +/* Chip IDs */
185 +#define SOC_ID_DANUBE1 0x129
186 +#define SOC_ID_DANUBE2 0x12B
187 +#define SOC_ID_TWINPASS 0x12D
188 +#define SOC_ID_AMAZON_SE 0x152
189 +#define SOC_ID_ARX188 0x16C
190 +#define SOC_ID_ARX168 0x16D
191 +#define SOC_ID_ARX182 0x16F
192 +
193 +/* SoC Types */
194 +#define SOC_TYPE_DANUBE 0x01
195 +#define SOC_TYPE_TWINPASS 0x02
196 +#define SOC_TYPE_AR9 0x03
197 +#define SOC_TYPE_VR9 0x04
198 +#define SOC_TYPE_AMAZON_SE 0x05
199 +
200 +/* ASC0/1 - serial port */
201 +#define LTQ_ASC0_BASE_ADDR 0x1E100400
202 +#define LTQ_ASC1_BASE_ADDR 0x1E100C00
203 +#define LTQ_ASC_SIZE 0x400
204 +
205 +/* RCU - reset control unit */
206 +#define LTQ_RCU_BASE_ADDR 0x1F203000
207 +#define LTQ_RCU_SIZE 0x1000
208 +
209 +/* GPTU - general purpose timer unit */
210 +#define LTQ_GPTU_BASE_ADDR 0x18000300
211 +#define LTQ_GPTU_SIZE 0x100
212 +
213 +/* EBU - external bus unit */
214 +#define LTQ_EBU_GPIO_START 0x14000000
215 +#define LTQ_EBU_GPIO_SIZE 0x1000
216 +
217 +#define LTQ_EBU_BASE_ADDR 0x1E105300
218 +#define LTQ_EBU_SIZE 0x100
219 +
220 +#define LTQ_EBU_BUSCON0 0x0060
221 +#define LTQ_EBU_PCC_CON 0x0090
222 +#define LTQ_EBU_PCC_IEN 0x00A4
223 +#define LTQ_EBU_PCC_ISTAT 0x00A0
224 +#define LTQ_EBU_BUSCON1 0x0064
225 +#define LTQ_EBU_ADDRSEL1 0x0024
226 +#define EBU_WRDIS 0x80000000
227 +
228 +/* CGU - clock generation unit */
229 +#define LTQ_CGU_BASE_ADDR 0x1F103000
230 +#define LTQ_CGU_SIZE 0x1000
231 +
232 +/* ICU - interrupt control unit */
233 +#define LTQ_ICU_BASE_ADDR 0x1F880200
234 +#define LTQ_ICU_SIZE 0x100
235 +
236 +/* EIU - external interrupt unit */
237 +#define LTQ_EIU_BASE_ADDR 0x1F101000
238 +#define LTQ_EIU_SIZE 0x1000
239 +
240 +/* PMU - power management unit */
241 +#define LTQ_PMU_BASE_ADDR 0x1F102000
242 +#define LTQ_PMU_SIZE 0x1000
243 +
244 +#define PMU_DMA 0x0020
245 +#define PMU_USB 0x8041
246 +#define PMU_LED 0x0800
247 +#define PMU_GPT 0x1000
248 +#define PMU_PPE 0x2000
249 +#define PMU_FPI 0x4000
250 +#define PMU_SWITCH 0x10000000
251 +
252 +/* ETOP - ethernet */
253 +#define LTQ_PPE32_BASE_ADDR 0xBE180000
254 +#define LTQ_PPE32_SIZE 0x40000
255 +
256 +/* DMA */
257 +#define LTQ_DMA_BASE_ADDR 0xBE104100
258 +
259 +/* PCI */
260 +#define PCI_CR_BASE_ADDR 0x1E105400
261 +#define PCI_CR_SIZE 0x400
262 +
263 +/* WDT */
264 +#define LTQ_WDT_BASE_ADDR 0x1F8803F0
265 +#define LTQ_WDT_SIZE 0x10
266 +
267 +/* STP - serial to parallel conversion unit */
268 +#define LTQ_STP_BASE_ADDR 0x1E100BB0
269 +#define LTQ_STP_SIZE 0x40
270 +
271 +/* GPIO */
272 +#define LTQ_GPIO0_BASE_ADDR 0x1E100B10
273 +#define LTQ_GPIO1_BASE_ADDR 0x1E100B40
274 +#define LTQ_GPIO2_BASE_ADDR 0x1E100B70
275 +#define LTQ_GPIO_SIZE 0x30
276 +
277 +/* SSC */
278 +#define LTQ_SSC_BASE_ADDR 0x1e100800
279 +#define LTQ_SSC_SIZE 0x100
280 +
281 +/* MEI - dsl core */
282 +#define LTQ_MEI_BASE_ADDR 0x1E116000
283 +
284 +/* DEU - data encryption unit */
285 +#define LTQ_DEU_BASE_ADDR 0x1E103100
286 +
287 +/* MPS - multi processor unit (voice) */
288 +#define LTQ_MPS_BASE_ADDR (KSEG1 + 0x1F107000)
289 +#define LTQ_MPS_CHIPID ((u32 *)(LTQ_MPS_BASE_ADDR + 0x0344))
290 +
291 +/* request a non-gpio and set the PIO config */
292 +extern int ltq_gpio_request(unsigned int pin, unsigned int alt0,
293 + unsigned int alt1, unsigned int dir, const char *name);
294 +extern void ltq_pmu_enable(unsigned int module);
295 +extern void ltq_pmu_disable(unsigned int module);
296 +
297 +static inline int ltq_is_ar9(void)
298 +{
299 + return (ltq_get_soc_type() == SOC_TYPE_AR9);
300 +}
301 +
302 +static inline int ltq_is_vr9(void)
303 +{
304 + return (ltq_get_soc_type() == SOC_TYPE_VR9);
305 +}
306 +
307 +#endif /* CONFIG_SOC_TYPE_XWAY */
308 +#endif /* _LTQ_XWAY_H__ */
309 --- /dev/null
310 +++ b/arch/mips/lantiq/Kconfig
311 @@ -0,0 +1,21 @@
312 +if LANTIQ
313 +
314 +config SOC_TYPE_XWAY
315 + bool
316 + default n
317 +
318 +choice
319 + prompt "SoC Type"
320 + default SOC_XWAY
321 +
322 +config SOC_AMAZON_SE
323 + bool "Amazon SE"
324 + select SOC_TYPE_XWAY
325 +
326 +config SOC_XWAY
327 + bool "XWAY"
328 + select SOC_TYPE_XWAY
329 + select HW_HAS_PCI
330 +endchoice
331 +
332 +endif
333 --- a/arch/mips/lantiq/Makefile
334 +++ b/arch/mips/lantiq/Makefile
335 @@ -7,3 +7,5 @@
336 obj-y := irq.o setup.o clk.o prom.o
337
338 obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
339 +
340 +obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
341 --- a/arch/mips/lantiq/Platform
342 +++ b/arch/mips/lantiq/Platform
343 @@ -5,3 +5,4 @@
344 platform-$(CONFIG_LANTIQ) += lantiq/
345 cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
346 load-$(CONFIG_LANTIQ) = 0xffffffff80002000
347 +cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
348 --- /dev/null
349 +++ b/arch/mips/lantiq/xway/Makefile
350 @@ -0,0 +1,4 @@
351 +obj-y := pmu.o ebu.o reset.o gpio.o
352 +
353 +obj-$(CONFIG_SOC_XWAY) += clk-xway.o prom-xway.o
354 +obj-$(CONFIG_SOC_AMAZON_SE) += clk-ase.o prom-ase.o
355 --- /dev/null
356 +++ b/arch/mips/lantiq/xway/clk-ase.c
357 @@ -0,0 +1,48 @@
358 +/*
359 + * This program is free software; you can redistribute it and/or modify it
360 + * under the terms of the GNU General Public License version 2 as published
361 + * by the Free Software Foundation.
362 + *
363 + * Copyright (C) 2011 John Crispin <blogic@openwrt.org>
364 + */
365 +
366 +#include <linux/io.h>
367 +#include <linux/module.h>
368 +#include <linux/init.h>
369 +#include <linux/clk.h>
370 +
371 +#include <asm/time.h>
372 +#include <asm/irq.h>
373 +#include <asm/div64.h>
374 +
375 +#include <lantiq_soc.h>
376 +
377 +/* cgu registers */
378 +#define LTQ_CGU_SYS 0x0010
379 +
380 +unsigned int ltq_get_io_region_clock(void)
381 +{
382 + return CLOCK_133M;
383 +}
384 +EXPORT_SYMBOL(ltq_get_io_region_clock);
385 +
386 +unsigned int ltq_get_fpi_bus_clock(int fpi)
387 +{
388 + return CLOCK_133M;
389 +}
390 +EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
391 +
392 +unsigned int ltq_get_cpu_hz(void)
393 +{
394 + if (ltq_cgu_r32(LTQ_CGU_SYS) & (1 << 5))
395 + return CLOCK_266M;
396 + else
397 + return CLOCK_133M;
398 +}
399 +EXPORT_SYMBOL(ltq_get_cpu_hz);
400 +
401 +unsigned int ltq_get_fpi_hz(void)
402 +{
403 + return CLOCK_133M;
404 +}
405 +EXPORT_SYMBOL(ltq_get_fpi_hz);
406 --- /dev/null
407 +++ b/arch/mips/lantiq/xway/clk-xway.c
408 @@ -0,0 +1,223 @@
409 +/*
410 + * This program is free software; you can redistribute it and/or modify it
411 + * under the terms of the GNU General Public License version 2 as published
412 + * by the Free Software Foundation.
413 + *
414 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
415 + */
416 +
417 +#include <linux/io.h>
418 +#include <linux/module.h>
419 +#include <linux/init.h>
420 +#include <linux/clk.h>
421 +
422 +#include <asm/time.h>
423 +#include <asm/irq.h>
424 +#include <asm/div64.h>
425 +
426 +#include <lantiq_soc.h>
427 +
428 +static unsigned int ltq_ram_clocks[] = {
429 + CLOCK_167M, CLOCK_133M, CLOCK_111M, CLOCK_83M };
430 +#define DDR_HZ ltq_ram_clocks[ltq_cgu_r32(LTQ_CGU_SYS) & 0x3]
431 +
432 +#define BASIC_FREQUENCY_1 35328000
433 +#define BASIC_FREQUENCY_2 36000000
434 +#define BASIS_REQUENCY_USB 12000000
435 +
436 +#define GET_BITS(x, msb, lsb) \
437 + (((x) & ((1 << ((msb) + 1)) - 1)) >> (lsb))
438 +
439 +#define LTQ_CGU_PLL0_CFG 0x0004
440 +#define LTQ_CGU_PLL1_CFG 0x0008
441 +#define LTQ_CGU_PLL2_CFG 0x000C
442 +#define LTQ_CGU_SYS 0x0010
443 +#define LTQ_CGU_UPDATE 0x0014
444 +#define LTQ_CGU_IF_CLK 0x0018
445 +#define LTQ_CGU_OSC_CON 0x001C
446 +#define LTQ_CGU_SMD 0x0020
447 +#define LTQ_CGU_CT1SR 0x0028
448 +#define LTQ_CGU_CT2SR 0x002C
449 +#define LTQ_CGU_PCMCR 0x0030
450 +#define LTQ_CGU_PCI_CR 0x0034
451 +#define LTQ_CGU_PD_PC 0x0038
452 +#define LTQ_CGU_FMR 0x003C
453 +
454 +#define CGU_PLL0_PHASE_DIVIDER_ENABLE \
455 + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 31))
456 +#define CGU_PLL0_BYPASS \
457 + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 30))
458 +#define CGU_PLL0_CFG_DSMSEL \
459 + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 28))
460 +#define CGU_PLL0_CFG_FRAC_EN \
461 + (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & (1 << 27))
462 +#define CGU_PLL1_SRC \
463 + (ltq_cgu_r32(LTQ_CGU_PLL1_CFG) & (1 << 31))
464 +#define CGU_PLL2_PHASE_DIVIDER_ENABLE \
465 + (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & (1 << 20))
466 +#define CGU_SYS_FPI_SEL (1 << 6)
467 +#define CGU_SYS_DDR_SEL 0x3
468 +#define CGU_PLL0_SRC (1 << 29)
469 +
470 +#define CGU_PLL0_CFG_PLLK GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 26, 17)
471 +#define CGU_PLL0_CFG_PLLN GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 12, 6)
472 +#define CGU_PLL0_CFG_PLLM GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL0_CFG), 5, 2)
473 +#define CGU_PLL2_SRC GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 18, 17)
474 +#define CGU_PLL2_CFG_INPUT_DIV GET_BITS(ltq_cgu_r32(LTQ_CGU_PLL2_CFG), 16, 13)
475 +
476 +static unsigned int ltq_get_pll0_fdiv(void);
477 +
478 +static inline unsigned int get_input_clock(int pll)
479 +{
480 + switch (pll) {
481 + case 0:
482 + if (ltq_cgu_r32(LTQ_CGU_PLL0_CFG) & CGU_PLL0_SRC)
483 + return BASIS_REQUENCY_USB;
484 + else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
485 + return BASIC_FREQUENCY_1;
486 + else
487 + return BASIC_FREQUENCY_2;
488 + case 1:
489 + if (CGU_PLL1_SRC)
490 + return BASIS_REQUENCY_USB;
491 + else if (CGU_PLL0_PHASE_DIVIDER_ENABLE)
492 + return BASIC_FREQUENCY_1;
493 + else
494 + return BASIC_FREQUENCY_2;
495 + case 2:
496 + switch (CGU_PLL2_SRC) {
497 + case 0:
498 + return ltq_get_pll0_fdiv();
499 + case 1:
500 + return CGU_PLL2_PHASE_DIVIDER_ENABLE ?
501 + BASIC_FREQUENCY_1 :
502 + BASIC_FREQUENCY_2;
503 + case 2:
504 + return BASIS_REQUENCY_USB;
505 + }
506 + default:
507 + return 0;
508 + }
509 +}
510 +
511 +static inline unsigned int cal_dsm(int pll, unsigned int num, unsigned int den)
512 +{
513 + u64 res, clock = get_input_clock(pll);
514 +
515 + res = num * clock;
516 + do_div(res, den);
517 + return res;
518 +}
519 +
520 +static inline unsigned int mash_dsm(int pll, unsigned int M, unsigned int N,
521 + unsigned int K)
522 +{
523 + unsigned int num = ((N + 1) << 10) + K;
524 + unsigned int den = (M + 1) << 10;
525 +
526 + return cal_dsm(pll, num, den);
527 +}
528 +
529 +static inline unsigned int ssff_dsm_1(int pll, unsigned int M, unsigned int N,
530 + unsigned int K)
531 +{
532 + unsigned int num = ((N + 1) << 11) + K + 512;
533 + unsigned int den = (M + 1) << 11;
534 +
535 + return cal_dsm(pll, num, den);
536 +}
537 +
538 +static inline unsigned int ssff_dsm_2(int pll, unsigned int M, unsigned int N,
539 + unsigned int K)
540 +{
541 + unsigned int num = K >= 512 ?
542 + ((N + 1) << 12) + K - 512 : ((N + 1) << 12) + K + 3584;
543 + unsigned int den = (M + 1) << 12;
544 +
545 + return cal_dsm(pll, num, den);
546 +}
547 +
548 +static inline unsigned int dsm(int pll, unsigned int M, unsigned int N,
549 + unsigned int K, unsigned int dsmsel, unsigned int phase_div_en)
550 +{
551 + if (!dsmsel)
552 + return mash_dsm(pll, M, N, K);
553 + else if (!phase_div_en)
554 + return mash_dsm(pll, M, N, K);
555 + else
556 + return ssff_dsm_2(pll, M, N, K);
557 +}
558 +
559 +static inline unsigned int ltq_get_pll0_fosc(void)
560 +{
561 + if (CGU_PLL0_BYPASS)
562 + return get_input_clock(0);
563 + else
564 + return !CGU_PLL0_CFG_FRAC_EN
565 + ? dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN, 0,
566 + CGU_PLL0_CFG_DSMSEL,
567 + CGU_PLL0_PHASE_DIVIDER_ENABLE)
568 + : dsm(0, CGU_PLL0_CFG_PLLM, CGU_PLL0_CFG_PLLN,
569 + CGU_PLL0_CFG_PLLK, CGU_PLL0_CFG_DSMSEL,
570 + CGU_PLL0_PHASE_DIVIDER_ENABLE);
571 +}
572 +
573 +static unsigned int ltq_get_pll0_fdiv(void)
574 +{
575 + unsigned int div = CGU_PLL2_CFG_INPUT_DIV + 1;
576 +
577 + return (ltq_get_pll0_fosc() + (div >> 1)) / div;
578 +}
579 +
580 +unsigned int ltq_get_io_region_clock(void)
581 +{
582 + unsigned int ret = ltq_get_pll0_fosc();
583 +
584 + switch (ltq_cgu_r32(LTQ_CGU_PLL2_CFG) & CGU_SYS_DDR_SEL) {
585 + default:
586 + case 0:
587 + return (ret + 1) / 2;
588 + case 1:
589 + return (ret * 2 + 2) / 5;
590 + case 2:
591 + return (ret + 1) / 3;
592 + case 3:
593 + return (ret + 2) / 4;
594 + }
595 +}
596 +EXPORT_SYMBOL(ltq_get_io_region_clock);
597 +
598 +unsigned int ltq_get_fpi_bus_clock(int fpi)
599 +{
600 + unsigned int ret = ltq_get_io_region_clock();
601 +
602 + if ((fpi == 2) && (ltq_cgu_r32(LTQ_CGU_SYS) & CGU_SYS_FPI_SEL))
603 + ret >>= 1;
604 + return ret;
605 +}
606 +EXPORT_SYMBOL(ltq_get_fpi_bus_clock);
607 +
608 +unsigned int ltq_get_cpu_hz(void)
609 +{
610 + switch (ltq_cgu_r32(LTQ_CGU_SYS) & 0xc) {
611 + case 0:
612 + return CLOCK_333M;
613 + case 4:
614 + return DDR_HZ;
615 + case 8:
616 + return DDR_HZ << 1;
617 + default:
618 + return DDR_HZ >> 1;
619 + }
620 +}
621 +EXPORT_SYMBOL(ltq_get_cpu_hz);
622 +
623 +unsigned int ltq_get_fpi_hz(void)
624 +{
625 + unsigned int ddr_clock = DDR_HZ;
626 +
627 + if (ltq_cgu_r32(LTQ_CGU_SYS) & 0x40)
628 + return ddr_clock >> 1;
629 + return ddr_clock;
630 +}
631 +EXPORT_SYMBOL(ltq_get_fpi_hz);
632 --- /dev/null
633 +++ b/arch/mips/lantiq/xway/ebu.c
634 @@ -0,0 +1,53 @@
635 +/*
636 + * This program is free software; you can redistribute it and/or modify it
637 + * under the terms of the GNU General Public License version 2 as published
638 + * by the Free Software Foundation.
639 + *
640 + * EBU - the external bus unit attaches PCI, NOR and NAND
641 + *
642 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
643 + */
644 +
645 +#include <linux/kernel.h>
646 +#include <linux/module.h>
647 +#include <linux/version.h>
648 +#include <linux/ioport.h>
649 +
650 +#include <lantiq_soc.h>
651 +
652 +/* all access to the ebu must be locked */
653 +DEFINE_SPINLOCK(ebu_lock);
654 +EXPORT_SYMBOL_GPL(ebu_lock);
655 +
656 +static struct resource ltq_ebu_resource = {
657 + .name = "ebu",
658 + .start = LTQ_EBU_BASE_ADDR,
659 + .end = LTQ_EBU_BASE_ADDR + LTQ_EBU_SIZE - 1,
660 + .flags = IORESOURCE_MEM,
661 +};
662 +
663 +/* remapped base addr of the clock unit and external bus unit */
664 +void __iomem *ltq_ebu_membase;
665 +
666 +static int __init lantiq_ebu_init(void)
667 +{
668 + /* insert and request the memory region */
669 + if (insert_resource(&iomem_resource, &ltq_ebu_resource) < 0)
670 + panic("Failed to insert ebu memory\n");
671 +
672 + if (request_mem_region(ltq_ebu_resource.start,
673 + resource_size(&ltq_ebu_resource), "ebu") < 0)
674 + panic("Failed to request ebu memory\n");
675 +
676 + /* remap ebu register range */
677 + ltq_ebu_membase = ioremap_nocache(ltq_ebu_resource.start,
678 + resource_size(&ltq_ebu_resource));
679 + if (!ltq_ebu_membase)
680 + panic("Failed to remap ebu memory\n");
681 +
682 + /* make sure to unprotect the memory region where flash is located */
683 + ltq_ebu_w32(ltq_ebu_r32(LTQ_EBU_BUSCON0) & ~EBU_WRDIS, LTQ_EBU_BUSCON0);
684 + return 0;
685 +}
686 +
687 +postcore_initcall(lantiq_ebu_init);
688 --- /dev/null
689 +++ b/arch/mips/lantiq/xway/gpio.c
690 @@ -0,0 +1,195 @@
691 +/*
692 + * This program is free software; you can redistribute it and/or modify it
693 + * under the terms of the GNU General Public License version 2 as published
694 + * by the Free Software Foundation.
695 + *
696 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
697 + */
698 +
699 +#include <linux/slab.h>
700 +#include <linux/module.h>
701 +#include <linux/platform_device.h>
702 +#include <linux/gpio.h>
703 +#include <linux/ioport.h>
704 +#include <linux/io.h>
705 +
706 +#include <lantiq_soc.h>
707 +
708 +#define LTQ_GPIO_OUT 0x00
709 +#define LTQ_GPIO_IN 0x04
710 +#define LTQ_GPIO_DIR 0x08
711 +#define LTQ_GPIO_ALTSEL0 0x0C
712 +#define LTQ_GPIO_ALTSEL1 0x10
713 +#define LTQ_GPIO_OD 0x14
714 +
715 +#define PINS_PER_PORT 16
716 +#define MAX_PORTS 3
717 +
718 +#define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p)))
719 +#define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r)
720 +#define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r)
721 +
722 +struct ltq_gpio {
723 + void __iomem *membase;
724 + struct gpio_chip chip;
725 +};
726 +
727 +static struct ltq_gpio ltq_gpio_port[MAX_PORTS];
728 +
729 +int gpio_to_irq(unsigned int gpio)
730 +{
731 + return -EINVAL;
732 +}
733 +EXPORT_SYMBOL(gpio_to_irq);
734 +
735 +int irq_to_gpio(unsigned int gpio)
736 +{
737 + return -EINVAL;
738 +}
739 +EXPORT_SYMBOL(irq_to_gpio);
740 +
741 +int ltq_gpio_request(unsigned int pin, unsigned int alt0,
742 + unsigned int alt1, unsigned int dir, const char *name)
743 +{
744 + int id = 0;
745 +
746 + if (pin >= (MAX_PORTS * PINS_PER_PORT))
747 + return -EINVAL;
748 + if (gpio_request(pin, name)) {
749 + pr_err("failed to setup lantiq gpio: %s\n", name);
750 + return -EBUSY;
751 + }
752 + if (dir)
753 + gpio_direction_output(pin, 1);
754 + else
755 + gpio_direction_input(pin);
756 + while (pin >= PINS_PER_PORT) {
757 + pin -= PINS_PER_PORT;
758 + id++;
759 + }
760 + if (alt0)
761 + ltq_gpio_setbit(ltq_gpio_port[id].membase,
762 + LTQ_GPIO_ALTSEL0, pin);
763 + else
764 + ltq_gpio_clearbit(ltq_gpio_port[id].membase,
765 + LTQ_GPIO_ALTSEL0, pin);
766 + if (alt1)
767 + ltq_gpio_setbit(ltq_gpio_port[id].membase,
768 + LTQ_GPIO_ALTSEL1, pin);
769 + else
770 + ltq_gpio_clearbit(ltq_gpio_port[id].membase,
771 + LTQ_GPIO_ALTSEL1, pin);
772 + return 0;
773 +}
774 +EXPORT_SYMBOL(ltq_gpio_request);
775 +
776 +static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
777 +{
778 + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
779 +
780 + if (value)
781 + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
782 + else
783 + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
784 +}
785 +
786 +static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset)
787 +{
788 + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
789 +
790 + return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset);
791 +}
792 +
793 +static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
794 +{
795 + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
796 +
797 + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
798 + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
799 +
800 + return 0;
801 +}
802 +
803 +static int ltq_gpio_direction_output(struct gpio_chip *chip,
804 + unsigned int offset, int value)
805 +{
806 + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
807 +
808 + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
809 + ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
810 + ltq_gpio_set(chip, offset, value);
811 +
812 + return 0;
813 +}
814 +
815 +static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset)
816 +{
817 + struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
818 +
819 + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset);
820 + ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset);
821 + return 0;
822 +}
823 +
824 +static int ltq_gpio_probe(struct platform_device *pdev)
825 +{
826 + struct resource *res;
827 +
828 + if (pdev->id >= MAX_PORTS) {
829 + dev_err(&pdev->dev, "invalid gpio port %d\n",
830 + pdev->id);
831 + return -EINVAL;
832 + }
833 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
834 + if (!res) {
835 + dev_err(&pdev->dev, "failed to get memory for gpio port %d\n",
836 + pdev->id);
837 + return -ENOENT;
838 + }
839 + res = devm_request_mem_region(&pdev->dev, res->start,
840 + resource_size(res), dev_name(&pdev->dev));
841 + if (!res) {
842 + dev_err(&pdev->dev,
843 + "failed to request memory for gpio port %d\n",
844 + pdev->id);
845 + return -EBUSY;
846 + }
847 + ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev,
848 + res->start, resource_size(res));
849 + if (!ltq_gpio_port[pdev->id].membase) {
850 + dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n",
851 + pdev->id);
852 + return -ENOMEM;
853 + }
854 + ltq_gpio_port[pdev->id].chip.label = "ltq_gpio";
855 + ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input;
856 + ltq_gpio_port[pdev->id].chip.direction_output =
857 + ltq_gpio_direction_output;
858 + ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get;
859 + ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set;
860 + ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req;
861 + ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id;
862 + ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT;
863 + platform_set_drvdata(pdev, &ltq_gpio_port[pdev->id]);
864 + return gpiochip_add(&ltq_gpio_port[pdev->id].chip);
865 +}
866 +
867 +static struct platform_driver
868 +ltq_gpio_driver = {
869 + .probe = ltq_gpio_probe,
870 + .driver = {
871 + .name = "ltq_gpio",
872 + .owner = THIS_MODULE,
873 + },
874 +};
875 +
876 +int __init ltq_gpio_init(void)
877 +{
878 + int ret = platform_driver_register(&ltq_gpio_driver);
879 +
880 + if (ret)
881 + pr_info("ltq_gpio : Error registering platfom driver!");
882 + return ret;
883 +}
884 +
885 +postcore_initcall(ltq_gpio_init);
886 --- /dev/null
887 +++ b/arch/mips/lantiq/xway/pmu.c
888 @@ -0,0 +1,70 @@
889 +/*
890 + * This program is free software; you can redistribute it and/or modify it
891 + * under the terms of the GNU General Public License version 2 as published
892 + * by the Free Software Foundation.
893 + *
894 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
895 + */
896 +
897 +#include <linux/kernel.h>
898 +#include <linux/module.h>
899 +#include <linux/version.h>
900 +#include <linux/ioport.h>
901 +
902 +#include <lantiq_soc.h>
903 +
904 +/* PMU - the power management unit allows us to turn part of the core
905 + * on and off
906 + */
907 +
908 +/* the enable / disable registers */
909 +#define LTQ_PMU_PWDCR 0x1C
910 +#define LTQ_PMU_PWDSR 0x20
911 +
912 +#define ltq_pmu_w32(x, y) ltq_w32((x), ltq_pmu_membase + (y))
913 +#define ltq_pmu_r32(x) ltq_r32(ltq_pmu_membase + (x))
914 +
915 +static struct resource ltq_pmu_resource = {
916 + .name = "pmu",
917 + .start = LTQ_PMU_BASE_ADDR,
918 + .end = LTQ_PMU_BASE_ADDR + LTQ_PMU_SIZE - 1,
919 + .flags = IORESOURCE_MEM,
920 +};
921 +
922 +static void __iomem *ltq_pmu_membase;
923 +
924 +void ltq_pmu_enable(unsigned int module)
925 +{
926 + int err = 1000000;
927 +
928 + ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) & ~module, LTQ_PMU_PWDCR);
929 + do {} while (--err && (ltq_pmu_r32(LTQ_PMU_PWDSR) & module));
930 +
931 + if (!err)
932 + panic("activating PMU module failed!\n");
933 +}
934 +EXPORT_SYMBOL(ltq_pmu_enable);
935 +
936 +void ltq_pmu_disable(unsigned int module)
937 +{
938 + ltq_pmu_w32(ltq_pmu_r32(LTQ_PMU_PWDCR) | module, LTQ_PMU_PWDCR);
939 +}
940 +EXPORT_SYMBOL(ltq_pmu_disable);
941 +
942 +int __init ltq_pmu_init(void)
943 +{
944 + if (insert_resource(&iomem_resource, &ltq_pmu_resource) < 0)
945 + panic("Failed to insert pmu memory\n");
946 +
947 + if (request_mem_region(ltq_pmu_resource.start,
948 + resource_size(&ltq_pmu_resource), "pmu") < 0)
949 + panic("Failed to request pmu memory\n");
950 +
951 + ltq_pmu_membase = ioremap_nocache(ltq_pmu_resource.start,
952 + resource_size(&ltq_pmu_resource));
953 + if (!ltq_pmu_membase)
954 + panic("Failed to remap pmu memory\n");
955 + return 0;
956 +}
957 +
958 +core_initcall(ltq_pmu_init);
959 --- /dev/null
960 +++ b/arch/mips/lantiq/xway/prom-ase.c
961 @@ -0,0 +1,39 @@
962 +/*
963 + * This program is free software; you can redistribute it and/or modify it
964 + * under the terms of the GNU General Public License version 2 as published
965 + * by the Free Software Foundation.
966 + *
967 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
968 + */
969 +
970 +#include <linux/module.h>
971 +#include <linux/clk.h>
972 +#include <asm/bootinfo.h>
973 +#include <asm/time.h>
974 +
975 +#include <lantiq_soc.h>
976 +
977 +#include "../prom.h"
978 +
979 +#define SOC_AMAZON_SE "Amazon_SE"
980 +
981 +#define PART_SHIFT 12
982 +#define PART_MASK 0x0FFFFFFF
983 +#define REV_SHIFT 28
984 +#define REV_MASK 0xF0000000
985 +
986 +void __init ltq_soc_detect(struct ltq_soc_info *i)
987 +{
988 + i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
989 + i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
990 + switch (i->partnum) {
991 + case SOC_ID_AMAZON_SE:
992 + i->name = SOC_AMAZON_SE;
993 + i->type = SOC_TYPE_AMAZON_SE;
994 + break;
995 +
996 + default:
997 + unreachable();
998 + break;
999 + }
1000 +}
1001 --- /dev/null
1002 +++ b/arch/mips/lantiq/xway/prom-xway.c
1003 @@ -0,0 +1,54 @@
1004 +/*
1005 + * This program is free software; you can redistribute it and/or modify it
1006 + * under the terms of the GNU General Public License version 2 as published
1007 + * by the Free Software Foundation.
1008 + *
1009 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
1010 + */
1011 +
1012 +#include <linux/module.h>
1013 +#include <linux/clk.h>
1014 +#include <asm/bootinfo.h>
1015 +#include <asm/time.h>
1016 +
1017 +#include <lantiq_soc.h>
1018 +
1019 +#include "../prom.h"
1020 +
1021 +#define SOC_DANUBE "Danube"
1022 +#define SOC_TWINPASS "Twinpass"
1023 +#define SOC_AR9 "AR9"
1024 +
1025 +#define PART_SHIFT 12
1026 +#define PART_MASK 0x0FFFFFFF
1027 +#define REV_SHIFT 28
1028 +#define REV_MASK 0xF0000000
1029 +
1030 +void __init ltq_soc_detect(struct ltq_soc_info *i)
1031 +{
1032 + i->partnum = (ltq_r32(LTQ_MPS_CHIPID) & PART_MASK) >> PART_SHIFT;
1033 + i->rev = (ltq_r32(LTQ_MPS_CHIPID) & REV_MASK) >> REV_SHIFT;
1034 + switch (i->partnum) {
1035 + case SOC_ID_DANUBE1:
1036 + case SOC_ID_DANUBE2:
1037 + i->name = SOC_DANUBE;
1038 + i->type = SOC_TYPE_DANUBE;
1039 + break;
1040 +
1041 + case SOC_ID_TWINPASS:
1042 + i->name = SOC_TWINPASS;
1043 + i->type = SOC_TYPE_DANUBE;
1044 + break;
1045 +
1046 + case SOC_ID_ARX188:
1047 + case SOC_ID_ARX168:
1048 + case SOC_ID_ARX182:
1049 + i->name = SOC_AR9;
1050 + i->type = SOC_TYPE_AR9;
1051 + break;
1052 +
1053 + default:
1054 + unreachable();
1055 + break;
1056 + }
1057 +}
1058 --- /dev/null
1059 +++ b/arch/mips/lantiq/xway/reset.c
1060 @@ -0,0 +1,91 @@
1061 +/*
1062 + * This program is free software; you can redistribute it and/or modify it
1063 + * under the terms of the GNU General Public License version 2 as published
1064 + * by the Free Software Foundation.
1065 + *
1066 + * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
1067 + */
1068 +
1069 +#include <linux/init.h>
1070 +#include <linux/io.h>
1071 +#include <linux/ioport.h>
1072 +#include <linux/pm.h>
1073 +#include <linux/module.h>
1074 +#include <asm/reboot.h>
1075 +
1076 +#include <lantiq_soc.h>
1077 +
1078 +#define ltq_rcu_w32(x, y) ltq_w32((x), ltq_rcu_membase + (y))
1079 +#define ltq_rcu_r32(x) ltq_r32(ltq_rcu_membase + (x))
1080 +
1081 +/* register definitions */
1082 +#define LTQ_RCU_RST 0x0010
1083 +#define LTQ_RCU_RST_ALL 0x40000000
1084 +
1085 +#define LTQ_RCU_RST_STAT 0x0014
1086 +#define LTQ_RCU_STAT_SHIFT 26
1087 +
1088 +static struct resource ltq_rcu_resource = {
1089 + .name = "rcu",
1090 + .start = LTQ_RCU_BASE_ADDR,
1091 + .end = LTQ_RCU_BASE_ADDR + LTQ_RCU_SIZE - 1,
1092 + .flags = IORESOURCE_MEM,
1093 +};
1094 +
1095 +/* remapped base addr of the reset control unit */
1096 +static void __iomem *ltq_rcu_membase;
1097 +
1098 +/* This function is used by the watchdog driver */
1099 +int ltq_reset_cause(void)
1100 +{
1101 + u32 val = ltq_rcu_r32(LTQ_RCU_RST_STAT);
1102 + return val >> LTQ_RCU_STAT_SHIFT;
1103 +}
1104 +EXPORT_SYMBOL_GPL(ltq_reset_cause);
1105 +
1106 +static void ltq_machine_restart(char *command)
1107 +{
1108 + pr_notice("System restart\n");
1109 + local_irq_disable();
1110 + ltq_rcu_w32(ltq_rcu_r32(LTQ_RCU_RST) | LTQ_RCU_RST_ALL, LTQ_RCU_RST);
1111 + unreachable();
1112 +}
1113 +
1114 +static void ltq_machine_halt(void)
1115 +{
1116 + pr_notice("System halted.\n");
1117 + local_irq_disable();
1118 + unreachable();
1119 +}
1120 +
1121 +static void ltq_machine_power_off(void)
1122 +{
1123 + pr_notice("Please turn off the power now.\n");
1124 + local_irq_disable();
1125 + unreachable();
1126 +}
1127 +
1128 +static int __init mips_reboot_setup(void)
1129 +{
1130 + /* insert and request the memory region */
1131 + if (insert_resource(&iomem_resource, &ltq_rcu_resource) < 0)
1132 + panic("Failed to insert rcu memory\n");
1133 +
1134 + if (request_mem_region(ltq_rcu_resource.start,
1135 + resource_size(&ltq_rcu_resource), "rcu") < 0)
1136 + panic("Failed to request rcu memory\n");
1137 +
1138 + /* remap rcu register range */
1139 + ltq_rcu_membase = ioremap_nocache(ltq_rcu_resource.start,
1140 + resource_size(&ltq_rcu_resource));
1141 + if (!ltq_rcu_membase)
1142 + panic("Failed to remap rcu memory\n");
1143 +
1144 + _machine_restart = ltq_machine_restart;
1145 + _machine_halt = ltq_machine_halt;
1146 + pm_power_off = ltq_machine_power_off;
1147 +
1148 + return 0;
1149 +}
1150 +
1151 +arch_initcall(mips_reboot_setup);