diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-03-27 14:51:41 -0400 |
---|---|---|
committer | Nicolas Pitre <nico@marvell.com> | 2008-03-27 14:51:41 -0400 |
commit | 9dd0b194bf6804b1998f0fe261b2606ec7b58d72 (patch) | |
tree | c9fd5ab51dc256818c24a8a771dc068d021039e2 /arch/arm/mach-orion5x | |
parent | 159ffb3a04f6bc619643af680df406faafd0199d (diff) |
Orion: orion -> orion5x rename
Do a global s/orion/orion5x/ of the Orion 5x-specific bits (i.e.
not the plat-orion bits.)
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Reviewed-by: Tzachi Perelstein <tzachi@marvell.com>
Acked-by: Saeed Bishara <saeed@marvell.com>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Nicolas Pitre <nico@marvell.com>
Diffstat (limited to 'arch/arm/mach-orion5x')
-rw-r--r-- | arch/arm/mach-orion5x/Kconfig | 41 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/Makefile | 6 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/Makefile.boot | 3 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/addr-map.c | 240 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/common.c | 391 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/common.h | 72 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/db88f5281-setup.c | 361 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/dns323-setup.c | 320 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/gpio.c | 226 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/irq.c | 211 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/kurobox_pro-setup.c | 243 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/pci.c | 559 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/rd88f5182-setup.c | 312 | ||||
-rw-r--r-- | arch/arm/mach-orion5x/ts209-setup.c | 359 |
14 files changed, 3344 insertions, 0 deletions
diff --git a/arch/arm/mach-orion5x/Kconfig b/arch/arm/mach-orion5x/Kconfig new file mode 100644 index 000000000000..01c66957d8f4 --- /dev/null +++ b/arch/arm/mach-orion5x/Kconfig | |||
@@ -0,0 +1,41 @@ | |||
1 | if ARCH_ORION5X | ||
2 | |||
3 | menu "Orion Implementations" | ||
4 | |||
5 | config MACH_DB88F5281 | ||
6 | bool "Marvell Orion-2 Development Board" | ||
7 | select I2C_BOARDINFO | ||
8 | help | ||
9 | Say 'Y' here if you want your kernel to support the | ||
10 | Marvell Orion-2 (88F5281) Development Board | ||
11 | |||
12 | config MACH_RD88F5182 | ||
13 | bool "Marvell Orion-NAS Reference Design" | ||
14 | select I2C_BOARDINFO | ||
15 | help | ||
16 | Say 'Y' here if you want your kernel to support the | ||
17 | Marvell Orion-NAS (88F5182) RD2 | ||
18 | |||
19 | config MACH_KUROBOX_PRO | ||
20 | bool "KuroBox Pro" | ||
21 | select I2C_BOARDINFO | ||
22 | help | ||
23 | Say 'Y' here if you want your kernel to support the | ||
24 | KuroBox Pro platform. | ||
25 | |||
26 | config MACH_DNS323 | ||
27 | bool "D-Link DNS-323" | ||
28 | select I2C_BOARDINFO | ||
29 | help | ||
30 | Say 'Y' here if you want your kernel to support the | ||
31 | D-Link DNS-323 platform. | ||
32 | |||
33 | config MACH_TS209 | ||
34 | bool "QNAP TS-109/TS-209" | ||
35 | help | ||
36 | Say 'Y' here if you want your kernel to support the | ||
37 | QNAP TS-109/TS-209 platform. | ||
38 | |||
39 | endmenu | ||
40 | |||
41 | endif | ||
diff --git a/arch/arm/mach-orion5x/Makefile b/arch/arm/mach-orion5x/Makefile new file mode 100644 index 000000000000..d894caa5060f --- /dev/null +++ b/arch/arm/mach-orion5x/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | obj-y += common.o addr-map.o pci.o gpio.o irq.o | ||
2 | obj-$(CONFIG_MACH_DB88F5281) += db88f5281-setup.o | ||
3 | obj-$(CONFIG_MACH_RD88F5182) += rd88f5182-setup.o | ||
4 | obj-$(CONFIG_MACH_KUROBOX_PRO) += kurobox_pro-setup.o | ||
5 | obj-$(CONFIG_MACH_DNS323) += dns323-setup.o | ||
6 | obj-$(CONFIG_MACH_TS209) += ts209-setup.o | ||
diff --git a/arch/arm/mach-orion5x/Makefile.boot b/arch/arm/mach-orion5x/Makefile.boot new file mode 100644 index 000000000000..67039c3e0c48 --- /dev/null +++ b/arch/arm/mach-orion5x/Makefile.boot | |||
@@ -0,0 +1,3 @@ | |||
1 | zreladdr-y := 0x00008000 | ||
2 | params_phys-y := 0x00000100 | ||
3 | initrd_phys-y := 0x00800000 | ||
diff --git a/arch/arm/mach-orion5x/addr-map.c b/arch/arm/mach-orion5x/addr-map.c new file mode 100644 index 000000000000..6b179371e0a2 --- /dev/null +++ b/arch/arm/mach-orion5x/addr-map.c | |||
@@ -0,0 +1,240 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/addr-map.c | ||
3 | * | ||
4 | * Address map functions for Marvell Orion 5x SoCs | ||
5 | * | ||
6 | * Maintainer: Tzachi Perelstein <tzachi@marvell.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/mbus.h> | ||
16 | #include <asm/hardware.h> | ||
17 | #include <asm/io.h> | ||
18 | #include "common.h" | ||
19 | |||
20 | /* | ||
21 | * The Orion has fully programable address map. There's a separate address | ||
22 | * map for each of the device _master_ interfaces, e.g. CPU, PCI, PCIE, USB, | ||
23 | * Gigabit Ethernet, DMA/XOR engines, etc. Each interface has its own | ||
24 | * address decode windows that allow it to access any of the Orion resources. | ||
25 | * | ||
26 | * CPU address decoding -- | ||
27 | * Linux assumes that it is the boot loader that already setup the access to | ||
28 | * DDR and internal registers. | ||
29 | * Setup access to PCI and PCI-E IO/MEM space is issued by this file. | ||
30 | * Setup access to various devices located on the device bus interface (e.g. | ||
31 | * flashes, RTC, etc) should be issued by machine-setup.c according to | ||
32 | * specific board population (by using orion5x_setup_*_win()). | ||
33 | * | ||
34 | * Non-CPU Masters address decoding -- | ||
35 | * Unlike the CPU, we setup the access from Orion's master interfaces to DDR | ||
36 | * banks only (the typical use case). | ||
37 | * Setup access for each master to DDR is issued by common.c. | ||
38 | * | ||
39 | * Note: although orion_setbits() and orion_clrbits() are not atomic | ||
40 | * no locking is necessary here since code in this file is only called | ||
41 | * at boot time when there is no concurrency issues. | ||
42 | */ | ||
43 | |||
44 | /* | ||
45 | * Generic Address Decode Windows bit settings | ||
46 | */ | ||
47 | #define TARGET_DDR 0 | ||
48 | #define TARGET_DEV_BUS 1 | ||
49 | #define TARGET_PCI 3 | ||
50 | #define TARGET_PCIE 4 | ||
51 | #define ATTR_DDR_CS(n) (((n) ==0) ? 0xe : \ | ||
52 | ((n) == 1) ? 0xd : \ | ||
53 | ((n) == 2) ? 0xb : \ | ||
54 | ((n) == 3) ? 0x7 : 0xf) | ||
55 | #define ATTR_PCIE_MEM 0x59 | ||
56 | #define ATTR_PCIE_IO 0x51 | ||
57 | #define ATTR_PCIE_WA 0x79 | ||
58 | #define ATTR_PCI_MEM 0x59 | ||
59 | #define ATTR_PCI_IO 0x51 | ||
60 | #define ATTR_DEV_CS0 0x1e | ||
61 | #define ATTR_DEV_CS1 0x1d | ||
62 | #define ATTR_DEV_CS2 0x1b | ||
63 | #define ATTR_DEV_BOOT 0xf | ||
64 | #define WIN_EN 1 | ||
65 | |||
66 | /* | ||
67 | * Helpers to get DDR bank info | ||
68 | */ | ||
69 | #define DDR_BASE_CS(n) ORION5X_DDR_REG(0x1500 + ((n) * 8)) | ||
70 | #define DDR_SIZE_CS(n) ORION5X_DDR_REG(0x1504 + ((n) * 8)) | ||
71 | #define DDR_MAX_CS 4 | ||
72 | #define DDR_REG_TO_SIZE(reg) (((reg) | 0xffffff) + 1) | ||
73 | #define DDR_REG_TO_BASE(reg) ((reg) & 0xff000000) | ||
74 | #define DDR_BANK_EN 1 | ||
75 | |||
76 | /* | ||
77 | * CPU Address Decode Windows registers | ||
78 | */ | ||
79 | #define CPU_WIN_CTRL(n) ORION5X_BRIDGE_REG(0x000 | ((n) << 4)) | ||
80 | #define CPU_WIN_BASE(n) ORION5X_BRIDGE_REG(0x004 | ((n) << 4)) | ||
81 | #define CPU_WIN_REMAP_LO(n) ORION5X_BRIDGE_REG(0x008 | ((n) << 4)) | ||
82 | #define CPU_WIN_REMAP_HI(n) ORION5X_BRIDGE_REG(0x00c | ((n) << 4)) | ||
83 | |||
84 | /* | ||
85 | * Gigabit Ethernet Address Decode Windows registers | ||
86 | */ | ||
87 | #define ETH_WIN_BASE(win) ORION5X_ETH_REG(0x200 + ((win) * 8)) | ||
88 | #define ETH_WIN_SIZE(win) ORION5X_ETH_REG(0x204 + ((win) * 8)) | ||
89 | #define ETH_WIN_REMAP(win) ORION5X_ETH_REG(0x280 + ((win) * 4)) | ||
90 | #define ETH_WIN_EN ORION5X_ETH_REG(0x290) | ||
91 | #define ETH_WIN_PROT ORION5X_ETH_REG(0x294) | ||
92 | #define ETH_MAX_WIN 6 | ||
93 | #define ETH_MAX_REMAP_WIN 4 | ||
94 | |||
95 | |||
96 | struct mbus_dram_target_info orion5x_mbus_dram_info; | ||
97 | |||
98 | static int __init orion5x_cpu_win_can_remap(int win) | ||
99 | { | ||
100 | u32 dev, rev; | ||
101 | |||
102 | orion5x_pcie_id(&dev, &rev); | ||
103 | if ((dev == MV88F5281_DEV_ID && win < 4) | ||
104 | || (dev == MV88F5182_DEV_ID && win < 2) | ||
105 | || (dev == MV88F5181_DEV_ID && win < 2)) | ||
106 | return 1; | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static void __init setup_cpu_win(int win, u32 base, u32 size, | ||
112 | u8 target, u8 attr, int remap) | ||
113 | { | ||
114 | orion5x_write(CPU_WIN_BASE(win), base & 0xffff0000); | ||
115 | orion5x_write(CPU_WIN_CTRL(win), | ||
116 | ((size - 1) & 0xffff0000) | (attr << 8) | (target << 4) | 1); | ||
117 | |||
118 | if (orion5x_cpu_win_can_remap(win)) { | ||
119 | if (remap < 0) | ||
120 | remap = base; | ||
121 | |||
122 | orion5x_write(CPU_WIN_REMAP_LO(win), remap & 0xffff0000); | ||
123 | orion5x_write(CPU_WIN_REMAP_HI(win), 0); | ||
124 | } | ||
125 | } | ||
126 | |||
127 | void __init orion5x_setup_cpu_mbus_bridge(void) | ||
128 | { | ||
129 | int i; | ||
130 | int cs; | ||
131 | |||
132 | /* | ||
133 | * First, disable and clear windows. | ||
134 | */ | ||
135 | for (i = 0; i < 8; i++) { | ||
136 | orion5x_write(CPU_WIN_BASE(i), 0); | ||
137 | orion5x_write(CPU_WIN_CTRL(i), 0); | ||
138 | if (orion5x_cpu_win_can_remap(i)) { | ||
139 | orion5x_write(CPU_WIN_REMAP_LO(i), 0); | ||
140 | orion5x_write(CPU_WIN_REMAP_HI(i), 0); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Setup windows for PCI+PCIe IO+MEM space. | ||
146 | */ | ||
147 | setup_cpu_win(0, ORION5X_PCIE_IO_PHYS_BASE, ORION5X_PCIE_IO_SIZE, | ||
148 | TARGET_PCIE, ATTR_PCIE_IO, ORION5X_PCIE_IO_BUS_BASE); | ||
149 | setup_cpu_win(1, ORION5X_PCI_IO_PHYS_BASE, ORION5X_PCI_IO_SIZE, | ||
150 | TARGET_PCI, ATTR_PCI_IO, ORION5X_PCI_IO_BUS_BASE); | ||
151 | setup_cpu_win(2, ORION5X_PCIE_MEM_PHYS_BASE, ORION5X_PCIE_MEM_SIZE, | ||
152 | TARGET_PCIE, ATTR_PCIE_MEM, -1); | ||
153 | setup_cpu_win(3, ORION5X_PCI_MEM_PHYS_BASE, ORION5X_PCI_MEM_SIZE, | ||
154 | TARGET_PCI, ATTR_PCI_MEM, -1); | ||
155 | |||
156 | /* | ||
157 | * Setup MBUS dram target info. | ||
158 | */ | ||
159 | orion5x_mbus_dram_info.mbus_dram_target_id = TARGET_DDR; | ||
160 | |||
161 | for (i = 0, cs = 0; i < 4; i++) { | ||
162 | u32 base = readl(DDR_BASE_CS(i)); | ||
163 | u32 size = readl(DDR_SIZE_CS(i)); | ||
164 | |||
165 | /* | ||
166 | * Chip select enabled? | ||
167 | */ | ||
168 | if (size & 1) { | ||
169 | struct mbus_dram_window *w; | ||
170 | |||
171 | w = &orion5x_mbus_dram_info.cs[cs++]; | ||
172 | w->cs_index = i; | ||
173 | w->mbus_attr = 0xf & ~(1 << i); | ||
174 | w->base = base & 0xff000000; | ||
175 | w->size = (size | 0x00ffffff) + 1; | ||
176 | } | ||
177 | } | ||
178 | orion5x_mbus_dram_info.num_cs = cs; | ||
179 | } | ||
180 | |||
181 | void __init orion5x_setup_dev_boot_win(u32 base, u32 size) | ||
182 | { | ||
183 | setup_cpu_win(4, base, size, TARGET_DEV_BUS, ATTR_DEV_BOOT, -1); | ||
184 | } | ||
185 | |||
186 | void __init orion5x_setup_dev0_win(u32 base, u32 size) | ||
187 | { | ||
188 | setup_cpu_win(5, base, size, TARGET_DEV_BUS, ATTR_DEV_CS0, -1); | ||
189 | } | ||
190 | |||
191 | void __init orion5x_setup_dev1_win(u32 base, u32 size) | ||
192 | { | ||
193 | setup_cpu_win(6, base, size, TARGET_DEV_BUS, ATTR_DEV_CS1, -1); | ||
194 | } | ||
195 | |||
196 | void __init orion5x_setup_dev2_win(u32 base, u32 size) | ||
197 | { | ||
198 | setup_cpu_win(7, base, size, TARGET_DEV_BUS, ATTR_DEV_CS2, -1); | ||
199 | } | ||
200 | |||
201 | void __init orion5x_setup_pcie_wa_win(u32 base, u32 size) | ||
202 | { | ||
203 | setup_cpu_win(7, base, size, TARGET_PCIE, ATTR_PCIE_WA, -1); | ||
204 | } | ||
205 | |||
206 | void __init orion5x_setup_eth_wins(void) | ||
207 | { | ||
208 | int i; | ||
209 | |||
210 | /* | ||
211 | * First, disable and clear windows | ||
212 | */ | ||
213 | for (i = 0; i < ETH_MAX_WIN; i++) { | ||
214 | orion5x_write(ETH_WIN_BASE(i), 0); | ||
215 | orion5x_write(ETH_WIN_SIZE(i), 0); | ||
216 | orion5x_setbits(ETH_WIN_EN, 1 << i); | ||
217 | orion5x_clrbits(ETH_WIN_PROT, 0x3 << (i * 2)); | ||
218 | if (i < ETH_MAX_REMAP_WIN) | ||
219 | orion5x_write(ETH_WIN_REMAP(i), 0); | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * Setup windows for DDR banks. | ||
224 | */ | ||
225 | for (i = 0; i < DDR_MAX_CS; i++) { | ||
226 | u32 base, size; | ||
227 | size = orion5x_read(DDR_SIZE_CS(i)); | ||
228 | base = orion5x_read(DDR_BASE_CS(i)); | ||
229 | if (size & DDR_BANK_EN) { | ||
230 | base = DDR_REG_TO_BASE(base); | ||
231 | size = DDR_REG_TO_SIZE(size); | ||
232 | orion5x_write(ETH_WIN_SIZE(i), (size-1) & 0xffff0000); | ||
233 | orion5x_write(ETH_WIN_BASE(i), (base & 0xffff0000) | | ||
234 | (ATTR_DDR_CS(i) << 8) | | ||
235 | TARGET_DDR); | ||
236 | orion5x_clrbits(ETH_WIN_EN, 1 << i); | ||
237 | orion5x_setbits(ETH_WIN_PROT, 0x3 << (i * 2)); | ||
238 | } | ||
239 | } | ||
240 | } | ||
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c new file mode 100644 index 000000000000..439c7784af02 --- /dev/null +++ b/arch/arm/mach-orion5x/common.c | |||
@@ -0,0 +1,391 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/common.c | ||
3 | * | ||
4 | * Core functions for Marvell Orion 5x SoCs | ||
5 | * | ||
6 | * Maintainer: Tzachi Perelstein <tzachi@marvell.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/serial_8250.h> | ||
17 | #include <linux/mbus.h> | ||
18 | #include <linux/mv643xx_eth.h> | ||
19 | #include <linux/mv643xx_i2c.h> | ||
20 | #include <linux/ata_platform.h> | ||
21 | #include <asm/page.h> | ||
22 | #include <asm/setup.h> | ||
23 | #include <asm/timex.h> | ||
24 | #include <asm/mach/arch.h> | ||
25 | #include <asm/mach/map.h> | ||
26 | #include <asm/mach/time.h> | ||
27 | #include <asm/arch/hardware.h> | ||
28 | #include <asm/arch/orion5x.h> | ||
29 | #include <asm/plat-orion/ehci-orion.h> | ||
30 | #include <asm/plat-orion/orion_nand.h> | ||
31 | #include <asm/plat-orion/time.h> | ||
32 | #include "common.h" | ||
33 | |||
34 | /***************************************************************************** | ||
35 | * I/O Address Mapping | ||
36 | ****************************************************************************/ | ||
37 | static struct map_desc orion5x_io_desc[] __initdata = { | ||
38 | { | ||
39 | .virtual = ORION5X_REGS_VIRT_BASE, | ||
40 | .pfn = __phys_to_pfn(ORION5X_REGS_PHYS_BASE), | ||
41 | .length = ORION5X_REGS_SIZE, | ||
42 | .type = MT_DEVICE | ||
43 | }, | ||
44 | { | ||
45 | .virtual = ORION5X_PCIE_IO_VIRT_BASE, | ||
46 | .pfn = __phys_to_pfn(ORION5X_PCIE_IO_PHYS_BASE), | ||
47 | .length = ORION5X_PCIE_IO_SIZE, | ||
48 | .type = MT_DEVICE | ||
49 | }, | ||
50 | { | ||
51 | .virtual = ORION5X_PCI_IO_VIRT_BASE, | ||
52 | .pfn = __phys_to_pfn(ORION5X_PCI_IO_PHYS_BASE), | ||
53 | .length = ORION5X_PCI_IO_SIZE, | ||
54 | .type = MT_DEVICE | ||
55 | }, | ||
56 | { | ||
57 | .virtual = ORION5X_PCIE_WA_VIRT_BASE, | ||
58 | .pfn = __phys_to_pfn(ORION5X_PCIE_WA_PHYS_BASE), | ||
59 | .length = ORION5X_PCIE_WA_SIZE, | ||
60 | .type = MT_DEVICE | ||
61 | }, | ||
62 | }; | ||
63 | |||
64 | void __init orion5x_map_io(void) | ||
65 | { | ||
66 | iotable_init(orion5x_io_desc, ARRAY_SIZE(orion5x_io_desc)); | ||
67 | } | ||
68 | |||
69 | /***************************************************************************** | ||
70 | * UART | ||
71 | ****************************************************************************/ | ||
72 | |||
73 | static struct resource orion5x_uart_resources[] = { | ||
74 | { | ||
75 | .start = UART0_PHYS_BASE, | ||
76 | .end = UART0_PHYS_BASE + 0xff, | ||
77 | .flags = IORESOURCE_MEM, | ||
78 | }, | ||
79 | { | ||
80 | .start = IRQ_ORION5X_UART0, | ||
81 | .end = IRQ_ORION5X_UART0, | ||
82 | .flags = IORESOURCE_IRQ, | ||
83 | }, | ||
84 | { | ||
85 | .start = UART1_PHYS_BASE, | ||
86 | .end = UART1_PHYS_BASE + 0xff, | ||
87 | .flags = IORESOURCE_MEM, | ||
88 | }, | ||
89 | { | ||
90 | .start = IRQ_ORION5X_UART1, | ||
91 | .end = IRQ_ORION5X_UART1, | ||
92 | .flags = IORESOURCE_IRQ, | ||
93 | }, | ||
94 | }; | ||
95 | |||
96 | static struct plat_serial8250_port orion5x_uart_data[] = { | ||
97 | { | ||
98 | .mapbase = UART0_PHYS_BASE, | ||
99 | .membase = (char *)UART0_VIRT_BASE, | ||
100 | .irq = IRQ_ORION5X_UART0, | ||
101 | .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, | ||
102 | .iotype = UPIO_MEM, | ||
103 | .regshift = 2, | ||
104 | .uartclk = ORION5X_TCLK, | ||
105 | }, | ||
106 | { | ||
107 | .mapbase = UART1_PHYS_BASE, | ||
108 | .membase = (char *)UART1_VIRT_BASE, | ||
109 | .irq = IRQ_ORION5X_UART1, | ||
110 | .flags = UPF_SKIP_TEST | UPF_BOOT_AUTOCONF, | ||
111 | .iotype = UPIO_MEM, | ||
112 | .regshift = 2, | ||
113 | .uartclk = ORION5X_TCLK, | ||
114 | }, | ||
115 | { }, | ||
116 | }; | ||
117 | |||
118 | static struct platform_device orion5x_uart = { | ||
119 | .name = "serial8250", | ||
120 | .id = PLAT8250_DEV_PLATFORM, | ||
121 | .dev = { | ||
122 | .platform_data = orion5x_uart_data, | ||
123 | }, | ||
124 | .resource = orion5x_uart_resources, | ||
125 | .num_resources = ARRAY_SIZE(orion5x_uart_resources), | ||
126 | }; | ||
127 | |||
128 | /******************************************************************************* | ||
129 | * USB Controller - 2 interfaces | ||
130 | ******************************************************************************/ | ||
131 | |||
132 | static struct resource orion5x_ehci0_resources[] = { | ||
133 | { | ||
134 | .start = ORION5X_USB0_PHYS_BASE, | ||
135 | .end = ORION5X_USB0_PHYS_BASE + SZ_4K, | ||
136 | .flags = IORESOURCE_MEM, | ||
137 | }, | ||
138 | { | ||
139 | .start = IRQ_ORION5X_USB0_CTRL, | ||
140 | .end = IRQ_ORION5X_USB0_CTRL, | ||
141 | .flags = IORESOURCE_IRQ, | ||
142 | }, | ||
143 | }; | ||
144 | |||
145 | static struct resource orion5x_ehci1_resources[] = { | ||
146 | { | ||
147 | .start = ORION5X_USB1_PHYS_BASE, | ||
148 | .end = ORION5X_USB1_PHYS_BASE + SZ_4K, | ||
149 | .flags = IORESOURCE_MEM, | ||
150 | }, | ||
151 | { | ||
152 | .start = IRQ_ORION5X_USB1_CTRL, | ||
153 | .end = IRQ_ORION5X_USB1_CTRL, | ||
154 | .flags = IORESOURCE_IRQ, | ||
155 | }, | ||
156 | }; | ||
157 | |||
158 | static struct orion_ehci_data orion5x_ehci_data = { | ||
159 | .dram = &orion5x_mbus_dram_info, | ||
160 | }; | ||
161 | |||
162 | static u64 ehci_dmamask = 0xffffffffUL; | ||
163 | |||
164 | static struct platform_device orion5x_ehci0 = { | ||
165 | .name = "orion-ehci", | ||
166 | .id = 0, | ||
167 | .dev = { | ||
168 | .dma_mask = &ehci_dmamask, | ||
169 | .coherent_dma_mask = 0xffffffff, | ||
170 | .platform_data = &orion5x_ehci_data, | ||
171 | }, | ||
172 | .resource = orion5x_ehci0_resources, | ||
173 | .num_resources = ARRAY_SIZE(orion5x_ehci0_resources), | ||
174 | }; | ||
175 | |||
176 | static struct platform_device orion5x_ehci1 = { | ||
177 | .name = "orion-ehci", | ||
178 | .id = 1, | ||
179 | .dev = { | ||
180 | .dma_mask = &ehci_dmamask, | ||
181 | .coherent_dma_mask = 0xffffffff, | ||
182 | .platform_data = &orion5x_ehci_data, | ||
183 | }, | ||
184 | .resource = orion5x_ehci1_resources, | ||
185 | .num_resources = ARRAY_SIZE(orion5x_ehci1_resources), | ||
186 | }; | ||
187 | |||
188 | /***************************************************************************** | ||
189 | * Gigabit Ethernet port | ||
190 | * (The Orion and Discovery (MV643xx) families use the same Ethernet driver) | ||
191 | ****************************************************************************/ | ||
192 | |||
193 | static struct resource orion5x_eth_shared_resources[] = { | ||
194 | { | ||
195 | .start = ORION5X_ETH_PHYS_BASE + 0x2000, | ||
196 | .end = ORION5X_ETH_PHYS_BASE + 0x3fff, | ||
197 | .flags = IORESOURCE_MEM, | ||
198 | }, | ||
199 | }; | ||
200 | |||
201 | static struct platform_device orion5x_eth_shared = { | ||
202 | .name = MV643XX_ETH_SHARED_NAME, | ||
203 | .id = 0, | ||
204 | .num_resources = 1, | ||
205 | .resource = orion5x_eth_shared_resources, | ||
206 | }; | ||
207 | |||
208 | static struct resource orion5x_eth_resources[] = { | ||
209 | { | ||
210 | .name = "eth irq", | ||
211 | .start = IRQ_ORION5X_ETH_SUM, | ||
212 | .end = IRQ_ORION5X_ETH_SUM, | ||
213 | .flags = IORESOURCE_IRQ, | ||
214 | } | ||
215 | }; | ||
216 | |||
217 | static struct platform_device orion5x_eth = { | ||
218 | .name = MV643XX_ETH_NAME, | ||
219 | .id = 0, | ||
220 | .num_resources = 1, | ||
221 | .resource = orion5x_eth_resources, | ||
222 | }; | ||
223 | |||
224 | void __init orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data) | ||
225 | { | ||
226 | orion5x_eth.dev.platform_data = eth_data; | ||
227 | platform_device_register(&orion5x_eth_shared); | ||
228 | platform_device_register(&orion5x_eth); | ||
229 | } | ||
230 | |||
231 | /***************************************************************************** | ||
232 | * I2C controller | ||
233 | * (The Orion and Discovery (MV643xx) families share the same I2C controller) | ||
234 | ****************************************************************************/ | ||
235 | |||
236 | static struct mv64xxx_i2c_pdata orion5x_i2c_pdata = { | ||
237 | .freq_m = 8, /* assumes 166 MHz TCLK */ | ||
238 | .freq_n = 3, | ||
239 | .timeout = 1000, /* Default timeout of 1 second */ | ||
240 | }; | ||
241 | |||
242 | static struct resource orion5x_i2c_resources[] = { | ||
243 | { | ||
244 | .name = "i2c base", | ||
245 | .start = I2C_PHYS_BASE, | ||
246 | .end = I2C_PHYS_BASE + 0x20 -1, | ||
247 | .flags = IORESOURCE_MEM, | ||
248 | }, | ||
249 | { | ||
250 | .name = "i2c irq", | ||
251 | .start = IRQ_ORION5X_I2C, | ||
252 | .end = IRQ_ORION5X_I2C, | ||
253 | .flags = IORESOURCE_IRQ, | ||
254 | }, | ||
255 | }; | ||
256 | |||
257 | static struct platform_device orion5x_i2c = { | ||
258 | .name = MV64XXX_I2C_CTLR_NAME, | ||
259 | .id = 0, | ||
260 | .num_resources = ARRAY_SIZE(orion5x_i2c_resources), | ||
261 | .resource = orion5x_i2c_resources, | ||
262 | .dev = { | ||
263 | .platform_data = &orion5x_i2c_pdata, | ||
264 | }, | ||
265 | }; | ||
266 | |||
267 | /***************************************************************************** | ||
268 | * Sata port | ||
269 | ****************************************************************************/ | ||
270 | static struct resource orion5x_sata_resources[] = { | ||
271 | { | ||
272 | .name = "sata base", | ||
273 | .start = ORION5X_SATA_PHYS_BASE, | ||
274 | .end = ORION5X_SATA_PHYS_BASE + 0x5000 - 1, | ||
275 | .flags = IORESOURCE_MEM, | ||
276 | }, | ||
277 | { | ||
278 | .name = "sata irq", | ||
279 | .start = IRQ_ORION5X_SATA, | ||
280 | .end = IRQ_ORION5X_SATA, | ||
281 | .flags = IORESOURCE_IRQ, | ||
282 | }, | ||
283 | }; | ||
284 | |||
285 | static struct platform_device orion5x_sata = { | ||
286 | .name = "sata_mv", | ||
287 | .id = 0, | ||
288 | .dev = { | ||
289 | .coherent_dma_mask = 0xffffffff, | ||
290 | }, | ||
291 | .num_resources = ARRAY_SIZE(orion5x_sata_resources), | ||
292 | .resource = orion5x_sata_resources, | ||
293 | }; | ||
294 | |||
295 | void __init orion5x_sata_init(struct mv_sata_platform_data *sata_data) | ||
296 | { | ||
297 | sata_data->dram = &orion5x_mbus_dram_info; | ||
298 | orion5x_sata.dev.platform_data = sata_data; | ||
299 | platform_device_register(&orion5x_sata); | ||
300 | } | ||
301 | |||
302 | /***************************************************************************** | ||
303 | * Time handling | ||
304 | ****************************************************************************/ | ||
305 | |||
306 | static void orion5x_timer_init(void) | ||
307 | { | ||
308 | orion_time_init(IRQ_ORION5X_BRIDGE, ORION5X_TCLK); | ||
309 | } | ||
310 | |||
311 | struct sys_timer orion5x_timer = { | ||
312 | .init = orion5x_timer_init, | ||
313 | }; | ||
314 | |||
315 | /***************************************************************************** | ||
316 | * General | ||
317 | ****************************************************************************/ | ||
318 | |||
319 | /* | ||
320 | * Identify device ID and rev from PCIE configuration header space '0'. | ||
321 | */ | ||
322 | static void __init orion5x_id(u32 *dev, u32 *rev, char **dev_name) | ||
323 | { | ||
324 | orion5x_pcie_id(dev, rev); | ||
325 | |||
326 | if (*dev == MV88F5281_DEV_ID) { | ||
327 | if (*rev == MV88F5281_REV_D2) { | ||
328 | *dev_name = "MV88F5281-D2"; | ||
329 | } else if (*rev == MV88F5281_REV_D1) { | ||
330 | *dev_name = "MV88F5281-D1"; | ||
331 | } else { | ||
332 | *dev_name = "MV88F5281-Rev-Unsupported"; | ||
333 | } | ||
334 | } else if (*dev == MV88F5182_DEV_ID) { | ||
335 | if (*rev == MV88F5182_REV_A2) { | ||
336 | *dev_name = "MV88F5182-A2"; | ||
337 | } else { | ||
338 | *dev_name = "MV88F5182-Rev-Unsupported"; | ||
339 | } | ||
340 | } else if (*dev == MV88F5181_DEV_ID) { | ||
341 | if (*rev == MV88F5181_REV_B1) { | ||
342 | *dev_name = "MV88F5181-Rev-B1"; | ||
343 | } else { | ||
344 | *dev_name = "MV88F5181-Rev-Unsupported"; | ||
345 | } | ||
346 | } else { | ||
347 | *dev_name = "Device-Unknown"; | ||
348 | } | ||
349 | } | ||
350 | |||
351 | void __init orion5x_init(void) | ||
352 | { | ||
353 | char *dev_name; | ||
354 | u32 dev, rev; | ||
355 | |||
356 | orion5x_id(&dev, &rev, &dev_name); | ||
357 | printk(KERN_INFO "Orion ID: %s. TCLK=%d.\n", dev_name, ORION5X_TCLK); | ||
358 | |||
359 | /* | ||
360 | * Setup Orion address map | ||
361 | */ | ||
362 | orion5x_setup_cpu_mbus_bridge(); | ||
363 | orion5x_setup_eth_wins(); | ||
364 | |||
365 | /* | ||
366 | * Register devices. | ||
367 | */ | ||
368 | platform_device_register(&orion5x_uart); | ||
369 | platform_device_register(&orion5x_ehci0); | ||
370 | if (dev == MV88F5182_DEV_ID) | ||
371 | platform_device_register(&orion5x_ehci1); | ||
372 | platform_device_register(&orion5x_i2c); | ||
373 | } | ||
374 | |||
375 | /* | ||
376 | * Many orion-based systems have buggy bootloader implementations. | ||
377 | * This is a common fixup for bogus memory tags. | ||
378 | */ | ||
379 | void __init tag_fixup_mem32(struct machine_desc *mdesc, struct tag *t, | ||
380 | char **from, struct meminfo *meminfo) | ||
381 | { | ||
382 | for (; t->hdr.size; t = tag_next(t)) | ||
383 | if (t->hdr.tag == ATAG_MEM && | ||
384 | (!t->u.mem.size || t->u.mem.size & ~PAGE_MASK || | ||
385 | t->u.mem.start & ~PAGE_MASK)) { | ||
386 | printk(KERN_WARNING | ||
387 | "Clearing invalid memory bank %dKB@0x%08x\n", | ||
388 | t->u.mem.size / 1024, t->u.mem.start); | ||
389 | t->hdr.tag = 0; | ||
390 | } | ||
391 | } | ||
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h new file mode 100644 index 000000000000..f4c4c9a72a7c --- /dev/null +++ b/arch/arm/mach-orion5x/common.h | |||
@@ -0,0 +1,72 @@ | |||
1 | #ifndef __ARCH_ORION5X_COMMON_H | ||
2 | #define __ARCH_ORION5X_COMMON_H | ||
3 | |||
4 | /* | ||
5 | * Basic Orion init functions used early by machine-setup. | ||
6 | */ | ||
7 | |||
8 | void orion5x_map_io(void); | ||
9 | void orion5x_init_irq(void); | ||
10 | void orion5x_init(void); | ||
11 | extern struct sys_timer orion5x_timer; | ||
12 | |||
13 | /* | ||
14 | * Enumerations and functions for Orion windows mapping. Used by Orion core | ||
15 | * functions to map its interfaces and by the machine-setup to map its on- | ||
16 | * board devices. Details in /mach-orion/addr-map.c | ||
17 | */ | ||
18 | extern struct mbus_dram_target_info orion5x_mbus_dram_info; | ||
19 | void orion5x_setup_cpu_mbus_bridge(void); | ||
20 | void orion5x_setup_dev_boot_win(u32 base, u32 size); | ||
21 | void orion5x_setup_dev0_win(u32 base, u32 size); | ||
22 | void orion5x_setup_dev1_win(u32 base, u32 size); | ||
23 | void orion5x_setup_dev2_win(u32 base, u32 size); | ||
24 | void orion5x_setup_pcie_wa_win(u32 base, u32 size); | ||
25 | void orion5x_setup_eth_wins(void); | ||
26 | |||
27 | /* | ||
28 | * Shared code used internally by other Orion core functions. | ||
29 | * (/mach-orion/pci.c) | ||
30 | */ | ||
31 | |||
32 | struct pci_sys_data; | ||
33 | struct pci_bus; | ||
34 | |||
35 | void orion5x_pcie_id(u32 *dev, u32 *rev); | ||
36 | int orion5x_pcie_local_bus_nr(void); | ||
37 | int orion5x_pci_local_bus_nr(void); | ||
38 | int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys); | ||
39 | struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys); | ||
40 | |||
41 | /* | ||
42 | * Valid GPIO pins according to MPP setup, used by machine-setup. | ||
43 | * (/mach-orion/gpio.c). | ||
44 | */ | ||
45 | |||
46 | void orion5x_gpio_set_valid_pins(u32 pins); | ||
47 | void gpio_display(void); /* debug */ | ||
48 | |||
49 | /* | ||
50 | * Pull in Orion Ethernet platform_data, used by machine-setup | ||
51 | */ | ||
52 | |||
53 | struct mv643xx_eth_platform_data; | ||
54 | |||
55 | void orion5x_eth_init(struct mv643xx_eth_platform_data *eth_data); | ||
56 | |||
57 | /* | ||
58 | * Orion Sata platform_data, used by machine-setup | ||
59 | */ | ||
60 | |||
61 | struct mv_sata_platform_data; | ||
62 | |||
63 | void orion5x_sata_init(struct mv_sata_platform_data *sata_data); | ||
64 | |||
65 | struct machine_desc; | ||
66 | struct meminfo; | ||
67 | struct tag; | ||
68 | extern void __init tag_fixup_mem32(struct machine_desc *, struct tag *, | ||
69 | char **, struct meminfo *); | ||
70 | |||
71 | |||
72 | #endif | ||
diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c new file mode 100644 index 000000000000..872aed372327 --- /dev/null +++ b/arch/arm/mach-orion5x/db88f5281-setup.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/db88f5281-setup.c | ||
3 | * | ||
4 | * Marvell Orion-2 Development Board Setup | ||
5 | * | ||
6 | * Maintainer: Tzachi Perelstein <tzachi@marvell.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/mtd/physmap.h> | ||
19 | #include <linux/mtd/nand.h> | ||
20 | #include <linux/timer.h> | ||
21 | #include <linux/mv643xx_eth.h> | ||
22 | #include <linux/i2c.h> | ||
23 | #include <asm/mach-types.h> | ||
24 | #include <asm/gpio.h> | ||
25 | #include <asm/mach/arch.h> | ||
26 | #include <asm/mach/pci.h> | ||
27 | #include <asm/arch/orion5x.h> | ||
28 | #include <asm/plat-orion/orion_nand.h> | ||
29 | #include "common.h" | ||
30 | |||
31 | /***************************************************************************** | ||
32 | * DB-88F5281 on board devices | ||
33 | ****************************************************************************/ | ||
34 | |||
35 | /* | ||
36 | * 512K NOR flash Device bus boot chip select | ||
37 | */ | ||
38 | |||
39 | #define DB88F5281_NOR_BOOT_BASE 0xf4000000 | ||
40 | #define DB88F5281_NOR_BOOT_SIZE SZ_512K | ||
41 | |||
42 | /* | ||
43 | * 7-Segment on Device bus chip select 0 | ||
44 | */ | ||
45 | |||
46 | #define DB88F5281_7SEG_BASE 0xfa000000 | ||
47 | #define DB88F5281_7SEG_SIZE SZ_1K | ||
48 | |||
49 | /* | ||
50 | * 32M NOR flash on Device bus chip select 1 | ||
51 | */ | ||
52 | |||
53 | #define DB88F5281_NOR_BASE 0xfc000000 | ||
54 | #define DB88F5281_NOR_SIZE SZ_32M | ||
55 | |||
56 | /* | ||
57 | * 32M NAND flash on Device bus chip select 2 | ||
58 | */ | ||
59 | |||
60 | #define DB88F5281_NAND_BASE 0xfa800000 | ||
61 | #define DB88F5281_NAND_SIZE SZ_1K | ||
62 | |||
63 | /* | ||
64 | * PCI | ||
65 | */ | ||
66 | |||
67 | #define DB88F5281_PCI_SLOT0_OFFS 7 | ||
68 | #define DB88F5281_PCI_SLOT0_IRQ_PIN 12 | ||
69 | #define DB88F5281_PCI_SLOT1_SLOT2_IRQ_PIN 13 | ||
70 | |||
71 | /***************************************************************************** | ||
72 | * 512M NOR Flash on Device bus Boot CS | ||
73 | ****************************************************************************/ | ||
74 | |||
75 | static struct physmap_flash_data db88f5281_boot_flash_data = { | ||
76 | .width = 1, /* 8 bit bus width */ | ||
77 | }; | ||
78 | |||
79 | static struct resource db88f5281_boot_flash_resource = { | ||
80 | .flags = IORESOURCE_MEM, | ||
81 | .start = DB88F5281_NOR_BOOT_BASE, | ||
82 | .end = DB88F5281_NOR_BOOT_BASE + DB88F5281_NOR_BOOT_SIZE - 1, | ||
83 | }; | ||
84 | |||
85 | static struct platform_device db88f5281_boot_flash = { | ||
86 | .name = "physmap-flash", | ||
87 | .id = 0, | ||
88 | .dev = { | ||
89 | .platform_data = &db88f5281_boot_flash_data, | ||
90 | }, | ||
91 | .num_resources = 1, | ||
92 | .resource = &db88f5281_boot_flash_resource, | ||
93 | }; | ||
94 | |||
95 | /***************************************************************************** | ||
96 | * 32M NOR Flash on Device bus CS1 | ||
97 | ****************************************************************************/ | ||
98 | |||
99 | static struct physmap_flash_data db88f5281_nor_flash_data = { | ||
100 | .width = 4, /* 32 bit bus width */ | ||
101 | }; | ||
102 | |||
103 | static struct resource db88f5281_nor_flash_resource = { | ||
104 | .flags = IORESOURCE_MEM, | ||
105 | .start = DB88F5281_NOR_BASE, | ||
106 | .end = DB88F5281_NOR_BASE + DB88F5281_NOR_SIZE - 1, | ||
107 | }; | ||
108 | |||
109 | static struct platform_device db88f5281_nor_flash = { | ||
110 | .name = "physmap-flash", | ||
111 | .id = 1, | ||
112 | .dev = { | ||
113 | .platform_data = &db88f5281_nor_flash_data, | ||
114 | }, | ||
115 | .num_resources = 1, | ||
116 | .resource = &db88f5281_nor_flash_resource, | ||
117 | }; | ||
118 | |||
119 | /***************************************************************************** | ||
120 | * 32M NAND Flash on Device bus CS2 | ||
121 | ****************************************************************************/ | ||
122 | |||
123 | static struct mtd_partition db88f5281_nand_parts[] = { | ||
124 | { | ||
125 | .name = "kernel", | ||
126 | .offset = 0, | ||
127 | .size = SZ_2M, | ||
128 | }, | ||
129 | { | ||
130 | .name = "root", | ||
131 | .offset = SZ_2M, | ||
132 | .size = (SZ_16M - SZ_2M), | ||
133 | }, | ||
134 | { | ||
135 | .name = "user", | ||
136 | .offset = SZ_16M, | ||
137 | .size = SZ_8M, | ||
138 | }, | ||
139 | { | ||
140 | .name = "recovery", | ||
141 | .offset = (SZ_16M + SZ_8M), | ||
142 | .size = SZ_8M, | ||
143 | }, | ||
144 | }; | ||
145 | |||
146 | static struct resource db88f5281_nand_resource = { | ||
147 | .flags = IORESOURCE_MEM, | ||
148 | .start = DB88F5281_NAND_BASE, | ||
149 | .end = DB88F5281_NAND_BASE + DB88F5281_NAND_SIZE - 1, | ||
150 | }; | ||
151 | |||
152 | static struct orion_nand_data db88f5281_nand_data = { | ||
153 | .parts = db88f5281_nand_parts, | ||
154 | .nr_parts = ARRAY_SIZE(db88f5281_nand_parts), | ||
155 | .cle = 0, | ||
156 | .ale = 1, | ||
157 | .width = 8, | ||
158 | }; | ||
159 | |||
160 | static struct platform_device db88f5281_nand_flash = { | ||
161 | .name = "orion_nand", | ||
162 | .id = -1, | ||
163 | .dev = { | ||
164 | .platform_data = &db88f5281_nand_data, | ||
165 | }, | ||
166 | .resource = &db88f5281_nand_resource, | ||
167 | .num_resources = 1, | ||
168 | }; | ||
169 | |||
170 | /***************************************************************************** | ||
171 | * 7-Segment on Device bus CS0 | ||
172 | * Dummy counter every 2 sec | ||
173 | ****************************************************************************/ | ||
174 | |||
175 | static void __iomem *db88f5281_7seg; | ||
176 | static struct timer_list db88f5281_timer; | ||
177 | |||
178 | static void db88f5281_7seg_event(unsigned long data) | ||
179 | { | ||
180 | static int count = 0; | ||
181 | writel(0, db88f5281_7seg + (count << 4)); | ||
182 | count = (count + 1) & 7; | ||
183 | mod_timer(&db88f5281_timer, jiffies + 2 * HZ); | ||
184 | } | ||
185 | |||
186 | static int __init db88f5281_7seg_init(void) | ||
187 | { | ||
188 | if (machine_is_db88f5281()) { | ||
189 | db88f5281_7seg = ioremap(DB88F5281_7SEG_BASE, | ||
190 | DB88F5281_7SEG_SIZE); | ||
191 | if (!db88f5281_7seg) { | ||
192 | printk(KERN_ERR "Failed to ioremap db88f5281_7seg\n"); | ||
193 | return -EIO; | ||
194 | } | ||
195 | setup_timer(&db88f5281_timer, db88f5281_7seg_event, 0); | ||
196 | mod_timer(&db88f5281_timer, jiffies + 2 * HZ); | ||
197 | } | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | __initcall(db88f5281_7seg_init); | ||
203 | |||
204 | /***************************************************************************** | ||
205 | * PCI | ||
206 | ****************************************************************************/ | ||
207 | |||
208 | void __init db88f5281_pci_preinit(void) | ||
209 | { | ||
210 | int pin; | ||
211 | |||
212 | /* | ||
213 | * Configure PCI GPIO IRQ pins | ||
214 | */ | ||
215 | pin = DB88F5281_PCI_SLOT0_IRQ_PIN; | ||
216 | if (gpio_request(pin, "PCI Int1") == 0) { | ||
217 | if (gpio_direction_input(pin) == 0) { | ||
218 | set_irq_type(gpio_to_irq(pin), IRQT_LOW); | ||
219 | } else { | ||
220 | printk(KERN_ERR "db88f5281_pci_preinit faield to " | ||
221 | "set_irq_type pin %d\n", pin); | ||
222 | gpio_free(pin); | ||
223 | } | ||
224 | } else { | ||
225 | printk(KERN_ERR "db88f5281_pci_preinit failed to gpio_request %d\n", pin); | ||
226 | } | ||
227 | |||
228 | pin = DB88F5281_PCI_SLOT1_SLOT2_IRQ_PIN; | ||
229 | if (gpio_request(pin, "PCI Int2") == 0) { | ||
230 | if (gpio_direction_input(pin) == 0) { | ||
231 | set_irq_type(gpio_to_irq(pin), IRQT_LOW); | ||
232 | } else { | ||
233 | printk(KERN_ERR "db88f5281_pci_preinit faield " | ||
234 | "to set_irq_type pin %d\n", pin); | ||
235 | gpio_free(pin); | ||
236 | } | ||
237 | } else { | ||
238 | printk(KERN_ERR "db88f5281_pci_preinit failed to gpio_request %d\n", pin); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | static int __init db88f5281_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
243 | { | ||
244 | /* | ||
245 | * PCIE IRQ is connected internally (not GPIO) | ||
246 | */ | ||
247 | if (dev->bus->number == orion5x_pcie_local_bus_nr()) | ||
248 | return IRQ_ORION5X_PCIE0_INT; | ||
249 | |||
250 | /* | ||
251 | * PCI IRQs are connected via GPIOs | ||
252 | */ | ||
253 | switch (slot - DB88F5281_PCI_SLOT0_OFFS) { | ||
254 | case 0: | ||
255 | return gpio_to_irq(DB88F5281_PCI_SLOT0_IRQ_PIN); | ||
256 | case 1: | ||
257 | case 2: | ||
258 | return gpio_to_irq(DB88F5281_PCI_SLOT1_SLOT2_IRQ_PIN); | ||
259 | default: | ||
260 | return -1; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | static struct hw_pci db88f5281_pci __initdata = { | ||
265 | .nr_controllers = 2, | ||
266 | .preinit = db88f5281_pci_preinit, | ||
267 | .swizzle = pci_std_swizzle, | ||
268 | .setup = orion5x_pci_sys_setup, | ||
269 | .scan = orion5x_pci_sys_scan_bus, | ||
270 | .map_irq = db88f5281_pci_map_irq, | ||
271 | }; | ||
272 | |||
273 | static int __init db88f5281_pci_init(void) | ||
274 | { | ||
275 | if (machine_is_db88f5281()) | ||
276 | pci_common_init(&db88f5281_pci); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | subsys_initcall(db88f5281_pci_init); | ||
282 | |||
283 | /***************************************************************************** | ||
284 | * Ethernet | ||
285 | ****************************************************************************/ | ||
286 | static struct mv643xx_eth_platform_data db88f5281_eth_data = { | ||
287 | .phy_addr = 8, | ||
288 | .force_phy_addr = 1, | ||
289 | }; | ||
290 | |||
291 | /***************************************************************************** | ||
292 | * RTC DS1339 on I2C bus | ||
293 | ****************************************************************************/ | ||
294 | static struct i2c_board_info __initdata db88f5281_i2c_rtc = { | ||
295 | .driver_name = "rtc-ds1307", | ||
296 | .type = "ds1339", | ||
297 | .addr = 0x68, | ||
298 | }; | ||
299 | |||
300 | /***************************************************************************** | ||
301 | * General Setup | ||
302 | ****************************************************************************/ | ||
303 | |||
304 | static struct platform_device *db88f5281_devs[] __initdata = { | ||
305 | &db88f5281_boot_flash, | ||
306 | &db88f5281_nor_flash, | ||
307 | &db88f5281_nand_flash, | ||
308 | }; | ||
309 | |||
310 | static void __init db88f5281_init(void) | ||
311 | { | ||
312 | /* | ||
313 | * Basic Orion setup. Need to be called early. | ||
314 | */ | ||
315 | orion5x_init(); | ||
316 | |||
317 | /* | ||
318 | * Setup the CPU address decode windows for our on-board devices | ||
319 | */ | ||
320 | orion5x_setup_dev_boot_win(DB88F5281_NOR_BOOT_BASE, | ||
321 | DB88F5281_NOR_BOOT_SIZE); | ||
322 | orion5x_setup_dev0_win(DB88F5281_7SEG_BASE, DB88F5281_7SEG_SIZE); | ||
323 | orion5x_setup_dev1_win(DB88F5281_NOR_BASE, DB88F5281_NOR_SIZE); | ||
324 | orion5x_setup_dev2_win(DB88F5281_NAND_BASE, DB88F5281_NAND_SIZE); | ||
325 | |||
326 | /* | ||
327 | * Setup Multiplexing Pins: | ||
328 | * MPP0: GPIO (USB Over Current) MPP1: GPIO (USB Vbat input) | ||
329 | * MPP2: PCI_REQn[2] MPP3: PCI_GNTn[2] | ||
330 | * MPP4: PCI_REQn[3] MPP5: PCI_GNTn[3] | ||
331 | * MPP6: GPIO (JP0, CON17.2) MPP7: GPIO (JP1, CON17.1) | ||
332 | * MPP8: GPIO (JP2, CON11.2) MPP9: GPIO (JP3, CON11.3) | ||
333 | * MPP10: GPIO (RTC int) MPP11: GPIO (Baud Rate Generator) | ||
334 | * MPP12: GPIO (PCI int 1) MPP13: GPIO (PCI int 2) | ||
335 | * MPP14: NAND_REn[2] MPP15: NAND_WEn[2] | ||
336 | * MPP16: UART1_RX MPP17: UART1_TX | ||
337 | * MPP18: UART1_CTS MPP19: UART1_RTS | ||
338 | * MPP-DEV: DEV_D[16:31] | ||
339 | */ | ||
340 | orion5x_write(MPP_0_7_CTRL, 0x00222203); | ||
341 | orion5x_write(MPP_8_15_CTRL, 0x44000000); | ||
342 | orion5x_write(MPP_16_19_CTRL, 0); | ||
343 | orion5x_write(MPP_DEV_CTRL, 0); | ||
344 | |||
345 | orion5x_gpio_set_valid_pins(0x00003fc3); | ||
346 | |||
347 | platform_add_devices(db88f5281_devs, ARRAY_SIZE(db88f5281_devs)); | ||
348 | i2c_register_board_info(0, &db88f5281_i2c_rtc, 1); | ||
349 | orion5x_eth_init(&db88f5281_eth_data); | ||
350 | } | ||
351 | |||
352 | MACHINE_START(DB88F5281, "Marvell Orion-2 Development Board") | ||
353 | /* Maintainer: Tzachi Perelstein <tzachi@marvell.com> */ | ||
354 | .phys_io = ORION5X_REGS_PHYS_BASE, | ||
355 | .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xfffc, | ||
356 | .boot_params = 0x00000100, | ||
357 | .init_machine = db88f5281_init, | ||
358 | .map_io = orion5x_map_io, | ||
359 | .init_irq = orion5x_init_irq, | ||
360 | .timer = &orion5x_timer, | ||
361 | MACHINE_END | ||
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c new file mode 100644 index 000000000000..d67790ef236e --- /dev/null +++ b/arch/arm/mach-orion5x/dns323-setup.c | |||
@@ -0,0 +1,320 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/dns323-setup.c | ||
3 | * | ||
4 | * Copyright (C) 2007 Herbert Valerio Riedel <hvr@gnu.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU Lesser General Public License as | ||
8 | * published by the Free Software Foundation; either version 2 of the | ||
9 | * License, or (at your option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/mtd/physmap.h> | ||
19 | #include <linux/mv643xx_eth.h> | ||
20 | #include <linux/leds.h> | ||
21 | #include <linux/gpio_keys.h> | ||
22 | #include <linux/input.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <asm/mach-types.h> | ||
25 | #include <asm/gpio.h> | ||
26 | #include <asm/mach/arch.h> | ||
27 | #include <asm/mach/pci.h> | ||
28 | #include <asm/arch/orion5x.h> | ||
29 | #include "common.h" | ||
30 | |||
31 | #define DNS323_GPIO_LED_RIGHT_AMBER 1 | ||
32 | #define DNS323_GPIO_LED_LEFT_AMBER 2 | ||
33 | #define DNS323_GPIO_LED_POWER 5 | ||
34 | #define DNS323_GPIO_OVERTEMP 6 | ||
35 | #define DNS323_GPIO_RTC 7 | ||
36 | #define DNS323_GPIO_POWER_OFF 8 | ||
37 | #define DNS323_GPIO_KEY_POWER 9 | ||
38 | #define DNS323_GPIO_KEY_RESET 10 | ||
39 | |||
40 | /**************************************************************************** | ||
41 | * PCI setup | ||
42 | */ | ||
43 | |||
44 | static int __init dns323_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
45 | { | ||
46 | /* PCI-E */ | ||
47 | if (dev->bus->number == orion5x_pcie_local_bus_nr()) | ||
48 | return IRQ_ORION5X_PCIE0_INT; | ||
49 | |||
50 | pr_err("%s: requested mapping for unknown bus\n", __func__); | ||
51 | |||
52 | return -1; | ||
53 | } | ||
54 | |||
55 | static struct hw_pci dns323_pci __initdata = { | ||
56 | .nr_controllers = 1, | ||
57 | .swizzle = pci_std_swizzle, | ||
58 | .setup = orion5x_pci_sys_setup, | ||
59 | .scan = orion5x_pci_sys_scan_bus, | ||
60 | .map_irq = dns323_pci_map_irq, | ||
61 | }; | ||
62 | |||
63 | static int __init dns323_pci_init(void) | ||
64 | { | ||
65 | if (machine_is_dns323()) | ||
66 | pci_common_init(&dns323_pci); | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | subsys_initcall(dns323_pci_init); | ||
72 | |||
73 | /**************************************************************************** | ||
74 | * Ethernet | ||
75 | */ | ||
76 | |||
77 | static struct mv643xx_eth_platform_data dns323_eth_data = { | ||
78 | .phy_addr = 8, | ||
79 | .force_phy_addr = 1, | ||
80 | }; | ||
81 | |||
82 | /**************************************************************************** | ||
83 | * 8MiB NOR flash (Spansion S29GL064M90TFIR4) | ||
84 | * | ||
85 | * Layout as used by D-Link: | ||
86 | * 0x00000000-0x00010000 : "MTD1" | ||
87 | * 0x00010000-0x00020000 : "MTD2" | ||
88 | * 0x00020000-0x001a0000 : "Linux Kernel" | ||
89 | * 0x001a0000-0x007d0000 : "File System" | ||
90 | * 0x007d0000-0x00800000 : "u-boot" | ||
91 | */ | ||
92 | |||
93 | #define DNS323_NOR_BOOT_BASE 0xf4000000 | ||
94 | #define DNS323_NOR_BOOT_SIZE SZ_8M | ||
95 | |||
96 | static struct mtd_partition dns323_partitions[] = { | ||
97 | { | ||
98 | .name = "MTD1", | ||
99 | .size = 0x00010000, | ||
100 | .offset = 0, | ||
101 | }, { | ||
102 | .name = "MTD2", | ||
103 | .size = 0x00010000, | ||
104 | .offset = 0x00010000, | ||
105 | }, { | ||
106 | .name = "Linux Kernel", | ||
107 | .size = 0x00180000, | ||
108 | .offset = 0x00020000, | ||
109 | }, { | ||
110 | .name = "File System", | ||
111 | .size = 0x00630000, | ||
112 | .offset = 0x001A0000, | ||
113 | }, { | ||
114 | .name = "u-boot", | ||
115 | .size = 0x00030000, | ||
116 | .offset = 0x007d0000, | ||
117 | } | ||
118 | }; | ||
119 | |||
120 | static struct physmap_flash_data dns323_nor_flash_data = { | ||
121 | .width = 1, | ||
122 | .parts = dns323_partitions, | ||
123 | .nr_parts = ARRAY_SIZE(dns323_partitions) | ||
124 | }; | ||
125 | |||
126 | static struct resource dns323_nor_flash_resource = { | ||
127 | .flags = IORESOURCE_MEM, | ||
128 | .start = DNS323_NOR_BOOT_BASE, | ||
129 | .end = DNS323_NOR_BOOT_BASE + DNS323_NOR_BOOT_SIZE - 1, | ||
130 | }; | ||
131 | |||
132 | static struct platform_device dns323_nor_flash = { | ||
133 | .name = "physmap-flash", | ||
134 | .id = 0, | ||
135 | .dev = { .platform_data = &dns323_nor_flash_data, }, | ||
136 | .resource = &dns323_nor_flash_resource, | ||
137 | .num_resources = 1, | ||
138 | }; | ||
139 | |||
140 | /**************************************************************************** | ||
141 | * GPIO LEDs (simple - doesn't use hardware blinking support) | ||
142 | */ | ||
143 | |||
144 | static struct gpio_led dns323_leds[] = { | ||
145 | { | ||
146 | .name = "power:blue", | ||
147 | .gpio = DNS323_GPIO_LED_POWER, | ||
148 | .active_low = 1, | ||
149 | }, { | ||
150 | .name = "right:amber", | ||
151 | .gpio = DNS323_GPIO_LED_RIGHT_AMBER, | ||
152 | .active_low = 1, | ||
153 | }, { | ||
154 | .name = "left:amber", | ||
155 | .gpio = DNS323_GPIO_LED_LEFT_AMBER, | ||
156 | .active_low = 1, | ||
157 | }, | ||
158 | }; | ||
159 | |||
160 | static struct gpio_led_platform_data dns323_led_data = { | ||
161 | .num_leds = ARRAY_SIZE(dns323_leds), | ||
162 | .leds = dns323_leds, | ||
163 | }; | ||
164 | |||
165 | static struct platform_device dns323_gpio_leds = { | ||
166 | .name = "leds-gpio", | ||
167 | .id = -1, | ||
168 | .dev = { .platform_data = &dns323_led_data, }, | ||
169 | }; | ||
170 | |||
171 | /**************************************************************************** | ||
172 | * GPIO Attached Keys | ||
173 | */ | ||
174 | |||
175 | static struct gpio_keys_button dns323_buttons[] = { | ||
176 | { | ||
177 | .code = KEY_RESTART, | ||
178 | .gpio = DNS323_GPIO_KEY_RESET, | ||
179 | .desc = "Reset Button", | ||
180 | .active_low = 1, | ||
181 | }, | ||
182 | { | ||
183 | .code = KEY_POWER, | ||
184 | .gpio = DNS323_GPIO_KEY_POWER, | ||
185 | .desc = "Power Button", | ||
186 | .active_low = 1, | ||
187 | } | ||
188 | }; | ||
189 | |||
190 | static struct gpio_keys_platform_data dns323_button_data = { | ||
191 | .buttons = dns323_buttons, | ||
192 | .nbuttons = ARRAY_SIZE(dns323_buttons), | ||
193 | }; | ||
194 | |||
195 | static struct platform_device dns323_button_device = { | ||
196 | .name = "gpio-keys", | ||
197 | .id = -1, | ||
198 | .num_resources = 0, | ||
199 | .dev = { .platform_data = &dns323_button_data, }, | ||
200 | }; | ||
201 | |||
202 | /**************************************************************************** | ||
203 | * General Setup | ||
204 | */ | ||
205 | |||
206 | static struct platform_device *dns323_plat_devices[] __initdata = { | ||
207 | &dns323_nor_flash, | ||
208 | &dns323_gpio_leds, | ||
209 | &dns323_button_device, | ||
210 | }; | ||
211 | |||
212 | /* | ||
213 | * On the DNS-323 the following devices are attached via I2C: | ||
214 | * | ||
215 | * i2c addr | chip | description | ||
216 | * 0x3e | GMT G760Af | fan speed PWM controller | ||
217 | * 0x48 | GMT G751-2f | temp. sensor and therm. watchdog (LM75 compatible) | ||
218 | * 0x68 | ST M41T80 | RTC w/ alarm | ||
219 | */ | ||
220 | static struct i2c_board_info __initdata dns323_i2c_devices[] = { | ||
221 | { | ||
222 | I2C_BOARD_INFO("g760a", 0x3e), | ||
223 | .type = "g760a", | ||
224 | }, | ||
225 | #if 0 | ||
226 | /* this entry requires the new-style driver model lm75 driver, | ||
227 | * for the meantime "insmod lm75.ko force_lm75=0,0x48" is needed */ | ||
228 | { | ||
229 | I2C_BOARD_INFO("lm75", 0x48), | ||
230 | .type = "g751", | ||
231 | }, | ||
232 | #endif | ||
233 | { | ||
234 | I2C_BOARD_INFO("rtc-m41t80", 0x68), | ||
235 | .type = "m41t80", | ||
236 | } | ||
237 | }; | ||
238 | |||
239 | /* DNS-323 specific power off method */ | ||
240 | static void dns323_power_off(void) | ||
241 | { | ||
242 | pr_info("%s: triggering power-off...\n", __func__); | ||
243 | gpio_set_value(DNS323_GPIO_POWER_OFF, 1); | ||
244 | } | ||
245 | |||
246 | static void __init dns323_init(void) | ||
247 | { | ||
248 | /* Setup basic Orion functions. Need to be called early. */ | ||
249 | orion5x_init(); | ||
250 | |||
251 | /* setup flash mapping | ||
252 | * CS3 holds a 8 MB Spansion S29GL064M90TFIR4 | ||
253 | */ | ||
254 | orion5x_setup_dev_boot_win(DNS323_NOR_BOOT_BASE, DNS323_NOR_BOOT_SIZE); | ||
255 | |||
256 | /* DNS-323 has a Marvell 88X7042 SATA controller attached via PCIE | ||
257 | * | ||
258 | * Open a special address decode windows for the PCIE WA. | ||
259 | */ | ||
260 | orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE, | ||
261 | ORION5X_PCIE_WA_SIZE); | ||
262 | |||
263 | /* set MPP to 0 as D-Link's 2.6.12.6 kernel did */ | ||
264 | orion5x_write(MPP_0_7_CTRL, 0); | ||
265 | orion5x_write(MPP_8_15_CTRL, 0); | ||
266 | orion5x_write(MPP_16_19_CTRL, 0); | ||
267 | orion5x_write(MPP_DEV_CTRL, 0); | ||
268 | |||
269 | /* Define used GPIO pins | ||
270 | |||
271 | GPIO Map: | ||
272 | |||
273 | | 0 | | PEX_RST_OUT (not controlled by GPIO) | ||
274 | | 1 | Out | right amber LED (= sata ch0 LED) (low-active) | ||
275 | | 2 | Out | left amber LED (= sata ch1 LED) (low-active) | ||
276 | | 3 | Out | //unknown// | ||
277 | | 4 | Out | power button LED (low-active, together with pin #5) | ||
278 | | 5 | Out | power button LED (low-active, together with pin #4) | ||
279 | | 6 | In | GMT G751-2f overtemp. shutdown signal (low-active) | ||
280 | | 7 | In | M41T80 nIRQ/OUT/SQW signal | ||
281 | | 8 | Out | triggers power off (high-active) | ||
282 | | 9 | In | power button switch (low-active) | ||
283 | | 10 | In | reset button switch (low-active) | ||
284 | | 11 | Out | //unknown// | ||
285 | | 12 | Out | //unknown// | ||
286 | | 13 | Out | //unknown// | ||
287 | | 14 | Out | //unknown// | ||
288 | | 15 | Out | //unknown// | ||
289 | */ | ||
290 | orion5x_gpio_set_valid_pins(0x07f6); | ||
291 | |||
292 | /* register dns323 specific power-off method */ | ||
293 | if ((gpio_request(DNS323_GPIO_POWER_OFF, "POWEROFF") != 0) | ||
294 | || (gpio_direction_output(DNS323_GPIO_POWER_OFF, 0) != 0)) | ||
295 | pr_err("DNS323: failed to setup power-off GPIO\n"); | ||
296 | |||
297 | pm_power_off = dns323_power_off; | ||
298 | |||
299 | /* register flash and other platform devices */ | ||
300 | platform_add_devices(dns323_plat_devices, | ||
301 | ARRAY_SIZE(dns323_plat_devices)); | ||
302 | |||
303 | i2c_register_board_info(0, dns323_i2c_devices, | ||
304 | ARRAY_SIZE(dns323_i2c_devices)); | ||
305 | |||
306 | orion5x_eth_init(&dns323_eth_data); | ||
307 | } | ||
308 | |||
309 | /* Warning: D-Link uses a wrong mach-type (=526) in their bootloader */ | ||
310 | MACHINE_START(DNS323, "D-Link DNS-323") | ||
311 | /* Maintainer: Herbert Valerio Riedel <hvr@gnu.org> */ | ||
312 | .phys_io = ORION5X_REGS_PHYS_BASE, | ||
313 | .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC, | ||
314 | .boot_params = 0x00000100, | ||
315 | .init_machine = dns323_init, | ||
316 | .map_io = orion5x_map_io, | ||
317 | .init_irq = orion5x_init_irq, | ||
318 | .timer = &orion5x_timer, | ||
319 | .fixup = tag_fixup_mem32, | ||
320 | MACHINE_END | ||
diff --git a/arch/arm/mach-orion5x/gpio.c b/arch/arm/mach-orion5x/gpio.c new file mode 100644 index 000000000000..8108c316c426 --- /dev/null +++ b/arch/arm/mach-orion5x/gpio.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/gpio.c | ||
3 | * | ||
4 | * GPIO functions for Marvell Orion System On Chip | ||
5 | * | ||
6 | * Maintainer: Tzachi Perelstein <tzachi@marvell.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <linux/bitops.h> | ||
18 | #include <asm/gpio.h> | ||
19 | #include <asm/io.h> | ||
20 | #include <asm/arch/orion5x.h> | ||
21 | #include "common.h" | ||
22 | |||
23 | static DEFINE_SPINLOCK(gpio_lock); | ||
24 | static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)]; | ||
25 | static const char *gpio_label[GPIO_MAX]; /* non null for allocated GPIOs */ | ||
26 | |||
27 | void __init orion5x_gpio_set_valid_pins(u32 pins) | ||
28 | { | ||
29 | gpio_valid[0] = pins; | ||
30 | } | ||
31 | |||
32 | /* | ||
33 | * GENERIC_GPIO primitives | ||
34 | */ | ||
35 | int gpio_direction_input(unsigned pin) | ||
36 | { | ||
37 | unsigned long flags; | ||
38 | |||
39 | if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { | ||
40 | pr_debug("%s: invalid GPIO %d\n", __func__, pin); | ||
41 | return -EINVAL; | ||
42 | } | ||
43 | |||
44 | spin_lock_irqsave(&gpio_lock, flags); | ||
45 | |||
46 | /* | ||
47 | * Some callers might have not used the gpio_request(), | ||
48 | * so flag this pin as requested now. | ||
49 | */ | ||
50 | if (!gpio_label[pin]) | ||
51 | gpio_label[pin] = "?"; | ||
52 | |||
53 | orion5x_setbits(GPIO_IO_CONF, 1 << pin); | ||
54 | |||
55 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
56 | return 0; | ||
57 | } | ||
58 | EXPORT_SYMBOL(gpio_direction_input); | ||
59 | |||
60 | int gpio_direction_output(unsigned pin, int value) | ||
61 | { | ||
62 | unsigned long flags; | ||
63 | int mask; | ||
64 | |||
65 | if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { | ||
66 | pr_debug("%s: invalid GPIO %d\n", __func__, pin); | ||
67 | return -EINVAL; | ||
68 | } | ||
69 | |||
70 | spin_lock_irqsave(&gpio_lock, flags); | ||
71 | |||
72 | /* | ||
73 | * Some callers might have not used the gpio_request(), | ||
74 | * so flag this pin as requested now. | ||
75 | */ | ||
76 | if (!gpio_label[pin]) | ||
77 | gpio_label[pin] = "?"; | ||
78 | |||
79 | mask = 1 << pin; | ||
80 | orion5x_clrbits(GPIO_BLINK_EN, mask); | ||
81 | if (value) | ||
82 | orion5x_setbits(GPIO_OUT, mask); | ||
83 | else | ||
84 | orion5x_clrbits(GPIO_OUT, mask); | ||
85 | orion5x_clrbits(GPIO_IO_CONF, mask); | ||
86 | |||
87 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
88 | return 0; | ||
89 | } | ||
90 | EXPORT_SYMBOL(gpio_direction_output); | ||
91 | |||
92 | int gpio_get_value(unsigned pin) | ||
93 | { | ||
94 | int val, mask = 1 << pin; | ||
95 | |||
96 | if (orion5x_read(GPIO_IO_CONF) & mask) | ||
97 | val = orion5x_read(GPIO_DATA_IN) ^ orion5x_read(GPIO_IN_POL); | ||
98 | else | ||
99 | val = orion5x_read(GPIO_OUT); | ||
100 | |||
101 | return val & mask; | ||
102 | } | ||
103 | EXPORT_SYMBOL(gpio_get_value); | ||
104 | |||
105 | void gpio_set_value(unsigned pin, int value) | ||
106 | { | ||
107 | unsigned long flags; | ||
108 | int mask = 1 << pin; | ||
109 | |||
110 | spin_lock_irqsave(&gpio_lock, flags); | ||
111 | |||
112 | orion5x_clrbits(GPIO_BLINK_EN, mask); | ||
113 | if (value) | ||
114 | orion5x_setbits(GPIO_OUT, mask); | ||
115 | else | ||
116 | orion5x_clrbits(GPIO_OUT, mask); | ||
117 | |||
118 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
119 | } | ||
120 | EXPORT_SYMBOL(gpio_set_value); | ||
121 | |||
122 | void orion5x_gpio_set_blink(unsigned pin, int blink) | ||
123 | { | ||
124 | unsigned long flags; | ||
125 | int mask = 1 << pin; | ||
126 | |||
127 | spin_lock_irqsave(&gpio_lock, flags); | ||
128 | |||
129 | orion5x_clrbits(GPIO_OUT, mask); | ||
130 | if (blink) | ||
131 | orion5x_setbits(GPIO_BLINK_EN, mask); | ||
132 | else | ||
133 | orion5x_clrbits(GPIO_BLINK_EN, mask); | ||
134 | |||
135 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
136 | } | ||
137 | EXPORT_SYMBOL(orion5x_gpio_set_blink); | ||
138 | |||
139 | int gpio_request(unsigned pin, const char *label) | ||
140 | { | ||
141 | int ret = 0; | ||
142 | unsigned long flags; | ||
143 | |||
144 | if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { | ||
145 | pr_debug("%s: invalid GPIO %d\n", __func__, pin); | ||
146 | return -EINVAL; | ||
147 | } | ||
148 | |||
149 | spin_lock_irqsave(&gpio_lock, flags); | ||
150 | |||
151 | if (gpio_label[pin]) { | ||
152 | pr_debug("%s: GPIO %d already used as %s\n", | ||
153 | __func__, pin, gpio_label[pin]); | ||
154 | ret = -EBUSY; | ||
155 | } else | ||
156 | gpio_label[pin] = label ? label : "?"; | ||
157 | |||
158 | spin_unlock_irqrestore(&gpio_lock, flags); | ||
159 | return ret; | ||
160 | } | ||
161 | EXPORT_SYMBOL(gpio_request); | ||
162 | |||
163 | void gpio_free(unsigned pin) | ||
164 | { | ||
165 | if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) { | ||
166 | pr_debug("%s: invalid GPIO %d\n", __func__, pin); | ||
167 | return; | ||
168 | } | ||
169 | |||
170 | if (!gpio_label[pin]) | ||
171 | pr_warning("%s: GPIO %d already freed\n", __func__, pin); | ||
172 | else | ||
173 | gpio_label[pin] = NULL; | ||
174 | } | ||
175 | EXPORT_SYMBOL(gpio_free); | ||
176 | |||
177 | /* Debug helper */ | ||
178 | void gpio_display(void) | ||
179 | { | ||
180 | int i; | ||
181 | |||
182 | for (i = 0; i < GPIO_MAX; i++) { | ||
183 | printk(KERN_DEBUG "Pin-%d: ", i); | ||
184 | |||
185 | if (!test_bit(i, gpio_valid)) { | ||
186 | printk("non-GPIO\n"); | ||
187 | } else if (!gpio_label[i]) { | ||
188 | printk("GPIO, free\n"); | ||
189 | } else { | ||
190 | printk("GPIO, used by %s, ", gpio_label[i]); | ||
191 | if (orion5x_read(GPIO_IO_CONF) & (1 << i)) { | ||
192 | printk("input, active %s, level %s, edge %s\n", | ||
193 | ((orion5x_read(GPIO_IN_POL) >> i) & 1) ? "low" : "high", | ||
194 | ((orion5x_read(GPIO_LEVEL_MASK) >> i) & 1) ? "enabled" : "masked", | ||
195 | ((orion5x_read(GPIO_EDGE_MASK) >> i) & 1) ? "enabled" : "masked"); | ||
196 | } else { | ||
197 | printk("output, val=%d\n", (orion5x_read(GPIO_OUT) >> i) & 1); | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | |||
202 | printk(KERN_DEBUG "MPP_0_7_CTRL (0x%08x) = 0x%08x\n", | ||
203 | MPP_0_7_CTRL, orion5x_read(MPP_0_7_CTRL)); | ||
204 | printk(KERN_DEBUG "MPP_8_15_CTRL (0x%08x) = 0x%08x\n", | ||
205 | MPP_8_15_CTRL, orion5x_read(MPP_8_15_CTRL)); | ||
206 | printk(KERN_DEBUG "MPP_16_19_CTRL (0x%08x) = 0x%08x\n", | ||
207 | MPP_16_19_CTRL, orion5x_read(MPP_16_19_CTRL)); | ||
208 | printk(KERN_DEBUG "MPP_DEV_CTRL (0x%08x) = 0x%08x\n", | ||
209 | MPP_DEV_CTRL, orion5x_read(MPP_DEV_CTRL)); | ||
210 | printk(KERN_DEBUG "GPIO_OUT (0x%08x) = 0x%08x\n", | ||
211 | GPIO_OUT, orion5x_read(GPIO_OUT)); | ||
212 | printk(KERN_DEBUG "GPIO_IO_CONF (0x%08x) = 0x%08x\n", | ||
213 | GPIO_IO_CONF, orion5x_read(GPIO_IO_CONF)); | ||
214 | printk(KERN_DEBUG "GPIO_BLINK_EN (0x%08x) = 0x%08x\n", | ||
215 | GPIO_BLINK_EN, orion5x_read(GPIO_BLINK_EN)); | ||
216 | printk(KERN_DEBUG "GPIO_IN_POL (0x%08x) = 0x%08x\n", | ||
217 | GPIO_IN_POL, orion5x_read(GPIO_IN_POL)); | ||
218 | printk(KERN_DEBUG "GPIO_DATA_IN (0x%08x) = 0x%08x\n", | ||
219 | GPIO_DATA_IN, orion5x_read(GPIO_DATA_IN)); | ||
220 | printk(KERN_DEBUG "GPIO_LEVEL_MASK (0x%08x) = 0x%08x\n", | ||
221 | GPIO_LEVEL_MASK, orion5x_read(GPIO_LEVEL_MASK)); | ||
222 | printk(KERN_DEBUG "GPIO_EDGE_CAUSE (0x%08x) = 0x%08x\n", | ||
223 | GPIO_EDGE_CAUSE, orion5x_read(GPIO_EDGE_CAUSE)); | ||
224 | printk(KERN_DEBUG "GPIO_EDGE_MASK (0x%08x) = 0x%08x\n", | ||
225 | GPIO_EDGE_MASK, orion5x_read(GPIO_EDGE_MASK)); | ||
226 | } | ||
diff --git a/arch/arm/mach-orion5x/irq.c b/arch/arm/mach-orion5x/irq.c new file mode 100644 index 000000000000..dd21f38c5d37 --- /dev/null +++ b/arch/arm/mach-orion5x/irq.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/irq.c | ||
3 | * | ||
4 | * Core IRQ functions for Marvell Orion System On Chip | ||
5 | * | ||
6 | * Maintainer: Tzachi Perelstein <tzachi@marvell.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <asm/gpio.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/arch/orion5x.h> | ||
19 | #include <asm/plat-orion/irq.h> | ||
20 | #include "common.h" | ||
21 | |||
22 | /***************************************************************************** | ||
23 | * Orion GPIO IRQ | ||
24 | * | ||
25 | * GPIO_IN_POL register controlls whether GPIO_DATA_IN will hold the same | ||
26 | * value of the line or the opposite value. | ||
27 | * | ||
28 | * Level IRQ handlers: DATA_IN is used directly as cause register. | ||
29 | * Interrupt are masked by LEVEL_MASK registers. | ||
30 | * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. | ||
31 | * Interrupt are masked by EDGE_MASK registers. | ||
32 | * Both-edge handlers: Similar to regular Edge handlers, but also swaps | ||
33 | * the polarity to catch the next line transaction. | ||
34 | * This is a race condition that might not perfectly | ||
35 | * work on some use cases. | ||
36 | * | ||
37 | * Every eight GPIO lines are grouped (OR'ed) before going up to main | ||
38 | * cause register. | ||
39 | * | ||
40 | * EDGE cause mask | ||
41 | * data-in /--------| |-----| |----\ | ||
42 | * -----| |----- ---- to main cause reg | ||
43 | * X \----------------| |----/ | ||
44 | * polarity LEVEL mask | ||
45 | * | ||
46 | ****************************************************************************/ | ||
47 | static void orion5x_gpio_irq_ack(u32 irq) | ||
48 | { | ||
49 | int pin = irq_to_gpio(irq); | ||
50 | if (irq_desc[irq].status & IRQ_LEVEL) | ||
51 | /* | ||
52 | * Mask bit for level interrupt | ||
53 | */ | ||
54 | orion5x_clrbits(GPIO_LEVEL_MASK, 1 << pin); | ||
55 | else | ||
56 | /* | ||
57 | * Clear casue bit for egde interrupt | ||
58 | */ | ||
59 | orion5x_clrbits(GPIO_EDGE_CAUSE, 1 << pin); | ||
60 | } | ||
61 | |||
62 | static void orion5x_gpio_irq_mask(u32 irq) | ||
63 | { | ||
64 | int pin = irq_to_gpio(irq); | ||
65 | if (irq_desc[irq].status & IRQ_LEVEL) | ||
66 | orion5x_clrbits(GPIO_LEVEL_MASK, 1 << pin); | ||
67 | else | ||
68 | orion5x_clrbits(GPIO_EDGE_MASK, 1 << pin); | ||
69 | } | ||
70 | |||
71 | static void orion5x_gpio_irq_unmask(u32 irq) | ||
72 | { | ||
73 | int pin = irq_to_gpio(irq); | ||
74 | if (irq_desc[irq].status & IRQ_LEVEL) | ||
75 | orion5x_setbits(GPIO_LEVEL_MASK, 1 << pin); | ||
76 | else | ||
77 | orion5x_setbits(GPIO_EDGE_MASK, 1 << pin); | ||
78 | } | ||
79 | |||
80 | static int orion5x_gpio_set_irq_type(u32 irq, u32 type) | ||
81 | { | ||
82 | int pin = irq_to_gpio(irq); | ||
83 | struct irq_desc *desc; | ||
84 | |||
85 | if ((orion5x_read(GPIO_IO_CONF) & (1 << pin)) == 0) { | ||
86 | printk(KERN_ERR "orion5x_gpio_set_irq_type failed " | ||
87 | "(irq %d, pin %d).\n", irq, pin); | ||
88 | return -EINVAL; | ||
89 | } | ||
90 | |||
91 | desc = irq_desc + irq; | ||
92 | |||
93 | switch (type) { | ||
94 | case IRQT_HIGH: | ||
95 | desc->handle_irq = handle_level_irq; | ||
96 | desc->status |= IRQ_LEVEL; | ||
97 | orion5x_clrbits(GPIO_IN_POL, (1 << pin)); | ||
98 | break; | ||
99 | case IRQT_LOW: | ||
100 | desc->handle_irq = handle_level_irq; | ||
101 | desc->status |= IRQ_LEVEL; | ||
102 | orion5x_setbits(GPIO_IN_POL, (1 << pin)); | ||
103 | break; | ||
104 | case IRQT_RISING: | ||
105 | desc->handle_irq = handle_edge_irq; | ||
106 | desc->status &= ~IRQ_LEVEL; | ||
107 | orion5x_clrbits(GPIO_IN_POL, (1 << pin)); | ||
108 | break; | ||
109 | case IRQT_FALLING: | ||
110 | desc->handle_irq = handle_edge_irq; | ||
111 | desc->status &= ~IRQ_LEVEL; | ||
112 | orion5x_setbits(GPIO_IN_POL, (1 << pin)); | ||
113 | break; | ||
114 | case IRQT_BOTHEDGE: | ||
115 | desc->handle_irq = handle_edge_irq; | ||
116 | desc->status &= ~IRQ_LEVEL; | ||
117 | /* | ||
118 | * set initial polarity based on current input level | ||
119 | */ | ||
120 | if ((orion5x_read(GPIO_IN_POL) ^ orion5x_read(GPIO_DATA_IN)) | ||
121 | & (1 << pin)) | ||
122 | orion5x_setbits(GPIO_IN_POL, (1 << pin)); /* falling */ | ||
123 | else | ||
124 | orion5x_clrbits(GPIO_IN_POL, (1 << pin)); /* rising */ | ||
125 | |||
126 | break; | ||
127 | default: | ||
128 | printk(KERN_ERR "failed to set irq=%d (type=%d)\n", irq, type); | ||
129 | return -EINVAL; | ||
130 | } | ||
131 | |||
132 | desc->status &= ~IRQ_TYPE_SENSE_MASK; | ||
133 | desc->status |= type & IRQ_TYPE_SENSE_MASK; | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static struct irq_chip orion5x_gpio_irq_chip = { | ||
139 | .name = "Orion-IRQ-GPIO", | ||
140 | .ack = orion5x_gpio_irq_ack, | ||
141 | .mask = orion5x_gpio_irq_mask, | ||
142 | .unmask = orion5x_gpio_irq_unmask, | ||
143 | .set_type = orion5x_gpio_set_irq_type, | ||
144 | }; | ||
145 | |||
146 | static void orion5x_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) | ||
147 | { | ||
148 | u32 cause, offs, pin; | ||
149 | |||
150 | BUG_ON(irq < IRQ_ORION5X_GPIO_0_7 || irq > IRQ_ORION5X_GPIO_24_31); | ||
151 | offs = (irq - IRQ_ORION5X_GPIO_0_7) * 8; | ||
152 | cause = (orion5x_read(GPIO_DATA_IN) & orion5x_read(GPIO_LEVEL_MASK)) | | ||
153 | (orion5x_read(GPIO_EDGE_CAUSE) & orion5x_read(GPIO_EDGE_MASK)); | ||
154 | |||
155 | for (pin = offs; pin < offs + 8; pin++) { | ||
156 | if (cause & (1 << pin)) { | ||
157 | irq = gpio_to_irq(pin); | ||
158 | desc = irq_desc + irq; | ||
159 | if ((desc->status & IRQ_TYPE_SENSE_MASK) == IRQT_BOTHEDGE) { | ||
160 | /* Swap polarity (race with GPIO line) */ | ||
161 | u32 polarity = orion5x_read(GPIO_IN_POL); | ||
162 | polarity ^= 1 << pin; | ||
163 | orion5x_write(GPIO_IN_POL, polarity); | ||
164 | } | ||
165 | desc_handle_irq(irq, desc); | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | |||
170 | static void __init orion5x_init_gpio_irq(void) | ||
171 | { | ||
172 | int i; | ||
173 | struct irq_desc *desc; | ||
174 | |||
175 | /* | ||
176 | * Mask and clear GPIO IRQ interrupts | ||
177 | */ | ||
178 | orion5x_write(GPIO_LEVEL_MASK, 0x0); | ||
179 | orion5x_write(GPIO_EDGE_MASK, 0x0); | ||
180 | orion5x_write(GPIO_EDGE_CAUSE, 0x0); | ||
181 | |||
182 | /* | ||
183 | * Register chained level handlers for GPIO IRQs by default. | ||
184 | * User can use set_type() if he wants to use edge types handlers. | ||
185 | */ | ||
186 | for (i = IRQ_ORION5X_GPIO_START; i < NR_IRQS; i++) { | ||
187 | set_irq_chip(i, &orion5x_gpio_irq_chip); | ||
188 | set_irq_handler(i, handle_level_irq); | ||
189 | desc = irq_desc + i; | ||
190 | desc->status |= IRQ_LEVEL; | ||
191 | set_irq_flags(i, IRQF_VALID); | ||
192 | } | ||
193 | set_irq_chained_handler(IRQ_ORION5X_GPIO_0_7, orion5x_gpio_irq_handler); | ||
194 | set_irq_chained_handler(IRQ_ORION5X_GPIO_8_15, orion5x_gpio_irq_handler); | ||
195 | set_irq_chained_handler(IRQ_ORION5X_GPIO_16_23, orion5x_gpio_irq_handler); | ||
196 | set_irq_chained_handler(IRQ_ORION5X_GPIO_24_31, orion5x_gpio_irq_handler); | ||
197 | } | ||
198 | |||
199 | /***************************************************************************** | ||
200 | * Orion Main IRQ | ||
201 | ****************************************************************************/ | ||
202 | static void __init orion5x_init_main_irq(void) | ||
203 | { | ||
204 | orion_irq_init(0, (void __iomem *)MAIN_IRQ_MASK); | ||
205 | } | ||
206 | |||
207 | void __init orion5x_init_irq(void) | ||
208 | { | ||
209 | orion5x_init_main_irq(); | ||
210 | orion5x_init_gpio_irq(); | ||
211 | } | ||
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c new file mode 100644 index 000000000000..8ad4390b4b7b --- /dev/null +++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/kurobox_pro-setup.c | ||
3 | * | ||
4 | * Maintainer: Ronen Shitrit <rshitrit@marvell.com> | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public | ||
7 | * License version 2. This program is licensed "as is" without any | ||
8 | * warranty of any kind, whether express or implied. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include <linux/irq.h> | ||
16 | #include <linux/mtd/physmap.h> | ||
17 | #include <linux/mtd/nand.h> | ||
18 | #include <linux/mv643xx_eth.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/ata_platform.h> | ||
21 | #include <asm/mach-types.h> | ||
22 | #include <asm/gpio.h> | ||
23 | #include <asm/mach/arch.h> | ||
24 | #include <asm/mach/pci.h> | ||
25 | #include <asm/arch/orion5x.h> | ||
26 | #include <asm/plat-orion/orion_nand.h> | ||
27 | #include "common.h" | ||
28 | |||
29 | /***************************************************************************** | ||
30 | * KUROBOX-PRO Info | ||
31 | ****************************************************************************/ | ||
32 | |||
33 | /* | ||
34 | * 256K NOR flash Device bus boot chip select | ||
35 | */ | ||
36 | |||
37 | #define KUROBOX_PRO_NOR_BOOT_BASE 0xf4000000 | ||
38 | #define KUROBOX_PRO_NOR_BOOT_SIZE SZ_256K | ||
39 | |||
40 | /* | ||
41 | * 256M NAND flash on Device bus chip select 1 | ||
42 | */ | ||
43 | |||
44 | #define KUROBOX_PRO_NAND_BASE 0xfc000000 | ||
45 | #define KUROBOX_PRO_NAND_SIZE SZ_2M | ||
46 | |||
47 | /***************************************************************************** | ||
48 | * 256MB NAND Flash on Device bus CS0 | ||
49 | ****************************************************************************/ | ||
50 | |||
51 | static struct mtd_partition kurobox_pro_nand_parts[] = { | ||
52 | { | ||
53 | .name = "uImage", | ||
54 | .offset = 0, | ||
55 | .size = SZ_4M, | ||
56 | }, | ||
57 | { | ||
58 | .name = "rootfs", | ||
59 | .offset = SZ_4M, | ||
60 | .size = SZ_64M, | ||
61 | }, | ||
62 | { | ||
63 | .name = "extra", | ||
64 | .offset = SZ_4M + SZ_64M, | ||
65 | .size = SZ_256M - (SZ_4M + SZ_64M), | ||
66 | }, | ||
67 | }; | ||
68 | |||
69 | static struct resource kurobox_pro_nand_resource = { | ||
70 | .flags = IORESOURCE_MEM, | ||
71 | .start = KUROBOX_PRO_NAND_BASE, | ||
72 | .end = KUROBOX_PRO_NAND_BASE + KUROBOX_PRO_NAND_SIZE - 1, | ||
73 | }; | ||
74 | |||
75 | static struct orion_nand_data kurobox_pro_nand_data = { | ||
76 | .parts = kurobox_pro_nand_parts, | ||
77 | .nr_parts = ARRAY_SIZE(kurobox_pro_nand_parts), | ||
78 | .cle = 0, | ||
79 | .ale = 1, | ||
80 | .width = 8, | ||
81 | }; | ||
82 | |||
83 | static struct platform_device kurobox_pro_nand_flash = { | ||
84 | .name = "orion_nand", | ||
85 | .id = -1, | ||
86 | .dev = { | ||
87 | .platform_data = &kurobox_pro_nand_data, | ||
88 | }, | ||
89 | .resource = &kurobox_pro_nand_resource, | ||
90 | .num_resources = 1, | ||
91 | }; | ||
92 | |||
93 | /***************************************************************************** | ||
94 | * 256KB NOR Flash on BOOT Device | ||
95 | ****************************************************************************/ | ||
96 | |||
97 | static struct physmap_flash_data kurobox_pro_nor_flash_data = { | ||
98 | .width = 1, | ||
99 | }; | ||
100 | |||
101 | static struct resource kurobox_pro_nor_flash_resource = { | ||
102 | .flags = IORESOURCE_MEM, | ||
103 | .start = KUROBOX_PRO_NOR_BOOT_BASE, | ||
104 | .end = KUROBOX_PRO_NOR_BOOT_BASE + KUROBOX_PRO_NOR_BOOT_SIZE - 1, | ||
105 | }; | ||
106 | |||
107 | static struct platform_device kurobox_pro_nor_flash = { | ||
108 | .name = "physmap-flash", | ||
109 | .id = 0, | ||
110 | .dev = { | ||
111 | .platform_data = &kurobox_pro_nor_flash_data, | ||
112 | }, | ||
113 | .num_resources = 1, | ||
114 | .resource = &kurobox_pro_nor_flash_resource, | ||
115 | }; | ||
116 | |||
117 | /***************************************************************************** | ||
118 | * PCI | ||
119 | ****************************************************************************/ | ||
120 | |||
121 | static int __init kurobox_pro_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
122 | { | ||
123 | /* | ||
124 | * PCI isn't used on the Kuro | ||
125 | */ | ||
126 | if (dev->bus->number == orion5x_pcie_local_bus_nr()) | ||
127 | return IRQ_ORION5X_PCIE0_INT; | ||
128 | else | ||
129 | printk(KERN_ERR "kurobox_pro_pci_map_irq failed, unknown bus\n"); | ||
130 | |||
131 | return -1; | ||
132 | } | ||
133 | |||
134 | static struct hw_pci kurobox_pro_pci __initdata = { | ||
135 | .nr_controllers = 1, | ||
136 | .swizzle = pci_std_swizzle, | ||
137 | .setup = orion5x_pci_sys_setup, | ||
138 | .scan = orion5x_pci_sys_scan_bus, | ||
139 | .map_irq = kurobox_pro_pci_map_irq, | ||
140 | }; | ||
141 | |||
142 | static int __init kurobox_pro_pci_init(void) | ||
143 | { | ||
144 | if (machine_is_kurobox_pro()) | ||
145 | pci_common_init(&kurobox_pro_pci); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | subsys_initcall(kurobox_pro_pci_init); | ||
151 | |||
152 | /***************************************************************************** | ||
153 | * Ethernet | ||
154 | ****************************************************************************/ | ||
155 | |||
156 | static struct mv643xx_eth_platform_data kurobox_pro_eth_data = { | ||
157 | .phy_addr = 8, | ||
158 | .force_phy_addr = 1, | ||
159 | }; | ||
160 | |||
161 | /***************************************************************************** | ||
162 | * RTC 5C372a on I2C bus | ||
163 | ****************************************************************************/ | ||
164 | static struct i2c_board_info __initdata kurobox_pro_i2c_rtc = { | ||
165 | .driver_name = "rtc-rs5c372", | ||
166 | .type = "rs5c372a", | ||
167 | .addr = 0x32, | ||
168 | }; | ||
169 | |||
170 | /***************************************************************************** | ||
171 | * SATA | ||
172 | ****************************************************************************/ | ||
173 | static struct mv_sata_platform_data kurobox_pro_sata_data = { | ||
174 | .n_ports = 2, | ||
175 | }; | ||
176 | |||
177 | /***************************************************************************** | ||
178 | * General Setup | ||
179 | ****************************************************************************/ | ||
180 | |||
181 | static struct platform_device *kurobox_pro_devices[] __initdata = { | ||
182 | &kurobox_pro_nor_flash, | ||
183 | &kurobox_pro_nand_flash, | ||
184 | }; | ||
185 | |||
186 | static void __init kurobox_pro_init(void) | ||
187 | { | ||
188 | /* | ||
189 | * Setup basic Orion functions. Need to be called early. | ||
190 | */ | ||
191 | orion5x_init(); | ||
192 | |||
193 | /* | ||
194 | * Setup the CPU address decode windows for our devices | ||
195 | */ | ||
196 | orion5x_setup_dev_boot_win(KUROBOX_PRO_NOR_BOOT_BASE, | ||
197 | KUROBOX_PRO_NOR_BOOT_SIZE); | ||
198 | orion5x_setup_dev0_win(KUROBOX_PRO_NAND_BASE, KUROBOX_PRO_NAND_SIZE); | ||
199 | |||
200 | /* | ||
201 | * Open a special address decode windows for the PCIE WA. | ||
202 | */ | ||
203 | orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE, | ||
204 | ORION5X_PCIE_WA_SIZE); | ||
205 | |||
206 | /* | ||
207 | * Setup Multiplexing Pins -- | ||
208 | * MPP[0-1] Not used | ||
209 | * MPP[2] GPIO Micon | ||
210 | * MPP[3] GPIO RTC | ||
211 | * MPP[4-5] Not used | ||
212 | * MPP[6] Nand Flash REn | ||
213 | * MPP[7] Nand Flash WEn | ||
214 | * MPP[8-11] Not used | ||
215 | * MPP[12] SATA 0 presence Indication | ||
216 | * MPP[13] SATA 1 presence Indication | ||
217 | * MPP[14] SATA 0 active Indication | ||
218 | * MPP[15] SATA 1 active indication | ||
219 | * MPP[16-19] Not used | ||
220 | */ | ||
221 | orion5x_write(MPP_0_7_CTRL, 0x44220003); | ||
222 | orion5x_write(MPP_8_15_CTRL, 0x55550000); | ||
223 | orion5x_write(MPP_16_19_CTRL, 0x0); | ||
224 | |||
225 | orion5x_gpio_set_valid_pins(0x0000000c); | ||
226 | |||
227 | platform_add_devices(kurobox_pro_devices, ARRAY_SIZE(kurobox_pro_devices)); | ||
228 | i2c_register_board_info(0, &kurobox_pro_i2c_rtc, 1); | ||
229 | orion5x_eth_init(&kurobox_pro_eth_data); | ||
230 | orion5x_sata_init(&kurobox_pro_sata_data); | ||
231 | } | ||
232 | |||
233 | MACHINE_START(KUROBOX_PRO, "Buffalo/Revogear Kurobox Pro") | ||
234 | /* Maintainer: Ronen Shitrit <rshitrit@marvell.com> */ | ||
235 | .phys_io = ORION5X_REGS_PHYS_BASE, | ||
236 | .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC, | ||
237 | .boot_params = 0x00000100, | ||
238 | .init_machine = kurobox_pro_init, | ||
239 | .map_io = orion5x_map_io, | ||
240 | .init_irq = orion5x_init_irq, | ||
241 | .timer = &orion5x_timer, | ||
242 | .fixup = tag_fixup_mem32, | ||
243 | MACHINE_END | ||
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c new file mode 100644 index 000000000000..27b4afc8f486 --- /dev/null +++ b/arch/arm/mach-orion5x/pci.c | |||
@@ -0,0 +1,559 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/pci.c | ||
3 | * | ||
4 | * PCI and PCIe functions for Marvell Orion System On Chip | ||
5 | * | ||
6 | * Maintainer: Tzachi Perelstein <tzachi@marvell.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/pci.h> | ||
15 | #include <linux/mbus.h> | ||
16 | #include <asm/mach/pci.h> | ||
17 | #include <asm/plat-orion/pcie.h> | ||
18 | #include "common.h" | ||
19 | |||
20 | /***************************************************************************** | ||
21 | * Orion has one PCIe controller and one PCI controller. | ||
22 | * | ||
23 | * Note1: The local PCIe bus number is '0'. The local PCI bus number | ||
24 | * follows the scanned PCIe bridged busses, if any. | ||
25 | * | ||
26 | * Note2: It is possible for PCI/PCIe agents to access many subsystem's | ||
27 | * space, by configuring BARs and Address Decode Windows, e.g. flashes on | ||
28 | * device bus, Orion registers, etc. However this code only enable the | ||
29 | * access to DDR banks. | ||
30 | ****************************************************************************/ | ||
31 | |||
32 | |||
33 | /***************************************************************************** | ||
34 | * PCIe controller | ||
35 | ****************************************************************************/ | ||
36 | #define PCIE_BASE ((void __iomem *)ORION5X_PCIE_VIRT_BASE) | ||
37 | |||
38 | void __init orion5x_pcie_id(u32 *dev, u32 *rev) | ||
39 | { | ||
40 | *dev = orion_pcie_dev_id(PCIE_BASE); | ||
41 | *rev = orion_pcie_rev(PCIE_BASE); | ||
42 | } | ||
43 | |||
44 | int orion5x_pcie_local_bus_nr(void) | ||
45 | { | ||
46 | return orion_pcie_get_local_bus_nr(PCIE_BASE); | ||
47 | } | ||
48 | |||
49 | static int pcie_valid_config(int bus, int dev) | ||
50 | { | ||
51 | /* | ||
52 | * Don't go out when trying to access -- | ||
53 | * 1. nonexisting device on local bus | ||
54 | * 2. where there's no device connected (no link) | ||
55 | */ | ||
56 | if (bus == 0 && dev == 0) | ||
57 | return 1; | ||
58 | |||
59 | if (!orion_pcie_link_up(PCIE_BASE)) | ||
60 | return 0; | ||
61 | |||
62 | if (bus == 0 && dev != 1) | ||
63 | return 0; | ||
64 | |||
65 | return 1; | ||
66 | } | ||
67 | |||
68 | |||
69 | /* | ||
70 | * PCIe config cycles are done by programming the PCIE_CONF_ADDR register | ||
71 | * and then reading the PCIE_CONF_DATA register. Need to make sure these | ||
72 | * transactions are atomic. | ||
73 | */ | ||
74 | static DEFINE_SPINLOCK(orion5x_pcie_lock); | ||
75 | |||
76 | static int pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where, | ||
77 | int size, u32 *val) | ||
78 | { | ||
79 | unsigned long flags; | ||
80 | int ret; | ||
81 | |||
82 | if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) { | ||
83 | *val = 0xffffffff; | ||
84 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
85 | } | ||
86 | |||
87 | spin_lock_irqsave(&orion5x_pcie_lock, flags); | ||
88 | ret = orion_pcie_rd_conf(PCIE_BASE, bus, devfn, where, size, val); | ||
89 | spin_unlock_irqrestore(&orion5x_pcie_lock, flags); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | static int pcie_rd_conf_wa(struct pci_bus *bus, u32 devfn, | ||
95 | int where, int size, u32 *val) | ||
96 | { | ||
97 | int ret; | ||
98 | |||
99 | if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) { | ||
100 | *val = 0xffffffff; | ||
101 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * We only support access to the non-extended configuration | ||
106 | * space when using the WA access method (or we would have to | ||
107 | * sacrifice 256M of CPU virtual address space.) | ||
108 | */ | ||
109 | if (where >= 0x100) { | ||
110 | *val = 0xffffffff; | ||
111 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
112 | } | ||
113 | |||
114 | ret = orion_pcie_rd_conf_wa((void __iomem *)ORION5X_PCIE_WA_VIRT_BASE, | ||
115 | bus, devfn, where, size, val); | ||
116 | |||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static int pcie_wr_conf(struct pci_bus *bus, u32 devfn, | ||
121 | int where, int size, u32 val) | ||
122 | { | ||
123 | unsigned long flags; | ||
124 | int ret; | ||
125 | |||
126 | if (pcie_valid_config(bus->number, PCI_SLOT(devfn)) == 0) | ||
127 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
128 | |||
129 | spin_lock_irqsave(&orion5x_pcie_lock, flags); | ||
130 | ret = orion_pcie_wr_conf(PCIE_BASE, bus, devfn, where, size, val); | ||
131 | spin_unlock_irqrestore(&orion5x_pcie_lock, flags); | ||
132 | |||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | static struct pci_ops pcie_ops = { | ||
137 | .read = pcie_rd_conf, | ||
138 | .write = pcie_wr_conf, | ||
139 | }; | ||
140 | |||
141 | |||
142 | static int __init pcie_setup(struct pci_sys_data *sys) | ||
143 | { | ||
144 | struct resource *res; | ||
145 | int dev; | ||
146 | |||
147 | /* | ||
148 | * Generic PCIe unit setup. | ||
149 | */ | ||
150 | orion_pcie_setup(PCIE_BASE, &orion5x_mbus_dram_info); | ||
151 | |||
152 | /* | ||
153 | * Check whether to apply Orion-1/Orion-NAS PCIe config | ||
154 | * read transaction workaround. | ||
155 | */ | ||
156 | dev = orion_pcie_dev_id(PCIE_BASE); | ||
157 | if (dev == MV88F5181_DEV_ID || dev == MV88F5182_DEV_ID) { | ||
158 | printk(KERN_NOTICE "Applying Orion-1/Orion-NAS PCIe config " | ||
159 | "read transaction workaround\n"); | ||
160 | pcie_ops.read = pcie_rd_conf_wa; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Request resources. | ||
165 | */ | ||
166 | res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); | ||
167 | if (!res) | ||
168 | panic("pcie_setup unable to alloc resources"); | ||
169 | |||
170 | /* | ||
171 | * IORESOURCE_IO | ||
172 | */ | ||
173 | res[0].name = "PCIe I/O Space"; | ||
174 | res[0].flags = IORESOURCE_IO; | ||
175 | res[0].start = ORION5X_PCIE_IO_BUS_BASE; | ||
176 | res[0].end = res[0].start + ORION5X_PCIE_IO_SIZE - 1; | ||
177 | if (request_resource(&ioport_resource, &res[0])) | ||
178 | panic("Request PCIe IO resource failed\n"); | ||
179 | sys->resource[0] = &res[0]; | ||
180 | |||
181 | /* | ||
182 | * IORESOURCE_MEM | ||
183 | */ | ||
184 | res[1].name = "PCIe Memory Space"; | ||
185 | res[1].flags = IORESOURCE_MEM; | ||
186 | res[1].start = ORION5X_PCIE_MEM_PHYS_BASE; | ||
187 | res[1].end = res[1].start + ORION5X_PCIE_MEM_SIZE - 1; | ||
188 | if (request_resource(&iomem_resource, &res[1])) | ||
189 | panic("Request PCIe Memory resource failed\n"); | ||
190 | sys->resource[1] = &res[1]; | ||
191 | |||
192 | sys->resource[2] = NULL; | ||
193 | sys->io_offset = 0; | ||
194 | |||
195 | return 1; | ||
196 | } | ||
197 | |||
198 | /***************************************************************************** | ||
199 | * PCI controller | ||
200 | ****************************************************************************/ | ||
201 | #define PCI_MODE ORION5X_PCI_REG(0xd00) | ||
202 | #define PCI_CMD ORION5X_PCI_REG(0xc00) | ||
203 | #define PCI_P2P_CONF ORION5X_PCI_REG(0x1d14) | ||
204 | #define PCI_CONF_ADDR ORION5X_PCI_REG(0xc78) | ||
205 | #define PCI_CONF_DATA ORION5X_PCI_REG(0xc7c) | ||
206 | |||
207 | /* | ||
208 | * PCI_MODE bits | ||
209 | */ | ||
210 | #define PCI_MODE_64BIT (1 << 2) | ||
211 | #define PCI_MODE_PCIX ((1 << 4) | (1 << 5)) | ||
212 | |||
213 | /* | ||
214 | * PCI_CMD bits | ||
215 | */ | ||
216 | #define PCI_CMD_HOST_REORDER (1 << 29) | ||
217 | |||
218 | /* | ||
219 | * PCI_P2P_CONF bits | ||
220 | */ | ||
221 | #define PCI_P2P_BUS_OFFS 16 | ||
222 | #define PCI_P2P_BUS_MASK (0xff << PCI_P2P_BUS_OFFS) | ||
223 | #define PCI_P2P_DEV_OFFS 24 | ||
224 | #define PCI_P2P_DEV_MASK (0x1f << PCI_P2P_DEV_OFFS) | ||
225 | |||
226 | /* | ||
227 | * PCI_CONF_ADDR bits | ||
228 | */ | ||
229 | #define PCI_CONF_REG(reg) ((reg) & 0xfc) | ||
230 | #define PCI_CONF_FUNC(func) (((func) & 0x3) << 8) | ||
231 | #define PCI_CONF_DEV(dev) (((dev) & 0x1f) << 11) | ||
232 | #define PCI_CONF_BUS(bus) (((bus) & 0xff) << 16) | ||
233 | #define PCI_CONF_ADDR_EN (1 << 31) | ||
234 | |||
235 | /* | ||
236 | * Internal configuration space | ||
237 | */ | ||
238 | #define PCI_CONF_FUNC_STAT_CMD 0 | ||
239 | #define PCI_CONF_REG_STAT_CMD 4 | ||
240 | #define PCIX_STAT 0x64 | ||
241 | #define PCIX_STAT_BUS_OFFS 8 | ||
242 | #define PCIX_STAT_BUS_MASK (0xff << PCIX_STAT_BUS_OFFS) | ||
243 | |||
244 | /* | ||
245 | * PCI Address Decode Windows registers | ||
246 | */ | ||
247 | #define PCI_BAR_SIZE_DDR_CS(n) (((n) == 0) ? ORION5X_PCI_REG(0xc08) : \ | ||
248 | ((n) == 1) ? ORION5X_PCI_REG(0xd08) : \ | ||
249 | ((n) == 2) ? ORION5X_PCI_REG(0xc0c) : \ | ||
250 | ((n) == 3) ? ORION5X_PCI_REG(0xd0c) : 0) | ||
251 | #define PCI_BAR_REMAP_DDR_CS(n) (((n) ==0) ? ORION5X_PCI_REG(0xc48) : \ | ||
252 | ((n) == 1) ? ORION5X_PCI_REG(0xd48) : \ | ||
253 | ((n) == 2) ? ORION5X_PCI_REG(0xc4c) : \ | ||
254 | ((n) == 3) ? ORION5X_PCI_REG(0xd4c) : 0) | ||
255 | #define PCI_BAR_ENABLE ORION5X_PCI_REG(0xc3c) | ||
256 | #define PCI_ADDR_DECODE_CTRL ORION5X_PCI_REG(0xd3c) | ||
257 | |||
258 | /* | ||
259 | * PCI configuration helpers for BAR settings | ||
260 | */ | ||
261 | #define PCI_CONF_FUNC_BAR_CS(n) ((n) >> 1) | ||
262 | #define PCI_CONF_REG_BAR_LO_CS(n) (((n) & 1) ? 0x18 : 0x10) | ||
263 | #define PCI_CONF_REG_BAR_HI_CS(n) (((n) & 1) ? 0x1c : 0x14) | ||
264 | |||
265 | /* | ||
266 | * PCI config cycles are done by programming the PCI_CONF_ADDR register | ||
267 | * and then reading the PCI_CONF_DATA register. Need to make sure these | ||
268 | * transactions are atomic. | ||
269 | */ | ||
270 | static DEFINE_SPINLOCK(orion5x_pci_lock); | ||
271 | |||
272 | int orion5x_pci_local_bus_nr(void) | ||
273 | { | ||
274 | u32 conf = orion5x_read(PCI_P2P_CONF); | ||
275 | return((conf & PCI_P2P_BUS_MASK) >> PCI_P2P_BUS_OFFS); | ||
276 | } | ||
277 | |||
278 | static int orion5x_pci_hw_rd_conf(int bus, int dev, u32 func, | ||
279 | u32 where, u32 size, u32 *val) | ||
280 | { | ||
281 | unsigned long flags; | ||
282 | spin_lock_irqsave(&orion5x_pci_lock, flags); | ||
283 | |||
284 | orion5x_write(PCI_CONF_ADDR, PCI_CONF_BUS(bus) | | ||
285 | PCI_CONF_DEV(dev) | PCI_CONF_REG(where) | | ||
286 | PCI_CONF_FUNC(func) | PCI_CONF_ADDR_EN); | ||
287 | |||
288 | *val = orion5x_read(PCI_CONF_DATA); | ||
289 | |||
290 | if (size == 1) | ||
291 | *val = (*val >> (8*(where & 0x3))) & 0xff; | ||
292 | else if (size == 2) | ||
293 | *val = (*val >> (8*(where & 0x3))) & 0xffff; | ||
294 | |||
295 | spin_unlock_irqrestore(&orion5x_pci_lock, flags); | ||
296 | |||
297 | return PCIBIOS_SUCCESSFUL; | ||
298 | } | ||
299 | |||
300 | static int orion5x_pci_hw_wr_conf(int bus, int dev, u32 func, | ||
301 | u32 where, u32 size, u32 val) | ||
302 | { | ||
303 | unsigned long flags; | ||
304 | int ret = PCIBIOS_SUCCESSFUL; | ||
305 | |||
306 | spin_lock_irqsave(&orion5x_pci_lock, flags); | ||
307 | |||
308 | orion5x_write(PCI_CONF_ADDR, PCI_CONF_BUS(bus) | | ||
309 | PCI_CONF_DEV(dev) | PCI_CONF_REG(where) | | ||
310 | PCI_CONF_FUNC(func) | PCI_CONF_ADDR_EN); | ||
311 | |||
312 | if (size == 4) { | ||
313 | __raw_writel(val, PCI_CONF_DATA); | ||
314 | } else if (size == 2) { | ||
315 | __raw_writew(val, PCI_CONF_DATA + (where & 0x3)); | ||
316 | } else if (size == 1) { | ||
317 | __raw_writeb(val, PCI_CONF_DATA + (where & 0x3)); | ||
318 | } else { | ||
319 | ret = PCIBIOS_BAD_REGISTER_NUMBER; | ||
320 | } | ||
321 | |||
322 | spin_unlock_irqrestore(&orion5x_pci_lock, flags); | ||
323 | |||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | static int orion5x_pci_rd_conf(struct pci_bus *bus, u32 devfn, | ||
328 | int where, int size, u32 *val) | ||
329 | { | ||
330 | /* | ||
331 | * Don't go out for local device | ||
332 | */ | ||
333 | if (bus->number == orion5x_pci_local_bus_nr() && | ||
334 | PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) != 0) { | ||
335 | *val = 0xffffffff; | ||
336 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
337 | } | ||
338 | |||
339 | return orion5x_pci_hw_rd_conf(bus->number, PCI_SLOT(devfn), | ||
340 | PCI_FUNC(devfn), where, size, val); | ||
341 | } | ||
342 | |||
343 | static int orion5x_pci_wr_conf(struct pci_bus *bus, u32 devfn, | ||
344 | int where, int size, u32 val) | ||
345 | { | ||
346 | if (bus->number == orion5x_pci_local_bus_nr() && | ||
347 | PCI_SLOT(devfn) == 0 && PCI_FUNC(devfn) != 0) | ||
348 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
349 | |||
350 | return orion5x_pci_hw_wr_conf(bus->number, PCI_SLOT(devfn), | ||
351 | PCI_FUNC(devfn), where, size, val); | ||
352 | } | ||
353 | |||
354 | static struct pci_ops pci_ops = { | ||
355 | .read = orion5x_pci_rd_conf, | ||
356 | .write = orion5x_pci_wr_conf, | ||
357 | }; | ||
358 | |||
359 | static void __init orion5x_pci_set_bus_nr(int nr) | ||
360 | { | ||
361 | u32 p2p = orion5x_read(PCI_P2P_CONF); | ||
362 | |||
363 | if (orion5x_read(PCI_MODE) & PCI_MODE_PCIX) { | ||
364 | /* | ||
365 | * PCI-X mode | ||
366 | */ | ||
367 | u32 pcix_status, bus, dev; | ||
368 | bus = (p2p & PCI_P2P_BUS_MASK) >> PCI_P2P_BUS_OFFS; | ||
369 | dev = (p2p & PCI_P2P_DEV_MASK) >> PCI_P2P_DEV_OFFS; | ||
370 | orion5x_pci_hw_rd_conf(bus, dev, 0, PCIX_STAT, 4, &pcix_status); | ||
371 | pcix_status &= ~PCIX_STAT_BUS_MASK; | ||
372 | pcix_status |= (nr << PCIX_STAT_BUS_OFFS); | ||
373 | orion5x_pci_hw_wr_conf(bus, dev, 0, PCIX_STAT, 4, pcix_status); | ||
374 | } else { | ||
375 | /* | ||
376 | * PCI Conventional mode | ||
377 | */ | ||
378 | p2p &= ~PCI_P2P_BUS_MASK; | ||
379 | p2p |= (nr << PCI_P2P_BUS_OFFS); | ||
380 | orion5x_write(PCI_P2P_CONF, p2p); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | static void __init orion5x_pci_master_slave_enable(void) | ||
385 | { | ||
386 | int bus_nr, func, reg; | ||
387 | u32 val; | ||
388 | |||
389 | bus_nr = orion5x_pci_local_bus_nr(); | ||
390 | func = PCI_CONF_FUNC_STAT_CMD; | ||
391 | reg = PCI_CONF_REG_STAT_CMD; | ||
392 | orion5x_pci_hw_rd_conf(bus_nr, 0, func, reg, 4, &val); | ||
393 | val |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); | ||
394 | orion5x_pci_hw_wr_conf(bus_nr, 0, func, reg, 4, val | 0x7); | ||
395 | } | ||
396 | |||
397 | static void __init orion5x_setup_pci_wins(struct mbus_dram_target_info *dram) | ||
398 | { | ||
399 | u32 win_enable; | ||
400 | int bus; | ||
401 | int i; | ||
402 | |||
403 | /* | ||
404 | * First, disable windows. | ||
405 | */ | ||
406 | win_enable = 0xffffffff; | ||
407 | orion5x_write(PCI_BAR_ENABLE, win_enable); | ||
408 | |||
409 | /* | ||
410 | * Setup windows for DDR banks. | ||
411 | */ | ||
412 | bus = orion5x_pci_local_bus_nr(); | ||
413 | |||
414 | for (i = 0; i < dram->num_cs; i++) { | ||
415 | struct mbus_dram_window *cs = dram->cs + i; | ||
416 | u32 func = PCI_CONF_FUNC_BAR_CS(cs->cs_index); | ||
417 | u32 reg; | ||
418 | u32 val; | ||
419 | |||
420 | /* | ||
421 | * Write DRAM bank base address register. | ||
422 | */ | ||
423 | reg = PCI_CONF_REG_BAR_LO_CS(cs->cs_index); | ||
424 | orion5x_pci_hw_rd_conf(bus, 0, func, reg, 4, &val); | ||
425 | val = (cs->base & 0xfffff000) | (val & 0xfff); | ||
426 | orion5x_pci_hw_wr_conf(bus, 0, func, reg, 4, val); | ||
427 | |||
428 | /* | ||
429 | * Write DRAM bank size register. | ||
430 | */ | ||
431 | reg = PCI_CONF_REG_BAR_HI_CS(cs->cs_index); | ||
432 | orion5x_pci_hw_wr_conf(bus, 0, func, reg, 4, 0); | ||
433 | orion5x_write(PCI_BAR_SIZE_DDR_CS(cs->cs_index), | ||
434 | (cs->size - 1) & 0xfffff000); | ||
435 | orion5x_write(PCI_BAR_REMAP_DDR_CS(cs->cs_index), | ||
436 | cs->base & 0xfffff000); | ||
437 | |||
438 | /* | ||
439 | * Enable decode window for this chip select. | ||
440 | */ | ||
441 | win_enable &= ~(1 << cs->cs_index); | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | * Re-enable decode windows. | ||
446 | */ | ||
447 | orion5x_write(PCI_BAR_ENABLE, win_enable); | ||
448 | |||
449 | /* | ||
450 | * Disable automatic update of address remaping when writing to BARs. | ||
451 | */ | ||
452 | orion5x_setbits(PCI_ADDR_DECODE_CTRL, 1); | ||
453 | } | ||
454 | |||
455 | static int __init pci_setup(struct pci_sys_data *sys) | ||
456 | { | ||
457 | struct resource *res; | ||
458 | |||
459 | /* | ||
460 | * Point PCI unit MBUS decode windows to DRAM space. | ||
461 | */ | ||
462 | orion5x_setup_pci_wins(&orion5x_mbus_dram_info); | ||
463 | |||
464 | /* | ||
465 | * Master + Slave enable | ||
466 | */ | ||
467 | orion5x_pci_master_slave_enable(); | ||
468 | |||
469 | /* | ||
470 | * Force ordering | ||
471 | */ | ||
472 | orion5x_setbits(PCI_CMD, PCI_CMD_HOST_REORDER); | ||
473 | |||
474 | /* | ||
475 | * Request resources | ||
476 | */ | ||
477 | res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL); | ||
478 | if (!res) | ||
479 | panic("pci_setup unable to alloc resources"); | ||
480 | |||
481 | /* | ||
482 | * IORESOURCE_IO | ||
483 | */ | ||
484 | res[0].name = "PCI I/O Space"; | ||
485 | res[0].flags = IORESOURCE_IO; | ||
486 | res[0].start = ORION5X_PCI_IO_BUS_BASE; | ||
487 | res[0].end = res[0].start + ORION5X_PCI_IO_SIZE - 1; | ||
488 | if (request_resource(&ioport_resource, &res[0])) | ||
489 | panic("Request PCI IO resource failed\n"); | ||
490 | sys->resource[0] = &res[0]; | ||
491 | |||
492 | /* | ||
493 | * IORESOURCE_MEM | ||
494 | */ | ||
495 | res[1].name = "PCI Memory Space"; | ||
496 | res[1].flags = IORESOURCE_MEM; | ||
497 | res[1].start = ORION5X_PCI_MEM_PHYS_BASE; | ||
498 | res[1].end = res[1].start + ORION5X_PCI_MEM_SIZE - 1; | ||
499 | if (request_resource(&iomem_resource, &res[1])) | ||
500 | panic("Request PCI Memory resource failed\n"); | ||
501 | sys->resource[1] = &res[1]; | ||
502 | |||
503 | sys->resource[2] = NULL; | ||
504 | sys->io_offset = 0; | ||
505 | |||
506 | return 1; | ||
507 | } | ||
508 | |||
509 | |||
510 | /***************************************************************************** | ||
511 | * General PCIe + PCI | ||
512 | ****************************************************************************/ | ||
513 | static void __devinit rc_pci_fixup(struct pci_dev *dev) | ||
514 | { | ||
515 | /* | ||
516 | * Prevent enumeration of root complex. | ||
517 | */ | ||
518 | if (dev->bus->parent == NULL && dev->devfn == 0) { | ||
519 | int i; | ||
520 | |||
521 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | ||
522 | dev->resource[i].start = 0; | ||
523 | dev->resource[i].end = 0; | ||
524 | dev->resource[i].flags = 0; | ||
525 | } | ||
526 | } | ||
527 | } | ||
528 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MARVELL, PCI_ANY_ID, rc_pci_fixup); | ||
529 | |||
530 | int __init orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys) | ||
531 | { | ||
532 | int ret = 0; | ||
533 | |||
534 | if (nr == 0) { | ||
535 | orion_pcie_set_local_bus_nr(PCIE_BASE, sys->busnr); | ||
536 | ret = pcie_setup(sys); | ||
537 | } else if (nr == 1) { | ||
538 | orion5x_pci_set_bus_nr(sys->busnr); | ||
539 | ret = pci_setup(sys); | ||
540 | } | ||
541 | |||
542 | return ret; | ||
543 | } | ||
544 | |||
545 | struct pci_bus __init *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys) | ||
546 | { | ||
547 | struct pci_bus *bus; | ||
548 | |||
549 | if (nr == 0) { | ||
550 | bus = pci_scan_bus(sys->busnr, &pcie_ops, sys); | ||
551 | } else if (nr == 1) { | ||
552 | bus = pci_scan_bus(sys->busnr, &pci_ops, sys); | ||
553 | } else { | ||
554 | bus = NULL; | ||
555 | BUG(); | ||
556 | } | ||
557 | |||
558 | return bus; | ||
559 | } | ||
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c new file mode 100644 index 000000000000..37e8b2dc3ed5 --- /dev/null +++ b/arch/arm/mach-orion5x/rd88f5182-setup.c | |||
@@ -0,0 +1,312 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-orion5x/rd88f5182-setup.c | ||
3 | * | ||
4 | * Marvell Orion-NAS Reference Design Setup | ||
5 | * | ||
6 | * Maintainer: Ronen Shitrit <rshitrit@marvell.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public | ||
9 | * License version 2. This program is licensed "as is" without any | ||
10 | * warranty of any kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/pci.h> | ||
17 | #include <linux/irq.h> | ||
18 | #include <linux/mtd/physmap.h> | ||
19 | #include <linux/mv643xx_eth.h> | ||
20 | #include <linux/ata_platform.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <asm/mach-types.h> | ||
23 | #include <asm/gpio.h> | ||
24 | #include <asm/leds.h> | ||
25 | #include <asm/mach/arch.h> | ||
26 | #include <asm/mach/pci.h> | ||
27 | #include <asm/arch/orion5x.h> | ||
28 | #include "common.h" | ||
29 | |||
30 | /***************************************************************************** | ||
31 | * RD-88F5182 Info | ||
32 | ****************************************************************************/ | ||
33 | |||
34 | /* | ||
35 | * 512K NOR flash Device bus boot chip select | ||
36 | */ | ||
37 | |||
38 | #define RD88F5182_NOR_BOOT_BASE 0xf4000000 | ||
39 | #define RD88F5182_NOR_BOOT_SIZE SZ_512K | ||
40 | |||
41 | /* | ||
42 | * 16M NOR flash on Device bus chip select 1 | ||
43 | */ | ||
44 | |||
45 | #define RD88F5182_NOR_BASE 0xfc000000 | ||
46 | #define RD88F5182_NOR_SIZE SZ_16M | ||
47 | |||
48 | /* | ||
49 | * PCI | ||
50 | */ | ||
51 | |||
52 | #define RD88F5182_PCI_SLOT0_OFFS 7 | ||
53 | #define RD88F5182_PCI_SLOT0_IRQ_A_PIN 7 | ||
54 | #define RD88F5182_PCI_SLOT0_IRQ_B_PIN 6 | ||
55 | |||
56 | /* | ||
57 | * GPIO Debug LED | ||
58 | */ | ||
59 | |||
60 | #define RD88F5182_GPIO_DBG_LED 0 | ||
61 | |||
62 | /***************************************************************************** | ||
63 | * 16M NOR Flash on Device bus CS1 | ||
64 | ****************************************************************************/ | ||
65 | |||
66 | static struct physmap_flash_data rd88f5182_nor_flash_data = { | ||
67 | .width = 1, | ||
68 | }; | ||
69 | |||
70 | static struct resource rd88f5182_nor_flash_resource = { | ||
71 | .flags = IORESOURCE_MEM, | ||
72 | .start = RD88F5182_NOR_BASE, | ||
73 | .end = RD88F5182_NOR_BASE + RD88F5182_NOR_SIZE - 1, | ||
74 | }; | ||
75 | |||
76 | static struct platform_device rd88f5182_nor_flash = { | ||
77 | .name = "physmap-flash", | ||
78 | .id = 0, | ||
79 | .dev = { | ||
80 | .platform_data = &rd88f5182_nor_flash_data, | ||
81 | }, | ||
82 | .num_resources = 1, | ||
83 | .resource = &rd88f5182_nor_flash_resource, | ||
84 | }; | ||
85 | |||
86 | #ifdef CONFIG_LEDS | ||
87 | |||
88 | /***************************************************************************** | ||
89 | * Use GPIO debug led as CPU active indication | ||
90 | ****************************************************************************/ | ||
91 | |||
92 | static void rd88f5182_dbgled_event(led_event_t evt) | ||
93 | { | ||
94 | int val; | ||
95 | |||
96 | if (evt == led_idle_end) | ||
97 | val = 1; | ||
98 | else if (evt == led_idle_start) | ||
99 | val = 0; | ||
100 | else | ||
101 | return; | ||
102 | |||
103 | gpio_set_value(RD88F5182_GPIO_DBG_LED, val); | ||
104 | } | ||
105 | |||
106 | static int __init rd88f5182_dbgled_init(void) | ||
107 | { | ||
108 | int pin; | ||
109 | |||
110 | if (machine_is_rd88f5182()) { | ||
111 | pin = RD88F5182_GPIO_DBG_LED; | ||
112 | |||
113 | if (gpio_request(pin, "DBGLED") == 0) { | ||
114 | if (gpio_direction_output(pin, 0) != 0) { | ||
115 | printk(KERN_ERR "rd88f5182_dbgled_init failed " | ||
116 | "to set output pin %d\n", pin); | ||
117 | gpio_free(pin); | ||
118 | return 0; | ||
119 | } | ||
120 | } else { | ||
121 | printk(KERN_ERR "rd88f5182_dbgled_init failed " | ||
122 | "to request gpio %d\n", pin); | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | leds_event = rd88f5182_dbgled_event; | ||
127 | } | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | __initcall(rd88f5182_dbgled_init); | ||
132 | |||
133 | #endif | ||
134 | |||
135 | /***************************************************************************** | ||
136 | * PCI | ||
137 | ****************************************************************************/ | ||
138 | |||
139 | void __init rd88f5182_pci_preinit(void) | ||
140 | { | ||
141 | int pin; | ||
142 | |||
143 | /* | ||
144 | * Configure PCI GPIO IRQ pins | ||
145 | */ | ||
146 | pin = RD88F5182_PCI_SLOT0_IRQ_A_PIN; | ||
147 | if (gpio_request(pin, "PCI IntA") == 0) { | ||
148 | if (gpio_direction_input(pin) == 0) { | ||
149 | set_irq_type(gpio_to_irq(pin), IRQT_LOW); | ||
150 | } else { | ||
151 | printk(KERN_ERR "rd88f5182_pci_preinit faield to " | ||
152 | "set_irq_type pin %d\n", pin); | ||
153 | gpio_free(pin); | ||
154 | } | ||
155 | } else { | ||
156 | printk(KERN_ERR "rd88f5182_pci_preinit failed to request gpio %d\n", pin); | ||
157 | } | ||
158 | |||
159 | pin = RD88F5182_PCI_SLOT0_IRQ_B_PIN; | ||
160 | if (gpio_request(pin, "PCI IntB") == 0) { | ||
161 | if (gpio_direction_input(pin) == 0) { | ||
162 | set_irq_type(gpio_to_irq(pin), IRQT_LOW); | ||
163 | } else { | ||
164 | printk(KERN_ERR "rd88f5182_pci_preinit faield to " | ||
165 | "set_irq_type pin %d\n", pin); | ||
166 | gpio_free(pin); | ||
167 | } | ||
168 | } else { | ||
169 | printk(KERN_ERR "rd88f5182_pci_preinit failed to gpio_request %d\n", pin); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static int __init rd88f5182_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
174 | { | ||
175 | /* | ||
176 | * PCI-E isn't used on the RD2 | ||
177 | */ | ||
178 | if (dev->bus->number == orion5x_pcie_local_bus_nr()) | ||
179 | return IRQ_ORION5X_PCIE0_INT; | ||
180 | |||
181 | /* | ||
182 | * PCI IRQs are connected via GPIOs | ||
183 | */ | ||
184 | switch (slot - RD88F5182_PCI_SLOT0_OFFS) { | ||
185 | case 0: | ||
186 | if (pin == 1) | ||
187 | return gpio_to_irq(RD88F5182_PCI_SLOT0_IRQ_A_PIN); | ||
188 | else | ||
189 | return gpio_to_irq(RD88F5182_PCI_SLOT0_IRQ_B_PIN); | ||
190 | default: | ||
191 | return -1; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | static struct hw_pci rd88f5182_pci __initdata = { | ||
196 | .nr_controllers = 2, | ||
197 | .preinit = rd88f5182_pci_preinit, | ||
198 | .swizzle = pci_std_swizzle, | ||
199 | .setup = orion5x_pci_sys_setup, | ||
200 | .scan = orion5x_pci_sys_scan_bus, | ||
201 | .map_irq = rd88f5182_pci_map_irq, | ||
202 | }; | ||
203 | |||
204 | static int __init rd88f5182_pci_init(void) | ||
205 | { | ||
206 | if (machine_is_rd88f5182()) | ||
207 | pci_common_init(&rd88f5182_pci); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | subsys_initcall(rd88f5182_pci_init); | ||
213 | |||
214 | /***************************************************************************** | ||
215 | * Ethernet | ||
216 | ****************************************************************************/ | ||
217 | |||
218 | static struct mv643xx_eth_platform_data rd88f5182_eth_data = { | ||
219 | .phy_addr = 8, | ||
220 | .force_phy_addr = 1, | ||
221 | }; | ||
222 | |||
223 | /***************************************************************************** | ||
224 | * RTC DS1338 on I2C bus | ||
225 | ****************************************************************************/ | ||
226 | static struct i2c_board_info __initdata rd88f5182_i2c_rtc = { | ||
227 | .driver_name = "rtc-ds1307", | ||
228 | .type = "ds1338", | ||
229 | .addr = 0x68, | ||
230 | }; | ||
231 | |||
232 | /***************************************************************************** | ||
233 | * Sata | ||
234 | ****************************************************************************/ | ||
235 | static struct mv_sata_platform_data rd88f5182_sata_data = { | ||
236 | .n_ports = 2, | ||
237 | }; | ||
238 | |||
239 | /***************************************************************************** | ||
240 | * General Setup | ||
241 | ****************************************************************************/ | ||
242 | |||
243 | static struct platform_device *rd88f5182_devices[] __initdata = { | ||
244 | &rd88f5182_nor_flash, | ||
245 | }; | ||
246 | |||
247 | static void __init rd88f5182_init(void) | ||
248 | { | ||
249 | /* | ||
250 | * Setup basic Orion functions. Need to be called early. | ||
251 | */ | ||
252 | orion5x_init(); | ||
253 | |||
254 | /* | ||
255 | * Setup the CPU address decode windows for our devices | ||
256 | */ | ||
257 | orion5x_setup_dev_boot_win(RD88F5182_NOR_BOOT_BASE, | ||
258 | RD88F5182_NOR_BOOT_SIZE); | ||
259 | orion5x_setup_dev1_win(RD88F5182_NOR_BASE, RD88F5182_NOR_SIZE); | ||
260 | |||
261 | /* | ||
262 | * Open a special address decode windows for the PCIE WA. | ||
263 | */ | ||
264 | orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE, | ||
265 | ORION5X_PCIE_WA_SIZE); | ||
266 | |||
267 | /* | ||
268 | * Setup Multiplexing Pins -- | ||
269 | * MPP[0] Debug Led (GPIO - Out) | ||
270 | * MPP[1] Debug Led (GPIO - Out) | ||
271 | * MPP[2] N/A | ||
272 | * MPP[3] RTC_Int (GPIO - In) | ||
273 | * MPP[4] GPIO | ||
274 | * MPP[5] GPIO | ||
275 | * MPP[6] PCI_intA (GPIO - In) | ||
276 | * MPP[7] PCI_intB (GPIO - In) | ||
277 | * MPP[8-11] N/A | ||
278 | * MPP[12] SATA 0 presence Indication | ||
279 | * MPP[13] SATA 1 presence Indication | ||
280 | * MPP[14] SATA 0 active Indication | ||
281 | * MPP[15] SATA 1 active indication | ||
282 | * MPP[16-19] Not used | ||
283 | * MPP[20] PCI Clock to MV88F5182 | ||
284 | * MPP[21] PCI Clock to mini PCI CON11 | ||
285 | * MPP[22] USB 0 over current indication | ||
286 | * MPP[23] USB 1 over current indication | ||
287 | * MPP[24] USB 1 over current enable | ||
288 | * MPP[25] USB 0 over current enable | ||
289 | */ | ||
290 | |||
291 | orion5x_write(MPP_0_7_CTRL, 0x00000003); | ||
292 | orion5x_write(MPP_8_15_CTRL, 0x55550000); | ||
293 | orion5x_write(MPP_16_19_CTRL, 0x5555); | ||
294 | |||
295 | orion5x_gpio_set_valid_pins(0x000000fb); | ||
296 | |||
297 | platform_add_devices(rd88f5182_devices, ARRAY_SIZE(rd88f5182_devices)); | ||
298 | i2c_register_board_info(0, &rd88f5182_i2c_rtc, 1); | ||
299 | orion5x_eth_init(&rd88f5182_eth_data); | ||
300 | orion5x_sata_init(&rd88f5182_sata_data); | ||
301 | } | ||
302 | |||
303 | MACHINE_START(RD88F5182, "Marvell Orion-NAS Reference Design") | ||
304 | /* Maintainer: Ronen Shitrit <rshitrit@marvell.com> */ | ||
305 | .phys_io = ORION5X_REGS_PHYS_BASE, | ||
306 | .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC, | ||
307 | .boot_params = 0x00000100, | ||
308 | .init_machine = rd88f5182_init, | ||
309 | .map_io = orion5x_map_io, | ||
310 | .init_irq = orion5x_init_irq, | ||
311 | .timer = &orion5x_timer, | ||
312 | MACHINE_END | ||
diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c new file mode 100644 index 000000000000..71b0cffa2fe0 --- /dev/null +++ b/arch/arm/mach-orion5x/ts209-setup.c | |||
@@ -0,0 +1,359 @@ | |||
1 | /* | ||
2 | * QNAP TS-109/TS-209 Board Setup | ||
3 | * | ||
4 | * Maintainer: Byron Bradley <byron.bbradley@gmail.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/mtd/physmap.h> | ||
18 | #include <linux/mtd/nand.h> | ||
19 | #include <linux/mv643xx_eth.h> | ||
20 | #include <linux/gpio_keys.h> | ||
21 | #include <linux/input.h> | ||
22 | #include <linux/i2c.h> | ||
23 | #include <linux/serial_reg.h> | ||
24 | #include <linux/ata_platform.h> | ||
25 | #include <asm/mach-types.h> | ||
26 | #include <asm/gpio.h> | ||
27 | #include <asm/mach/arch.h> | ||
28 | #include <asm/mach/pci.h> | ||
29 | #include <asm/arch/orion5x.h> | ||
30 | #include "common.h" | ||
31 | |||
32 | #define QNAP_TS209_NOR_BOOT_BASE 0xf4000000 | ||
33 | #define QNAP_TS209_NOR_BOOT_SIZE SZ_8M | ||
34 | |||
35 | /**************************************************************************** | ||
36 | * 8MiB NOR flash. The struct mtd_partition is not in the same order as the | ||
37 | * partitions on the device because we want to keep compatability with | ||
38 | * existing QNAP firmware. | ||
39 | * | ||
40 | * Layout as used by QNAP: | ||
41 | * [2] 0x00000000-0x00200000 : "Kernel" | ||
42 | * [3] 0x00200000-0x00600000 : "RootFS1" | ||
43 | * [4] 0x00600000-0x00700000 : "RootFS2" | ||
44 | * [6] 0x00700000-0x00760000 : "NAS Config" (read-only) | ||
45 | * [5] 0x00760000-0x00780000 : "U-Boot Config" | ||
46 | * [1] 0x00780000-0x00800000 : "U-Boot" (read-only) | ||
47 | ***************************************************************************/ | ||
48 | static struct mtd_partition qnap_ts209_partitions[] = { | ||
49 | { | ||
50 | .name = "U-Boot", | ||
51 | .size = 0x00080000, | ||
52 | .offset = 0x00780000, | ||
53 | .mask_flags = MTD_WRITEABLE, | ||
54 | }, { | ||
55 | .name = "Kernel", | ||
56 | .size = 0x00200000, | ||
57 | .offset = 0, | ||
58 | }, { | ||
59 | .name = "RootFS1", | ||
60 | .size = 0x00400000, | ||
61 | .offset = 0x00200000, | ||
62 | }, { | ||
63 | .name = "RootFS2", | ||
64 | .size = 0x00100000, | ||
65 | .offset = 0x00600000, | ||
66 | }, { | ||
67 | .name = "U-Boot Config", | ||
68 | .size = 0x00020000, | ||
69 | .offset = 0x00760000, | ||
70 | }, { | ||
71 | .name = "NAS Config", | ||
72 | .size = 0x00060000, | ||
73 | .offset = 0x00700000, | ||
74 | .mask_flags = MTD_WRITEABLE, | ||
75 | } | ||
76 | }; | ||
77 | |||
78 | static struct physmap_flash_data qnap_ts209_nor_flash_data = { | ||
79 | .width = 1, | ||
80 | .parts = qnap_ts209_partitions, | ||
81 | .nr_parts = ARRAY_SIZE(qnap_ts209_partitions) | ||
82 | }; | ||
83 | |||
84 | static struct resource qnap_ts209_nor_flash_resource = { | ||
85 | .flags = IORESOURCE_MEM, | ||
86 | .start = QNAP_TS209_NOR_BOOT_BASE, | ||
87 | .end = QNAP_TS209_NOR_BOOT_BASE + QNAP_TS209_NOR_BOOT_SIZE - 1, | ||
88 | }; | ||
89 | |||
90 | static struct platform_device qnap_ts209_nor_flash = { | ||
91 | .name = "physmap-flash", | ||
92 | .id = 0, | ||
93 | .dev = { .platform_data = &qnap_ts209_nor_flash_data, }, | ||
94 | .resource = &qnap_ts209_nor_flash_resource, | ||
95 | .num_resources = 1, | ||
96 | }; | ||
97 | |||
98 | /***************************************************************************** | ||
99 | * PCI | ||
100 | ****************************************************************************/ | ||
101 | |||
102 | #define QNAP_TS209_PCI_SLOT0_OFFS 7 | ||
103 | #define QNAP_TS209_PCI_SLOT0_IRQ_PIN 6 | ||
104 | #define QNAP_TS209_PCI_SLOT1_IRQ_PIN 7 | ||
105 | |||
106 | void __init qnap_ts209_pci_preinit(void) | ||
107 | { | ||
108 | int pin; | ||
109 | |||
110 | /* | ||
111 | * Configure PCI GPIO IRQ pins | ||
112 | */ | ||
113 | pin = QNAP_TS209_PCI_SLOT0_IRQ_PIN; | ||
114 | if (gpio_request(pin, "PCI Int1") == 0) { | ||
115 | if (gpio_direction_input(pin) == 0) { | ||
116 | set_irq_type(gpio_to_irq(pin), IRQT_LOW); | ||
117 | } else { | ||
118 | printk(KERN_ERR "qnap_ts209_pci_preinit failed to " | ||
119 | "set_irq_type pin %d\n", pin); | ||
120 | gpio_free(pin); | ||
121 | } | ||
122 | } else { | ||
123 | printk(KERN_ERR "qnap_ts209_pci_preinit failed to gpio_request " | ||
124 | "%d\n", pin); | ||
125 | } | ||
126 | |||
127 | pin = QNAP_TS209_PCI_SLOT1_IRQ_PIN; | ||
128 | if (gpio_request(pin, "PCI Int2") == 0) { | ||
129 | if (gpio_direction_input(pin) == 0) { | ||
130 | set_irq_type(gpio_to_irq(pin), IRQT_LOW); | ||
131 | } else { | ||
132 | printk(KERN_ERR "qnap_ts209_pci_preinit failed " | ||
133 | "to set_irq_type pin %d\n", pin); | ||
134 | gpio_free(pin); | ||
135 | } | ||
136 | } else { | ||
137 | printk(KERN_ERR "qnap_ts209_pci_preinit failed to gpio_request " | ||
138 | "%d\n", pin); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static int __init qnap_ts209_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin) | ||
143 | { | ||
144 | /* | ||
145 | * PCIE IRQ is connected internally (not GPIO) | ||
146 | */ | ||
147 | if (dev->bus->number == orion5x_pcie_local_bus_nr()) | ||
148 | return IRQ_ORION5X_PCIE0_INT; | ||
149 | |||
150 | /* | ||
151 | * PCI IRQs are connected via GPIOs | ||
152 | */ | ||
153 | switch (slot - QNAP_TS209_PCI_SLOT0_OFFS) { | ||
154 | case 0: | ||
155 | return gpio_to_irq(QNAP_TS209_PCI_SLOT0_IRQ_PIN); | ||
156 | case 1: | ||
157 | return gpio_to_irq(QNAP_TS209_PCI_SLOT1_IRQ_PIN); | ||
158 | default: | ||
159 | return -1; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static struct hw_pci qnap_ts209_pci __initdata = { | ||
164 | .nr_controllers = 2, | ||
165 | .preinit = qnap_ts209_pci_preinit, | ||
166 | .swizzle = pci_std_swizzle, | ||
167 | .setup = orion5x_pci_sys_setup, | ||
168 | .scan = orion5x_pci_sys_scan_bus, | ||
169 | .map_irq = qnap_ts209_pci_map_irq, | ||
170 | }; | ||
171 | |||
172 | static int __init qnap_ts209_pci_init(void) | ||
173 | { | ||
174 | if (machine_is_ts_x09()) | ||
175 | pci_common_init(&qnap_ts209_pci); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | subsys_initcall(qnap_ts209_pci_init); | ||
181 | |||
182 | /***************************************************************************** | ||
183 | * Ethernet | ||
184 | ****************************************************************************/ | ||
185 | |||
186 | static struct mv643xx_eth_platform_data qnap_ts209_eth_data = { | ||
187 | .phy_addr = 8, | ||
188 | .force_phy_addr = 1, | ||
189 | }; | ||
190 | |||
191 | /***************************************************************************** | ||
192 | * RTC S35390A on I2C bus | ||
193 | ****************************************************************************/ | ||
194 | |||
195 | #define TS209_RTC_GPIO 3 | ||
196 | |||
197 | static struct i2c_board_info __initdata qnap_ts209_i2c_rtc = { | ||
198 | .driver_name = "rtc-s35390a", | ||
199 | .addr = 0x30, | ||
200 | .irq = 0, | ||
201 | }; | ||
202 | |||
203 | /**************************************************************************** | ||
204 | * GPIO Attached Keys | ||
205 | * Power button is attached to the PIC microcontroller | ||
206 | ****************************************************************************/ | ||
207 | |||
208 | #define QNAP_TS209_GPIO_KEY_MEDIA 1 | ||
209 | #define QNAP_TS209_GPIO_KEY_RESET 2 | ||
210 | |||
211 | static struct gpio_keys_button qnap_ts209_buttons[] = { | ||
212 | { | ||
213 | .code = KEY_RESTART, | ||
214 | .gpio = QNAP_TS209_GPIO_KEY_MEDIA, | ||
215 | .desc = "USB Copy Button", | ||
216 | .active_low = 1, | ||
217 | }, | ||
218 | { | ||
219 | .code = KEY_POWER, | ||
220 | .gpio = QNAP_TS209_GPIO_KEY_RESET, | ||
221 | .desc = "Reset Button", | ||
222 | .active_low = 1, | ||
223 | } | ||
224 | }; | ||
225 | |||
226 | static struct gpio_keys_platform_data qnap_ts209_button_data = { | ||
227 | .buttons = qnap_ts209_buttons, | ||
228 | .nbuttons = ARRAY_SIZE(qnap_ts209_buttons), | ||
229 | }; | ||
230 | |||
231 | static struct platform_device qnap_ts209_button_device = { | ||
232 | .name = "gpio-keys", | ||
233 | .id = -1, | ||
234 | .num_resources = 0, | ||
235 | .dev = { .platform_data = &qnap_ts209_button_data, }, | ||
236 | }; | ||
237 | |||
238 | /***************************************************************************** | ||
239 | * SATA | ||
240 | ****************************************************************************/ | ||
241 | static struct mv_sata_platform_data qnap_ts209_sata_data = { | ||
242 | .n_ports = 2, | ||
243 | }; | ||
244 | |||
245 | /***************************************************************************** | ||
246 | |||
247 | * General Setup | ||
248 | ****************************************************************************/ | ||
249 | |||
250 | static struct platform_device *qnap_ts209_devices[] __initdata = { | ||
251 | &qnap_ts209_nor_flash, | ||
252 | &qnap_ts209_button_device, | ||
253 | }; | ||
254 | |||
255 | /* | ||
256 | * QNAP TS-[12]09 specific power off method via UART1-attached PIC | ||
257 | */ | ||
258 | |||
259 | #define UART1_REG(x) (UART1_VIRT_BASE + ((UART_##x) << 2)) | ||
260 | |||
261 | static void qnap_ts209_power_off(void) | ||
262 | { | ||
263 | /* 19200 baud divisor */ | ||
264 | const unsigned divisor = ((ORION5X_TCLK + (8 * 19200)) / (16 * 19200)); | ||
265 | |||
266 | pr_info("%s: triggering power-off...\n", __func__); | ||
267 | |||
268 | /* hijack uart1 and reset into sane state (19200,8n1) */ | ||
269 | orion5x_write(UART1_REG(LCR), 0x83); | ||
270 | orion5x_write(UART1_REG(DLL), divisor & 0xff); | ||
271 | orion5x_write(UART1_REG(DLM), (divisor >> 8) & 0xff); | ||
272 | orion5x_write(UART1_REG(LCR), 0x03); | ||
273 | orion5x_write(UART1_REG(IER), 0x00); | ||
274 | orion5x_write(UART1_REG(FCR), 0x00); | ||
275 | orion5x_write(UART1_REG(MCR), 0x00); | ||
276 | |||
277 | /* send the power-off command 'A' to PIC */ | ||
278 | orion5x_write(UART1_REG(TX), 'A'); | ||
279 | } | ||
280 | |||
281 | static void __init qnap_ts209_init(void) | ||
282 | { | ||
283 | /* | ||
284 | * Setup basic Orion functions. Need to be called early. | ||
285 | */ | ||
286 | orion5x_init(); | ||
287 | |||
288 | /* | ||
289 | * Setup flash mapping | ||
290 | */ | ||
291 | orion5x_setup_dev_boot_win(QNAP_TS209_NOR_BOOT_BASE, | ||
292 | QNAP_TS209_NOR_BOOT_SIZE); | ||
293 | |||
294 | /* | ||
295 | * Open a special address decode windows for the PCIE WA. | ||
296 | */ | ||
297 | orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE, | ||
298 | ORION5X_PCIE_WA_SIZE); | ||
299 | |||
300 | /* | ||
301 | * Setup Multiplexing Pins -- | ||
302 | * MPP[0] Reserved | ||
303 | * MPP[1] USB copy button (0 active) | ||
304 | * MPP[2] Load defaults button (0 active) | ||
305 | * MPP[3] GPIO RTC | ||
306 | * MPP[4-5] Reserved | ||
307 | * MPP[6] PCI Int A | ||
308 | * MPP[7] PCI Int B | ||
309 | * MPP[8-11] Reserved | ||
310 | * MPP[12] SATA 0 presence | ||
311 | * MPP[13] SATA 1 presence | ||
312 | * MPP[14] SATA 0 active | ||
313 | * MPP[15] SATA 1 active | ||
314 | * MPP[16] UART1 RXD | ||
315 | * MPP[17] UART1 TXD | ||
316 | * MPP[18] SW_RST (0 active) | ||
317 | * MPP[19] Reserved | ||
318 | * MPP[20] PCI clock 0 | ||
319 | * MPP[21] PCI clock 1 | ||
320 | * MPP[22] USB 0 over current | ||
321 | * MPP[23-25] Reserved | ||
322 | */ | ||
323 | orion5x_write(MPP_0_7_CTRL, 0x3); | ||
324 | orion5x_write(MPP_8_15_CTRL, 0x55550000); | ||
325 | orion5x_write(MPP_16_19_CTRL, 0x5500); | ||
326 | orion5x_gpio_set_valid_pins(0x3cc0fff); | ||
327 | |||
328 | /* register ts209 specific power-off method */ | ||
329 | pm_power_off = qnap_ts209_power_off; | ||
330 | |||
331 | platform_add_devices(qnap_ts209_devices, | ||
332 | ARRAY_SIZE(qnap_ts209_devices)); | ||
333 | |||
334 | /* Get RTC IRQ and register the chip */ | ||
335 | if (gpio_request(TS209_RTC_GPIO, "rtc") == 0) { | ||
336 | if (gpio_direction_input(TS209_RTC_GPIO) == 0) | ||
337 | qnap_ts209_i2c_rtc.irq = gpio_to_irq(TS209_RTC_GPIO); | ||
338 | else | ||
339 | gpio_free(TS209_RTC_GPIO); | ||
340 | } | ||
341 | if (qnap_ts209_i2c_rtc.irq == 0) | ||
342 | pr_warning("qnap_ts209_init: failed to get RTC IRQ\n"); | ||
343 | i2c_register_board_info(0, &qnap_ts209_i2c_rtc, 1); | ||
344 | |||
345 | orion5x_eth_init(&qnap_ts209_eth_data); | ||
346 | orion5x_sata_init(&qnap_ts209_sata_data); | ||
347 | } | ||
348 | |||
349 | MACHINE_START(TS209, "QNAP TS-109/TS-209") | ||
350 | /* Maintainer: Byron Bradley <byron.bbradley@gmail.com> */ | ||
351 | .phys_io = ORION5X_REGS_PHYS_BASE, | ||
352 | .io_pg_offst = ((ORION5X_REGS_VIRT_BASE) >> 18) & 0xFFFC, | ||
353 | .boot_params = 0x00000100, | ||
354 | .init_machine = qnap_ts209_init, | ||
355 | .map_io = orion5x_map_io, | ||
356 | .init_irq = orion5x_init_irq, | ||
357 | .timer = &orion5x_timer, | ||
358 | .fixup = tag_fixup_mem32, | ||
359 | MACHINE_END | ||