aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/lantiq
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
committerWe-unite <3205135446@qq.com>2025-03-08 22:04:20 +0800
commita07bb8fd1299070229f0e8f3dcb57ffd5ef9870a (patch)
tree84f21bd0bf7071bc5fc7dd989e77d7ceb5476682 /arch/mips/lantiq
downloadohosKernel-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/Kconfig55
-rw-r--r--arch/mips/lantiq/Makefile10
-rw-r--r--arch/mips/lantiq/Platform8
-rw-r--r--arch/mips/lantiq/clk.c201
-rw-r--r--arch/mips/lantiq/clk.h94
-rw-r--r--arch/mips/lantiq/early_printk.c31
-rw-r--r--arch/mips/lantiq/falcon/Makefile2
-rw-r--r--arch/mips/lantiq/falcon/prom.c90
-rw-r--r--arch/mips/lantiq/falcon/reset.c75
-rw-r--r--arch/mips/lantiq/falcon/sysctrl.c265
-rw-r--r--arch/mips/lantiq/irq.c433
-rw-r--r--arch/mips/lantiq/prom.c113
-rw-r--r--arch/mips/lantiq/prom.h27
-rw-r--r--arch/mips/lantiq/xway/Makefile4
-rw-r--r--arch/mips/lantiq/xway/clk.c351
-rw-r--r--arch/mips/lantiq/xway/dcdc.c60
-rw-r--r--arch/mips/lantiq/xway/dma.c271
-rw-r--r--arch/mips/lantiq/xway/gptu.c208
-rw-r--r--arch/mips/lantiq/xway/prom.c144
-rw-r--r--arch/mips/lantiq/xway/sysctrl.c588
-rw-r--r--arch/mips/lantiq/xway/vmmc.c64
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
2if LANTIQ
3
4config SOC_TYPE_XWAY
5 bool
6 select PINCTRL_XWAY
7 default n
8
9choice
10 prompt "SoC Type"
11 default SOC_XWAY
12
13config SOC_AMAZON_SE
14 bool "Amazon SE"
15 select SOC_TYPE_XWAY
16 select MFD_SYSCON
17 select MFD_CORE
18
19config SOC_XWAY
20 bool "XWAY"
21 select SOC_TYPE_XWAY
22 select HAVE_PCI
23 select MFD_SYSCON
24 select MFD_CORE
25
26config SOC_FALCON
27 bool "FALCON"
28 select PINCTRL_FALCON
29
30endchoice
31
32choice
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
42config LANTIQ_DT_NONE
43 bool "None"
44
45config DT_EASY50712
46 bool "Easy50712"
47 depends on SOC_XWAY
48 select BUILTIN_DTB
49endchoice
50
51config PCI_LANTIQ
52 bool "PCI Support"
53 depends on SOC_XWAY && PCI
54
55endif
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
5obj-y := irq.o clk.o prom.o
6
7obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
8
9obj-$(CONFIG_SOC_TYPE_XWAY) += xway/
10obj-$(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
5cflags-$(CONFIG_LANTIQ) += -I$(srctree)/arch/mips/include/asm/mach-lantiq
6load-$(CONFIG_LANTIQ) = 0xffffffff80002000
7cflags-$(CONFIG_SOC_TYPE_XWAY) += -I$(srctree)/arch/mips/include/asm/mach-lantiq/xway
8cflags-$(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 */
27static struct clk cpu_clk_generic[4];
28
29void 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
38struct clk *clk_get_cpu(void)
39{
40 return &cpu_clk_generic[0];
41}
42
43struct clk *clk_get_fpi(void)
44{
45 return &cpu_clk_generic[1];
46}
47EXPORT_SYMBOL_GPL(clk_get_fpi);
48
49struct clk *clk_get_io(void)
50{
51 return &cpu_clk_generic[2];
52}
53EXPORT_SYMBOL_GPL(clk_get_io);
54
55struct clk *clk_get_ppe(void)
56{
57 return &cpu_clk_generic[3];
58}
59EXPORT_SYMBOL_GPL(clk_get_ppe);
60
61static inline int clk_good(struct clk *clk)
62{
63 return clk && !IS_ERR(clk);
64}
65
66unsigned 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}
79EXPORT_SYMBOL(clk_get_rate);
80
81int 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}
99EXPORT_SYMBOL(clk_set_rate);
100
101long 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}
116EXPORT_SYMBOL(clk_round_rate);
117
118int 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}
128EXPORT_SYMBOL(clk_enable);
129
130void clk_disable(struct clk *clk)
131{
132 if (unlikely(!clk_good(clk)))
133 return;
134
135 if (clk->disable)
136 clk->disable(clk);
137}
138EXPORT_SYMBOL(clk_disable);
139
140int 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}
150EXPORT_SYMBOL(clk_activate);
151
152void clk_deactivate(struct clk *clk)
153{
154 if (unlikely(!clk_good(clk)))
155 return;
156
157 if (clk->deactivate)
158 clk->deactivate(clk);
159}
160EXPORT_SYMBOL(clk_deactivate);
161
162struct clk *clk_get_parent(struct clk *clk)
163{
164 return NULL;
165}
166EXPORT_SYMBOL(clk_get_parent);
167
168int clk_set_parent(struct clk *clk, struct clk *parent)
169{
170 return 0;
171}
172EXPORT_SYMBOL(clk_set_parent);
173
174static 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
190void __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
58struct 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
72extern void clkdev_add_static(unsigned long cpu, unsigned long fpi,
73 unsigned long io, unsigned long ppe);
74
75extern unsigned long ltq_danube_cpu_hz(void);
76extern unsigned long ltq_danube_fpi_hz(void);
77extern unsigned long ltq_danube_pp32_hz(void);
78
79extern unsigned long ltq_ar9_cpu_hz(void);
80extern unsigned long ltq_ar9_fpi_hz(void);
81
82extern unsigned long ltq_vr9_cpu_hz(void);
83extern unsigned long ltq_vr9_fpi_hz(void);
84extern unsigned long ltq_vr9_pp32_hz(void);
85
86extern unsigned long ltq_ar10_cpu_hz(void);
87extern unsigned long ltq_ar10_fpi_hz(void);
88extern unsigned long ltq_ar10_pp32_hz(void);
89
90extern unsigned long ltq_grx390_cpu_hz(void);
91extern unsigned long ltq_grx390_fpi_hz(void);
92extern 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
21void 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
2obj-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
39void __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
46void __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
53void __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 */
20unsigned 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
35static 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
55static void machine_halt(void)
56{
57 local_irq_disable();
58 unreachable();
59}
60
61static void machine_power_off(void)
62{
63 local_irq_disable();
64 unreachable();
65}
66
67static 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
75arch_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
72static void __iomem *sysctl_membase[3], *status_membase;
73void __iomem *ltq_sys1_membase, *ltq_ebu_membase;
74
75void falcon_trigger_hrst(int level)
76{
77 sysctl_w32(SYSCTL_SYS1, level & 1, SYS1_HRSTOUTC);
78}
79
80static 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
93static 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
101static 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
108static 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
116static 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
122static 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 */
139static 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
165static 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
185void __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
61static int exin_avail;
62static u32 ltq_eiu_irq[MAX_EIU];
63static void __iomem *ltq_icu_membase[NR_CPUS];
64static void __iomem *ltq_eiu_membase;
65static struct irq_domain *ltq_domain;
66static DEFINE_SPINLOCK(ltq_eiu_lock);
67static DEFINE_RAW_SPINLOCK(ltq_icu_lock);
68static int ltq_perfcount_irq;
69
70int ltq_eiu_get_irq(int exin)
71{
72 if (exin < exin_avail)
73 return ltq_eiu_irq[exin];
74 return -1;
75}
76
77void 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(&ltq_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(&ltq_icu_lock, flags);
93}
94
95void 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(&ltq_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(&ltq_icu_lock, flags);
112}
113
114static 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(&ltq_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(&ltq_icu_lock, flags);
128}
129
130void 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(&ltq_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(&ltq_icu_lock, flags);
151}
152
153static 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(&ltq_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(&ltq_eiu_lock, flags);
198 }
199 }
200
201 return 0;
202}
203
204static 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
226static 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)
242static 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
256static 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
269static 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
285static 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
310static int icu_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
311{
312 struct irq_chip *chip = &ltq_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 = &ltq_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
332static const struct irq_domain_ops irq_domain_ops = {
333 .xlate = irq_domain_xlate_onetwocell,
334 .map = icu_map,
335};
336
337int __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
414int get_c0_perfcount_int(void)
415{
416 return ltq_perfcount_irq;
417}
418EXPORT_SYMBOL_GPL(get_c0_perfcount_int);
419
420unsigned int get_c0_compare_int(void)
421{
422 return CP0_LEGACY_COMPARE_IRQ;
423}
424
425static const struct of_device_id of_irq_ids[] __initconst = {
426 { .compatible = "lantiq,icu", .data = icu_of_init },
427 {},
428};
429
430void __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 */
22DEFINE_SPINLOCK(ebu_lock);
23EXPORT_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 */
29unsigned 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 */
35static struct ltq_soc_info soc_info;
36
37const char *get_system_type(void)
38{
39 return soc_info.sys_type;
40}
41
42int ltq_soc_type(void)
43{
44 return soc_info.type;
45}
46
47void __init prom_free_prom_memory(void)
48{
49}
50
51static 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
69void __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
94void __init device_tree_init(void)
95{
96 unflatten_and_copy_device_tree();
97}
98
99void __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
13struct 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
24extern void ltq_soc_detect(struct ltq_soc_info *i);
25extern 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
2obj-y := prom.o sysctrl.o clk.o dma.o gptu.o dcdc.o
3
4obj-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
20static 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
31unsigned 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
40unsigned 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
54unsigned 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
77unsigned 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
84unsigned 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
94unsigned 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
102unsigned 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
142unsigned 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
175unsigned 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
198unsigned 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
228unsigned 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
247unsigned 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
267unsigned 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
300unsigned 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
331unsigned 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
21static void __iomem *dcdc_membase;
22
23static 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
38static const struct of_device_id dcdc_match[] = {
39 { .compatible = "lantiq,dcdc-xrx200" },
40 {},
41};
42
43static struct platform_driver dcdc_driver = {
44 .probe = dcdc_probe,
45 .driver = {
46 .name = "dcdc-xrx200",
47 .of_match_table = dcdc_match,
48 },
49};
50
51int __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
60arch_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
56static void __iomem *ltq_dma_membase;
57static DEFINE_SPINLOCK(ltq_dma_lock);
58
59void
60ltq_dma_enable_irq(struct ltq_dma_channel *ch)
61{
62 unsigned long flags;
63
64 spin_lock_irqsave(&ltq_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(&ltq_dma_lock, flags);
68}
69EXPORT_SYMBOL_GPL(ltq_dma_enable_irq);
70
71void
72ltq_dma_disable_irq(struct ltq_dma_channel *ch)
73{
74 unsigned long flags;
75
76 spin_lock_irqsave(&ltq_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(&ltq_dma_lock, flags);
80}
81EXPORT_SYMBOL_GPL(ltq_dma_disable_irq);
82
83void
84ltq_dma_ack_irq(struct ltq_dma_channel *ch)
85{
86 unsigned long flags;
87
88 spin_lock_irqsave(&ltq_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(&ltq_dma_lock, flags);
92}
93EXPORT_SYMBOL_GPL(ltq_dma_ack_irq);
94
95void
96ltq_dma_open(struct ltq_dma_channel *ch)
97{
98 unsigned long flag;
99
100 spin_lock_irqsave(&ltq_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(&ltq_dma_lock, flag);
104}
105EXPORT_SYMBOL_GPL(ltq_dma_open);
106
107void
108ltq_dma_close(struct ltq_dma_channel *ch)
109{
110 unsigned long flag;
111
112 spin_lock_irqsave(&ltq_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(&ltq_dma_lock, flag);
117}
118EXPORT_SYMBOL_GPL(ltq_dma_close);
119
120static void
121ltq_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(&ltq_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(&ltq_dma_lock, flags);
140}
141
142void
143ltq_dma_alloc_tx(struct ltq_dma_channel *ch)
144{
145 unsigned long flags;
146
147 ltq_dma_alloc(ch);
148
149 spin_lock_irqsave(&ltq_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(&ltq_dma_lock, flags);
154}
155EXPORT_SYMBOL_GPL(ltq_dma_alloc_tx);
156
157void
158ltq_dma_alloc_rx(struct ltq_dma_channel *ch)
159{
160 unsigned long flags;
161
162 ltq_dma_alloc(ch);
163
164 spin_lock_irqsave(&ltq_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(&ltq_dma_lock, flags);
169}
170EXPORT_SYMBOL_GPL(ltq_dma_alloc_rx);
171
172void
173ltq_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}
181EXPORT_SYMBOL_GPL(ltq_dma_free);
182
183void
184ltq_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}
207EXPORT_SYMBOL_GPL(ltq_dma_init_port);
208
209static int
210ltq_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
252static const struct of_device_id dma_match[] = {
253 { .compatible = "lantiq,dma-xway" },
254 {},
255};
256
257static 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
265int __init
266dma_init(void)
267{
268 return platform_driver_register(&dma_driver);
269}
270
271postcore_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
61enum gptu_timer {
62 TIMER1A = 0,
63 TIMER1B,
64 TIMER2A,
65 TIMER2B,
66 TIMER3A,
67 TIMER3B
68};
69
70static void __iomem *gptu_membase;
71static struct resource irqres[6];
72
73static 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
80static 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
87static 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
94static 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
111static 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
120static 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
136static 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
186static const struct of_device_id gptu_match[] = {
187 { .compatible = "lantiq,gptu-xway" },
188 {},
189};
190
191static struct platform_driver dma_driver = {
192 .probe = gptu_probe,
193 .driver = {
194 .name = "gptu-xway",
195 .of_match_table = gptu_match,
196 },
197};
198
199int __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
208arch_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
41void __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 */
63static u32 pmu_clk_sr[] = {
64 PMU_CLK_SR,
65 PMU_CLK_SR1,
66 PMU_ANA_SR,
67};
68
69/* Enable */
70static u32 pmu_clk_cr_a[] = {
71 PMU_CLK_CR_A,
72 PMU_CLK_CR1_A,
73 PMU_ANA_CR_A,
74};
75
76/* Disable */
77static 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
150static void __iomem *pmu_membase;
151void __iomem *ltq_cgu_membase;
152void __iomem *ltq_ebu_membase;
153
154static u32 ifccr = CGU_IFCCR;
155static u32 pcicr = CGU_PCICR;
156
157static DEFINE_SPINLOCK(g_pmu_lock);
158
159/* legacy function kept alive to ease clkdev transition */
160void 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}
172EXPORT_SYMBOL(ltq_pmu_enable);
173
174/* legacy function kept alive to ease clkdev transition */
175void 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}
187EXPORT_SYMBOL(ltq_pmu_disable);
188
189/* enable a hw clock */
190static 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 */
197static 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 */
203static 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 */
229static 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 */
252static 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 */
276static 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 */
284static 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 */
291static 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 */
313static 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 */
338static 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 */
355static unsigned long valid_pci_rates[] = {CLOCK_33M, CLOCK_62_5M, 0};
356
357static 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 */
388static 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
395static 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 */
425void __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
14static unsigned int *cp1_base;
15
16unsigned 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}
23EXPORT_SYMBOL(ltq_get_cp1_base);
24
25static 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
52static const struct of_device_id vmmc_match[] = {
53 { .compatible = "lantiq,vmmc-xway" },
54 {},
55};
56
57static struct platform_driver vmmc_driver = {
58 .probe = vmmc_probe,
59 .driver = {
60 .name = "lantiq,vmmc",
61 .of_match_table = vmmc_match,
62 },
63};
64builtin_platform_driver(vmmc_driver);