aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ppc/syslib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/ppc/syslib
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/ppc/syslib')
-rw-r--r--arch/ppc/syslib/Makefile115
-rw-r--r--arch/ppc/syslib/btext.c861
-rw-r--r--arch/ppc/syslib/cpc700.h98
-rw-r--r--arch/ppc/syslib/cpc700_pic.c187
-rw-r--r--arch/ppc/syslib/cpc710.h83
-rw-r--r--arch/ppc/syslib/cpm2_common.c198
-rw-r--r--arch/ppc/syslib/cpm2_pic.c172
-rw-r--r--arch/ppc/syslib/cpm2_pic.h8
-rw-r--r--arch/ppc/syslib/dcr.S41
-rw-r--r--arch/ppc/syslib/gen550.h16
-rw-r--r--arch/ppc/syslib/gen550_dbg.c182
-rw-r--r--arch/ppc/syslib/gen550_kgdb.c86
-rw-r--r--arch/ppc/syslib/gt64260_pic.c328
-rw-r--r--arch/ppc/syslib/harrier.c302
-rw-r--r--arch/ppc/syslib/hawk_common.c319
-rw-r--r--arch/ppc/syslib/i8259.c211
-rw-r--r--arch/ppc/syslib/ibm440gp_common.c76
-rw-r--r--arch/ppc/syslib/ibm440gp_common.h35
-rw-r--r--arch/ppc/syslib/ibm440gx_common.c270
-rw-r--r--arch/ppc/syslib/ibm440gx_common.h57
-rw-r--r--arch/ppc/syslib/ibm440sp_common.c71
-rw-r--r--arch/ppc/syslib/ibm440sp_common.h25
-rw-r--r--arch/ppc/syslib/ibm44x_common.c193
-rw-r--r--arch/ppc/syslib/ibm44x_common.h42
-rw-r--r--arch/ppc/syslib/ibm_ocp.c9
-rw-r--r--arch/ppc/syslib/indirect_pci.c135
-rw-r--r--arch/ppc/syslib/ipic.c646
-rw-r--r--arch/ppc/syslib/ipic.h49
-rw-r--r--arch/ppc/syslib/m8260_pci.c194
-rw-r--r--arch/ppc/syslib/m8260_pci.h76
-rw-r--r--arch/ppc/syslib/m8260_pci_erratum9.c473
-rw-r--r--arch/ppc/syslib/m8260_setup.c264
-rw-r--r--arch/ppc/syslib/m8xx_setup.c433
-rw-r--r--arch/ppc/syslib/m8xx_wdt.c99
-rw-r--r--arch/ppc/syslib/m8xx_wdt.h16
-rw-r--r--arch/ppc/syslib/mpc10x_common.c510
-rw-r--r--arch/ppc/syslib/mpc52xx_devices.c318
-rw-r--r--arch/ppc/syslib/mpc52xx_pci.c235
-rw-r--r--arch/ppc/syslib/mpc52xx_pci.h139
-rw-r--r--arch/ppc/syslib/mpc52xx_pic.c257
-rw-r--r--arch/ppc/syslib/mpc52xx_setup.c230
-rw-r--r--arch/ppc/syslib/mpc52xx_sys.c38
-rw-r--r--arch/ppc/syslib/mpc83xx_devices.c237
-rw-r--r--arch/ppc/syslib/mpc83xx_sys.c100
-rw-r--r--arch/ppc/syslib/mpc85xx_devices.c552
-rw-r--r--arch/ppc/syslib/mpc85xx_sys.c118
-rw-r--r--arch/ppc/syslib/mv64360_pic.c426
-rw-r--r--arch/ppc/syslib/mv64x60.c2392
-rw-r--r--arch/ppc/syslib/mv64x60_dbg.c123
-rw-r--r--arch/ppc/syslib/mv64x60_win.c1168
-rw-r--r--arch/ppc/syslib/ocp.c485
-rw-r--r--arch/ppc/syslib/of_device.c273
-rw-r--r--arch/ppc/syslib/open_pic.c1083
-rw-r--r--arch/ppc/syslib/open_pic2.c716
-rw-r--r--arch/ppc/syslib/open_pic_defs.h292
-rw-r--r--arch/ppc/syslib/pci_auto.c517
-rw-r--r--arch/ppc/syslib/ppc403_pic.c127
-rw-r--r--arch/ppc/syslib/ppc405_pci.c177
-rw-r--r--arch/ppc/syslib/ppc4xx_dma.c708
-rw-r--r--arch/ppc/syslib/ppc4xx_kgdb.c124
-rw-r--r--arch/ppc/syslib/ppc4xx_pic.c244
-rw-r--r--arch/ppc/syslib/ppc4xx_pm.c47
-rw-r--r--arch/ppc/syslib/ppc4xx_setup.c321
-rw-r--r--arch/ppc/syslib/ppc4xx_sgdma.c467
-rw-r--r--arch/ppc/syslib/ppc83xx_setup.c138
-rw-r--r--arch/ppc/syslib/ppc83xx_setup.h53
-rw-r--r--arch/ppc/syslib/ppc85xx_common.c33
-rw-r--r--arch/ppc/syslib/ppc85xx_common.h25
-rw-r--r--arch/ppc/syslib/ppc85xx_setup.c354
-rw-r--r--arch/ppc/syslib/ppc85xx_setup.h59
-rw-r--r--arch/ppc/syslib/ppc8xx_pic.c130
-rw-r--r--arch/ppc/syslib/ppc8xx_pic.h21
-rw-r--r--arch/ppc/syslib/ppc_sys.c103
-rw-r--r--arch/ppc/syslib/prep_nvram.c141
-rw-r--r--arch/ppc/syslib/prom.c1447
-rw-r--r--arch/ppc/syslib/prom_init.c1002
-rw-r--r--arch/ppc/syslib/qspan_pci.c381
-rw-r--r--arch/ppc/syslib/todc_time.c513
-rw-r--r--arch/ppc/syslib/xilinx_pic.c157
79 files changed, 23351 insertions, 0 deletions
diff --git a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
new file mode 100644
index 000000000000..dd418ea3426c
--- /dev/null
+++ b/arch/ppc/syslib/Makefile
@@ -0,0 +1,115 @@
1#
2# Makefile for the linux kernel.
3#
4
5CFLAGS_prom_init.o += -fPIC
6CFLAGS_btext.o += -fPIC
7
8wdt-mpc8xx-$(CONFIG_8xx_WDT) += m8xx_wdt.o
9
10obj-$(CONFIG_PPCBUG_NVRAM) += prep_nvram.o
11obj-$(CONFIG_PPC_OCP) += ocp.o
12obj-$(CONFIG_IBM_OCP) += ibm_ocp.o
13obj-$(CONFIG_44x) += ibm44x_common.o
14obj-$(CONFIG_440GP) += ibm440gp_common.o
15obj-$(CONFIG_440GX) += ibm440gx_common.o
16obj-$(CONFIG_440SP) += ibm440gx_common.o ibm440sp_common.o
17ifeq ($(CONFIG_4xx),y)
18ifeq ($(CONFIG_VIRTEX_II_PRO),y)
19obj-$(CONFIG_40x) += xilinx_pic.o
20else
21ifeq ($(CONFIG_403),y)
22obj-$(CONFIG_40x) += ppc403_pic.o
23else
24obj-$(CONFIG_40x) += ppc4xx_pic.o
25endif
26endif
27obj-$(CONFIG_44x) += ppc4xx_pic.o
28obj-$(CONFIG_40x) += ppc4xx_setup.o
29obj-$(CONFIG_GEN_RTC) += todc_time.o
30obj-$(CONFIG_PPC4xx_DMA) += ppc4xx_dma.o
31obj-$(CONFIG_PPC4xx_EDMA) += ppc4xx_sgdma.o
32ifeq ($(CONFIG_40x),y)
33obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o ppc405_pci.o
34endif
35endif
36obj-$(CONFIG_8xx) += m8xx_setup.o ppc8xx_pic.o $(wdt-mpc8xx-y)
37ifeq ($(CONFIG_8xx),y)
38obj-$(CONFIG_PCI) += qspan_pci.o i8259.o
39endif
40obj-$(CONFIG_PPC_OF) += prom_init.o prom.o of_device.o
41obj-$(CONFIG_PPC_PMAC) += open_pic.o indirect_pci.o
42obj-$(CONFIG_POWER4) += open_pic2.o
43obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o
44obj-$(CONFIG_PPC_PREP) += open_pic.o indirect_pci.o i8259.o todc_time.o
45obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \
46 todc_time.o
47obj-$(CONFIG_CPCI690) += todc_time.o pci_auto.o
48obj-$(CONFIG_EBONY) += indirect_pci.o pci_auto.o todc_time.o
49obj-$(CONFIG_EV64260) += todc_time.o pci_auto.o
50obj-$(CONFIG_CHESTNUT) += mv64360_pic.o pci_auto.o
51obj-$(CONFIG_GEMINI) += open_pic.o indirect_pci.o
52obj-$(CONFIG_GT64260) += gt64260_pic.o
53obj-$(CONFIG_K2) += i8259.o indirect_pci.o todc_time.o \
54 pci_auto.o
55obj-$(CONFIG_LOPEC) += i8259.o pci_auto.o todc_time.o
56obj-$(CONFIG_HDPU) += pci_auto.o
57obj-$(CONFIG_LUAN) += indirect_pci.o pci_auto.o todc_time.o
58obj-$(CONFIG_KATANA) += pci_auto.o
59obj-$(CONFIG_MCPN765) += todc_time.o indirect_pci.o pci_auto.o \
60 open_pic.o i8259.o hawk_common.o
61obj-$(CONFIG_MENF1) += todc_time.o i8259.o mpc10x_common.o \
62 pci_auto.o indirect_pci.o
63obj-$(CONFIG_MV64360) += mv64360_pic.o
64obj-$(CONFIG_MV64X60) += mv64x60.o mv64x60_win.o indirect_pci.o
65obj-$(CONFIG_MVME5100) += open_pic.o todc_time.o indirect_pci.o \
66 pci_auto.o hawk_common.o
67obj-$(CONFIG_MVME5100_IPMC761_PRESENT) += i8259.o
68obj-$(CONFIG_OCOTEA) += indirect_pci.o pci_auto.o todc_time.o
69obj-$(CONFIG_PAL4) += cpc700_pic.o
70obj-$(CONFIG_PCORE) += todc_time.o i8259.o pci_auto.o
71obj-$(CONFIG_POWERPMC250) += pci_auto.o
72obj-$(CONFIG_PPLUS) += hawk_common.o open_pic.o i8259.o \
73 indirect_pci.o todc_time.o pci_auto.o
74obj-$(CONFIG_PRPMC750) += open_pic.o indirect_pci.o pci_auto.o \
75 hawk_common.o
76obj-$(CONFIG_HARRIER) += harrier.o
77obj-$(CONFIG_PRPMC800) += open_pic.o indirect_pci.o pci_auto.o
78obj-$(CONFIG_RADSTONE_PPC7D) += i8259.o pci_auto.o
79obj-$(CONFIG_SANDPOINT) += i8259.o pci_auto.o todc_time.o
80obj-$(CONFIG_SBC82xx) += todc_time.o
81obj-$(CONFIG_SPRUCE) += cpc700_pic.o indirect_pci.o pci_auto.o \
82 todc_time.o
83obj-$(CONFIG_8260) += m8260_setup.o
84obj-$(CONFIG_PCI_8260) += m8260_pci.o indirect_pci.o
85obj-$(CONFIG_8260_PCI9) += m8260_pci_erratum9.o
86obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
87ifeq ($(CONFIG_PPC_GEN550),y)
88obj-$(CONFIG_KGDB) += gen550_kgdb.o gen550_dbg.o
89obj-$(CONFIG_SERIAL_TEXT_DEBUG) += gen550_dbg.o
90endif
91ifeq ($(CONFIG_SERIAL_MPSC_CONSOLE),y)
92obj-$(CONFIG_SERIAL_TEXT_DEBUG) += mv64x60_dbg.o
93endif
94obj-$(CONFIG_BOOTX_TEXT) += btext.o
95obj-$(CONFIG_MPC10X_BRIDGE) += mpc10x_common.o indirect_pci.o
96obj-$(CONFIG_MPC10X_OPENPIC) += open_pic.o
97obj-$(CONFIG_40x) += dcr.o
98obj-$(CONFIG_BOOKE) += dcr.o
99obj-$(CONFIG_85xx) += open_pic.o ppc85xx_common.o ppc85xx_setup.o \
100 ppc_sys.o mpc85xx_sys.o \
101 mpc85xx_devices.o
102ifeq ($(CONFIG_85xx),y)
103obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o
104endif
105obj-$(CONFIG_83xx) += ipic.o ppc83xx_setup.o ppc_sys.o \
106 mpc83xx_sys.o mpc83xx_devices.o
107ifeq ($(CONFIG_83xx),y)
108obj-$(CONFIG_PCI) += indirect_pci.o pci_auto.o
109endif
110obj-$(CONFIG_MPC8555_CDS) += todc_time.o
111obj-$(CONFIG_PPC_MPC52xx) += mpc52xx_setup.o mpc52xx_pic.o \
112 mpc52xx_sys.o mpc52xx_devices.o ppc_sys.o
113ifeq ($(CONFIG_PPC_MPC52xx),y)
114obj-$(CONFIG_PCI) += mpc52xx_pci.o
115endif
diff --git a/arch/ppc/syslib/btext.c b/arch/ppc/syslib/btext.c
new file mode 100644
index 000000000000..7734f6836174
--- /dev/null
+++ b/arch/ppc/syslib/btext.c
@@ -0,0 +1,861 @@
1/*
2 * Procedures for drawing on the screen early on in the boot process.
3 *
4 * Benjamin Herrenschmidt <benh@kernel.crashing.org>
5 */
6#include <linux/config.h>
7#include <linux/kernel.h>
8#include <linux/string.h>
9#include <linux/init.h>
10#include <linux/version.h>
11
12#include <asm/sections.h>
13#include <asm/bootx.h>
14#include <asm/btext.h>
15#include <asm/prom.h>
16#include <asm/page.h>
17#include <asm/mmu.h>
18#include <asm/pgtable.h>
19#include <asm/io.h>
20#include <asm/reg.h>
21
22#define NO_SCROLL
23
24#ifndef NO_SCROLL
25static void scrollscreen(void);
26#endif
27
28static void draw_byte(unsigned char c, long locX, long locY);
29static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
30static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);
31static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);
32
33static int g_loc_X;
34static int g_loc_Y;
35static int g_max_loc_X;
36static int g_max_loc_Y;
37
38unsigned long disp_BAT[2] __initdata = {0, 0};
39
40#define cmapsz (16*256)
41
42static unsigned char vga_font[cmapsz];
43
44int boot_text_mapped;
45int force_printk_to_btext = 0;
46
47boot_infos_t disp_bi;
48
49extern char *klimit;
50
51/*
52 * Powermac can use btext_* after boot for xmon,
53 * chrp only uses it during early boot.
54 */
55#ifdef CONFIG_XMON
56#define BTEXT __pmac
57#define BTDATA __pmacdata
58#else
59#define BTEXT __init
60#define BTDATA __initdata
61#endif /* CONFIG_XMON */
62
63/*
64 * This is called only when we are booted via BootX.
65 */
66void __init
67btext_init(boot_infos_t *bi)
68{
69 g_loc_X = 0;
70 g_loc_Y = 0;
71 g_max_loc_X = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
72 g_max_loc_Y = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
73 disp_bi = *bi;
74 boot_text_mapped = 1;
75}
76
77void __init
78btext_welcome(void)
79{
80 unsigned long flags;
81 unsigned long pvr;
82 boot_infos_t* bi = &disp_bi;
83
84 btext_drawstring("Welcome to Linux, kernel " UTS_RELEASE "\n");
85 btext_drawstring("\nlinked at : 0x");
86 btext_drawhex(KERNELBASE);
87 btext_drawstring("\nframe buffer at : 0x");
88 btext_drawhex((unsigned long)bi->dispDeviceBase);
89 btext_drawstring(" (phys), 0x");
90 btext_drawhex((unsigned long)bi->logicalDisplayBase);
91 btext_drawstring(" (log)");
92 btext_drawstring("\nklimit : 0x");
93 btext_drawhex((unsigned long)klimit);
94 btext_drawstring("\nMSR : 0x");
95 __asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
96 btext_drawhex(flags);
97 __asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
98 pvr >>= 16;
99 if (pvr > 1) {
100 btext_drawstring("\nHID0 : 0x");
101 __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
102 btext_drawhex(flags);
103 }
104 if (pvr == 8 || pvr == 12 || pvr == 0x800c) {
105 btext_drawstring("\nICTC : 0x");
106 __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
107 btext_drawhex(flags);
108 }
109 btext_drawstring("\n\n");
110}
111
112/* Calc BAT values for mapping the display and store them
113 * in disp_BAT. Those values are then used from head.S to map
114 * the display during identify_machine() and MMU_Init()
115 *
116 * The display is mapped to virtual address 0xD0000000, rather
117 * than 1:1, because some some CHRP machines put the frame buffer
118 * in the region starting at 0xC0000000 (KERNELBASE).
119 * This mapping is temporary and will disappear as soon as the
120 * setup done by MMU_Init() is applied.
121 *
122 * For now, we align the BAT and then map 8Mb on 601 and 16Mb
123 * on other PPCs. This may cause trouble if the framebuffer
124 * is really badly aligned, but I didn't encounter this case
125 * yet.
126 */
127void __init
128btext_prepare_BAT(void)
129{
130 boot_infos_t* bi = &disp_bi;
131 unsigned long vaddr = KERNELBASE + 0x10000000;
132 unsigned long addr;
133 unsigned long lowbits;
134
135 addr = (unsigned long)bi->dispDeviceBase;
136 if (!addr) {
137 boot_text_mapped = 0;
138 return;
139 }
140 if (PVR_VER(mfspr(SPRN_PVR)) != 1) {
141 /* 603, 604, G3, G4, ... */
142 lowbits = addr & ~0xFF000000UL;
143 addr &= 0xFF000000UL;
144 disp_BAT[0] = vaddr | (BL_16M<<2) | 2;
145 disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);
146 } else {
147 /* 601 */
148 lowbits = addr & ~0xFF800000UL;
149 addr &= 0xFF800000UL;
150 disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
151 disp_BAT[1] = addr | BL_8M | 0x40;
152 }
153 bi->logicalDisplayBase = (void *) (vaddr + lowbits);
154}
155
156/* This function will enable the early boot text when doing OF booting. This
157 * way, xmon output should work too
158 */
159void __init
160btext_setup_display(int width, int height, int depth, int pitch,
161 unsigned long address)
162{
163 boot_infos_t* bi = &disp_bi;
164
165 g_loc_X = 0;
166 g_loc_Y = 0;
167 g_max_loc_X = width / 8;
168 g_max_loc_Y = height / 16;
169 bi->logicalDisplayBase = (unsigned char *)address;
170 bi->dispDeviceBase = (unsigned char *)address;
171 bi->dispDeviceRowBytes = pitch;
172 bi->dispDeviceDepth = depth;
173 bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
174 bi->dispDeviceRect[2] = width;
175 bi->dispDeviceRect[3] = height;
176 boot_text_mapped = 1;
177}
178
179/* Here's a small text engine to use during early boot
180 * or for debugging purposes
181 *
182 * todo:
183 *
184 * - build some kind of vgacon with it to enable early printk
185 * - move to a separate file
186 * - add a few video driver hooks to keep in sync with display
187 * changes.
188 */
189
190void __openfirmware
191map_boot_text(void)
192{
193 unsigned long base, offset, size;
194 boot_infos_t *bi = &disp_bi;
195 unsigned char *vbase;
196
197 /* By default, we are no longer mapped */
198 boot_text_mapped = 0;
199 if (bi->dispDeviceBase == 0)
200 return;
201 base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL;
202 offset = ((unsigned long) bi->dispDeviceBase) - base;
203 size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset
204 + bi->dispDeviceRect[0];
205 vbase = ioremap(base, size);
206 if (vbase == 0)
207 return;
208 bi->logicalDisplayBase = vbase + offset;
209 boot_text_mapped = 1;
210}
211
212/* Calc the base address of a given point (x,y) */
213static unsigned char * BTEXT
214calc_base(boot_infos_t *bi, int x, int y)
215{
216 unsigned char *base;
217
218 base = bi->logicalDisplayBase;
219 if (base == 0)
220 base = bi->dispDeviceBase;
221 base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3);
222 base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes;
223 return base;
224}
225
226/* Adjust the display to a new resolution */
227void
228btext_update_display(unsigned long phys, int width, int height,
229 int depth, int pitch)
230{
231 boot_infos_t *bi = &disp_bi;
232
233 if (bi->dispDeviceBase == 0)
234 return;
235
236 /* check it's the same frame buffer (within 256MB) */
237 if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000)
238 return;
239
240 bi->dispDeviceBase = (__u8 *) phys;
241 bi->dispDeviceRect[0] = 0;
242 bi->dispDeviceRect[1] = 0;
243 bi->dispDeviceRect[2] = width;
244 bi->dispDeviceRect[3] = height;
245 bi->dispDeviceDepth = depth;
246 bi->dispDeviceRowBytes = pitch;
247 if (boot_text_mapped) {
248 iounmap(bi->logicalDisplayBase);
249 boot_text_mapped = 0;
250 }
251 map_boot_text();
252 g_loc_X = 0;
253 g_loc_Y = 0;
254 g_max_loc_X = width / 8;
255 g_max_loc_Y = height / 16;
256}
257
258void BTEXT btext_clearscreen(void)
259{
260 boot_infos_t* bi = &disp_bi;
261 unsigned long *base = (unsigned long *)calc_base(bi, 0, 0);
262 unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
263 (bi->dispDeviceDepth >> 3)) >> 2;
264 int i,j;
265
266 for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
267 {
268 unsigned long *ptr = base;
269 for(j=width; j; --j)
270 *(ptr++) = 0;
271 base += (bi->dispDeviceRowBytes >> 2);
272 }
273}
274
275__inline__ void dcbst(const void* addr)
276{
277 __asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
278}
279
280void BTEXT btext_flushscreen(void)
281{
282 boot_infos_t* bi = &disp_bi;
283 unsigned long *base = (unsigned long *)calc_base(bi, 0, 0);
284 unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
285 (bi->dispDeviceDepth >> 3)) >> 2;
286 int i,j;
287
288 for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
289 {
290 unsigned long *ptr = base;
291 for(j=width; j>0; j-=8) {
292 dcbst(ptr);
293 ptr += 8;
294 }
295 base += (bi->dispDeviceRowBytes >> 2);
296 }
297}
298
299#ifndef NO_SCROLL
300static BTEXT void
301scrollscreen(void)
302{
303 boot_infos_t* bi = &disp_bi;
304 unsigned long *src = (unsigned long *)calc_base(bi,0,16);
305 unsigned long *dst = (unsigned long *)calc_base(bi,0,0);
306 unsigned long width = ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
307 (bi->dispDeviceDepth >> 3)) >> 2;
308 int i,j;
309
310#ifdef CONFIG_ADB_PMU
311 pmu_suspend(); /* PMU will not shut us down ! */
312#endif
313 for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
314 {
315 unsigned long *src_ptr = src;
316 unsigned long *dst_ptr = dst;
317 for(j=width; j; --j)
318 *(dst_ptr++) = *(src_ptr++);
319 src += (bi->dispDeviceRowBytes >> 2);
320 dst += (bi->dispDeviceRowBytes >> 2);
321 }
322 for (i=0; i<16; i++)
323 {
324 unsigned long *dst_ptr = dst;
325 for(j=width; j; --j)
326 *(dst_ptr++) = 0;
327 dst += (bi->dispDeviceRowBytes >> 2);
328 }
329#ifdef CONFIG_ADB_PMU
330 pmu_resume(); /* PMU will not shut us down ! */
331#endif
332}
333#endif /* ndef NO_SCROLL */
334
335void BTEXT btext_drawchar(char c)
336{
337 int cline = 0, x;
338
339 if (!boot_text_mapped)
340 return;
341
342 switch (c) {
343 case '\b':
344 if (g_loc_X > 0)
345 --g_loc_X;
346 break;
347 case '\t':
348 g_loc_X = (g_loc_X & -8) + 8;
349 break;
350 case '\r':
351 g_loc_X = 0;
352 break;
353 case '\n':
354 g_loc_X = 0;
355 g_loc_Y++;
356 cline = 1;
357 break;
358 default:
359 draw_byte(c, g_loc_X++, g_loc_Y);
360 }
361 if (g_loc_X >= g_max_loc_X) {
362 g_loc_X = 0;
363 g_loc_Y++;
364 cline = 1;
365 }
366#ifndef NO_SCROLL
367 while (g_loc_Y >= g_max_loc_Y) {
368 scrollscreen();
369 g_loc_Y--;
370 }
371#else
372 /* wrap around from bottom to top of screen so we don't
373 waste time scrolling each line. -- paulus. */
374 if (g_loc_Y >= g_max_loc_Y)
375 g_loc_Y = 0;
376 if (cline) {
377 for (x = 0; x < g_max_loc_X; ++x)
378 draw_byte(' ', x, g_loc_Y);
379 }
380#endif
381}
382
383void BTEXT
384btext_drawstring(const char *c)
385{
386 if (!boot_text_mapped)
387 return;
388 while (*c)
389 btext_drawchar(*c++);
390}
391
392void BTEXT
393btext_drawhex(unsigned long v)
394{
395 static char hex_table[] = "0123456789abcdef";
396
397 if (!boot_text_mapped)
398 return;
399 btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
400 btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
401 btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
402 btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
403 btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
404 btext_drawchar(hex_table[(v >> 8) & 0x0000000FUL]);
405 btext_drawchar(hex_table[(v >> 4) & 0x0000000FUL]);
406 btext_drawchar(hex_table[(v >> 0) & 0x0000000FUL]);
407 btext_drawchar(' ');
408}
409
410static void BTEXT
411draw_byte(unsigned char c, long locX, long locY)
412{
413 boot_infos_t* bi = &disp_bi;
414 unsigned char *base = calc_base(bi, locX << 3, locY << 4);
415 unsigned char *font = &vga_font[((unsigned long)c) * 16];
416 int rb = bi->dispDeviceRowBytes;
417
418 switch(bi->dispDeviceDepth) {
419 case 24:
420 case 32:
421 draw_byte_32(font, (unsigned long *)base, rb);
422 break;
423 case 15:
424 case 16:
425 draw_byte_16(font, (unsigned long *)base, rb);
426 break;
427 case 8:
428 draw_byte_8(font, (unsigned long *)base, rb);
429 break;
430 }
431}
432
433static unsigned long expand_bits_8[16] BTDATA = {
434 0x00000000,
435 0x000000ff,
436 0x0000ff00,
437 0x0000ffff,
438 0x00ff0000,
439 0x00ff00ff,
440 0x00ffff00,
441 0x00ffffff,
442 0xff000000,
443 0xff0000ff,
444 0xff00ff00,
445 0xff00ffff,
446 0xffff0000,
447 0xffff00ff,
448 0xffffff00,
449 0xffffffff
450};
451
452static unsigned long expand_bits_16[4] BTDATA = {
453 0x00000000,
454 0x0000ffff,
455 0xffff0000,
456 0xffffffff
457};
458
459
460static void BTEXT
461draw_byte_32(unsigned char *font, unsigned long *base, int rb)
462{
463 int l, bits;
464 int fg = 0xFFFFFFFFUL;
465 int bg = 0x00000000UL;
466
467 for (l = 0; l < 16; ++l)
468 {
469 bits = *font++;
470 base[0] = (-(bits >> 7) & fg) ^ bg;
471 base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
472 base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
473 base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
474 base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
475 base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
476 base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
477 base[7] = (-(bits & 1) & fg) ^ bg;
478 base = (unsigned long *) ((char *)base + rb);
479 }
480}
481
482static void BTEXT
483draw_byte_16(unsigned char *font, unsigned long *base, int rb)
484{
485 int l, bits;
486 int fg = 0xFFFFFFFFUL;
487 int bg = 0x00000000UL;
488 unsigned long *eb = expand_bits_16;
489
490 for (l = 0; l < 16; ++l)
491 {
492 bits = *font++;
493 base[0] = (eb[bits >> 6] & fg) ^ bg;
494 base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
495 base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
496 base[3] = (eb[bits & 3] & fg) ^ bg;
497 base = (unsigned long *) ((char *)base + rb);
498 }
499}
500
501static void BTEXT
502draw_byte_8(unsigned char *font, unsigned long *base, int rb)
503{
504 int l, bits;
505 int fg = 0x0F0F0F0FUL;
506 int bg = 0x00000000UL;
507 unsigned long *eb = expand_bits_8;
508
509 for (l = 0; l < 16; ++l)
510 {
511 bits = *font++;
512 base[0] = (eb[bits >> 4] & fg) ^ bg;
513 base[1] = (eb[bits & 0xf] & fg) ^ bg;
514 base = (unsigned long *) ((char *)base + rb);
515 }
516}
517
518static unsigned char vga_font[cmapsz] BTDATA = {
5190x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5200x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd,
5210x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff,
5220xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
5230x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10,
5240x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe,
5250x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
5260x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
5270x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c,
5280x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
5290x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
5300xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
5310x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
5320x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
5330xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e,
5340x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
5350x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18,
5360x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30,
5370x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63,
5380x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00,
5390x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18,
5400x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8,
5410xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e,
5420x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
5430x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00,
5440x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
5450x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb,
5460xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00,
5470x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6,
5480x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5490xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
5500x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
5510x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
5520x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
5530x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5540x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5550x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
5560x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0,
5570xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5580x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5590x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00,
5600x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c,
5610x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5620x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5630x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
5640x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
5650x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c,
5660x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
5670x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c,
5680x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18,
5690x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c,
5700x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
5710x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5720x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
5730x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18,
5740x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
5750x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00,
5760x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
5770x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5780x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00,
5790x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
5800x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5810x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5820x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00,
5830x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c,
5840x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18,
5850x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
5860x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
5870x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c,
5880x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe,
5890x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
5900xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
5910x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
5920x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18,
5930x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
5940xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
5950x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78,
5960x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
5970x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
5980x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
5990x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06,
6000x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
6010x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60,
6020x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
6030x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18,
6040x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde,
6050xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38,
6060x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
6070x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc,
6080x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0,
6090xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c,
6100x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00,
6110x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe,
6120x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68,
6130x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
6140xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00,
6150x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
6160x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
6170x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c,
6180x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00,
6190x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6,
6200x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60,
6210x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7,
6220xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
6230x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6,
6240x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
6250xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66,
6260x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00,
6270x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c,
6280x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c,
6290x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6,
6300xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
6310x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
6320x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
6330xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
6340xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
6350x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66,
6360x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18,
6370x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3,
6380xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
6390x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff,
6400x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
6410x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
6420xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00,
6430x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c,
6440x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00,
6450x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6460x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
6470x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6480x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c,
6490xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60,
6500x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00,
6510x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c,
6520x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc,
6530xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6540x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
6550x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0,
6560x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc,
6570xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60,
6580x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
6590x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
6600x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06,
6610x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60,
6620x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00,
6630x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
6640x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb,
6650xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6660x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
6670x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
6680x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66,
6690x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00,
6700x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00,
6710x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0,
6720x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60,
6730x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30,
6740x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
6750x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
6760x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
6770xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6780x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
6790x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3,
6800x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6,
6810xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00,
6820x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00,
6830x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e,
6840x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
6850x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18,
6860x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
6870x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
6880x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6,
6890xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66,
6900xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00,
6910x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
6920x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe,
6930xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c,
6940x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
6950x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76,
6960x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c,
6970xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38,
6980x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00,
6990x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06,
7000x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe,
7010xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
7020x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
7030x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c,
7040x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18,
7050x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66,
7060x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
7070x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c,
7080x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6,
7090xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00,
7100x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
7110x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe,
7120x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b,
7130x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c,
7140xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00,
7150x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
7160x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6,
7170xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18,
7180x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00,
7190x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76,
7200x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc,
7210xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00,
7220x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00,
7230x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
7240x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6,
7250xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
7260xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
7270x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc,
7280x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
7290xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66,
7300x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00,
7310x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18,
7320xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c,
7330xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30,
7340x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
7350x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c,
7360x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc,
7370xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc,
7380x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
7390x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6,
7400x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00,
7410x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
7420x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7430x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c,
7440x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0,
7450xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7460x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
7470x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06,
7480x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30,
7490x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18,
7500x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
7510x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00,
7520x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36,
7530x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44,
7540x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44,
7550x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
7560x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77,
7570xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18,
7580x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
7590x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18,
7600x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
7610x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
7620x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
7630x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36,
7640x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
7650x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36,
7660x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
7670x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
7680x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6,
7690x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
7700x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7710x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00,
7720x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
7730x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7740x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
7750x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00,
7760x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
7770x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7780x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
7790x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
7800x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
7810x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
7820x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
7830x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
7840x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37,
7850x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
7860x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7870x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
7880x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff,
7890x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7900x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
7910x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36,
7920x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
7930x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36,
7940x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
7950x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
7960x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff,
7970x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
7980x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
7990x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36,
8000x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f,
8010x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
8020x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8030x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18,
8040x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f,
8050x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
8060x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
8070x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18,
8080x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
8090x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8100x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
8110xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
8120xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
8130xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0,
8140xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
8150x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
8160x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
8170x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8180x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00,
8190x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc,
8200x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0,
8210xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8220xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00,
8230x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe,
8240x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8,
8250xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8260x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00,
8270x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
8280x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66,
8290x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38,
8300x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
8310x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee,
8320x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66,
8330x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8340x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8350x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0,
8360x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60,
8370x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c,
8380xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00,
8390x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00,
8400x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
8410x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30,
8420x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
8430x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e,
8440x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18,
8450x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
8460x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00,
8470x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00,
8480x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00,
8490x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c,
8500x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8510x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
8520x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8530x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c,
8540x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00,
8550x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00,
8560x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00,
8570x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8580x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00,
8590x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8600x00, 0x00, 0x00, 0x00,
861};
diff --git a/arch/ppc/syslib/cpc700.h b/arch/ppc/syslib/cpc700.h
new file mode 100644
index 000000000000..f2c002531019
--- /dev/null
+++ b/arch/ppc/syslib/cpc700.h
@@ -0,0 +1,98 @@
1/*
2 * arch/ppc/syslib/cpc700.h
3 *
4 * Header file for IBM CPC700 Host Bridge, et. al.
5 *
6 * Author: Mark A. Greer
7 * mgreer@mvista.com
8 *
9 * 2000-2002 (c) MontaVista, Software, Inc. This file is licensed under
10 * the terms of the GNU General Public License version 2. This program
11 * is licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 */
14
15/*
16 * This file contains the defines and macros for the IBM CPC700 host bridge,
17 * memory controller, PIC, UARTs, IIC, and Timers.
18 */
19
20#ifndef __PPC_SYSLIB_CPC700_H__
21#define __PPC_SYSLIB_CPC700_H__
22
23#include <linux/stddef.h>
24#include <linux/types.h>
25#include <linux/init.h>
26
27/* XXX no barriers? not even any volatiles? -- paulus */
28#define CPC700_OUT_32(a,d) (*(u_int *)a = d)
29#define CPC700_IN_32(a) (*(u_int *)a)
30
31/*
32 * PCI Section
33 */
34#define CPC700_PCI_CONFIG_ADDR 0xfec00000
35#define CPC700_PCI_CONFIG_DATA 0xfec00004
36
37/* CPU -> PCI memory window 0 */
38#define CPC700_PMM0_LOCAL 0xff400000 /* CPU physical addr */
39#define CPC700_PMM0_MASK_ATTR 0xff400004 /* size and attrs */
40#define CPC700_PMM0_PCI_LOW 0xff400008 /* PCI addr, low word */
41#define CPC700_PMM0_PCI_HIGH 0xff40000c /* PCI addr, high wd */
42/* CPU -> PCI memory window 1 */
43#define CPC700_PMM1_LOCAL 0xff400010
44#define CPC700_PMM1_MASK_ATTR 0xff400014
45#define CPC700_PMM1_PCI_LOW 0xff400018
46#define CPC700_PMM1_PCI_HIGH 0xff40001c
47/* CPU -> PCI memory window 2 */
48#define CPC700_PMM2_LOCAL 0xff400020
49#define CPC700_PMM2_MASK_ATTR 0xff400024
50#define CPC700_PMM2_PCI_LOW 0xff400028
51#define CPC700_PMM2_PCI_HIGH 0xff40002c
52/* PCI memory -> CPU window 1 */
53#define CPC700_PTM1_MEMSIZE 0xff400030 /* window size */
54#define CPC700_PTM1_LOCAL 0xff400034 /* CPU phys addr */
55/* PCI memory -> CPU window 2 */
56#define CPC700_PTM2_MEMSIZE 0xff400038 /* size and enable */
57#define CPC700_PTM2_LOCAL 0xff40003c
58
59/*
60 * PIC Section
61 *
62 * IBM calls the CPC700's programmable interrupt controller the Universal
63 * Interrupt Controller or UIC.
64 */
65
66/*
67 * UIC Register Addresses.
68 */
69#define CPC700_UIC_UICSR 0xff500880 /* Status Reg (Rd/Clr)*/
70#define CPC700_UIC_UICSRS 0xff500884 /* Status Reg (Set) */
71#define CPC700_UIC_UICER 0xff500888 /* Enable Reg */
72#define CPC700_UIC_UICCR 0xff50088c /* Critical Reg */
73#define CPC700_UIC_UICPR 0xff500890 /* Polarity Reg */
74#define CPC700_UIC_UICTR 0xff500894 /* Trigger Reg */
75#define CPC700_UIC_UICMSR 0xff500898 /* Masked Status Reg */
76#define CPC700_UIC_UICVR 0xff50089c /* Vector Reg */
77#define CPC700_UIC_UICVCR 0xff5008a0 /* Vector Config Reg */
78
79#define CPC700_UIC_UICER_ENABLE 0x00000001 /* Enable an IRQ */
80
81#define CPC700_UIC_UICVCR_31_HI 0x00000000 /* IRQ 31 hi priority */
82#define CPC700_UIC_UICVCR_0_HI 0x00000001 /* IRQ 0 hi priority */
83#define CPC700_UIC_UICVCR_BASE_MASK 0xfffffffc
84#define CPC700_UIC_UICVCR_ORDER_MASK 0x00000001
85
86/* Specify value of a bit for an IRQ. */
87#define CPC700_UIC_IRQ_BIT(i) ((0x00000001) << (31 - (i)))
88
89/*
90 * UIC Exports...
91 */
92extern struct hw_interrupt_type cpc700_pic;
93extern unsigned int cpc700_irq_assigns[32][2];
94
95extern void __init cpc700_init_IRQ(void);
96extern int cpc700_get_irq(struct pt_regs *);
97
98#endif /* __PPC_SYSLIB_CPC700_H__ */
diff --git a/arch/ppc/syslib/cpc700_pic.c b/arch/ppc/syslib/cpc700_pic.c
new file mode 100644
index 000000000000..774709807538
--- /dev/null
+++ b/arch/ppc/syslib/cpc700_pic.c
@@ -0,0 +1,187 @@
1/*
2 * arch/ppc/syslib/cpc700_pic.c
3 *
4 * Interrupt controller support for IBM Spruce
5 *
6 * Authors: Mark Greer, Matt Porter, and Johnnie Peters
7 * mgreer@mvista.com
8 * mporter@mvista.com
9 * jpeters@mvista.com
10 *
11 * 2001-2002 (c) MontaVista, Software, Inc. This file is licensed under
12 * the terms of the GNU General Public License version 2. This program
13 * is licensed "as is" without any warranty of any kind, whether express
14 * or implied.
15 */
16
17#include <linux/stddef.h>
18#include <linux/init.h>
19#include <linux/sched.h>
20#include <linux/signal.h>
21#include <linux/irq.h>
22
23#include <asm/io.h>
24#include <asm/system.h>
25#include <asm/irq.h>
26
27#include "cpc700.h"
28
29static void
30cpc700_unmask_irq(unsigned int irq)
31{
32 unsigned int tr_bits;
33
34 /*
35 * IRQ 31 is largest IRQ supported.
36 * IRQs 17-19 are reserved.
37 */
38 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
39 tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
40
41 if ((tr_bits & (1 << (31 - irq))) == 0) {
42 /* level trigger interrupt, clear bit in status
43 * register */
44 CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
45 }
46
47 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
48 ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
49
50 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
51 }
52 return;
53}
54
55static void
56cpc700_mask_irq(unsigned int irq)
57{
58 /*
59 * IRQ 31 is largest IRQ supported.
60 * IRQs 17-19 are reserved.
61 */
62 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
63 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
64 ppc_cached_irq_mask[0] &=
65 ~CPC700_UIC_IRQ_BIT(irq);
66
67 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
68 }
69 return;
70}
71
72static void
73cpc700_mask_and_ack_irq(unsigned int irq)
74{
75 u_int bit;
76
77 /*
78 * IRQ 31 is largest IRQ supported.
79 * IRQs 17-19 are reserved.
80 */
81 if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
82 /* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
83 bit = CPC700_UIC_IRQ_BIT(irq);
84
85 ppc_cached_irq_mask[0] &= ~bit;
86 CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
87 CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
88 }
89 return;
90}
91
92static struct hw_interrupt_type cpc700_pic = {
93 "CPC700 PIC",
94 NULL,
95 NULL,
96 cpc700_unmask_irq,
97 cpc700_mask_irq,
98 cpc700_mask_and_ack_irq,
99 NULL,
100 NULL
101};
102
103__init static void
104cpc700_pic_init_irq(unsigned int irq)
105{
106 unsigned int tmp;
107
108 /* Set interrupt sense */
109 tmp = CPC700_IN_32(CPC700_UIC_UICTR);
110 if (cpc700_irq_assigns[irq][0] == 0) {
111 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
112 } else {
113 tmp |= CPC700_UIC_IRQ_BIT(irq);
114 }
115 CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
116
117 /* Set interrupt polarity */
118 tmp = CPC700_IN_32(CPC700_UIC_UICPR);
119 if (cpc700_irq_assigns[irq][1]) {
120 tmp |= CPC700_UIC_IRQ_BIT(irq);
121 } else {
122 tmp &= ~CPC700_UIC_IRQ_BIT(irq);
123 }
124 CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
125
126 /* Set interrupt critical */
127 tmp = CPC700_IN_32(CPC700_UIC_UICCR);
128 tmp |= CPC700_UIC_IRQ_BIT(irq);
129 CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
130
131 return;
132}
133
134__init void
135cpc700_init_IRQ(void)
136{
137 int i;
138
139 ppc_cached_irq_mask[0] = 0;
140 CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000); /* Disable all irq's */
141 CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff); /* Clear cur intrs */
142 CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff); /* Gen INT not MCP */
143 CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000); /* Active low */
144 CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000); /* Level Sensitive */
145 CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
146 /* IRQ 0 is highest */
147
148 for (i = 0; i < 17; i++) {
149 irq_desc[i].handler = &cpc700_pic;
150 cpc700_pic_init_irq(i);
151 }
152
153 for (i = 20; i < 32; i++) {
154 irq_desc[i].handler = &cpc700_pic;
155 cpc700_pic_init_irq(i);
156 }
157
158 return;
159}
160
161
162
163/*
164 * Find the highest IRQ that generating an interrupt, if any.
165 */
166int
167cpc700_get_irq(struct pt_regs *regs)
168{
169 int irq = 0;
170 u_int irq_status, irq_test = 1;
171
172 irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
173
174 do
175 {
176 if (irq_status & irq_test)
177 break;
178 irq++;
179 irq_test <<= 1;
180 } while (irq < NR_IRQS);
181
182
183 if (irq == NR_IRQS)
184 irq = 33;
185
186 return (31 - irq);
187}
diff --git a/arch/ppc/syslib/cpc710.h b/arch/ppc/syslib/cpc710.h
new file mode 100644
index 000000000000..cc0afd804029
--- /dev/null
+++ b/arch/ppc/syslib/cpc710.h
@@ -0,0 +1,83 @@
1/*
2 * arch/ppc/syslib/cpc710.h
3 *
4 * Definitions for the IBM CPC710 PCI Host Bridge
5 *
6 * Author: Matt Porter <mporter@mvista.com>
7 *
8 * 2001 (c) MontaVista, Software, Inc. This file is licensed under
9 * the terms of the GNU General Public License version 2. This program
10 * is licensed "as is" without any warranty of any kind, whether express
11 * or implied.
12 */
13
14#ifndef __PPC_PLATFORMS_CPC710_H
15#define __PPC_PLATFORMS_CPC710_H
16
17/* General bridge and memory controller registers */
18#define PIDR 0xff000008
19#define CNFR 0xff00000c
20#define RSTR 0xff000010
21#define UCTL 0xff001000
22#define MPSR 0xff001010
23#define SIOC 0xff001020
24#define ABCNTL 0xff001030
25#define SRST 0xff001040
26#define ERRC 0xff001050
27#define SESR 0xff001060
28#define SEAR 0xff001070
29#define SIOC1 0xff001090
30#define PGCHP 0xff001100
31#define GPDIR 0xff001130
32#define GPOUT 0xff001150
33#define ATAS 0xff001160
34#define AVDG 0xff001170
35#define MCCR 0xff001200
36#define MESR 0xff001220
37#define MEAR 0xff001230
38#define MCER0 0xff001300
39#define MCER1 0xff001310
40#define MCER2 0xff001320
41#define MCER3 0xff001330
42#define MCER4 0xff001340
43#define MCER5 0xff001350
44#define MCER6 0xff001360
45#define MCER7 0xff001370
46
47/*
48 * PCI32/64 configuration registers
49 * Given as offsets from their
50 * respective physical segment BAR
51 */
52#define PIBAR 0x000f7800
53#define PMBAR 0x000f7810
54#define MSIZE 0x000f7f40
55#define IOSIZE 0x000f7f60
56#define SMBAR 0x000f7f80
57#define SIBAR 0x000f7fc0
58#define PSSIZE 0x000f8100
59#define PPSIZE 0x000f8110
60#define BARPS 0x000f8120
61#define BARPP 0x000f8130
62#define PSBAR 0x000f8140
63#define PPBAR 0x000f8150
64#define BPMDLK 0x000f8200 /* Bottom of Peripheral Memory Space */
65#define TPMDLK 0x000f8210 /* Top of Peripheral Memory Space */
66#define BIODLK 0x000f8220 /* Bottom of Peripheral I/O Space */
67#define TIODLK 0x000f8230 /* Top of Perioheral I/O Space */
68#define DLKCTRL 0x000f8240 /* Deadlock control */
69#define DLKDEV 0x000f8250 /* Deadlock device */
70
71/* System standard configuration registers space */
72#define DCR 0xff200000
73#define DID 0xff200004
74#define BAR 0xff200018
75
76/* Device specific configuration space */
77#define PCIENB 0xff201000
78
79/* Configuration space registers */
80#define CPC710_BUS_NUMBER 0x40
81#define CPC710_SUB_BUS_NUMBER 0x41
82
83#endif /* __PPC_PLATFORMS_CPC710_H */
diff --git a/arch/ppc/syslib/cpm2_common.c b/arch/ppc/syslib/cpm2_common.c
new file mode 100644
index 000000000000..ea5e77080e8d
--- /dev/null
+++ b/arch/ppc/syslib/cpm2_common.c
@@ -0,0 +1,198 @@
1/*
2 * General Purpose functions for the global management of the
3 * 8260 Communication Processor Module.
4 * Copyright (c) 1999 Dan Malek (dmalek@jlc.net)
5 * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
6 * 2.3.99 Updates
7 *
8 * In addition to the individual control of the communication
9 * channels, there are a few functions that globally affect the
10 * communication processor.
11 *
12 * Buffer descriptors must be allocated from the dual ported memory
13 * space. The allocator for that is here. When the communication
14 * process is reset, we reclaim the memory available. There is
15 * currently no deallocator for this memory.
16 */
17#include <linux/errno.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/param.h>
21#include <linux/string.h>
22#include <linux/mm.h>
23#include <linux/interrupt.h>
24#include <linux/bootmem.h>
25#include <linux/module.h>
26#include <asm/irq.h>
27#include <asm/mpc8260.h>
28#include <asm/page.h>
29#include <asm/pgtable.h>
30#include <asm/immap_cpm2.h>
31#include <asm/cpm2.h>
32#include <asm/rheap.h>
33
34static void cpm2_dpinit(void);
35cpm_cpm2_t *cpmp; /* Pointer to comm processor space */
36
37/* We allocate this here because it is used almost exclusively for
38 * the communication processor devices.
39 */
40cpm2_map_t *cpm2_immr;
41
42#define CPM_MAP_SIZE (0x40000) /* 256k - the PQ3 reserve this amount
43 of space for CPM as it is larger
44 than on PQ2 */
45
46void
47cpm2_reset(void)
48{
49 cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
50
51 /* Reclaim the DP memory for our use.
52 */
53 cpm2_dpinit();
54
55 /* Tell everyone where the comm processor resides.
56 */
57 cpmp = &cpm2_immr->im_cpm;
58}
59
60/* Set a baud rate generator. This needs lots of work. There are
61 * eight BRGs, which can be connected to the CPM channels or output
62 * as clocks. The BRGs are in two different block of internal
63 * memory mapped space.
64 * The baud rate clock is the system clock divided by something.
65 * It was set up long ago during the initial boot phase and is
66 * is given to us.
67 * Baud rate clocks are zero-based in the driver code (as that maps
68 * to port numbers). Documentation uses 1-based numbering.
69 */
70#define BRG_INT_CLK (((bd_t *)__res)->bi_brgfreq)
71#define BRG_UART_CLK (BRG_INT_CLK/16)
72
73/* This function is used by UARTS, or anything else that uses a 16x
74 * oversampled clock.
75 */
76void
77cpm_setbrg(uint brg, uint rate)
78{
79 volatile uint *bp;
80
81 /* This is good enough to get SMCs running.....
82 */
83 if (brg < 4) {
84 bp = (uint *)&cpm2_immr->im_brgc1;
85 }
86 else {
87 bp = (uint *)&cpm2_immr->im_brgc5;
88 brg -= 4;
89 }
90 bp += brg;
91 *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
92}
93
94/* This function is used to set high speed synchronous baud rate
95 * clocks.
96 */
97void
98cpm2_fastbrg(uint brg, uint rate, int div16)
99{
100 volatile uint *bp;
101
102 if (brg < 4) {
103 bp = (uint *)&cpm2_immr->im_brgc1;
104 }
105 else {
106 bp = (uint *)&cpm2_immr->im_brgc5;
107 brg -= 4;
108 }
109 bp += brg;
110 *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
111 if (div16)
112 *bp |= CPM_BRG_DIV16;
113}
114
115/*
116 * dpalloc / dpfree bits.
117 */
118static spinlock_t cpm_dpmem_lock;
119/* 16 blocks should be enough to satisfy all requests
120 * until the memory subsystem goes up... */
121static rh_block_t cpm_boot_dpmem_rh_block[16];
122static rh_info_t cpm_dpmem_info;
123
124static void cpm2_dpinit(void)
125{
126 spin_lock_init(&cpm_dpmem_lock);
127
128 /* initialize the info header */
129 rh_init(&cpm_dpmem_info, 1,
130 sizeof(cpm_boot_dpmem_rh_block) /
131 sizeof(cpm_boot_dpmem_rh_block[0]),
132 cpm_boot_dpmem_rh_block);
133
134 /* Attach the usable dpmem area */
135 /* XXX: This is actually crap. CPM_DATAONLY_BASE and
136 * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
137 * varies with the processor and the microcode patches activated.
138 * But the following should be at least safe.
139 */
140 rh_attach_region(&cpm_dpmem_info, (void *)CPM_DATAONLY_BASE,
141 CPM_DATAONLY_SIZE);
142}
143
144/* This function returns an index into the DPRAM area.
145 */
146uint cpm_dpalloc(uint size, uint align)
147{
148 void *start;
149 unsigned long flags;
150
151 spin_lock_irqsave(&cpm_dpmem_lock, flags);
152 cpm_dpmem_info.alignment = align;
153 start = rh_alloc(&cpm_dpmem_info, size, "commproc");
154 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
155
156 return (uint)start;
157}
158EXPORT_SYMBOL(cpm_dpalloc);
159
160int cpm_dpfree(uint offset)
161{
162 int ret;
163 unsigned long flags;
164
165 spin_lock_irqsave(&cpm_dpmem_lock, flags);
166 ret = rh_free(&cpm_dpmem_info, (void *)offset);
167 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
168
169 return ret;
170}
171EXPORT_SYMBOL(cpm_dpfree);
172
173/* not sure if this is ever needed */
174uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
175{
176 void *start;
177 unsigned long flags;
178
179 spin_lock_irqsave(&cpm_dpmem_lock, flags);
180 cpm_dpmem_info.alignment = align;
181 start = rh_alloc_fixed(&cpm_dpmem_info, (void *)offset, size, "commproc");
182 spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
183
184 return (uint)start;
185}
186EXPORT_SYMBOL(cpm_dpalloc_fixed);
187
188void cpm_dpdump(void)
189{
190 rh_dump(&cpm_dpmem_info);
191}
192EXPORT_SYMBOL(cpm_dpdump);
193
194void *cpm_dpram_addr(uint offset)
195{
196 return (void *)&cpm2_immr->im_dprambase[offset];
197}
198EXPORT_SYMBOL(cpm_dpram_addr);
diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c
new file mode 100644
index 000000000000..954b07fc1df3
--- /dev/null
+++ b/arch/ppc/syslib/cpm2_pic.c
@@ -0,0 +1,172 @@
1/* The CPM2 internal interrupt controller. It is usually
2 * the only interrupt controller.
3 * There are two 32-bit registers (high/low) for up to 64
4 * possible interrupts.
5 *
6 * Now, the fun starts.....Interrupt Numbers DO NOT MAP
7 * in a simple arithmetic fashion to mask or pending registers.
8 * That is, interrupt 4 does not map to bit position 4.
9 * We create two tables, indexed by vector number, to indicate
10 * which register to use and which bit in the register to use.
11 */
12
13#include <linux/stddef.h>
14#include <linux/init.h>
15#include <linux/sched.h>
16#include <linux/signal.h>
17#include <linux/irq.h>
18
19#include <asm/immap_cpm2.h>
20#include <asm/mpc8260.h>
21
22#include "cpm2_pic.h"
23
24static u_char irq_to_siureg[] = {
25 1, 1, 1, 1, 1, 1, 1, 1,
26 1, 1, 1, 1, 1, 1, 1, 1,
27 0, 0, 0, 0, 0, 0, 0, 0,
28 0, 0, 0, 0, 0, 0, 0, 0,
29 1, 1, 1, 1, 1, 1, 1, 1,
30 1, 1, 1, 1, 1, 1, 1, 1,
31 0, 0, 0, 0, 0, 0, 0, 0,
32 0, 0, 0, 0, 0, 0, 0, 0
33};
34
35/* bit numbers do not match the docs, these are precomputed so the bit for
36 * a given irq is (1 << irq_to_siubit[irq]) */
37static u_char irq_to_siubit[] = {
38 0, 15, 14, 13, 12, 11, 10, 9,
39 8, 7, 6, 5, 4, 3, 2, 1,
40 2, 1, 15, 14, 13, 12, 11, 10,
41 9, 8, 7, 6, 5, 4, 3, 0,
42 31, 30, 29, 28, 27, 26, 25, 24,
43 23, 22, 21, 20, 19, 18, 17, 16,
44 16, 17, 18, 19, 20, 21, 22, 23,
45 24, 25, 26, 27, 28, 29, 30, 31,
46};
47
48static void cpm2_mask_irq(unsigned int irq_nr)
49{
50 int bit, word;
51 volatile uint *simr;
52
53 irq_nr -= CPM_IRQ_OFFSET;
54
55 bit = irq_to_siubit[irq_nr];
56 word = irq_to_siureg[irq_nr];
57
58 simr = &(cpm2_immr->im_intctl.ic_simrh);
59 ppc_cached_irq_mask[word] &= ~(1 << bit);
60 simr[word] = ppc_cached_irq_mask[word];
61}
62
63static void cpm2_unmask_irq(unsigned int irq_nr)
64{
65 int bit, word;
66 volatile uint *simr;
67
68 irq_nr -= CPM_IRQ_OFFSET;
69
70 bit = irq_to_siubit[irq_nr];
71 word = irq_to_siureg[irq_nr];
72
73 simr = &(cpm2_immr->im_intctl.ic_simrh);
74 ppc_cached_irq_mask[word] |= 1 << bit;
75 simr[word] = ppc_cached_irq_mask[word];
76}
77
78static void cpm2_mask_and_ack(unsigned int irq_nr)
79{
80 int bit, word;
81 volatile uint *simr, *sipnr;
82
83 irq_nr -= CPM_IRQ_OFFSET;
84
85 bit = irq_to_siubit[irq_nr];
86 word = irq_to_siureg[irq_nr];
87
88 simr = &(cpm2_immr->im_intctl.ic_simrh);
89 sipnr = &(cpm2_immr->im_intctl.ic_sipnrh);
90 ppc_cached_irq_mask[word] &= ~(1 << bit);
91 simr[word] = ppc_cached_irq_mask[word];
92 sipnr[word] = 1 << bit;
93}
94
95static void cpm2_end_irq(unsigned int irq_nr)
96{
97 int bit, word;
98 volatile uint *simr;
99
100 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
101 && irq_desc[irq_nr].action) {
102
103 irq_nr -= CPM_IRQ_OFFSET;
104 bit = irq_to_siubit[irq_nr];
105 word = irq_to_siureg[irq_nr];
106
107 simr = &(cpm2_immr->im_intctl.ic_simrh);
108 ppc_cached_irq_mask[word] |= 1 << bit;
109 simr[word] = ppc_cached_irq_mask[word];
110 }
111}
112
113static struct hw_interrupt_type cpm2_pic = {
114 .typename = " CPM2 SIU ",
115 .enable = cpm2_unmask_irq,
116 .disable = cpm2_mask_irq,
117 .ack = cpm2_mask_and_ack,
118 .end = cpm2_end_irq,
119};
120
121int cpm2_get_irq(struct pt_regs *regs)
122{
123 int irq;
124 unsigned long bits;
125
126 /* For CPM2, read the SIVEC register and shift the bits down
127 * to get the irq number. */
128 bits = cpm2_immr->im_intctl.ic_sivec;
129 irq = bits >> 26;
130
131 if (irq == 0)
132 return(-1);
133 return irq+CPM_IRQ_OFFSET;
134}
135
136void cpm2_init_IRQ(void)
137{
138 int i;
139
140 /* Clear the CPM IRQ controller, in case it has any bits set
141 * from the bootloader
142 */
143
144 /* Mask out everything */
145 cpm2_immr->im_intctl.ic_simrh = 0x00000000;
146 cpm2_immr->im_intctl.ic_simrl = 0x00000000;
147 wmb();
148
149 /* Ack everything */
150 cpm2_immr->im_intctl.ic_sipnrh = 0xffffffff;
151 cpm2_immr->im_intctl.ic_sipnrl = 0xffffffff;
152 wmb();
153
154 /* Dummy read of the vector */
155 i = cpm2_immr->im_intctl.ic_sivec;
156 rmb();
157
158 /* Initialize the default interrupt mapping priorities,
159 * in case the boot rom changed something on us.
160 */
161 cpm2_immr->im_intctl.ic_sicr = 0;
162 cpm2_immr->im_intctl.ic_scprrh = 0x05309770;
163 cpm2_immr->im_intctl.ic_scprrl = 0x05309770;
164
165
166 /* Enable chaining to OpenPIC, and make everything level
167 */
168 for (i = 0; i < NR_CPM_INTS; i++) {
169 irq_desc[i+CPM_IRQ_OFFSET].handler = &cpm2_pic;
170 irq_desc[i+CPM_IRQ_OFFSET].status |= IRQ_LEVEL;
171 }
172}
diff --git a/arch/ppc/syslib/cpm2_pic.h b/arch/ppc/syslib/cpm2_pic.h
new file mode 100644
index 000000000000..97cab8f13a1a
--- /dev/null
+++ b/arch/ppc/syslib/cpm2_pic.h
@@ -0,0 +1,8 @@
1#ifndef _PPC_KERNEL_CPM2_H
2#define _PPC_KERNEL_CPM2_H
3
4extern int cpm2_get_irq(struct pt_regs *regs);
5
6extern void cpm2_init_IRQ(void);
7
8#endif /* _PPC_KERNEL_CPM2_H */
diff --git a/arch/ppc/syslib/dcr.S b/arch/ppc/syslib/dcr.S
new file mode 100644
index 000000000000..895f10243a43
--- /dev/null
+++ b/arch/ppc/syslib/dcr.S
@@ -0,0 +1,41 @@
1/*
2 * arch/ppc/syslib/dcr.S
3 *
4 * "Indirect" DCR access
5 *
6 * Copyright (c) 2004 Eugene Surovegin <ebs@ebshome.net>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <asm/ppc_asm.h>
15#include <asm/processor.h>
16
17#define DCR_ACCESS_PROLOG(table) \
18 rlwinm r3,r3,4,18,27; \
19 lis r5,table@h; \
20 ori r5,r5,table@l; \
21 add r3,r3,r5; \
22 mtctr r3; \
23 bctr
24
25_GLOBAL(__mfdcr)
26 DCR_ACCESS_PROLOG(__mfdcr_table)
27
28_GLOBAL(__mtdcr)
29 DCR_ACCESS_PROLOG(__mtdcr_table)
30
31__mfdcr_table:
32 mfdcr r3,0; blr
33__mtdcr_table:
34 mtdcr 0,r4; blr
35
36dcr = 1
37 .rept 1023
38 mfdcr r3,dcr; blr
39 mtdcr dcr,r4; blr
40 dcr = dcr + 1
41 .endr
diff --git a/arch/ppc/syslib/gen550.h b/arch/ppc/syslib/gen550.h
new file mode 100644
index 000000000000..039d249e19a8
--- /dev/null
+++ b/arch/ppc/syslib/gen550.h
@@ -0,0 +1,16 @@
1/*
2 * arch/ppc/syslib/gen550.h
3 *
4 * gen550 prototypes
5 *
6 * Matt Porter <mporter@kernel.crashing.org>
7 *
8 * 2004 (c) MontaVista Software, Inc. This file is licensed under
9 * the terms of the GNU General Public License version 2. This program
10 * is licensed "as is" without any warranty of any kind, whether express
11 * or implied.
12 */
13
14extern void gen550_progress(char *, unsigned short);
15extern void gen550_init(int, struct uart_port *);
16extern void gen550_kgdb_map_scc(void);
diff --git a/arch/ppc/syslib/gen550_dbg.c b/arch/ppc/syslib/gen550_dbg.c
new file mode 100644
index 000000000000..9ef0113c83d1
--- /dev/null
+++ b/arch/ppc/syslib/gen550_dbg.c
@@ -0,0 +1,182 @@
1/*
2 * arch/ppc/syslib/gen550_dbg.c
3 *
4 * A library of polled 16550 serial routines. These are intended to
5 * be used to support progress messages, xmon, kgdb, etc. on a
6 * variety of platforms.
7 *
8 * Adapted from lots of code ripped from the arch/ppc/boot/ polled
9 * 16550 support.
10 *
11 * Author: Matt Porter <mporter@mvista.com>
12 *
13 * 2002-2003 (c) MontaVista Software, Inc. This file is licensed under
14 * the terms of the GNU General Public License version 2. This program
15 * is licensed "as is" without any warranty of any kind, whether express
16 * or implied.
17 */
18
19#include <linux/config.h>
20#include <linux/types.h>
21#include <linux/serial.h>
22#include <linux/tty.h> /* For linux/serial_core.h */
23#include <linux/serial_core.h>
24#include <linux/serialP.h>
25#include <linux/serial_reg.h>
26#include <asm/machdep.h>
27#include <asm/serial.h>
28#include <asm/io.h>
29
30#define SERIAL_BAUD 9600
31
32/* SERIAL_PORT_DFNS is defined in <asm/serial.h> */
33#ifndef SERIAL_PORT_DFNS
34#define SERIAL_PORT_DFNS
35#endif
36
37static struct serial_state rs_table[RS_TABLE_SIZE] = {
38 SERIAL_PORT_DFNS /* defined in <asm/serial.h> */
39};
40
41static void (*serial_outb)(unsigned long, unsigned char);
42static unsigned long (*serial_inb)(unsigned long);
43
44static int shift;
45
46unsigned long direct_inb(unsigned long addr)
47{
48 return readb((void __iomem *)addr);
49}
50
51void direct_outb(unsigned long addr, unsigned char val)
52{
53 writeb(val, (void __iomem *)addr);
54}
55
56unsigned long io_inb(unsigned long port)
57{
58 return inb(port);
59}
60
61void io_outb(unsigned long port, unsigned char val)
62{
63 outb(val, port);
64}
65
66unsigned long serial_init(int chan, void *ignored)
67{
68 unsigned long com_port;
69 unsigned char lcr, dlm;
70
71 /* We need to find out which type io we're expecting. If it's
72 * 'SERIAL_IO_PORT', we get an offset from the isa_io_base.
73 * If it's 'SERIAL_IO_MEM', we can the exact location. -- Tom */
74 switch (rs_table[chan].io_type) {
75 case SERIAL_IO_PORT:
76 com_port = rs_table[chan].port;
77 serial_outb = io_outb;
78 serial_inb = io_inb;
79 break;
80 case SERIAL_IO_MEM:
81 com_port = (unsigned long)rs_table[chan].iomem_base;
82 serial_outb = direct_outb;
83 serial_inb = direct_inb;
84 break;
85 default:
86 /* We can't deal with it. */
87 return -1;
88 }
89
90 /* How far apart the registers are. */
91 shift = rs_table[chan].iomem_reg_shift;
92
93 /* save the LCR */
94 lcr = serial_inb(com_port + (UART_LCR << shift));
95
96 /* Access baud rate */
97 serial_outb(com_port + (UART_LCR << shift), UART_LCR_DLAB);
98 dlm = serial_inb(com_port + (UART_DLM << shift));
99
100 /*
101 * Test if serial port is unconfigured
102 * We assume that no-one uses less than 110 baud or
103 * less than 7 bits per character these days.
104 * -- paulus.
105 */
106 if ((dlm <= 4) && (lcr & 2)) {
107 /* port is configured, put the old LCR back */
108 serial_outb(com_port + (UART_LCR << shift), lcr);
109 }
110 else {
111 /* Input clock. */
112 serial_outb(com_port + (UART_DLL << shift),
113 (rs_table[chan].baud_base / SERIAL_BAUD) & 0xFF);
114 serial_outb(com_port + (UART_DLM << shift),
115 (rs_table[chan].baud_base / SERIAL_BAUD) >> 8);
116 /* 8 data, 1 stop, no parity */
117 serial_outb(com_port + (UART_LCR << shift), 0x03);
118 /* RTS/DTR */
119 serial_outb(com_port + (UART_MCR << shift), 0x03);
120
121 /* Clear & enable FIFOs */
122 serial_outb(com_port + (UART_FCR << shift), 0x07);
123 }
124
125 return (com_port);
126}
127
128void
129serial_putc(unsigned long com_port, unsigned char c)
130{
131 while ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_THRE) == 0)
132 ;
133 serial_outb(com_port, c);
134}
135
136unsigned char
137serial_getc(unsigned long com_port)
138{
139 while ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) == 0)
140 ;
141 return serial_inb(com_port);
142}
143
144int
145serial_tstc(unsigned long com_port)
146{
147 return ((serial_inb(com_port + (UART_LSR << shift)) & UART_LSR_DR) != 0);
148}
149
150void
151serial_close(unsigned long com_port)
152{
153}
154
155void
156gen550_init(int i, struct uart_port *serial_req)
157{
158 rs_table[i].io_type = serial_req->iotype;
159 rs_table[i].port = serial_req->iobase;
160 rs_table[i].iomem_base = serial_req->membase;
161 rs_table[i].iomem_reg_shift = serial_req->regshift;
162 rs_table[i].baud_base = serial_req->uartclk ? serial_req->uartclk / 16 : BASE_BAUD;
163}
164
165#ifdef CONFIG_SERIAL_TEXT_DEBUG
166void
167gen550_progress(char *s, unsigned short hex)
168{
169 volatile unsigned int progress_debugport;
170 volatile char c;
171
172 progress_debugport = serial_init(0, NULL);
173
174 serial_putc(progress_debugport, '\r');
175
176 while ((c = *s++) != 0)
177 serial_putc(progress_debugport, c);
178
179 serial_putc(progress_debugport, '\n');
180 serial_putc(progress_debugport, '\r');
181}
182#endif /* CONFIG_SERIAL_TEXT_DEBUG */
diff --git a/arch/ppc/syslib/gen550_kgdb.c b/arch/ppc/syslib/gen550_kgdb.c
new file mode 100644
index 000000000000..7239d5d7ddcd
--- /dev/null
+++ b/arch/ppc/syslib/gen550_kgdb.c
@@ -0,0 +1,86 @@
1/*
2 * arch/ppc/syslib/gen550_kgdb.c
3 *
4 * Generic 16550 kgdb support intended to be useful on a variety
5 * of platforms. To enable this support, it is necessary to set
6 * the CONFIG_GEN550 option. Any virtual mapping of the serial
7 * port(s) to be used can be accomplished by setting
8 * ppc_md.early_serial_map to a platform-specific mapping function.
9 *
10 * Adapted from ppc4xx_kgdb.c.
11 *
12 * Author: Matt Porter <mporter@kernel.crashing.org>
13 *
14 * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under
15 * the terms of the GNU General Public License version 2. This program
16 * is licensed "as is" without any warranty of any kind, whether express
17 * or implied.
18 */
19
20#include <linux/config.h>
21#include <linux/types.h>
22#include <linux/kernel.h>
23
24#include <asm/machdep.h>
25
26extern unsigned long serial_init(int, void *);
27extern unsigned long serial_getc(unsigned long);
28extern unsigned long serial_putc(unsigned long, unsigned char);
29
30#if defined(CONFIG_KGDB_TTYS0)
31#define KGDB_PORT 0
32#elif defined(CONFIG_KGDB_TTYS1)
33#define KGDB_PORT 1
34#elif defined(CONFIG_KGDB_TTYS2)
35#define KGDB_PORT 2
36#elif defined(CONFIG_KGDB_TTYS3)
37#define KGDB_PORT 3
38#else
39#error "invalid kgdb_tty port"
40#endif
41
42static volatile unsigned int kgdb_debugport;
43
44void putDebugChar(unsigned char c)
45{
46 if (kgdb_debugport == 0)
47 kgdb_debugport = serial_init(KGDB_PORT, NULL);
48
49 serial_putc(kgdb_debugport, c);
50}
51
52int getDebugChar(void)
53{
54 if (kgdb_debugport == 0)
55 kgdb_debugport = serial_init(KGDB_PORT, NULL);
56
57 return(serial_getc(kgdb_debugport));
58}
59
60void kgdb_interruptible(int enable)
61{
62 return;
63}
64
65void putDebugString(char* str)
66{
67 while (*str != '\0') {
68 putDebugChar(*str);
69 str++;
70 }
71 putDebugChar('\r');
72 return;
73}
74
75/*
76 * Note: gen550_init() must be called already on the port we are going
77 * to use.
78 */
79void
80gen550_kgdb_map_scc(void)
81{
82 printk(KERN_DEBUG "kgdb init\n");
83 if (ppc_md.early_serial_map)
84 ppc_md.early_serial_map();
85 kgdb_debugport = serial_init(KGDB_PORT, NULL);
86}
diff --git a/arch/ppc/syslib/gt64260_pic.c b/arch/ppc/syslib/gt64260_pic.c
new file mode 100644
index 000000000000..44aa87385451
--- /dev/null
+++ b/arch/ppc/syslib/gt64260_pic.c
@@ -0,0 +1,328 @@
1/*
2 * arch/ppc/syslib/gt64260_pic.c
3 *
4 * Interrupt controller support for Galileo's GT64260.
5 *
6 * Author: Chris Zankel <source@mvista.com>
7 * Modified by: Mark A. Greer <mgreer@mvista.com>
8 *
9 * Based on sources from Rabeeh Khoury / Galileo Technology
10 *
11 * 2001 (c) MontaVista, Software, Inc. This file is licensed under
12 * the terms of the GNU General Public License version 2. This program
13 * is licensed "as is" without any warranty of any kind, whether express
14 * or implied.
15 */
16
17/*
18 * This file contains the specific functions to support the GT64260
19 * interrupt controller.
20 *
21 * The GT64260 has two main interrupt registers (high and low) that
22 * summarizes the interrupts generated by the units of the GT64260.
23 * Each bit is assigned to an interrupt number, where the low register
24 * are assigned from IRQ0 to IRQ31 and the high cause register
25 * from IRQ32 to IRQ63
26 * The GPP (General Purpose Port) interrupts are assigned from IRQ64 (GPP0)
27 * to IRQ95 (GPP31).
28 * get_irq() returns the lowest interrupt number that is currently asserted.
29 *
30 * Note:
31 * - This driver does not initialize the GPP when used as an interrupt
32 * input.
33 */
34
35#include <linux/stddef.h>
36#include <linux/init.h>
37#include <linux/interrupt.h>
38#include <linux/sched.h>
39#include <linux/signal.h>
40#include <linux/stddef.h>
41#include <linux/delay.h>
42#include <linux/irq.h>
43
44#include <asm/io.h>
45#include <asm/system.h>
46#include <asm/irq.h>
47#include <asm/mv64x60.h>
48
49#define CPU_INTR_STR "gt64260 cpu interface error"
50#define PCI0_INTR_STR "gt64260 pci 0 error"
51#define PCI1_INTR_STR "gt64260 pci 1 error"
52
53/* ========================== forward declaration ========================== */
54
55static void gt64260_unmask_irq(unsigned int);
56static void gt64260_mask_irq(unsigned int);
57
58/* ========================== local declarations =========================== */
59
60struct hw_interrupt_type gt64260_pic = {
61 .typename = " gt64260_pic ",
62 .enable = gt64260_unmask_irq,
63 .disable = gt64260_mask_irq,
64 .ack = gt64260_mask_irq,
65 .end = gt64260_unmask_irq,
66};
67
68u32 gt64260_irq_base = 0; /* GT64260 handles the next 96 IRQs from here */
69
70static struct mv64x60_handle bh;
71
72/* gt64260_init_irq()
73 *
74 * This function initializes the interrupt controller. It assigns
75 * all interrupts from IRQ0 to IRQ95 to the gt64260 interrupt controller.
76 *
77 * Note:
78 * We register all GPP inputs as interrupt source, but disable them.
79 */
80void __init
81gt64260_init_irq(void)
82{
83 int i;
84
85 if (ppc_md.progress)
86 ppc_md.progress("gt64260_init_irq: enter", 0x0);
87
88 bh.v_base = mv64x60_get_bridge_vbase();
89
90 ppc_cached_irq_mask[0] = 0;
91 ppc_cached_irq_mask[1] = 0x0f000000; /* Enable GPP intrs */
92 ppc_cached_irq_mask[2] = 0;
93
94 /* disable all interrupts and clear current interrupts */
95 mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, ppc_cached_irq_mask[2]);
96 mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, 0);
97 mv64x60_write(&bh, GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0]);
98 mv64x60_write(&bh, GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1]);
99
100 /* use the gt64260 for all (possible) interrupt sources */
101 for (i = gt64260_irq_base; i < (gt64260_irq_base + 96); i++)
102 irq_desc[i].handler = &gt64260_pic;
103
104 if (ppc_md.progress)
105 ppc_md.progress("gt64260_init_irq: exit", 0x0);
106}
107
108/*
109 * gt64260_get_irq()
110 *
111 * This function returns the lowest interrupt number of all interrupts that
112 * are currently asserted.
113 *
114 * Input Variable(s):
115 * struct pt_regs* not used
116 *
117 * Output Variable(s):
118 * None.
119 *
120 * Returns:
121 * int <interrupt number> or -2 (bogus interrupt)
122 */
123int
124gt64260_get_irq(struct pt_regs *regs)
125{
126 int irq;
127 int irq_gpp;
128
129 irq = mv64x60_read(&bh, GT64260_IC_MAIN_CAUSE_LO);
130 irq = __ilog2((irq & 0x3dfffffe) & ppc_cached_irq_mask[0]);
131
132 if (irq == -1) {
133 irq = mv64x60_read(&bh, GT64260_IC_MAIN_CAUSE_HI);
134 irq = __ilog2((irq & 0x0f000db7) & ppc_cached_irq_mask[1]);
135
136 if (irq == -1)
137 irq = -2; /* bogus interrupt, should never happen */
138 else {
139 if (irq >= 24) {
140 irq_gpp = mv64x60_read(&bh,
141 MV64x60_GPP_INTR_CAUSE);
142 irq_gpp = __ilog2(irq_gpp &
143 ppc_cached_irq_mask[2]);
144
145 if (irq_gpp == -1)
146 irq = -2;
147 else {
148 irq = irq_gpp + 64;
149 mv64x60_write(&bh,
150 MV64x60_GPP_INTR_CAUSE,
151 ~(1 << (irq - 64)));
152 }
153 } else
154 irq += 32;
155 }
156 }
157
158 (void)mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE);
159
160 if (irq < 0)
161 return (irq);
162 else
163 return (gt64260_irq_base + irq);
164}
165
166/* gt64260_unmask_irq()
167 *
168 * This function enables an interrupt.
169 *
170 * Input Variable(s):
171 * unsigned int interrupt number (IRQ0...IRQ95).
172 *
173 * Output Variable(s):
174 * None.
175 *
176 * Returns:
177 * void
178 */
179static void
180gt64260_unmask_irq(unsigned int irq)
181{
182 irq -= gt64260_irq_base;
183
184 if (irq > 31)
185 if (irq > 63) /* unmask GPP irq */
186 mv64x60_write(&bh, MV64x60_GPP_INTR_MASK,
187 ppc_cached_irq_mask[2] |= (1 << (irq - 64)));
188 else /* mask high interrupt register */
189 mv64x60_write(&bh, GT64260_IC_CPU_INTR_MASK_HI,
190 ppc_cached_irq_mask[1] |= (1 << (irq - 32)));
191 else /* mask low interrupt register */
192 mv64x60_write(&bh, GT64260_IC_CPU_INTR_MASK_LO,
193 ppc_cached_irq_mask[0] |= (1 << irq));
194
195 (void)mv64x60_read(&bh, MV64x60_GPP_INTR_MASK);
196 return;
197}
198
199/* gt64260_mask_irq()
200 *
201 * This function disables the requested interrupt.
202 *
203 * Input Variable(s):
204 * unsigned int interrupt number (IRQ0...IRQ95).
205 *
206 * Output Variable(s):
207 * None.
208 *
209 * Returns:
210 * void
211 */
212static void
213gt64260_mask_irq(unsigned int irq)
214{
215 irq -= gt64260_irq_base;
216
217 if (irq > 31)
218 if (irq > 63) /* mask GPP irq */
219 mv64x60_write(&bh, MV64x60_GPP_INTR_MASK,
220 ppc_cached_irq_mask[2] &= ~(1 << (irq - 64)));
221 else /* mask high interrupt register */
222 mv64x60_write(&bh, GT64260_IC_CPU_INTR_MASK_HI,
223 ppc_cached_irq_mask[1] &= ~(1 << (irq - 32)));
224 else /* mask low interrupt register */
225 mv64x60_write(&bh, GT64260_IC_CPU_INTR_MASK_LO,
226 ppc_cached_irq_mask[0] &= ~(1 << irq));
227
228 (void)mv64x60_read(&bh, MV64x60_GPP_INTR_MASK);
229 return;
230}
231
232static irqreturn_t
233gt64260_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
234{
235 printk(KERN_ERR "gt64260_cpu_error_int_handler: %s 0x%08x\n",
236 "Error on CPU interface - Cause regiser",
237 mv64x60_read(&bh, MV64x60_CPU_ERR_CAUSE));
238 printk(KERN_ERR "\tCPU error register dump:\n");
239 printk(KERN_ERR "\tAddress low 0x%08x\n",
240 mv64x60_read(&bh, MV64x60_CPU_ERR_ADDR_LO));
241 printk(KERN_ERR "\tAddress high 0x%08x\n",
242 mv64x60_read(&bh, MV64x60_CPU_ERR_ADDR_HI));
243 printk(KERN_ERR "\tData low 0x%08x\n",
244 mv64x60_read(&bh, MV64x60_CPU_ERR_DATA_LO));
245 printk(KERN_ERR "\tData high 0x%08x\n",
246 mv64x60_read(&bh, MV64x60_CPU_ERR_DATA_HI));
247 printk(KERN_ERR "\tParity 0x%08x\n",
248 mv64x60_read(&bh, MV64x60_CPU_ERR_PARITY));
249 mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0);
250 return IRQ_HANDLED;
251}
252
253static irqreturn_t
254gt64260_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
255{
256 u32 val;
257 unsigned int pci_bus = (unsigned int)dev_id;
258
259 if (pci_bus == 0) { /* Error on PCI 0 */
260 val = mv64x60_read(&bh, MV64x60_PCI0_ERR_CAUSE);
261 printk(KERN_ERR "%s: Error in PCI %d Interface\n",
262 "gt64260_pci_error_int_handler", pci_bus);
263 printk(KERN_ERR "\tPCI %d error register dump:\n", pci_bus);
264 printk(KERN_ERR "\tCause register 0x%08x\n", val);
265 printk(KERN_ERR "\tAddress Low 0x%08x\n",
266 mv64x60_read(&bh, MV64x60_PCI0_ERR_ADDR_LO));
267 printk(KERN_ERR "\tAddress High 0x%08x\n",
268 mv64x60_read(&bh, MV64x60_PCI0_ERR_ADDR_HI));
269 printk(KERN_ERR "\tAttribute 0x%08x\n",
270 mv64x60_read(&bh, MV64x60_PCI0_ERR_DATA_LO));
271 printk(KERN_ERR "\tCommand 0x%08x\n",
272 mv64x60_read(&bh, MV64x60_PCI0_ERR_CMD));
273 mv64x60_write(&bh, MV64x60_PCI0_ERR_CAUSE, ~val);
274 }
275 if (pci_bus == 1) { /* Error on PCI 1 */
276 val = mv64x60_read(&bh, MV64x60_PCI1_ERR_CAUSE);
277 printk(KERN_ERR "%s: Error in PCI %d Interface\n",
278 "gt64260_pci_error_int_handler", pci_bus);
279 printk(KERN_ERR "\tPCI %d error register dump:\n", pci_bus);
280 printk(KERN_ERR "\tCause register 0x%08x\n", val);
281 printk(KERN_ERR "\tAddress Low 0x%08x\n",
282 mv64x60_read(&bh, MV64x60_PCI1_ERR_ADDR_LO));
283 printk(KERN_ERR "\tAddress High 0x%08x\n",
284 mv64x60_read(&bh, MV64x60_PCI1_ERR_ADDR_HI));
285 printk(KERN_ERR "\tAttribute 0x%08x\n",
286 mv64x60_read(&bh, MV64x60_PCI1_ERR_DATA_LO));
287 printk(KERN_ERR "\tCommand 0x%08x\n",
288 mv64x60_read(&bh, MV64x60_PCI1_ERR_CMD));
289 mv64x60_write(&bh, MV64x60_PCI1_ERR_CAUSE, ~val);
290 }
291 return IRQ_HANDLED;
292}
293
294static int __init
295gt64260_register_hdlrs(void)
296{
297 int rc;
298
299 /* Register CPU interface error interrupt handler */
300 if ((rc = request_irq(MV64x60_IRQ_CPU_ERR,
301 gt64260_cpu_error_int_handler, SA_INTERRUPT, CPU_INTR_STR, 0)))
302 printk(KERN_WARNING "Can't register cpu error handler: %d", rc);
303
304 mv64x60_write(&bh, MV64x60_CPU_ERR_MASK, 0);
305 mv64x60_write(&bh, MV64x60_CPU_ERR_MASK, 0x000000fe);
306
307 /* Register PCI 0 error interrupt handler */
308 if ((rc = request_irq(MV64360_IRQ_PCI0, gt64260_pci_error_int_handler,
309 SA_INTERRUPT, PCI0_INTR_STR, (void *)0)))
310 printk(KERN_WARNING "Can't register pci 0 error handler: %d",
311 rc);
312
313 mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, 0);
314 mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, 0x003c0c24);
315
316 /* Register PCI 1 error interrupt handler */
317 if ((rc = request_irq(MV64360_IRQ_PCI1, gt64260_pci_error_int_handler,
318 SA_INTERRUPT, PCI1_INTR_STR, (void *)1)))
319 printk(KERN_WARNING "Can't register pci 1 error handler: %d",
320 rc);
321
322 mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, 0);
323 mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, 0x003c0c24);
324
325 return 0;
326}
327
328arch_initcall(gt64260_register_hdlrs);
diff --git a/arch/ppc/syslib/harrier.c b/arch/ppc/syslib/harrier.c
new file mode 100644
index 000000000000..a6b3f8645793
--- /dev/null
+++ b/arch/ppc/syslib/harrier.c
@@ -0,0 +1,302 @@
1/*
2 * arch/ppc/syslib/harrier.c
3 *
4 * Motorola MCG Harrier northbridge/memory controller support
5 *
6 * Author: Dale Farnsworth
7 * dale.farnsworth@mvista.com
8 *
9 * 2001 (c) MontaVista, Software, Inc. This file is licensed under
10 * the terms of the GNU General Public License version 2. This program
11 * is licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 */
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/pci.h>
17#include <linux/harrier_defs.h>
18
19#include <asm/byteorder.h>
20#include <asm/io.h>
21#include <asm/irq.h>
22#include <asm/pci.h>
23#include <asm/pci-bridge.h>
24#include <asm/open_pic.h>
25#include <asm/harrier.h>
26
27/* define defaults for inbound windows */
28#define HARRIER_ITAT_DEFAULT (HARRIER_ITAT_ENA | \
29 HARRIER_ITAT_MEM | \
30 HARRIER_ITAT_WPE | \
31 HARRIER_ITAT_GBL)
32
33#define HARRIER_MPAT_DEFAULT (HARRIER_ITAT_ENA | \
34 HARRIER_ITAT_MEM | \
35 HARRIER_ITAT_WPE | \
36 HARRIER_ITAT_GBL)
37
38/*
39 * Initialize the inbound window size on a non-monarch harrier.
40 */
41void __init harrier_setup_nonmonarch(uint ppc_reg_base, uint in0_size)
42{
43 u16 temps;
44 u32 temp;
45
46 if (in0_size > HARRIER_ITSZ_2GB) {
47 printk
48 ("harrier_setup_nonmonarch: Invalid window size code %d\n",
49 in0_size);
50 return;
51 }
52
53 /* Clear the PCI memory enable bit. If we don't, then when the
54 * inbound windows are enabled below, the corresponding BARs will be
55 * "live" and start answering to PCI memory reads from their default
56 * addresses (0x0), which overlap with system RAM.
57 */
58 temps = in_le16((u16 *) (ppc_reg_base +
59 HARRIER_XCSR_CONFIG(PCI_COMMAND)));
60 temps &= ~(PCI_COMMAND_MEMORY);
61 out_le16((u16 *) (ppc_reg_base + HARRIER_XCSR_CONFIG(PCI_COMMAND)),
62 temps);
63
64 /* Setup a non-prefetchable inbound window */
65 out_le32((u32 *) (ppc_reg_base +
66 HARRIER_XCSR_CONFIG(HARRIER_ITSZ0_OFF)), in0_size);
67
68 temp = in_le32((u32 *) (ppc_reg_base +
69 HARRIER_XCSR_CONFIG(HARRIER_ITAT0_OFF)));
70 temp &= ~HARRIER_ITAT_PRE;
71 temp |= HARRIER_ITAT_DEFAULT;
72 out_le32((u32 *) (ppc_reg_base +
73 HARRIER_XCSR_CONFIG(HARRIER_ITAT0_OFF)), temp);
74
75 /* Enable the message passing block */
76 temp = in_le32((u32 *) (ppc_reg_base +
77 HARRIER_XCSR_CONFIG(HARRIER_MPAT_OFF)));
78 temp |= HARRIER_MPAT_DEFAULT;
79 out_le32((u32 *) (ppc_reg_base +
80 HARRIER_XCSR_CONFIG(HARRIER_MPAT_OFF)), temp);
81}
82
83void __init harrier_release_eready(uint ppc_reg_base)
84{
85 ulong temp;
86
87 /*
88 * Set EREADY to allow the line to be pulled up after everyone is
89 * ready.
90 */
91 temp = in_be32((uint *) (ppc_reg_base + HARRIER_MISC_CSR_OFF));
92 temp |= HARRIER_EREADY;
93 out_be32((uint *) (ppc_reg_base + HARRIER_MISC_CSR_OFF), temp);
94}
95
96void __init harrier_wait_eready(uint ppc_reg_base)
97{
98 ulong temp;
99
100 /*
101 * Poll the ERDYS line until it goes high to indicate that all
102 * non-monarch PrPMCs are ready for bus enumeration (or that there are
103 * no PrPMCs present).
104 */
105
106 /* FIXME: Add a timeout of some kind to prevent endless waits. */
107 do {
108
109 temp = in_be32((uint *) (ppc_reg_base + HARRIER_MISC_CSR_OFF));
110
111 } while (!(temp & HARRIER_ERDYS));
112}
113
114/*
115 * Initialize the Motorola MCG Harrier host bridge.
116 *
117 * This means setting up the PPC bus to PCI memory and I/O space mappings,
118 * setting the PCI memory space address of the MPIC (mapped straight
119 * through), and ioremap'ing the mpic registers.
120 * 'OpenPIC_Addr' will be set correctly by this routine.
121 * This routine will not change the PCI_CONFIG_ADDR or PCI_CONFIG_DATA
122 * addresses and assumes that the mapping of PCI memory space back to system
123 * memory is set up correctly by PPCBug.
124 */
125int __init
126harrier_init(struct pci_controller *hose,
127 uint ppc_reg_base,
128 ulong processor_pci_mem_start,
129 ulong processor_pci_mem_end,
130 ulong processor_pci_io_start,
131 ulong processor_pci_io_end, ulong processor_mpic_base)
132{
133 uint addr, offset;
134
135 /*
136 * Some sanity checks...
137 */
138 if (((processor_pci_mem_start & 0xffff0000) != processor_pci_mem_start)
139 || ((processor_pci_io_start & 0xffff0000) !=
140 processor_pci_io_start)) {
141 printk("harrier_init: %s\n",
142 "PPC to PCI mappings must start on 64 KB boundaries");
143 return -1;
144 }
145
146 if (((processor_pci_mem_end & 0x0000ffff) != 0x0000ffff) ||
147 ((processor_pci_io_end & 0x0000ffff) != 0x0000ffff)) {
148 printk("harrier_init: PPC to PCI mappings %s\n",
149 "must end just before a 64 KB boundaries");
150 return -1;
151 }
152
153 if (((processor_pci_mem_end - processor_pci_mem_start) !=
154 (hose->mem_space.end - hose->mem_space.start)) ||
155 ((processor_pci_io_end - processor_pci_io_start) !=
156 (hose->io_space.end - hose->io_space.start))) {
157 printk("harrier_init: %s\n",
158 "PPC and PCI memory or I/O space sizes don't match");
159 return -1;
160 }
161
162 if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) {
163 printk("harrier_init: %s\n",
164 "MPIC address must start on 256 KB boundary");
165 return -1;
166 }
167
168 if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) {
169 printk("harrier_init: %s\n",
170 "pci_dram_offset must be multiple of 64 KB");
171 return -1;
172 }
173
174 /*
175 * Program the OTAD/OTOF registers to set up the PCI Mem & I/O
176 * space mappings. These are the mappings going from the processor to
177 * the PCI bus.
178 *
179 * Note: Don't need to 'AND' start/end addresses with 0xffff0000
180 * because sanity check above ensures that they are properly
181 * aligned.
182 */
183
184 /* Set up PPC->PCI Mem mapping */
185 addr = processor_pci_mem_start | (processor_pci_mem_end >> 16);
186#ifdef CONFIG_HARRIER_STORE_GATHERING
187 offset = (hose->mem_space.start - processor_pci_mem_start) | 0x9a;
188#else
189 offset = (hose->mem_space.start - processor_pci_mem_start) | 0x92;
190#endif
191 out_be32((uint *) (ppc_reg_base + HARRIER_OTAD0_OFF), addr);
192 out_be32((uint *) (ppc_reg_base + HARRIER_OTOF0_OFF), offset);
193
194 /* Set up PPC->PCI I/O mapping -- Contiguous I/O space */
195 addr = processor_pci_io_start | (processor_pci_io_end >> 16);
196 offset = (hose->io_space.start - processor_pci_io_start) | 0x80;
197 out_be32((uint *) (ppc_reg_base + HARRIER_OTAD1_OFF), addr);
198 out_be32((uint *) (ppc_reg_base + HARRIER_OTOF1_OFF), offset);
199
200 /* Enable MPIC */
201 OpenPIC_Addr = (void *)processor_mpic_base;
202 addr = (processor_mpic_base >> 16) | 1;
203 out_be16((ushort *) (ppc_reg_base + HARRIER_MBAR_OFF), addr);
204 out_8((u_char *) (ppc_reg_base + HARRIER_MPIC_CSR_OFF),
205 HARRIER_MPIC_OPI_ENABLE);
206
207 return 0;
208}
209
210/*
211 * Find the amount of RAM present.
212 * This assumes that PPCBug has initialized the memory controller (SMC)
213 * on the Harrier correctly (i.e., it does no sanity checking).
214 * It also assumes that the memory base registers are set to configure the
215 * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc.
216 * however, RAM base registers can be skipped (e.g. A, B, C are set,
217 * D is skipped but E is set is okay).
218 */
219#define MB (1024*1024UL)
220
221static uint harrier_size_table[] __initdata = {
222 0 * MB, /* 0 ==> 0 MB */
223 32 * MB, /* 1 ==> 32 MB */
224 64 * MB, /* 2 ==> 64 MB */
225 64 * MB, /* 3 ==> 64 MB */
226 128 * MB, /* 4 ==> 128 MB */
227 128 * MB, /* 5 ==> 128 MB */
228 128 * MB, /* 6 ==> 128 MB */
229 256 * MB, /* 7 ==> 256 MB */
230 256 * MB, /* 8 ==> 256 MB */
231 256 * MB, /* 9 ==> 256 MB */
232 512 * MB, /* a ==> 512 MB */
233 512 * MB, /* b ==> 512 MB */
234 512 * MB, /* c ==> 512 MB */
235 1024 * MB, /* d ==> 1024 MB */
236 1024 * MB, /* e ==> 1024 MB */
237 2048 * MB, /* f ==> 2048 MB */
238};
239
240/*
241 * *** WARNING: You MUST have a BAT set up to map in the XCSR regs ***
242 *
243 * Read the memory controller's registers to determine the amount of system
244 * memory. Assumes that the memory controller registers are already mapped
245 * into virtual memory--too early to use ioremap().
246 */
247unsigned long __init harrier_get_mem_size(uint xcsr_base)
248{
249 ulong last_addr;
250 int i;
251 uint vend_dev_id;
252 uint *size_table;
253 uint val;
254 uint *csrp;
255 uint size;
256 int size_table_entries;
257
258 vend_dev_id = in_be32((uint *) xcsr_base + PCI_VENDOR_ID);
259
260 if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) {
261 printk("harrier_get_mem_size: %s (0x%x)\n",
262 "Not a Motorola Memory Controller", vend_dev_id);
263 return 0;
264 }
265
266 vend_dev_id &= 0x0000ffff;
267
268 if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HARRIER) {
269 size_table = harrier_size_table;
270 size_table_entries = sizeof(harrier_size_table) /
271 sizeof(harrier_size_table[0]);
272 } else {
273 printk("harrier_get_mem_size: %s (0x%x)\n",
274 "Not a Harrier", vend_dev_id);
275 return 0;
276 }
277
278 last_addr = 0;
279
280 csrp = (uint *) (xcsr_base + HARRIER_SDBA_OFF);
281 for (i = 0; i < 8; i++) {
282 val = in_be32(csrp++);
283
284 if (val & 0x100) { /* If enabled */
285 size = val >> HARRIER_SDB_SIZE_SHIFT;
286 size &= HARRIER_SDB_SIZE_MASK;
287 if (size >= size_table_entries) {
288 break; /* Register not set correctly */
289 }
290 size = size_table[size];
291
292 val &= ~(size - 1);
293 val += size;
294
295 if (val > last_addr) {
296 last_addr = val;
297 }
298 }
299 }
300
301 return last_addr;
302}
diff --git a/arch/ppc/syslib/hawk_common.c b/arch/ppc/syslib/hawk_common.c
new file mode 100644
index 000000000000..a9911dc3a82f
--- /dev/null
+++ b/arch/ppc/syslib/hawk_common.c
@@ -0,0 +1,319 @@
1/*
2 * arch/ppc/syslib/hawk_common.c
3 *
4 * Common Motorola PowerPlus Platform--really Falcon/Raven or HAWK.
5 *
6 * Author: Mark A. Greer
7 * mgreer@mvista.com
8 *
9 * 2001 (c) MontaVista, Software, Inc. This file is licensed under
10 * the terms of the GNU General Public License version 2. This program
11 * is licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 */
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/pci.h>
17
18#include <asm/byteorder.h>
19#include <asm/io.h>
20#include <asm/irq.h>
21#include <asm/pci.h>
22#include <asm/pci-bridge.h>
23#include <asm/open_pic.h>
24#include <asm/hawk.h>
25
26/*
27 * The Falcon/Raven and HAWK has 4 sets of registers:
28 * 1) PPC Registers which define the mappings from PPC bus to PCI bus,
29 * etc.
30 * 2) PCI Registers which define the mappings from PCI bus to PPC bus and the
31 * MPIC base address.
32 * 3) MPIC registers.
33 * 4) System Memory Controller (SMC) registers.
34 */
35
36/*
37 * Initialize the Motorola MCG Raven or HAWK host bridge.
38 *
39 * This means setting up the PPC bus to PCI memory and I/O space mappings,
40 * setting the PCI memory space address of the MPIC (mapped straight
41 * through), and ioremap'ing the mpic registers.
42 * This routine will set the PCI_CONFIG_ADDR or PCI_CONFIG_DATA
43 * addresses based on the PCI I/O address that is passed in.
44 * 'OpenPIC_Addr' will be set correctly by this routine.
45 */
46int __init
47hawk_init(struct pci_controller *hose,
48 uint ppc_reg_base,
49 ulong processor_pci_mem_start,
50 ulong processor_pci_mem_end,
51 ulong processor_pci_io_start,
52 ulong processor_pci_io_end,
53 ulong processor_mpic_base)
54{
55 uint addr, offset;
56
57 /*
58 * Some sanity checks...
59 */
60 if (((processor_pci_mem_start&0xffff0000) != processor_pci_mem_start) ||
61 ((processor_pci_io_start &0xffff0000) != processor_pci_io_start)) {
62 printk("hawk_init: %s\n",
63 "PPC to PCI mappings must start on 64 KB boundaries");
64 return -1;
65 }
66
67 if (((processor_pci_mem_end &0x0000ffff) != 0x0000ffff) ||
68 ((processor_pci_io_end &0x0000ffff) != 0x0000ffff)) {
69 printk("hawk_init: PPC to PCI mappings %s\n",
70 "must end just before a 64 KB boundaries");
71 return -1;
72 }
73
74 if (((processor_pci_mem_end - processor_pci_mem_start) !=
75 (hose->mem_space.end - hose->mem_space.start)) ||
76 ((processor_pci_io_end - processor_pci_io_start) !=
77 (hose->io_space.end - hose->io_space.start))) {
78 printk("hawk_init: %s\n",
79 "PPC and PCI memory or I/O space sizes don't match");
80 return -1;
81 }
82
83 if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) {
84 printk("hawk_init: %s\n",
85 "MPIC address must start on 256 MB boundary");
86 return -1;
87 }
88
89 if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) {
90 printk("hawk_init: %s\n",
91 "pci_dram_offset must be multiple of 64 KB");
92 return -1;
93 }
94
95 /*
96 * Disable previous PPC->PCI mappings.
97 */
98 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF0_OFF), 0x00000000);
99 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF1_OFF), 0x00000000);
100 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF2_OFF), 0x00000000);
101 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF3_OFF), 0x00000000);
102
103 /*
104 * Program the XSADD/XSOFF registers to set up the PCI Mem & I/O
105 * space mappings. These are the mappings going from the processor to
106 * the PCI bus.
107 *
108 * Note: Don't need to 'AND' start/end addresses with 0xffff0000
109 * because sanity check above ensures that they are properly
110 * aligned.
111 */
112
113 /* Set up PPC->PCI Mem mapping */
114 addr = processor_pci_mem_start | (processor_pci_mem_end >> 16);
115 offset = (hose->mem_space.start - processor_pci_mem_start) | 0xd2;
116 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSADD0_OFF), addr);
117 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF0_OFF), offset);
118
119 /* Set up PPC->MPIC mapping on the bridge */
120 addr = processor_mpic_base |
121 (((processor_mpic_base + HAWK_MPIC_SIZE) >> 16) - 1);
122 /* No write posting for this PCI Mem space */
123 offset = (hose->mem_space.start - processor_pci_mem_start) | 0xc2;
124
125 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSADD1_OFF), addr);
126 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF1_OFF), offset);
127
128 /* Set up PPC->PCI I/O mapping -- Contiguous I/O space */
129 addr = processor_pci_io_start | (processor_pci_io_end >> 16);
130 offset = (hose->io_space.start - processor_pci_io_start) | 0xc0;
131 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSADD3_OFF), addr);
132 out_be32((uint *)(ppc_reg_base + HAWK_PPC_XSOFF3_OFF), offset);
133
134 hose->io_base_virt = (void *)ioremap(processor_pci_io_start,
135 (processor_pci_io_end - processor_pci_io_start + 1));
136
137 /*
138 * Set up the indirect method of accessing PCI config space.
139 * The PCI config addr/data pair based on start addr of PCI I/O space.
140 */
141 setup_indirect_pci(hose,
142 processor_pci_io_start + HAWK_PCI_CONFIG_ADDR_OFF,
143 processor_pci_io_start + HAWK_PCI_CONFIG_DATA_OFF);
144
145 /*
146 * Disable previous PCI->PPC mappings.
147 */
148
149 /* XXXX Put in mappings from PCI bus to processor bus XXXX */
150
151 /*
152 * Disable MPIC response to PCI I/O space (BAR 0).
153 * Make MPIC respond to PCI Mem space at specified address.
154 * (BAR 1).
155 */
156 early_write_config_dword(hose,
157 0,
158 PCI_DEVFN(0,0),
159 PCI_BASE_ADDRESS_0,
160 0x00000000 | 0x1);
161
162 early_write_config_dword(hose,
163 0,
164 PCI_DEVFN(0,0),
165 PCI_BASE_ADDRESS_1,
166 (processor_mpic_base -
167 processor_pci_mem_start +
168 hose->mem_space.start) | 0x0);
169
170 /* Map MPIC into vitual memory */
171 OpenPIC_Addr = ioremap(processor_mpic_base, HAWK_MPIC_SIZE);
172
173 return 0;
174}
175
176/*
177 * Find the amount of RAM present.
178 * This assumes that PPCBug has initialized the memory controller (SMC)
179 * on the Falcon/HAWK correctly (i.e., it does no sanity checking).
180 * It also assumes that the memory base registers are set to configure the
181 * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc.
182 * however, RAM base registers can be skipped (e.g. A, B, C are set,
183 * D is skipped but E is set is okay).
184 */
185#define MB (1024*1024)
186
187static uint reg_offset_table[] __initdata = {
188 HAWK_SMC_RAM_A_SIZE_REG_OFF,
189 HAWK_SMC_RAM_B_SIZE_REG_OFF,
190 HAWK_SMC_RAM_C_SIZE_REG_OFF,
191 HAWK_SMC_RAM_D_SIZE_REG_OFF,
192 HAWK_SMC_RAM_E_SIZE_REG_OFF,
193 HAWK_SMC_RAM_F_SIZE_REG_OFF,
194 HAWK_SMC_RAM_G_SIZE_REG_OFF,
195 HAWK_SMC_RAM_H_SIZE_REG_OFF
196};
197
198static uint falcon_size_table[] __initdata = {
199 0 * MB, /* 0 ==> 0 MB */
200 16 * MB, /* 1 ==> 16 MB */
201 32 * MB, /* 2 ==> 32 MB */
202 64 * MB, /* 3 ==> 64 MB */
203 128 * MB, /* 4 ==> 128 MB */
204 256 * MB, /* 5 ==> 256 MB */
205 1024 * MB, /* 6 ==> 1024 MB (1 GB) */
206};
207
208static uint hawk_size_table[] __initdata = {
209 0 * MB, /* 0 ==> 0 MB */
210 32 * MB, /* 1 ==> 32 MB */
211 64 * MB, /* 2 ==> 64 MB */
212 64 * MB, /* 3 ==> 64 MB */
213 128 * MB, /* 4 ==> 128 MB */
214 128 * MB, /* 5 ==> 128 MB */
215 128 * MB, /* 6 ==> 128 MB */
216 256 * MB, /* 7 ==> 256 MB */
217 256 * MB, /* 8 ==> 256 MB */
218 512 * MB, /* 9 ==> 512 MB */
219};
220
221/*
222 * *** WARNING: You MUST have a BAT set up to map in the SMC regs ***
223 *
224 * Read the memory controller's registers to determine the amount of system
225 * memory. Assumes that the memory controller registers are already mapped
226 * into virtual memory--too early to use ioremap().
227 */
228unsigned long __init
229hawk_get_mem_size(uint smc_base)
230{
231 unsigned long total;
232 int i, size_table_entries, reg_limit;
233 uint vend_dev_id;
234 uint *size_table;
235 u_char val;
236
237
238 vend_dev_id = in_be32((uint *)smc_base + PCI_VENDOR_ID);
239
240 if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) {
241 printk("hawk_get_mem_size: %s (0x%x)\n",
242 "Not a Motorola Memory Controller", vend_dev_id);
243 return 0;
244 }
245
246 vend_dev_id &= 0x0000ffff;
247
248 if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_FALCON) {
249 size_table = falcon_size_table;
250 size_table_entries = sizeof(falcon_size_table) /
251 sizeof(falcon_size_table[0]);
252
253 reg_limit = FALCON_SMC_REG_COUNT;
254 }
255 else if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HAWK) {
256 size_table = hawk_size_table;
257 size_table_entries = sizeof(hawk_size_table) /
258 sizeof(hawk_size_table[0]);
259 reg_limit = HAWK_SMC_REG_COUNT;
260 }
261 else {
262 printk("hawk_get_mem_size: %s (0x%x)\n",
263 "Not a Falcon or HAWK", vend_dev_id);
264 return 0;
265 }
266
267 total = 0;
268
269 /* Check every reg because PPCBug may skip some */
270 for (i=0; i<reg_limit; i++) {
271 val = in_8((u_char *)(smc_base + reg_offset_table[i]));
272
273 if (val & 0x80) { /* If enabled */
274 val &= 0x0f;
275
276 /* Don't go past end of size_table */
277 if (val < size_table_entries) {
278 total += size_table[val];
279 }
280 else { /* Register not set correctly */
281 break;
282 }
283 }
284 }
285
286 return total;
287}
288
289int __init
290hawk_mpic_init(unsigned int pci_mem_offset)
291{
292 unsigned short devid;
293 unsigned int pci_membase;
294
295 /* Check the first PCI device to see if it is a Raven or Hawk. */
296 early_read_config_word(0, 0, 0, PCI_DEVICE_ID, &devid);
297
298 switch (devid) {
299 case PCI_DEVICE_ID_MOTOROLA_RAVEN:
300 case PCI_DEVICE_ID_MOTOROLA_HAWK:
301 break;
302 default:
303 OpenPIC_Addr = NULL;
304 return 1;
305 }
306
307 /* Read the memory base register. */
308 early_read_config_dword(0, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
309
310 if (pci_membase == 0) {
311 OpenPIC_Addr = NULL;
312 return 1;
313 }
314
315 /* Map the MPIC registers to virtual memory. */
316 OpenPIC_Addr = ioremap(pci_membase + pci_mem_offset, 0x22000);
317
318 return 0;
319}
diff --git a/arch/ppc/syslib/i8259.c b/arch/ppc/syslib/i8259.c
new file mode 100644
index 000000000000..b9391e650141
--- /dev/null
+++ b/arch/ppc/syslib/i8259.c
@@ -0,0 +1,211 @@
1#include <linux/init.h>
2#include <linux/ioport.h>
3#include <linux/interrupt.h>
4#include <asm/io.h>
5#include <asm/i8259.h>
6
7static volatile unsigned char *pci_intack; /* RO, gives us the irq vector */
8
9unsigned char cached_8259[2] = { 0xff, 0xff };
10#define cached_A1 (cached_8259[0])
11#define cached_21 (cached_8259[1])
12
13static DEFINE_SPINLOCK(i8259_lock);
14
15int i8259_pic_irq_offset;
16
17/*
18 * Acknowledge the IRQ using either the PCI host bridge's interrupt
19 * acknowledge feature or poll. How i8259_init() is called determines
20 * which is called. It should be noted that polling is broken on some
21 * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
22 */
23int
24i8259_irq(struct pt_regs *regs)
25{
26 int irq;
27
28 spin_lock(&i8259_lock);
29
30 /* Either int-ack or poll for the IRQ */
31 if (pci_intack)
32 irq = *pci_intack;
33 else {
34 /* Perform an interrupt acknowledge cycle on controller 1. */
35 outb(0x0C, 0x20); /* prepare for poll */
36 irq = inb(0x20) & 7;
37 if (irq == 2 ) {
38 /*
39 * Interrupt is cascaded so perform interrupt
40 * acknowledge on controller 2.
41 */
42 outb(0x0C, 0xA0); /* prepare for poll */
43 irq = (inb(0xA0) & 7) + 8;
44 }
45 }
46
47 if (irq == 7) {
48 /*
49 * This may be a spurious interrupt.
50 *
51 * Read the interrupt status register (ISR). If the most
52 * significant bit is not set then there is no valid
53 * interrupt.
54 */
55 if (!pci_intack)
56 outb(0x0B, 0x20); /* ISR register */
57 if(~inb(0x20) & 0x80)
58 irq = -1;
59 }
60
61 spin_unlock(&i8259_lock);
62 return irq;
63}
64
65static void i8259_mask_and_ack_irq(unsigned int irq_nr)
66{
67 unsigned long flags;
68
69 spin_lock_irqsave(&i8259_lock, flags);
70 if ( irq_nr >= i8259_pic_irq_offset )
71 irq_nr -= i8259_pic_irq_offset;
72
73 if (irq_nr > 7) {
74 cached_A1 |= 1 << (irq_nr-8);
75 inb(0xA1); /* DUMMY */
76 outb(cached_A1,0xA1);
77 outb(0x20,0xA0); /* Non-specific EOI */
78 outb(0x20,0x20); /* Non-specific EOI to cascade */
79 } else {
80 cached_21 |= 1 << irq_nr;
81 inb(0x21); /* DUMMY */
82 outb(cached_21,0x21);
83 outb(0x20,0x20); /* Non-specific EOI */
84 }
85 spin_unlock_irqrestore(&i8259_lock, flags);
86}
87
88static void i8259_set_irq_mask(int irq_nr)
89{
90 outb(cached_A1,0xA1);
91 outb(cached_21,0x21);
92}
93
94static void i8259_mask_irq(unsigned int irq_nr)
95{
96 unsigned long flags;
97
98 spin_lock_irqsave(&i8259_lock, flags);
99 if ( irq_nr >= i8259_pic_irq_offset )
100 irq_nr -= i8259_pic_irq_offset;
101 if ( irq_nr < 8 )
102 cached_21 |= 1 << irq_nr;
103 else
104 cached_A1 |= 1 << (irq_nr-8);
105 i8259_set_irq_mask(irq_nr);
106 spin_unlock_irqrestore(&i8259_lock, flags);
107}
108
109static void i8259_unmask_irq(unsigned int irq_nr)
110{
111 unsigned long flags;
112
113 spin_lock_irqsave(&i8259_lock, flags);
114 if ( irq_nr >= i8259_pic_irq_offset )
115 irq_nr -= i8259_pic_irq_offset;
116 if ( irq_nr < 8 )
117 cached_21 &= ~(1 << irq_nr);
118 else
119 cached_A1 &= ~(1 << (irq_nr-8));
120 i8259_set_irq_mask(irq_nr);
121 spin_unlock_irqrestore(&i8259_lock, flags);
122}
123
124static void i8259_end_irq(unsigned int irq)
125{
126 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))
127 && irq_desc[irq].action)
128 i8259_unmask_irq(irq);
129}
130
131struct hw_interrupt_type i8259_pic = {
132 " i8259 ",
133 NULL,
134 NULL,
135 i8259_unmask_irq,
136 i8259_mask_irq,
137 i8259_mask_and_ack_irq,
138 i8259_end_irq,
139 NULL
140};
141
142static struct resource pic1_iores = {
143 .name = "8259 (master)",
144 .start = 0x20,
145 .end = 0x21,
146 .flags = IORESOURCE_BUSY,
147};
148
149static struct resource pic2_iores = {
150 .name = "8259 (slave)",
151 .start = 0xa0,
152 .end = 0xa1,
153 .flags = IORESOURCE_BUSY,
154};
155
156static struct resource pic_edgectrl_iores = {
157 .name = "8259 edge control",
158 .start = 0x4d0,
159 .end = 0x4d1,
160 .flags = IORESOURCE_BUSY,
161};
162
163static struct irqaction i8259_irqaction = {
164 .handler = no_action,
165 .flags = SA_INTERRUPT,
166 .mask = CPU_MASK_NONE,
167 .name = "82c59 secondary cascade",
168};
169
170/*
171 * i8259_init()
172 * intack_addr - PCI interrupt acknowledge (real) address which will return
173 * the active irq from the 8259
174 */
175void __init
176i8259_init(long intack_addr)
177{
178 unsigned long flags;
179
180 spin_lock_irqsave(&i8259_lock, flags);
181 /* init master interrupt controller */
182 outb(0x11, 0x20); /* Start init sequence */
183 outb(0x00, 0x21); /* Vector base */
184 outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
185 outb(0x01, 0x21); /* Select 8086 mode */
186
187 /* init slave interrupt controller */
188 outb(0x11, 0xA0); /* Start init sequence */
189 outb(0x08, 0xA1); /* Vector base */
190 outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
191 outb(0x01, 0xA1); /* Select 8086 mode */
192
193 /* always read ISR */
194 outb(0x0B, 0x20);
195 outb(0x0B, 0xA0);
196
197 /* Mask all interrupts */
198 outb(cached_A1, 0xA1);
199 outb(cached_21, 0x21);
200
201 spin_unlock_irqrestore(&i8259_lock, flags);
202
203 /* reserve our resources */
204 setup_irq( i8259_pic_irq_offset + 2, &i8259_irqaction);
205 request_resource(&ioport_resource, &pic1_iores);
206 request_resource(&ioport_resource, &pic2_iores);
207 request_resource(&ioport_resource, &pic_edgectrl_iores);
208
209 if (intack_addr != 0)
210 pci_intack = ioremap(intack_addr, 1);
211}
diff --git a/arch/ppc/syslib/ibm440gp_common.c b/arch/ppc/syslib/ibm440gp_common.c
new file mode 100644
index 000000000000..0d6be2d6dd67
--- /dev/null
+++ b/arch/ppc/syslib/ibm440gp_common.c
@@ -0,0 +1,76 @@
1/*
2 * arch/ppc/syslib/ibm440gp_common.c
3 *
4 * PPC440GP system library
5 *
6 * Matt Porter <mporter@mvista.com>
7 * Copyright 2002-2003 MontaVista Software Inc.
8 *
9 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
10 * Copyright (c) 2003 Zultys Technologies
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 */
18#include <linux/config.h>
19#include <linux/types.h>
20#include <asm/reg.h>
21#include <asm/ibm44x.h>
22#include <asm/mmu.h>
23
24/*
25 * Calculate 440GP clocks
26 */
27void __init ibm440gp_get_clocks(struct ibm44x_clocks* p,
28 unsigned int sys_clk,
29 unsigned int ser_clk)
30{
31 u32 cpc0_sys0 = mfdcr(DCRN_CPC0_SYS0);
32 u32 cpc0_cr0 = mfdcr(DCRN_CPC0_CR0);
33 u32 opdv = ((cpc0_sys0 >> 10) & 0x3) + 1;
34 u32 epdv = ((cpc0_sys0 >> 8) & 0x3) + 1;
35
36 if (cpc0_sys0 & 0x2){
37 /* Bypass system PLL */
38 p->cpu = p->plb = sys_clk;
39 }
40 else {
41 u32 fbdv, fwdva, fwdvb, m, vco;
42
43 fbdv = (cpc0_sys0 >> 18) & 0x0f;
44 if (!fbdv)
45 fbdv = 16;
46
47 fwdva = 8 - ((cpc0_sys0 >> 15) & 0x7);
48 fwdvb = 8 - ((cpc0_sys0 >> 12) & 0x7);
49
50 /* Feedback path */
51 if (cpc0_sys0 & 0x00000080){
52 /* PerClk */
53 m = fwdvb * opdv * epdv;
54 }
55 else {
56 /* CPU clock */
57 m = fbdv * fwdva;
58 }
59 vco = sys_clk * m;
60 p->cpu = vco / fwdva;
61 p->plb = vco / fwdvb;
62 }
63
64 p->opb = p->plb / opdv;
65 p->ebc = p->opb / epdv;
66
67 if (cpc0_cr0 & 0x00400000){
68 /* External UART clock */
69 p->uart0 = p->uart1 = ser_clk;
70 }
71 else {
72 /* Internal UART clock */
73 u32 uart_div = ((cpc0_cr0 >> 16) & 0x1f) + 1;
74 p->uart0 = p->uart1 = p->plb / uart_div;
75 }
76}
diff --git a/arch/ppc/syslib/ibm440gp_common.h b/arch/ppc/syslib/ibm440gp_common.h
new file mode 100644
index 000000000000..a054d83cb1ac
--- /dev/null
+++ b/arch/ppc/syslib/ibm440gp_common.h
@@ -0,0 +1,35 @@
1/*
2 * arch/ppc/kernel/ibm440gp_common.h
3 *
4 * PPC440GP system library
5 *
6 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
7 * Copyright (c) 2003 Zultys Technologies
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15#ifdef __KERNEL__
16#ifndef __PPC_SYSLIB_IBM440GP_COMMON_H
17#define __PPC_SYSLIB_IBM440GP_COMMON_H
18
19#ifndef __ASSEMBLY__
20
21#include <linux/config.h>
22#include <linux/init.h>
23#include <syslib/ibm44x_common.h>
24
25/*
26 * Please, refer to the Figure 13.1 in 440GP user manual
27 *
28 * if internal UART clock is used, ser_clk is ignored
29 */
30void ibm440gp_get_clocks(struct ibm44x_clocks*, unsigned int sys_clk,
31 unsigned int ser_clk) __init;
32
33#endif /* __ASSEMBLY__ */
34#endif /* __PPC_SYSLIB_IBM440GP_COMMON_H */
35#endif /* __KERNEL__ */
diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c
new file mode 100644
index 000000000000..4ad85e0e0234
--- /dev/null
+++ b/arch/ppc/syslib/ibm440gx_common.c
@@ -0,0 +1,270 @@
1/*
2 * arch/ppc/kernel/ibm440gx_common.c
3 *
4 * PPC440GX system library
5 *
6 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
7 * Copyright (c) 2003, 2004 Zultys Technologies
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15#include <linux/config.h>
16#include <linux/kernel.h>
17#include <linux/interrupt.h>
18#include <asm/ibm44x.h>
19#include <asm/mmu.h>
20#include <asm/processor.h>
21#include <syslib/ibm440gx_common.h>
22
23/*
24 * Calculate 440GX clocks
25 */
26static inline u32 __fix_zero(u32 v, u32 def){
27 return v ? v : def;
28}
29
30void __init ibm440gx_get_clocks(struct ibm44x_clocks* p, unsigned int sys_clk,
31 unsigned int ser_clk)
32{
33 u32 pllc = CPR_READ(DCRN_CPR_PLLC);
34 u32 plld = CPR_READ(DCRN_CPR_PLLD);
35 u32 uart0 = SDR_READ(DCRN_SDR_UART0);
36 u32 uart1 = SDR_READ(DCRN_SDR_UART1);
37
38 /* Dividers */
39 u32 fbdv = __fix_zero((plld >> 24) & 0x1f, 32);
40 u32 fwdva = __fix_zero((plld >> 16) & 0xf, 16);
41 u32 fwdvb = __fix_zero((plld >> 8) & 7, 8);
42 u32 lfbdv = __fix_zero(plld & 0x3f, 64);
43 u32 pradv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMAD) >> 24) & 7, 8);
44 u32 prbdv0 = __fix_zero((CPR_READ(DCRN_CPR_PRIMBD) >> 24) & 7, 8);
45 u32 opbdv0 = __fix_zero((CPR_READ(DCRN_CPR_OPBD) >> 24) & 3, 4);
46 u32 perdv0 = __fix_zero((CPR_READ(DCRN_CPR_PERD) >> 24) & 3, 4);
47
48 /* Input clocks for primary dividers */
49 u32 clk_a, clk_b;
50
51 if (pllc & 0x40000000){
52 u32 m;
53
54 /* Feedback path */
55 switch ((pllc >> 24) & 7){
56 case 0:
57 /* PLLOUTx */
58 m = ((pllc & 0x20000000) ? fwdvb : fwdva) * lfbdv;
59 break;
60 case 1:
61 /* CPU */
62 m = fwdva * pradv0;
63 break;
64 case 5:
65 /* PERClk */
66 m = fwdvb * prbdv0 * opbdv0 * perdv0;
67 break;
68 default:
69 printk(KERN_EMERG "invalid PLL feedback source\n");
70 goto bypass;
71 }
72 m *= fbdv;
73 p->vco = sys_clk * m;
74 clk_a = p->vco / fwdva;
75 clk_b = p->vco / fwdvb;
76 }
77 else {
78bypass:
79 /* Bypass system PLL */
80 p->vco = 0;
81 clk_a = clk_b = sys_clk;
82 }
83
84 p->cpu = clk_a / pradv0;
85 p->plb = clk_b / prbdv0;
86 p->opb = p->plb / opbdv0;
87 p->ebc = p->opb / perdv0;
88
89 /* UARTs clock */
90 if (uart0 & 0x00800000)
91 p->uart0 = ser_clk;
92 else
93 p->uart0 = p->plb / __fix_zero(uart0 & 0xff, 256);
94
95 if (uart1 & 0x00800000)
96 p->uart1 = ser_clk;
97 else
98 p->uart1 = p->plb / __fix_zero(uart1 & 0xff, 256);
99}
100
101/* Issue L2C diagnostic command */
102static inline u32 l2c_diag(u32 addr)
103{
104 mtdcr(DCRN_L2C0_ADDR, addr);
105 mtdcr(DCRN_L2C0_CMD, L2C_CMD_DIAG);
106 while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ;
107 return mfdcr(DCRN_L2C0_DATA);
108}
109
110static irqreturn_t l2c_error_handler(int irq, void* dev, struct pt_regs* regs)
111{
112 u32 sr = mfdcr(DCRN_L2C0_SR);
113 if (sr & L2C_SR_CPE){
114 /* Read cache trapped address */
115 u32 addr = l2c_diag(0x42000000);
116 printk(KERN_EMERG "L2C: Cache Parity Error, addr[16:26] = 0x%08x\n", addr);
117 }
118 if (sr & L2C_SR_TPE){
119 /* Read tag trapped address */
120 u32 addr = l2c_diag(0x82000000) >> 16;
121 printk(KERN_EMERG "L2C: Tag Parity Error, addr[16:26] = 0x%08x\n", addr);
122 }
123
124 /* Clear parity errors */
125 if (sr & (L2C_SR_CPE | L2C_SR_TPE)){
126 mtdcr(DCRN_L2C0_ADDR, 0);
127 mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
128 } else
129 printk(KERN_EMERG "L2C: LRU error\n");
130
131 return IRQ_HANDLED;
132}
133
134/* Enable L2 cache */
135void __init ibm440gx_l2c_enable(void){
136 u32 r;
137 unsigned long flags;
138
139 /* Install error handler */
140 if (request_irq(87, l2c_error_handler, SA_INTERRUPT, "L2C", 0) < 0){
141 printk(KERN_ERR "Cannot install L2C error handler, cache is not enabled\n");
142 return;
143 }
144
145 local_irq_save(flags);
146 asm volatile ("sync" ::: "memory");
147
148 /* Disable SRAM */
149 mtdcr(DCRN_SRAM0_DPC, mfdcr(DCRN_SRAM0_DPC) & ~SRAM_DPC_ENABLE);
150 mtdcr(DCRN_SRAM0_SB0CR, mfdcr(DCRN_SRAM0_SB0CR) & ~SRAM_SBCR_BU_MASK);
151 mtdcr(DCRN_SRAM0_SB1CR, mfdcr(DCRN_SRAM0_SB1CR) & ~SRAM_SBCR_BU_MASK);
152 mtdcr(DCRN_SRAM0_SB2CR, mfdcr(DCRN_SRAM0_SB2CR) & ~SRAM_SBCR_BU_MASK);
153 mtdcr(DCRN_SRAM0_SB3CR, mfdcr(DCRN_SRAM0_SB3CR) & ~SRAM_SBCR_BU_MASK);
154
155 /* Enable L2_MODE without ICU/DCU */
156 r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_SS_MASK);
157 r |= L2C_CFG_L2M | L2C_CFG_SS_256;
158 mtdcr(DCRN_L2C0_CFG, r);
159
160 mtdcr(DCRN_L2C0_ADDR, 0);
161
162 /* Hardware Clear Command */
163 mtdcr(DCRN_L2C0_CMD, L2C_CMD_HCC);
164 while (!(mfdcr(DCRN_L2C0_SR) & L2C_SR_CC)) ;
165
166 /* Clear Cache Parity and Tag Errors */
167 mtdcr(DCRN_L2C0_CMD, L2C_CMD_CCP | L2C_CMD_CTE);
168
169 /* Enable 64G snoop region starting at 0 */
170 r = mfdcr(DCRN_L2C0_SNP0) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
171 r |= L2C_SNP_SSR_32G | L2C_SNP_ESR;
172 mtdcr(DCRN_L2C0_SNP0, r);
173
174 r = mfdcr(DCRN_L2C0_SNP1) & ~(L2C_SNP_BA_MASK | L2C_SNP_SSR_MASK);
175 r |= 0x80000000 | L2C_SNP_SSR_32G | L2C_SNP_ESR;
176 mtdcr(DCRN_L2C0_SNP1, r);
177
178 asm volatile ("sync" ::: "memory");
179
180 /* Enable ICU/DCU ports */
181 r = mfdcr(DCRN_L2C0_CFG);
182 r &= ~(L2C_CFG_DCW_MASK | L2C_CFG_PMUX_MASK | L2C_CFG_PMIM | L2C_CFG_TPEI
183 | L2C_CFG_CPEI | L2C_CFG_NAM | L2C_CFG_NBRM);
184 r |= L2C_CFG_ICU | L2C_CFG_DCU | L2C_CFG_TPC | L2C_CFG_CPC | L2C_CFG_FRAN
185 | L2C_CFG_CPIM | L2C_CFG_TPIM | L2C_CFG_LIM | L2C_CFG_SMCM;
186 mtdcr(DCRN_L2C0_CFG, r);
187
188 asm volatile ("sync; isync" ::: "memory");
189 local_irq_restore(flags);
190}
191
192/* Disable L2 cache */
193void __init ibm440gx_l2c_disable(void){
194 u32 r;
195 unsigned long flags;
196
197 local_irq_save(flags);
198 asm volatile ("sync" ::: "memory");
199
200 /* Disable L2C mode */
201 r = mfdcr(DCRN_L2C0_CFG) & ~(L2C_CFG_L2M | L2C_CFG_ICU | L2C_CFG_DCU);
202 mtdcr(DCRN_L2C0_CFG, r);
203
204 /* Enable SRAM */
205 mtdcr(DCRN_SRAM0_DPC, mfdcr(DCRN_SRAM0_DPC) | SRAM_DPC_ENABLE);
206 mtdcr(DCRN_SRAM0_SB0CR,
207 SRAM_SBCR_BAS0 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
208 mtdcr(DCRN_SRAM0_SB1CR,
209 SRAM_SBCR_BAS1 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
210 mtdcr(DCRN_SRAM0_SB2CR,
211 SRAM_SBCR_BAS2 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
212 mtdcr(DCRN_SRAM0_SB3CR,
213 SRAM_SBCR_BAS3 | SRAM_SBCR_BS_64KB | SRAM_SBCR_BU_RW);
214
215 asm volatile ("sync; isync" ::: "memory");
216 local_irq_restore(flags);
217}
218
219void __init ibm440gx_l2c_setup(struct ibm44x_clocks* p)
220{
221 /* Disable L2C on rev.A, rev.B and 800MHz version of rev.C,
222 enable it on all other revisions
223 */
224 u32 pvr = mfspr(SPRN_PVR);
225 if (pvr == PVR_440GX_RA || pvr == PVR_440GX_RB ||
226 (pvr == PVR_440GX_RC && p->cpu > 667000000))
227 ibm440gx_l2c_disable();
228 else
229 ibm440gx_l2c_enable();
230}
231
232int __init ibm440gx_get_eth_grp(void)
233{
234 return (SDR_READ(DCRN_SDR_PFC1) & DCRN_SDR_PFC1_EPS) >> DCRN_SDR_PFC1_EPS_SHIFT;
235}
236
237void __init ibm440gx_set_eth_grp(int group)
238{
239 SDR_WRITE(DCRN_SDR_PFC1, (SDR_READ(DCRN_SDR_PFC1) & ~DCRN_SDR_PFC1_EPS) | (group << DCRN_SDR_PFC1_EPS_SHIFT));
240}
241
242void __init ibm440gx_tah_enable(void)
243{
244 /* Enable TAH0 and TAH1 */
245 SDR_WRITE(DCRN_SDR_MFR,SDR_READ(DCRN_SDR_MFR) &
246 ~DCRN_SDR_MFR_TAH0);
247 SDR_WRITE(DCRN_SDR_MFR,SDR_READ(DCRN_SDR_MFR) &
248 ~DCRN_SDR_MFR_TAH1);
249}
250
251int ibm440gx_show_cpuinfo(struct seq_file *m){
252
253 u32 l2c_cfg = mfdcr(DCRN_L2C0_CFG);
254 const char* s;
255 if (l2c_cfg & L2C_CFG_L2M){
256 switch (l2c_cfg & (L2C_CFG_ICU | L2C_CFG_DCU)){
257 case L2C_CFG_ICU: s = "I-Cache only"; break;
258 case L2C_CFG_DCU: s = "D-Cache only"; break;
259 default: s = "I-Cache/D-Cache"; break;
260 }
261 }
262 else
263 s = "disabled";
264
265 seq_printf(m, "L2-Cache\t: %s (0x%08x 0x%08x)\n", s,
266 l2c_cfg, mfdcr(DCRN_L2C0_SR));
267
268 return 0;
269}
270
diff --git a/arch/ppc/syslib/ibm440gx_common.h b/arch/ppc/syslib/ibm440gx_common.h
new file mode 100644
index 000000000000..e73aa0411d35
--- /dev/null
+++ b/arch/ppc/syslib/ibm440gx_common.h
@@ -0,0 +1,57 @@
1/*
2 * arch/ppc/kernel/ibm440gx_common.h
3 *
4 * PPC440GX system library
5 *
6 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
7 * Copyright (c) 2003, 2004 Zultys Technologies
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15#ifdef __KERNEL__
16#ifndef __PPC_SYSLIB_IBM440GX_COMMON_H
17#define __PPC_SYSLIB_IBM440GX_COMMON_H
18
19#ifndef __ASSEMBLY__
20
21#include <linux/config.h>
22#include <linux/init.h>
23#include <linux/seq_file.h>
24#include <syslib/ibm44x_common.h>
25
26/*
27 * Please, refer to the Figure 14.1 in 440GX user manual
28 *
29 * if internal UART clock is used, ser_clk is ignored
30 */
31void ibm440gx_get_clocks(struct ibm44x_clocks*, unsigned int sys_clk,
32 unsigned int ser_clk) __init;
33
34/* Enable L2 cache */
35void ibm440gx_l2c_enable(void) __init;
36
37/* Disable L2 cache */
38void ibm440gx_l2c_disable(void) __init;
39
40/* Enable/disable L2 cache for a particular chip revision */
41void ibm440gx_l2c_setup(struct ibm44x_clocks*) __init;
42
43/* Get Ethernet Group */
44int ibm440gx_get_eth_grp(void) __init;
45
46/* Set Ethernet Group */
47void ibm440gx_set_eth_grp(int group) __init;
48
49/* Enable TAH devices */
50void ibm440gx_tah_enable(void) __init;
51
52/* Add L2C info to /proc/cpuinfo */
53int ibm440gx_show_cpuinfo(struct seq_file*);
54
55#endif /* __ASSEMBLY__ */
56#endif /* __PPC_SYSLIB_IBM440GX_COMMON_H */
57#endif /* __KERNEL__ */
diff --git a/arch/ppc/syslib/ibm440sp_common.c b/arch/ppc/syslib/ibm440sp_common.c
new file mode 100644
index 000000000000..417d4cff77a0
--- /dev/null
+++ b/arch/ppc/syslib/ibm440sp_common.c
@@ -0,0 +1,71 @@
1/*
2 * arch/ppc/syslib/ibm440sp_common.c
3 *
4 * PPC440SP system library
5 *
6 * Matt Porter <mporter@kernel.crashing.org>
7 * Copyright 2002-2005 MontaVista Software Inc.
8 *
9 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
10 * Copyright (c) 2003, 2004 Zultys Technologies
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 */
18#include <linux/config.h>
19#include <linux/types.h>
20#include <linux/serial.h>
21
22#include <asm/param.h>
23#include <asm/ibm44x.h>
24#include <asm/mmu.h>
25#include <asm/machdep.h>
26#include <asm/time.h>
27#include <asm/ppc4xx_pic.h>
28
29/*
30 * Read the 440SP memory controller to get size of system memory.
31 */
32unsigned long __init ibm440sp_find_end_of_memory(void)
33{
34 u32 i;
35 u32 mem_size = 0;
36
37 /* Read two bank sizes and sum */
38 for (i=0; i<2; i++)
39 switch (mfdcr(DCRN_MQ0_BS0BAS + i) & MQ0_CONFIG_SIZE_MASK) {
40 case MQ0_CONFIG_SIZE_8M:
41 mem_size += PPC44x_MEM_SIZE_8M;
42 break;
43 case MQ0_CONFIG_SIZE_16M:
44 mem_size += PPC44x_MEM_SIZE_16M;
45 break;
46 case MQ0_CONFIG_SIZE_32M:
47 mem_size += PPC44x_MEM_SIZE_32M;
48 break;
49 case MQ0_CONFIG_SIZE_64M:
50 mem_size += PPC44x_MEM_SIZE_64M;
51 break;
52 case MQ0_CONFIG_SIZE_128M:
53 mem_size += PPC44x_MEM_SIZE_128M;
54 break;
55 case MQ0_CONFIG_SIZE_256M:
56 mem_size += PPC44x_MEM_SIZE_256M;
57 break;
58 case MQ0_CONFIG_SIZE_512M:
59 mem_size += PPC44x_MEM_SIZE_512M;
60 break;
61 case MQ0_CONFIG_SIZE_1G:
62 mem_size += PPC44x_MEM_SIZE_1G;
63 break;
64 case MQ0_CONFIG_SIZE_2G:
65 mem_size += PPC44x_MEM_SIZE_2G;
66 break;
67 default:
68 break;
69 }
70 return mem_size;
71}
diff --git a/arch/ppc/syslib/ibm440sp_common.h b/arch/ppc/syslib/ibm440sp_common.h
new file mode 100644
index 000000000000..a21a9906dcc9
--- /dev/null
+++ b/arch/ppc/syslib/ibm440sp_common.h
@@ -0,0 +1,25 @@
1/*
2 * arch/ppc/syslib/ibm440sp_common.h
3 *
4 * PPC440SP system library
5 *
6 * Matt Porter <mporter@kernel.crashing.org>
7 * Copyright 2004-2005 MontaVista Software, Inc.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15#ifdef __KERNEL__
16#ifndef __PPC_SYSLIB_IBM440SP_COMMON_H
17#define __PPC_SYSLIB_IBM440SP_COMMON_H
18
19#ifndef __ASSEMBLY__
20
21extern unsigned long __init ibm440sp_find_end_of_memory(void);
22
23#endif /* __ASSEMBLY__ */
24#endif /* __PPC_SYSLIB_IBM440SP_COMMON_H */
25#endif /* __KERNEL__ */
diff --git a/arch/ppc/syslib/ibm44x_common.c b/arch/ppc/syslib/ibm44x_common.c
new file mode 100644
index 000000000000..7612e0623f99
--- /dev/null
+++ b/arch/ppc/syslib/ibm44x_common.c
@@ -0,0 +1,193 @@
1/*
2 * arch/ppc/syslib/ibm44x_common.c
3 *
4 * PPC44x system library
5 *
6 * Matt Porter <mporter@kernel.crashing.org>
7 * Copyright 2002-2005 MontaVista Software Inc.
8 *
9 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
10 * Copyright (c) 2003, 2004 Zultys Technologies
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 */
18#include <linux/config.h>
19#include <linux/time.h>
20#include <linux/types.h>
21#include <linux/serial.h>
22#include <linux/module.h>
23
24#include <asm/ibm44x.h>
25#include <asm/mmu.h>
26#include <asm/machdep.h>
27#include <asm/time.h>
28#include <asm/ppc4xx_pic.h>
29#include <asm/param.h>
30
31#include <syslib/gen550.h>
32
33phys_addr_t fixup_bigphys_addr(phys_addr_t addr, phys_addr_t size)
34{
35 phys_addr_t page_4gb = 0;
36
37 /*
38 * Trap the least significant 32-bit portions of an
39 * address in the 440's 36-bit address space. Fix
40 * them up with the appropriate ERPN
41 */
42 if ((addr >= PPC44x_IO_LO) && (addr <= PPC44x_IO_HI))
43 page_4gb = PPC44x_IO_PAGE;
44 else if ((addr >= PPC44x_PCI0CFG_LO) && (addr <= PPC44x_PCI0CFG_HI))
45 page_4gb = PPC44x_PCICFG_PAGE;
46#ifdef CONFIG_440SP
47 else if ((addr >= PPC44x_PCI1CFG_LO) && (addr <= PPC44x_PCI1CFG_HI))
48 page_4gb = PPC44x_PCICFG_PAGE;
49 else if ((addr >= PPC44x_PCI2CFG_LO) && (addr <= PPC44x_PCI2CFG_HI))
50 page_4gb = PPC44x_PCICFG_PAGE;
51#endif
52 else if ((addr >= PPC44x_PCIMEM_LO) && (addr <= PPC44x_PCIMEM_HI))
53 page_4gb = PPC44x_PCIMEM_PAGE;
54
55 return (page_4gb | addr);
56};
57EXPORT_SYMBOL(fixup_bigphys_addr);
58
59void __init ibm44x_calibrate_decr(unsigned int freq)
60{
61 tb_ticks_per_jiffy = freq / HZ;
62 tb_to_us = mulhwu_scale_factor(freq, 1000000);
63
64 /* Set the time base to zero */
65 mtspr(SPRN_TBWL, 0);
66 mtspr(SPRN_TBWU, 0);
67
68 /* Clear any pending timer interrupts */
69 mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
70
71 /* Enable decrementer interrupt */
72 mtspr(SPRN_TCR, TCR_DIE);
73}
74
75extern void abort(void);
76
77static void ibm44x_restart(char *cmd)
78{
79 local_irq_disable();
80 abort();
81}
82
83static void ibm44x_power_off(void)
84{
85 local_irq_disable();
86 for(;;);
87}
88
89static void ibm44x_halt(void)
90{
91 local_irq_disable();
92 for(;;);
93}
94
95/*
96 * Read the 44x memory controller to get size of system memory.
97 */
98static unsigned long __init ibm44x_find_end_of_memory(void)
99{
100 u32 i, bank_config;
101 u32 mem_size = 0;
102
103 for (i=0; i<4; i++)
104 {
105 switch (i)
106 {
107 case 0:
108 mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B0CR);
109 break;
110 case 1:
111 mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B1CR);
112 break;
113 case 2:
114 mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B2CR);
115 break;
116 case 3:
117 mtdcr(DCRN_SDRAM0_CFGADDR, SDRAM0_B3CR);
118 break;
119 }
120
121 bank_config = mfdcr(DCRN_SDRAM0_CFGDATA);
122
123 if (!(bank_config & SDRAM_CONFIG_BANK_ENABLE))
124 continue;
125 switch (SDRAM_CONFIG_BANK_SIZE(bank_config))
126 {
127 case SDRAM_CONFIG_SIZE_8M:
128 mem_size += PPC44x_MEM_SIZE_8M;
129 break;
130 case SDRAM_CONFIG_SIZE_16M:
131 mem_size += PPC44x_MEM_SIZE_16M;
132 break;
133 case SDRAM_CONFIG_SIZE_32M:
134 mem_size += PPC44x_MEM_SIZE_32M;
135 break;
136 case SDRAM_CONFIG_SIZE_64M:
137 mem_size += PPC44x_MEM_SIZE_64M;
138 break;
139 case SDRAM_CONFIG_SIZE_128M:
140 mem_size += PPC44x_MEM_SIZE_128M;
141 break;
142 case SDRAM_CONFIG_SIZE_256M:
143 mem_size += PPC44x_MEM_SIZE_256M;
144 break;
145 case SDRAM_CONFIG_SIZE_512M:
146 mem_size += PPC44x_MEM_SIZE_512M;
147 break;
148 }
149 }
150 return mem_size;
151}
152
153void __init ibm44x_platform_init(void)
154{
155 ppc_md.init_IRQ = ppc4xx_pic_init;
156 ppc_md.find_end_of_memory = ibm44x_find_end_of_memory;
157 ppc_md.restart = ibm44x_restart;
158 ppc_md.power_off = ibm44x_power_off;
159 ppc_md.halt = ibm44x_halt;
160
161#ifdef CONFIG_SERIAL_TEXT_DEBUG
162 ppc_md.progress = gen550_progress;
163#endif /* CONFIG_SERIAL_TEXT_DEBUG */
164#ifdef CONFIG_KGDB
165 ppc_md.kgdb_map_scc = gen550_kgdb_map_scc;
166#endif
167
168 /*
169 * The Abatron BDI JTAG debugger does not tolerate others
170 * mucking with the debug registers.
171 */
172#if !defined(CONFIG_BDI_SWITCH)
173 /* Enable internal debug mode */
174 mtspr(SPRN_DBCR0, (DBCR0_IDM));
175
176 /* Clear any residual debug events */
177 mtspr(SPRN_DBSR, 0xffffffff);
178#endif
179}
180
181/* Called from MachineCheckException */
182void platform_machine_check(struct pt_regs *regs)
183{
184 printk("PLB0: BEAR=0x%08x%08x ACR= 0x%08x BESR= 0x%08x\n",
185 mfdcr(DCRN_PLB0_BEARH), mfdcr(DCRN_PLB0_BEARL),
186 mfdcr(DCRN_PLB0_ACR), mfdcr(DCRN_PLB0_BESR));
187 printk("POB0: BEAR=0x%08x%08x BESR0=0x%08x BESR1=0x%08x\n",
188 mfdcr(DCRN_POB0_BEARH), mfdcr(DCRN_POB0_BEARL),
189 mfdcr(DCRN_POB0_BESR0), mfdcr(DCRN_POB0_BESR1));
190 printk("OPB0: BEAR=0x%08x%08x BSTAT=0x%08x\n",
191 mfdcr(DCRN_OPB0_BEARH), mfdcr(DCRN_OPB0_BEARL),
192 mfdcr(DCRN_OPB0_BSTAT));
193}
diff --git a/arch/ppc/syslib/ibm44x_common.h b/arch/ppc/syslib/ibm44x_common.h
new file mode 100644
index 000000000000..b14eb603ce01
--- /dev/null
+++ b/arch/ppc/syslib/ibm44x_common.h
@@ -0,0 +1,42 @@
1/*
2 * arch/ppc/kernel/ibm44x_common.h
3 *
4 * PPC44x system library
5 *
6 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
7 * Copyright (c) 2003, 2004 Zultys Technologies
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
13 *
14 */
15#ifdef __KERNEL__
16#ifndef __PPC_SYSLIB_IBM44x_COMMON_H
17#define __PPC_SYSLIB_IBM44x_COMMON_H
18
19#ifndef __ASSEMBLY__
20
21/*
22 * All clocks are in Hz
23 */
24struct ibm44x_clocks {
25 unsigned int vco; /* VCO, 0 if system PLL is bypassed */
26 unsigned int cpu; /* CPUCoreClk */
27 unsigned int plb; /* PLBClk */
28 unsigned int opb; /* OPBClk */
29 unsigned int ebc; /* PerClk */
30 unsigned int uart0;
31 unsigned int uart1;
32};
33
34/* common 44x platform init */
35void ibm44x_platform_init(void) __init;
36
37/* initialize decrementer and tick-related variables */
38void ibm44x_calibrate_decr(unsigned int freq) __init;
39
40#endif /* __ASSEMBLY__ */
41#endif /* __PPC_SYSLIB_IBM44x_COMMON_H */
42#endif /* __KERNEL__ */
diff --git a/arch/ppc/syslib/ibm_ocp.c b/arch/ppc/syslib/ibm_ocp.c
new file mode 100644
index 000000000000..3f6e55c79181
--- /dev/null
+++ b/arch/ppc/syslib/ibm_ocp.c
@@ -0,0 +1,9 @@
1#include <linux/module.h>
2#include <asm/ocp.h>
3
4struct ocp_sys_info_data ocp_sys_info = {
5 .opb_bus_freq = 50000000, /* OPB Bus Frequency (Hz) */
6 .ebc_bus_freq = 33333333, /* EBC Bus Frequency (Hz) */
7};
8
9EXPORT_SYMBOL(ocp_sys_info);
diff --git a/arch/ppc/syslib/indirect_pci.c b/arch/ppc/syslib/indirect_pci.c
new file mode 100644
index 000000000000..a5a752609e2c
--- /dev/null
+++ b/arch/ppc/syslib/indirect_pci.c
@@ -0,0 +1,135 @@
1/*
2 * Support for indirect PCI bridges.
3 *
4 * Copyright (C) 1998 Gabriel Paubert.
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/pci.h>
14#include <linux/delay.h>
15#include <linux/string.h>
16#include <linux/init.h>
17#include <linux/bootmem.h>
18
19#include <asm/io.h>
20#include <asm/prom.h>
21#include <asm/pci-bridge.h>
22#include <asm/machdep.h>
23
24#ifdef CONFIG_PPC_INDIRECT_PCI_BE
25#define PCI_CFG_OUT out_be32
26#else
27#define PCI_CFG_OUT out_le32
28#endif
29
30static int
31indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
32 int len, u32 *val)
33{
34 struct pci_controller *hose = bus->sysdata;
35 volatile void __iomem *cfg_data;
36 u8 cfg_type = 0;
37
38 if (ppc_md.pci_exclude_device)
39 if (ppc_md.pci_exclude_device(bus->number, devfn))
40 return PCIBIOS_DEVICE_NOT_FOUND;
41
42 if (hose->set_cfg_type)
43 if (bus->number != hose->first_busno)
44 cfg_type = 1;
45
46 PCI_CFG_OUT(hose->cfg_addr,
47 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
48 | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
49
50 /*
51 * Note: the caller has already checked that offset is
52 * suitably aligned and that len is 1, 2 or 4.
53 */
54 cfg_data = hose->cfg_data + (offset & 3);
55 switch (len) {
56 case 1:
57 *val = in_8(cfg_data);
58 break;
59 case 2:
60 *val = in_le16(cfg_data);
61 break;
62 default:
63 *val = in_le32(cfg_data);
64 break;
65 }
66 return PCIBIOS_SUCCESSFUL;
67}
68
69static int
70indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
71 int len, u32 val)
72{
73 struct pci_controller *hose = bus->sysdata;
74 volatile void __iomem *cfg_data;
75 u8 cfg_type = 0;
76
77 if (ppc_md.pci_exclude_device)
78 if (ppc_md.pci_exclude_device(bus->number, devfn))
79 return PCIBIOS_DEVICE_NOT_FOUND;
80
81 if (hose->set_cfg_type)
82 if (bus->number != hose->first_busno)
83 cfg_type = 1;
84
85 PCI_CFG_OUT(hose->cfg_addr,
86 (0x80000000 | ((bus->number - hose->bus_offset) << 16)
87 | (devfn << 8) | ((offset & 0xfc) | cfg_type)));
88
89 /*
90 * Note: the caller has already checked that offset is
91 * suitably aligned and that len is 1, 2 or 4.
92 */
93 cfg_data = hose->cfg_data + (offset & 3);
94 switch (len) {
95 case 1:
96 out_8(cfg_data, val);
97 break;
98 case 2:
99 out_le16(cfg_data, val);
100 break;
101 default:
102 out_le32(cfg_data, val);
103 break;
104 }
105 return PCIBIOS_SUCCESSFUL;
106}
107
108static struct pci_ops indirect_pci_ops =
109{
110 indirect_read_config,
111 indirect_write_config
112};
113
114void __init
115setup_indirect_pci_nomap(struct pci_controller* hose, void __iomem * cfg_addr,
116 void __iomem * cfg_data)
117{
118 hose->cfg_addr = cfg_addr;
119 hose->cfg_data = cfg_data;
120 hose->ops = &indirect_pci_ops;
121}
122
123void __init
124setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
125{
126 unsigned long base = cfg_addr & PAGE_MASK;
127 void __iomem *mbase, *addr, *data;
128
129 mbase = ioremap(base, PAGE_SIZE);
130 addr = mbase + (cfg_addr & ~PAGE_MASK);
131 if ((cfg_data & PAGE_MASK) != base)
132 mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
133 data = mbase + (cfg_data & ~PAGE_MASK);
134 setup_indirect_pci_nomap(hose, addr, data);
135}
diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
new file mode 100644
index 000000000000..acb2cde3171f
--- /dev/null
+++ b/arch/ppc/syslib/ipic.c
@@ -0,0 +1,646 @@
1/*
2 * include/asm-ppc/ipic.c
3 *
4 * IPIC routines implementations.
5 *
6 * Copyright 2005 Freescale Semiconductor, Inc.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13#include <linux/kernel.h>
14#include <linux/init.h>
15#include <linux/errno.h>
16#include <linux/reboot.h>
17#include <linux/slab.h>
18#include <linux/stddef.h>
19#include <linux/sched.h>
20#include <linux/signal.h>
21#include <linux/sysdev.h>
22#include <asm/irq.h>
23#include <asm/io.h>
24#include <asm/ipic.h>
25#include <asm/mpc83xx.h>
26
27#include "ipic.h"
28
29static struct ipic p_ipic;
30static struct ipic * primary_ipic;
31
32static struct ipic_info ipic_info[] = {
33 [9] = {
34 .pend = IPIC_SIPNR_H,
35 .mask = IPIC_SIMSR_H,
36 .prio = IPIC_SIPRR_D,
37 .force = IPIC_SIFCR_H,
38 .bit = 24,
39 .prio_mask = 0,
40 },
41 [10] = {
42 .pend = IPIC_SIPNR_H,
43 .mask = IPIC_SIMSR_H,
44 .prio = IPIC_SIPRR_D,
45 .force = IPIC_SIFCR_H,
46 .bit = 25,
47 .prio_mask = 1,
48 },
49 [11] = {
50 .pend = IPIC_SIPNR_H,
51 .mask = IPIC_SIMSR_H,
52 .prio = IPIC_SIPRR_D,
53 .force = IPIC_SIFCR_H,
54 .bit = 26,
55 .prio_mask = 2,
56 },
57 [14] = {
58 .pend = IPIC_SIPNR_H,
59 .mask = IPIC_SIMSR_H,
60 .prio = IPIC_SIPRR_D,
61 .force = IPIC_SIFCR_H,
62 .bit = 29,
63 .prio_mask = 5,
64 },
65 [15] = {
66 .pend = IPIC_SIPNR_H,
67 .mask = IPIC_SIMSR_H,
68 .prio = IPIC_SIPRR_D,
69 .force = IPIC_SIFCR_H,
70 .bit = 30,
71 .prio_mask = 6,
72 },
73 [16] = {
74 .pend = IPIC_SIPNR_H,
75 .mask = IPIC_SIMSR_H,
76 .prio = IPIC_SIPRR_D,
77 .force = IPIC_SIFCR_H,
78 .bit = 31,
79 .prio_mask = 7,
80 },
81 [17] = {
82 .pend = IPIC_SIPNR_H,
83 .mask = IPIC_SEMSR,
84 .prio = IPIC_SMPRR_A,
85 .force = IPIC_SEFCR,
86 .bit = 1,
87 .prio_mask = 5,
88 },
89 [18] = {
90 .pend = IPIC_SIPNR_H,
91 .mask = IPIC_SEMSR,
92 .prio = IPIC_SMPRR_A,
93 .force = IPIC_SEFCR,
94 .bit = 2,
95 .prio_mask = 6,
96 },
97 [19] = {
98 .pend = IPIC_SIPNR_H,
99 .mask = IPIC_SEMSR,
100 .prio = IPIC_SMPRR_A,
101 .force = IPIC_SEFCR,
102 .bit = 3,
103 .prio_mask = 7,
104 },
105 [20] = {
106 .pend = IPIC_SIPNR_H,
107 .mask = IPIC_SEMSR,
108 .prio = IPIC_SMPRR_B,
109 .force = IPIC_SEFCR,
110 .bit = 4,
111 .prio_mask = 4,
112 },
113 [21] = {
114 .pend = IPIC_SIPNR_H,
115 .mask = IPIC_SEMSR,
116 .prio = IPIC_SMPRR_B,
117 .force = IPIC_SEFCR,
118 .bit = 5,
119 .prio_mask = 5,
120 },
121 [22] = {
122 .pend = IPIC_SIPNR_H,
123 .mask = IPIC_SEMSR,
124 .prio = IPIC_SMPRR_B,
125 .force = IPIC_SEFCR,
126 .bit = 6,
127 .prio_mask = 6,
128 },
129 [23] = {
130 .pend = IPIC_SIPNR_H,
131 .mask = IPIC_SEMSR,
132 .prio = IPIC_SMPRR_B,
133 .force = IPIC_SEFCR,
134 .bit = 7,
135 .prio_mask = 7,
136 },
137 [32] = {
138 .pend = IPIC_SIPNR_H,
139 .mask = IPIC_SIMSR_H,
140 .prio = IPIC_SIPRR_A,
141 .force = IPIC_SIFCR_H,
142 .bit = 0,
143 .prio_mask = 0,
144 },
145 [33] = {
146 .pend = IPIC_SIPNR_H,
147 .mask = IPIC_SIMSR_H,
148 .prio = IPIC_SIPRR_A,
149 .force = IPIC_SIFCR_H,
150 .bit = 1,
151 .prio_mask = 1,
152 },
153 [34] = {
154 .pend = IPIC_SIPNR_H,
155 .mask = IPIC_SIMSR_H,
156 .prio = IPIC_SIPRR_A,
157 .force = IPIC_SIFCR_H,
158 .bit = 2,
159 .prio_mask = 2,
160 },
161 [35] = {
162 .pend = IPIC_SIPNR_H,
163 .mask = IPIC_SIMSR_H,
164 .prio = IPIC_SIPRR_A,
165 .force = IPIC_SIFCR_H,
166 .bit = 3,
167 .prio_mask = 3,
168 },
169 [36] = {
170 .pend = IPIC_SIPNR_H,
171 .mask = IPIC_SIMSR_H,
172 .prio = IPIC_SIPRR_A,
173 .force = IPIC_SIFCR_H,
174 .bit = 4,
175 .prio_mask = 4,
176 },
177 [37] = {
178 .pend = IPIC_SIPNR_H,
179 .mask = IPIC_SIMSR_H,
180 .prio = IPIC_SIPRR_A,
181 .force = IPIC_SIFCR_H,
182 .bit = 5,
183 .prio_mask = 5,
184 },
185 [38] = {
186 .pend = IPIC_SIPNR_H,
187 .mask = IPIC_SIMSR_H,
188 .prio = IPIC_SIPRR_A,
189 .force = IPIC_SIFCR_H,
190 .bit = 6,
191 .prio_mask = 6,
192 },
193 [39] = {
194 .pend = IPIC_SIPNR_H,
195 .mask = IPIC_SIMSR_H,
196 .prio = IPIC_SIPRR_A,
197 .force = IPIC_SIFCR_H,
198 .bit = 7,
199 .prio_mask = 7,
200 },
201 [48] = {
202 .pend = IPIC_SEPNR,
203 .mask = IPIC_SEMSR,
204 .prio = IPIC_SMPRR_A,
205 .force = IPIC_SEFCR,
206 .bit = 0,
207 .prio_mask = 4,
208 },
209 [64] = {
210 .pend = IPIC_SIPNR_H,
211 .mask = IPIC_SIMSR_L,
212 .prio = IPIC_SMPRR_A,
213 .force = IPIC_SIFCR_L,
214 .bit = 0,
215 .prio_mask = 0,
216 },
217 [65] = {
218 .pend = IPIC_SIPNR_H,
219 .mask = IPIC_SIMSR_L,
220 .prio = IPIC_SMPRR_A,
221 .force = IPIC_SIFCR_L,
222 .bit = 1,
223 .prio_mask = 1,
224 },
225 [66] = {
226 .pend = IPIC_SIPNR_H,
227 .mask = IPIC_SIMSR_L,
228 .prio = IPIC_SMPRR_A,
229 .force = IPIC_SIFCR_L,
230 .bit = 2,
231 .prio_mask = 2,
232 },
233 [67] = {
234 .pend = IPIC_SIPNR_H,
235 .mask = IPIC_SIMSR_L,
236 .prio = IPIC_SMPRR_A,
237 .force = IPIC_SIFCR_L,
238 .bit = 3,
239 .prio_mask = 3,
240 },
241 [68] = {
242 .pend = IPIC_SIPNR_H,
243 .mask = IPIC_SIMSR_L,
244 .prio = IPIC_SMPRR_B,
245 .force = IPIC_SIFCR_L,
246 .bit = 4,
247 .prio_mask = 0,
248 },
249 [69] = {
250 .pend = IPIC_SIPNR_H,
251 .mask = IPIC_SIMSR_L,
252 .prio = IPIC_SMPRR_B,
253 .force = IPIC_SIFCR_L,
254 .bit = 5,
255 .prio_mask = 1,
256 },
257 [70] = {
258 .pend = IPIC_SIPNR_H,
259 .mask = IPIC_SIMSR_L,
260 .prio = IPIC_SMPRR_B,
261 .force = IPIC_SIFCR_L,
262 .bit = 6,
263 .prio_mask = 2,
264 },
265 [71] = {
266 .pend = IPIC_SIPNR_H,
267 .mask = IPIC_SIMSR_L,
268 .prio = IPIC_SMPRR_B,
269 .force = IPIC_SIFCR_L,
270 .bit = 7,
271 .prio_mask = 3,
272 },
273 [72] = {
274 .pend = IPIC_SIPNR_H,
275 .mask = IPIC_SIMSR_L,
276 .prio = 0,
277 .force = IPIC_SIFCR_L,
278 .bit = 8,
279 },
280 [73] = {
281 .pend = IPIC_SIPNR_H,
282 .mask = IPIC_SIMSR_L,
283 .prio = 0,
284 .force = IPIC_SIFCR_L,
285 .bit = 9,
286 },
287 [74] = {
288 .pend = IPIC_SIPNR_H,
289 .mask = IPIC_SIMSR_L,
290 .prio = 0,
291 .force = IPIC_SIFCR_L,
292 .bit = 10,
293 },
294 [75] = {
295 .pend = IPIC_SIPNR_H,
296 .mask = IPIC_SIMSR_L,
297 .prio = 0,
298 .force = IPIC_SIFCR_L,
299 .bit = 11,
300 },
301 [76] = {
302 .pend = IPIC_SIPNR_H,
303 .mask = IPIC_SIMSR_L,
304 .prio = 0,
305 .force = IPIC_SIFCR_L,
306 .bit = 12,
307 },
308 [77] = {
309 .pend = IPIC_SIPNR_H,
310 .mask = IPIC_SIMSR_L,
311 .prio = 0,
312 .force = IPIC_SIFCR_L,
313 .bit = 13,
314 },
315 [78] = {
316 .pend = IPIC_SIPNR_H,
317 .mask = IPIC_SIMSR_L,
318 .prio = 0,
319 .force = IPIC_SIFCR_L,
320 .bit = 14,
321 },
322 [79] = {
323 .pend = IPIC_SIPNR_H,
324 .mask = IPIC_SIMSR_L,
325 .prio = 0,
326 .force = IPIC_SIFCR_L,
327 .bit = 15,
328 },
329 [80] = {
330 .pend = IPIC_SIPNR_H,
331 .mask = IPIC_SIMSR_L,
332 .prio = 0,
333 .force = IPIC_SIFCR_L,
334 .bit = 16,
335 },
336 [84] = {
337 .pend = IPIC_SIPNR_H,
338 .mask = IPIC_SIMSR_L,
339 .prio = 0,
340 .force = IPIC_SIFCR_L,
341 .bit = 20,
342 },
343 [85] = {
344 .pend = IPIC_SIPNR_H,
345 .mask = IPIC_SIMSR_L,
346 .prio = 0,
347 .force = IPIC_SIFCR_L,
348 .bit = 21,
349 },
350 [90] = {
351 .pend = IPIC_SIPNR_H,
352 .mask = IPIC_SIMSR_L,
353 .prio = 0,
354 .force = IPIC_SIFCR_L,
355 .bit = 26,
356 },
357 [91] = {
358 .pend = IPIC_SIPNR_H,
359 .mask = IPIC_SIMSR_L,
360 .prio = 0,
361 .force = IPIC_SIFCR_L,
362 .bit = 27,
363 },
364};
365
366static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg)
367{
368 return in_be32(base + (reg >> 2));
369}
370
371static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value)
372{
373 out_be32(base + (reg >> 2), value);
374}
375
376static inline struct ipic * ipic_from_irq(unsigned int irq)
377{
378 return primary_ipic;
379}
380
381static void ipic_enable_irq(unsigned int irq)
382{
383 struct ipic *ipic = ipic_from_irq(irq);
384 unsigned int src = irq - ipic->irq_offset;
385 u32 temp;
386
387 temp = ipic_read(ipic->regs, ipic_info[src].mask);
388 temp |= (1 << (31 - ipic_info[src].bit));
389 ipic_write(ipic->regs, ipic_info[src].mask, temp);
390}
391
392static void ipic_disable_irq(unsigned int irq)
393{
394 struct ipic *ipic = ipic_from_irq(irq);
395 unsigned int src = irq - ipic->irq_offset;
396 u32 temp;
397
398 temp = ipic_read(ipic->regs, ipic_info[src].mask);
399 temp &= ~(1 << (31 - ipic_info[src].bit));
400 ipic_write(ipic->regs, ipic_info[src].mask, temp);
401}
402
403static void ipic_disable_irq_and_ack(unsigned int irq)
404{
405 struct ipic *ipic = ipic_from_irq(irq);
406 unsigned int src = irq - ipic->irq_offset;
407 u32 temp;
408
409 ipic_disable_irq(irq);
410
411 temp = ipic_read(ipic->regs, ipic_info[src].pend);
412 temp |= (1 << (31 - ipic_info[src].bit));
413 ipic_write(ipic->regs, ipic_info[src].pend, temp);
414}
415
416static void ipic_end_irq(unsigned int irq)
417{
418 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
419 ipic_enable_irq(irq);
420}
421
422struct hw_interrupt_type ipic = {
423 .typename = " IPIC ",
424 .enable = ipic_enable_irq,
425 .disable = ipic_disable_irq,
426 .ack = ipic_disable_irq_and_ack,
427 .end = ipic_end_irq,
428};
429
430void __init ipic_init(phys_addr_t phys_addr,
431 unsigned int flags,
432 unsigned int irq_offset,
433 unsigned char *senses,
434 unsigned int senses_count)
435{
436 u32 i, temp = 0;
437
438 primary_ipic = &p_ipic;
439 primary_ipic->regs = ioremap(phys_addr, MPC83xx_IPIC_SIZE);
440
441 primary_ipic->irq_offset = irq_offset;
442
443 ipic_write(primary_ipic->regs, IPIC_SICNR, 0x0);
444
445 /* default priority scheme is grouped. If spread mode is required
446 * configure SICFR accordingly */
447 if (flags & IPIC_SPREADMODE_GRP_A)
448 temp |= SICFR_IPSA;
449 if (flags & IPIC_SPREADMODE_GRP_D)
450 temp |= SICFR_IPSD;
451 if (flags & IPIC_SPREADMODE_MIX_A)
452 temp |= SICFR_MPSA;
453 if (flags & IPIC_SPREADMODE_MIX_B)
454 temp |= SICFR_MPSB;
455
456 ipic_write(primary_ipic->regs, IPIC_SICNR, temp);
457
458 /* handle MCP route */
459 temp = 0;
460 if (flags & IPIC_DISABLE_MCP_OUT)
461 temp = SERCR_MCPR;
462 ipic_write(primary_ipic->regs, IPIC_SERCR, temp);
463
464 /* handle routing of IRQ0 to MCP */
465 temp = ipic_read(primary_ipic->regs, IPIC_SEMSR);
466
467 if (flags & IPIC_IRQ0_MCP)
468 temp |= SEMSR_SIRQ0;
469 else
470 temp &= ~SEMSR_SIRQ0;
471
472 ipic_write(primary_ipic->regs, IPIC_SEMSR, temp);
473
474 for (i = 0 ; i < NR_IPIC_INTS ; i++) {
475 irq_desc[i+irq_offset].handler = &ipic;
476 irq_desc[i+irq_offset].status = IRQ_LEVEL;
477 }
478
479 temp = 0;
480 for (i = 0 ; i < senses_count ; i++) {
481 if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) {
482 temp |= 1 << (16 - i);
483 if (i != 0)
484 irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0;
485 else
486 irq_desc[irq_offset + MPC83xx_IRQ_EXT0].status = 0;
487 }
488 }
489 ipic_write(primary_ipic->regs, IPIC_SECNR, temp);
490
491 printk ("IPIC (%d IRQ sources, %d External IRQs) at %p\n", NR_IPIC_INTS,
492 senses_count, primary_ipic->regs);
493}
494
495int ipic_set_priority(unsigned int irq, unsigned int priority)
496{
497 struct ipic *ipic = ipic_from_irq(irq);
498 unsigned int src = irq - ipic->irq_offset;
499 u32 temp;
500
501 if (priority > 7)
502 return -EINVAL;
503 if (src > 127)
504 return -EINVAL;
505 if (ipic_info[src].prio == 0)
506 return -EINVAL;
507
508 temp = ipic_read(ipic->regs, ipic_info[src].prio);
509
510 if (priority < 4) {
511 temp &= ~(0x7 << (20 + (3 - priority) * 3));
512 temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3);
513 } else {
514 temp &= ~(0x7 << (4 + (7 - priority) * 3));
515 temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3);
516 }
517
518 ipic_write(ipic->regs, ipic_info[src].prio, temp);
519
520 return 0;
521}
522
523void ipic_set_highest_priority(unsigned int irq)
524{
525 struct ipic *ipic = ipic_from_irq(irq);
526 unsigned int src = irq - ipic->irq_offset;
527 u32 temp;
528
529 temp = ipic_read(ipic->regs, IPIC_SICFR);
530
531 /* clear and set HPI */
532 temp &= 0x7f000000;
533 temp |= (src & 0x7f) << 24;
534
535 ipic_write(ipic->regs, IPIC_SICFR, temp);
536}
537
538void ipic_set_default_priority(void)
539{
540 ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0);
541 ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1);
542 ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2);
543 ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3);
544 ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4);
545 ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5);
546 ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6);
547 ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7);
548
549 ipic_set_priority(MPC83xx_IRQ_UART1, 0);
550 ipic_set_priority(MPC83xx_IRQ_UART2, 1);
551 ipic_set_priority(MPC83xx_IRQ_SEC2, 2);
552 ipic_set_priority(MPC83xx_IRQ_IIC1, 5);
553 ipic_set_priority(MPC83xx_IRQ_IIC2, 6);
554 ipic_set_priority(MPC83xx_IRQ_SPI, 7);
555 ipic_set_priority(MPC83xx_IRQ_RTC_SEC, 0);
556 ipic_set_priority(MPC83xx_IRQ_PIT, 1);
557 ipic_set_priority(MPC83xx_IRQ_PCI1, 2);
558 ipic_set_priority(MPC83xx_IRQ_PCI2, 3);
559 ipic_set_priority(MPC83xx_IRQ_EXT0, 4);
560 ipic_set_priority(MPC83xx_IRQ_EXT1, 5);
561 ipic_set_priority(MPC83xx_IRQ_EXT2, 6);
562 ipic_set_priority(MPC83xx_IRQ_EXT3, 7);
563 ipic_set_priority(MPC83xx_IRQ_RTC_ALR, 0);
564 ipic_set_priority(MPC83xx_IRQ_MU, 1);
565 ipic_set_priority(MPC83xx_IRQ_SBA, 2);
566 ipic_set_priority(MPC83xx_IRQ_DMA, 3);
567 ipic_set_priority(MPC83xx_IRQ_EXT4, 4);
568 ipic_set_priority(MPC83xx_IRQ_EXT5, 5);
569 ipic_set_priority(MPC83xx_IRQ_EXT6, 6);
570 ipic_set_priority(MPC83xx_IRQ_EXT7, 7);
571}
572
573void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq)
574{
575 struct ipic *ipic = primary_ipic;
576 u32 temp;
577
578 temp = ipic_read(ipic->regs, IPIC_SERMR);
579 temp |= (1 << (31 - mcp_irq));
580 ipic_write(ipic->regs, IPIC_SERMR, temp);
581}
582
583void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq)
584{
585 struct ipic *ipic = primary_ipic;
586 u32 temp;
587
588 temp = ipic_read(ipic->regs, IPIC_SERMR);
589 temp &= (1 << (31 - mcp_irq));
590 ipic_write(ipic->regs, IPIC_SERMR, temp);
591}
592
593u32 ipic_get_mcp_status(void)
594{
595 return ipic_read(primary_ipic->regs, IPIC_SERMR);
596}
597
598void ipic_clear_mcp_status(u32 mask)
599{
600 ipic_write(primary_ipic->regs, IPIC_SERMR, mask);
601}
602
603/* Return an interrupt vector or -1 if no interrupt is pending. */
604int ipic_get_irq(struct pt_regs *regs)
605{
606 int irq;
607
608 irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & 0x7f;
609
610 if (irq == 0) /* 0 --> no irq is pending */
611 irq = -1;
612
613 return irq;
614}
615
616static struct sysdev_class ipic_sysclass = {
617 set_kset_name("ipic"),
618};
619
620static struct sys_device device_ipic = {
621 .id = 0,
622 .cls = &ipic_sysclass,
623};
624
625static int __init init_ipic_sysfs(void)
626{
627 int rc;
628
629 if (!primary_ipic->regs)
630 return -ENODEV;
631 printk(KERN_DEBUG "Registering ipic with sysfs...\n");
632
633 rc = sysdev_class_register(&ipic_sysclass);
634 if (rc) {
635 printk(KERN_ERR "Failed registering ipic sys class\n");
636 return -ENODEV;
637 }
638 rc = sysdev_register(&device_ipic);
639 if (rc) {
640 printk(KERN_ERR "Failed registering ipic sys device\n");
641 return -ENODEV;
642 }
643 return 0;
644}
645
646subsys_initcall(init_ipic_sysfs);
diff --git a/arch/ppc/syslib/ipic.h b/arch/ppc/syslib/ipic.h
new file mode 100644
index 000000000000..2b56a4fcf373
--- /dev/null
+++ b/arch/ppc/syslib/ipic.h
@@ -0,0 +1,49 @@
1/*
2 * arch/ppc/kernel/ipic.h
3 *
4 * IPIC private definitions and structure.
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2005 Freescale Semiconductor, Inc
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15#ifndef __IPIC_H__
16#define __IPIC_H__
17
18#include <asm/ipic.h>
19
20#define MPC83xx_IPIC_SIZE (0x00100)
21
22/* System Global Interrupt Configuration Register */
23#define SICFR_IPSA 0x00010000
24#define SICFR_IPSD 0x00080000
25#define SICFR_MPSA 0x00200000
26#define SICFR_MPSB 0x00400000
27
28/* System External Interrupt Mask Register */
29#define SEMSR_SIRQ0 0x00008000
30
31/* System Error Control Register */
32#define SERCR_MCPR 0x00000001
33
34struct ipic {
35 volatile u32 __iomem *regs;
36 unsigned int irq_offset;
37};
38
39struct ipic_info {
40 u8 pend; /* pending register offset from base */
41 u8 mask; /* mask register offset from base */
42 u8 prio; /* priority register offset from base */
43 u8 force; /* force register offset from base */
44 u8 bit; /* register bit position (as per doc)
45 bit mask = 1 << (31 - bit) */
46 u8 prio_mask; /* priority mask value */
47};
48
49#endif /* __IPIC_H__ */
diff --git a/arch/ppc/syslib/m8260_pci.c b/arch/ppc/syslib/m8260_pci.c
new file mode 100644
index 000000000000..bd564fb35ab6
--- /dev/null
+++ b/arch/ppc/syslib/m8260_pci.c
@@ -0,0 +1,194 @@
1/*
2 * (C) Copyright 2003
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
5 * (C) Copyright 2004 Red Hat, Inc.
6 *
7 * See file CREDITS for list of people who contributed to this
8 * project.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License as
12 * published by the Free Software Foundation; either version 2 of
13 * the License, or (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 * MA 02111-1307 USA
24 */
25
26#include <linux/kernel.h>
27#include <linux/init.h>
28#include <linux/pci.h>
29#include <linux/slab.h>
30#include <linux/delay.h>
31
32#include <asm/byteorder.h>
33#include <asm/io.h>
34#include <asm/irq.h>
35#include <asm/uaccess.h>
36#include <asm/machdep.h>
37#include <asm/pci-bridge.h>
38#include <asm/immap_cpm2.h>
39#include <asm/mpc8260.h>
40
41#include "m8260_pci.h"
42
43
44/* PCI bus configuration registers.
45 */
46
47static void __init m8260_setup_pci(struct pci_controller *hose)
48{
49 volatile cpm2_map_t *immap = cpm2_immr;
50 unsigned long pocmr;
51 u16 tempShort;
52
53#ifndef CONFIG_ATC /* already done in U-Boot */
54 /*
55 * Setting required to enable IRQ1-IRQ7 (SIUMCR [DPPC]),
56 * and local bus for PCI (SIUMCR [LBPC]).
57 */
58 immap->im_siu_conf.siu_82xx.sc_siumcr = 0x00640000;
59#endif
60
61 /* Make PCI lowest priority */
62 /* Each 4 bits is a device bus request and the MS 4bits
63 is highest priority */
64 /* Bus 4bit value
65 --- ----------
66 CPM high 0b0000
67 CPM middle 0b0001
68 CPM low 0b0010
69 PCI reguest 0b0011
70 Reserved 0b0100
71 Reserved 0b0101
72 Internal Core 0b0110
73 External Master 1 0b0111
74 External Master 2 0b1000
75 External Master 3 0b1001
76 The rest are reserved */
77 immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x61207893;
78
79 /* Park bus on core while modifying PCI Bus accesses */
80 immap->im_siu_conf.siu_82xx.sc_ppc_acr = 0x6;
81
82 /*
83 * Set up master window that allows the CPU to access PCI space. This
84 * window is set up using the first SIU PCIBR registers.
85 */
86 immap->im_memctl.memc_pcimsk0 = MPC826x_PCI_MASK;
87 immap->im_memctl.memc_pcibr0 = MPC826x_PCI_BASE | PCIBR_ENABLE;
88
89 /* Disable machine check on no response or target abort */
90 immap->im_pci.pci_emr = cpu_to_le32(0x1fe7);
91 /* Release PCI RST (by default the PCI RST signal is held low) */
92 immap->im_pci.pci_gcr = cpu_to_le32(PCIGCR_PCI_BUS_EN);
93
94 /* give it some time */
95 mdelay(1);
96
97 /*
98 * Set up master window that allows the CPU to access PCI Memory (prefetch)
99 * space. This window is set up using the first set of Outbound ATU registers.
100 */
101 immap->im_pci.pci_potar0 = cpu_to_le32(MPC826x_PCI_LOWER_MEM >> 12);
102 immap->im_pci.pci_pobar0 = cpu_to_le32((MPC826x_PCI_LOWER_MEM - MPC826x_PCI_MEM_OFFSET) >> 12);
103 pocmr = ((MPC826x_PCI_UPPER_MEM - MPC826x_PCI_LOWER_MEM) >> 12) ^ 0xfffff;
104 immap->im_pci.pci_pocmr0 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PREFETCH_EN);
105
106 /*
107 * Set up master window that allows the CPU to access PCI Memory (non-prefetch)
108 * space. This window is set up using the second set of Outbound ATU registers.
109 */
110 immap->im_pci.pci_potar1 = cpu_to_le32(MPC826x_PCI_LOWER_MMIO >> 12);
111 immap->im_pci.pci_pobar1 = cpu_to_le32((MPC826x_PCI_LOWER_MMIO - MPC826x_PCI_MMIO_OFFSET) >> 12);
112 pocmr = ((MPC826x_PCI_UPPER_MMIO - MPC826x_PCI_LOWER_MMIO) >> 12) ^ 0xfffff;
113 immap->im_pci.pci_pocmr1 = cpu_to_le32(pocmr | POCMR_ENABLE);
114
115 /*
116 * Set up master window that allows the CPU to access PCI IO space. This window
117 * is set up using the third set of Outbound ATU registers.
118 */
119 immap->im_pci.pci_potar2 = cpu_to_le32(MPC826x_PCI_IO_BASE >> 12);
120 immap->im_pci.pci_pobar2 = cpu_to_le32(MPC826x_PCI_LOWER_IO >> 12);
121 pocmr = ((MPC826x_PCI_UPPER_IO - MPC826x_PCI_LOWER_IO) >> 12) ^ 0xfffff;
122 immap->im_pci.pci_pocmr2 = cpu_to_le32(pocmr | POCMR_ENABLE | POCMR_PCI_IO);
123
124 /*
125 * Set up slave window that allows PCI masters to access MPC826x local memory.
126 * This window is set up using the first set of Inbound ATU registers
127 */
128
129 immap->im_pci.pci_pitar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_LOCAL >> 12);
130 immap->im_pci.pci_pibar0 = cpu_to_le32(MPC826x_PCI_SLAVE_MEM_BUS >> 12);
131 pocmr = ((MPC826x_PCI_SLAVE_MEM_SIZE-1) >> 12) ^ 0xfffff;
132 immap->im_pci.pci_picmr0 = cpu_to_le32(pocmr | PICMR_ENABLE | PICMR_PREFETCH_EN);
133
134 /* See above for description - puts PCI request as highest priority */
135 immap->im_siu_conf.siu_82xx.sc_ppc_alrh = 0x03124567;
136
137 /* Park the bus on the PCI */
138 immap->im_siu_conf.siu_82xx.sc_ppc_acr = PPC_ACR_BUS_PARK_PCI;
139
140 /* Host mode - specify the bridge as a host-PCI bridge */
141 early_write_config_word(hose, 0, 0, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_HOST);
142
143 /* Enable the host bridge to be a master on the PCI bus, and to act as a PCI memory target */
144 early_read_config_word(hose, 0, 0, PCI_COMMAND, &tempShort);
145 early_write_config_word(hose, 0, 0, PCI_COMMAND,
146 tempShort | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
147}
148
149void __init m8260_find_bridges(void)
150{
151 extern int pci_assign_all_busses;
152 struct pci_controller * hose;
153
154 pci_assign_all_busses = 1;
155
156 hose = pcibios_alloc_controller();
157
158 if (!hose)
159 return;
160
161 ppc_md.pci_swizzle = common_swizzle;
162
163 hose->first_busno = 0;
164 hose->bus_offset = 0;
165 hose->last_busno = 0xff;
166
167 setup_m8260_indirect_pci(hose,
168 (unsigned long)&cpm2_immr->im_pci.pci_cfg_addr,
169 (unsigned long)&cpm2_immr->im_pci.pci_cfg_data);
170
171 m8260_setup_pci(hose);
172 hose->pci_mem_offset = MPC826x_PCI_MEM_OFFSET;
173
174 isa_io_base =
175 (unsigned long) ioremap(MPC826x_PCI_IO_BASE,
176 MPC826x_PCI_IO_SIZE);
177 hose->io_base_virt = (void *) isa_io_base;
178
179 /* setup resources */
180 pci_init_resource(&hose->mem_resources[0],
181 MPC826x_PCI_LOWER_MEM,
182 MPC826x_PCI_UPPER_MEM,
183 IORESOURCE_MEM|IORESOURCE_PREFETCH, "PCI prefetchable memory");
184
185 pci_init_resource(&hose->mem_resources[1],
186 MPC826x_PCI_LOWER_MMIO,
187 MPC826x_PCI_UPPER_MMIO,
188 IORESOURCE_MEM, "PCI memory");
189
190 pci_init_resource(&hose->io_resource,
191 MPC826x_PCI_LOWER_IO,
192 MPC826x_PCI_UPPER_IO,
193 IORESOURCE_IO, "PCI I/O");
194}
diff --git a/arch/ppc/syslib/m8260_pci.h b/arch/ppc/syslib/m8260_pci.h
new file mode 100644
index 000000000000..d1352120acd7
--- /dev/null
+++ b/arch/ppc/syslib/m8260_pci.h
@@ -0,0 +1,76 @@
1
2#ifndef _PPC_KERNEL_M8260_PCI_H
3#define _PPC_KERNEL_M8260_PCI_H
4
5#include <asm/m8260_pci.h>
6
7/*
8 * Local->PCI map (from CPU) controlled by
9 * MPC826x master window
10 *
11 * 0x80000000 - 0xBFFFFFFF Total CPU2PCI space PCIBR0
12 *
13 * 0x80000000 - 0x9FFFFFFF PCI Mem with prefetch (Outbound ATU #1)
14 * 0xA0000000 - 0xAFFFFFFF PCI Mem w/o prefetch (Outbound ATU #2)
15 * 0xB0000000 - 0xB0FFFFFF 32-bit PCI IO (Outbound ATU #3)
16 *
17 * PCI->Local map (from PCI)
18 * MPC826x slave window controlled by
19 *
20 * 0x00000000 - 0x07FFFFFF MPC826x local memory (Inbound ATU #1)
21 */
22
23/*
24 * Slave window that allows PCI masters to access MPC826x local memory.
25 * This window is set up using the first set of Inbound ATU registers
26 */
27
28#ifndef MPC826x_PCI_SLAVE_MEM_LOCAL
29#define MPC826x_PCI_SLAVE_MEM_LOCAL (((struct bd_info *)__res)->bi_memstart)
30#define MPC826x_PCI_SLAVE_MEM_BUS (((struct bd_info *)__res)->bi_memstart)
31#define MPC826x_PCI_SLAVE_MEM_SIZE (((struct bd_info *)__res)->bi_memsize)
32#endif
33
34/*
35 * This is the window that allows the CPU to access PCI address space.
36 * It will be setup with the SIU PCIBR0 register. All three PCI master
37 * windows, which allow the CPU to access PCI prefetch, non prefetch,
38 * and IO space (see below), must all fit within this window.
39 */
40#ifndef MPC826x_PCI_BASE
41#define MPC826x_PCI_BASE 0x80000000
42#define MPC826x_PCI_MASK 0xc0000000
43#endif
44
45#ifndef MPC826x_PCI_LOWER_MEM
46#define MPC826x_PCI_LOWER_MEM 0x80000000
47#define MPC826x_PCI_UPPER_MEM 0x9fffffff
48#define MPC826x_PCI_MEM_OFFSET 0x00000000
49#endif
50
51#ifndef MPC826x_PCI_LOWER_MMIO
52#define MPC826x_PCI_LOWER_MMIO 0xa0000000
53#define MPC826x_PCI_UPPER_MMIO 0xafffffff
54#define MPC826x_PCI_MMIO_OFFSET 0x00000000
55#endif
56
57#ifndef MPC826x_PCI_LOWER_IO
58#define MPC826x_PCI_LOWER_IO 0x00000000
59#define MPC826x_PCI_UPPER_IO 0x00ffffff
60#define MPC826x_PCI_IO_BASE 0xb0000000
61#define MPC826x_PCI_IO_SIZE 0x01000000
62#endif
63
64#ifndef _IO_BASE
65#define _IO_BASE isa_io_base
66#endif
67
68#ifdef CONFIG_8260_PCI9
69struct pci_controller;
70extern void setup_m8260_indirect_pci(struct pci_controller* hose,
71 u32 cfg_addr, u32 cfg_data);
72#else
73#define setup_m8260_indirect_pci setup_indirect_pci
74#endif
75
76#endif /* _PPC_KERNEL_M8260_PCI_H */
diff --git a/arch/ppc/syslib/m8260_pci_erratum9.c b/arch/ppc/syslib/m8260_pci_erratum9.c
new file mode 100644
index 000000000000..9c0582d639e0
--- /dev/null
+++ b/arch/ppc/syslib/m8260_pci_erratum9.c
@@ -0,0 +1,473 @@
1/*
2 * arch/ppc/platforms/mpc8260_pci9.c
3 *
4 * Workaround for device erratum PCI 9.
5 * See Motorola's "XPC826xA Family Device Errata Reference."
6 * The erratum applies to all 8260 family Hip4 processors. It is scheduled
7 * to be fixed in HiP4 Rev C. Erratum PCI 9 states that a simultaneous PCI
8 * inbound write transaction and PCI outbound read transaction can result in a
9 * bus deadlock. The suggested workaround is to use the IDMA controller to
10 * perform all reads from PCI configuration, memory, and I/O space.
11 *
12 * Author: andy_lowe@mvista.com
13 *
14 * 2003 (c) MontaVista Software, Inc. This file is licensed under
15 * the terms of the GNU General Public License version 2. This program
16 * is licensed "as is" without any warranty of any kind, whether express
17 * or implied.
18 */
19#include <linux/kernel.h>
20#include <linux/config.h>
21#include <linux/module.h>
22#include <linux/pci.h>
23#include <linux/types.h>
24#include <linux/string.h>
25
26#include <asm/io.h>
27#include <asm/pci-bridge.h>
28#include <asm/machdep.h>
29#include <asm/byteorder.h>
30#include <asm/mpc8260.h>
31#include <asm/immap_cpm2.h>
32#include <asm/cpm2.h>
33
34#include "m8260_pci.h"
35
36#ifdef CONFIG_8260_PCI9
37/*#include <asm/mpc8260_pci9.h>*/ /* included in asm/io.h */
38
39#define IDMA_XFER_BUF_SIZE 64 /* size of the IDMA transfer buffer */
40
41/* define a structure for the IDMA dpram usage */
42typedef struct idma_dpram_s {
43 idma_t pram; /* IDMA parameter RAM */
44 u_char xfer_buf[IDMA_XFER_BUF_SIZE]; /* IDMA transfer buffer */
45 idma_bd_t bd; /* buffer descriptor */
46} idma_dpram_t;
47
48/* define offsets relative to start of IDMA dpram */
49#define IDMA_XFER_BUF_OFFSET (sizeof(idma_t))
50#define IDMA_BD_OFFSET (sizeof(idma_t) + IDMA_XFER_BUF_SIZE)
51
52/* define globals */
53static volatile idma_dpram_t *idma_dpram;
54
55/* Exactly one of CONFIG_8260_PCI9_IDMAn must be defined,
56 * where n is 1, 2, 3, or 4. This selects the IDMA channel used for
57 * the PCI9 workaround.
58 */
59#ifdef CONFIG_8260_PCI9_IDMA1
60#define IDMA_CHAN 0
61#define PROFF_IDMA PROFF_IDMA1_BASE
62#define IDMA_PAGE CPM_CR_IDMA1_PAGE
63#define IDMA_SBLOCK CPM_CR_IDMA1_SBLOCK
64#endif
65#ifdef CONFIG_8260_PCI9_IDMA2
66#define IDMA_CHAN 1
67#define PROFF_IDMA PROFF_IDMA2_BASE
68#define IDMA_PAGE CPM_CR_IDMA2_PAGE
69#define IDMA_SBLOCK CPM_CR_IDMA2_SBLOCK
70#endif
71#ifdef CONFIG_8260_PCI9_IDMA3
72#define IDMA_CHAN 2
73#define PROFF_IDMA PROFF_IDMA3_BASE
74#define IDMA_PAGE CPM_CR_IDMA3_PAGE
75#define IDMA_SBLOCK CPM_CR_IDMA3_SBLOCK
76#endif
77#ifdef CONFIG_8260_PCI9_IDMA4
78#define IDMA_CHAN 3
79#define PROFF_IDMA PROFF_IDMA4_BASE
80#define IDMA_PAGE CPM_CR_IDMA4_PAGE
81#define IDMA_SBLOCK CPM_CR_IDMA4_SBLOCK
82#endif
83
84void idma_pci9_init(void)
85{
86 uint dpram_offset;
87 volatile idma_t *pram;
88 volatile im_idma_t *idma_reg;
89 volatile cpm2_map_t *immap = cpm2_immr;
90
91 /* allocate IDMA dpram */
92 dpram_offset = cpm_dpalloc(sizeof(idma_dpram_t), 64);
93 idma_dpram = cpm_dpram_addr(dpram_offset);
94
95 /* initialize the IDMA parameter RAM */
96 memset((void *)idma_dpram, 0, sizeof(idma_dpram_t));
97 pram = &idma_dpram->pram;
98 pram->ibase = dpram_offset + IDMA_BD_OFFSET;
99 pram->dpr_buf = dpram_offset + IDMA_XFER_BUF_OFFSET;
100 pram->ss_max = 32;
101 pram->dts = 32;
102
103 /* initialize the IDMA_BASE pointer to the IDMA parameter RAM */
104 *((ushort *) &immap->im_dprambase[PROFF_IDMA]) = dpram_offset;
105
106 /* initialize the IDMA registers */
107 idma_reg = (volatile im_idma_t *) &immap->im_sdma.sdma_idsr1;
108 idma_reg[IDMA_CHAN].idmr = 0; /* mask all IDMA interrupts */
109 idma_reg[IDMA_CHAN].idsr = 0xff; /* clear all event flags */
110
111 printk("<4>Using IDMA%d for MPC8260 device erratum PCI 9 workaround\n",
112 IDMA_CHAN + 1);
113
114 return;
115}
116
117/* Use the IDMA controller to transfer data from I/O memory to local RAM.
118 * The src address must be a physical address suitable for use by the DMA
119 * controller with no translation. The dst address must be a kernel virtual
120 * address. The dst address is translated to a physical address via
121 * virt_to_phys().
122 * The sinc argument specifies whether or not the source address is incremented
123 * by the DMA controller. The source address is incremented if and only if sinc
124 * is non-zero. The destination address is always incremented since the
125 * destination is always host RAM.
126 */
127static void
128idma_pci9_read(u8 *dst, u8 *src, int bytes, int unit_size, int sinc)
129{
130 unsigned long flags;
131 volatile idma_t *pram = &idma_dpram->pram;
132 volatile idma_bd_t *bd = &idma_dpram->bd;
133 volatile cpm2_map_t *immap = cpm2_immr;
134
135 local_irq_save(flags);
136
137 /* initialize IDMA parameter RAM for this transfer */
138 if (sinc)
139 pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC
140 | IDMA_DCM_DINC | IDMA_DCM_SD_MEM2MEM;
141 else
142 pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_DINC
143 | IDMA_DCM_SD_MEM2MEM;
144 pram->ibdptr = pram->ibase;
145 pram->sts = unit_size;
146 pram->istate = 0;
147
148 /* initialize the buffer descriptor */
149 bd->dst = virt_to_phys(dst);
150 bd->src = (uint) src;
151 bd->len = bytes;
152 bd->flags = IDMA_BD_V | IDMA_BD_W | IDMA_BD_I | IDMA_BD_L | IDMA_BD_DGBL
153 | IDMA_BD_DBO_BE | IDMA_BD_SBO_BE | IDMA_BD_SDTB;
154
155 /* issue the START_IDMA command to the CP */
156 while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
157 immap->im_cpm.cp_cpcr = mk_cr_cmd(IDMA_PAGE, IDMA_SBLOCK, 0,
158 CPM_CR_START_IDMA) | CPM_CR_FLG;
159 while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
160
161 /* wait for transfer to complete */
162 while(bd->flags & IDMA_BD_V);
163
164 local_irq_restore(flags);
165
166 return;
167}
168
169/* Use the IDMA controller to transfer data from I/O memory to local RAM.
170 * The dst address must be a physical address suitable for use by the DMA
171 * controller with no translation. The src address must be a kernel virtual
172 * address. The src address is translated to a physical address via
173 * virt_to_phys().
174 * The dinc argument specifies whether or not the dest address is incremented
175 * by the DMA controller. The source address is incremented if and only if sinc
176 * is non-zero. The source address is always incremented since the
177 * source is always host RAM.
178 */
179static void
180idma_pci9_write(u8 *dst, u8 *src, int bytes, int unit_size, int dinc)
181{
182 unsigned long flags;
183 volatile idma_t *pram = &idma_dpram->pram;
184 volatile idma_bd_t *bd = &idma_dpram->bd;
185 volatile cpm2_map_t *immap = cpm2_immr;
186
187 local_irq_save(flags);
188
189 /* initialize IDMA parameter RAM for this transfer */
190 if (dinc)
191 pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC
192 | IDMA_DCM_DINC | IDMA_DCM_SD_MEM2MEM;
193 else
194 pram->dcm = IDMA_DCM_DMA_WRAP_64 | IDMA_DCM_SINC
195 | IDMA_DCM_SD_MEM2MEM;
196 pram->ibdptr = pram->ibase;
197 pram->sts = unit_size;
198 pram->istate = 0;
199
200 /* initialize the buffer descriptor */
201 bd->dst = (uint) dst;
202 bd->src = virt_to_phys(src);
203 bd->len = bytes;
204 bd->flags = IDMA_BD_V | IDMA_BD_W | IDMA_BD_I | IDMA_BD_L | IDMA_BD_DGBL
205 | IDMA_BD_DBO_BE | IDMA_BD_SBO_BE | IDMA_BD_SDTB;
206
207 /* issue the START_IDMA command to the CP */
208 while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
209 immap->im_cpm.cp_cpcr = mk_cr_cmd(IDMA_PAGE, IDMA_SBLOCK, 0,
210 CPM_CR_START_IDMA) | CPM_CR_FLG;
211 while (immap->im_cpm.cp_cpcr & CPM_CR_FLG);
212
213 /* wait for transfer to complete */
214 while(bd->flags & IDMA_BD_V);
215
216 local_irq_restore(flags);
217
218 return;
219}
220
221/* Same as idma_pci9_read, but 16-bit little-endian byte swapping is performed
222 * if the unit_size is 2, and 32-bit little-endian byte swapping is performed if
223 * the unit_size is 4.
224 */
225static void
226idma_pci9_read_le(u8 *dst, u8 *src, int bytes, int unit_size, int sinc)
227{
228 int i;
229 u8 *p;
230
231 idma_pci9_read(dst, src, bytes, unit_size, sinc);
232 switch(unit_size) {
233 case 2:
234 for (i = 0, p = dst; i < bytes; i += 2, p += 2)
235 swab16s((u16 *) p);
236 break;
237 case 4:
238 for (i = 0, p = dst; i < bytes; i += 4, p += 4)
239 swab32s((u32 *) p);
240 break;
241 default:
242 break;
243 }
244}
245EXPORT_SYMBOL(idma_pci9_init);
246EXPORT_SYMBOL(idma_pci9_read);
247EXPORT_SYMBOL(idma_pci9_read_le);
248
249static inline int is_pci_mem(unsigned long addr)
250{
251 if (addr >= MPC826x_PCI_LOWER_MMIO &&
252 addr <= MPC826x_PCI_UPPER_MMIO)
253 return 1;
254 if (addr >= MPC826x_PCI_LOWER_MEM &&
255 addr <= MPC826x_PCI_UPPER_MEM)
256 return 1;
257 return 0;
258}
259
260#define is_pci_mem(pa) ( (pa > 0x80000000) && (pa < 0xc0000000))
261int readb(volatile unsigned char *addr)
262{
263 u8 val;
264 unsigned long pa = iopa((unsigned long) addr);
265
266 if (!is_pci_mem(pa))
267 return in_8(addr);
268
269 idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0);
270 return val;
271}
272
273int readw(volatile unsigned short *addr)
274{
275 u16 val;
276 unsigned long pa = iopa((unsigned long) addr);
277
278 if (!is_pci_mem(pa))
279 return in_le16(addr);
280
281 idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0);
282 return swab16(val);
283}
284
285unsigned readl(volatile unsigned *addr)
286{
287 u32 val;
288 unsigned long pa = iopa((unsigned long) addr);
289
290 if (!is_pci_mem(pa))
291 return in_le32(addr);
292
293 idma_pci9_read((u8 *)&val, (u8 *)pa, sizeof(val), sizeof(val), 0);
294 return swab32(val);
295}
296
297int inb(unsigned port)
298{
299 u8 val;
300 u8 *addr = (u8 *)(port + _IO_BASE);
301
302 idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0);
303 return val;
304}
305
306int inw(unsigned port)
307{
308 u16 val;
309 u8 *addr = (u8 *)(port + _IO_BASE);
310
311 idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0);
312 return swab16(val);
313}
314
315unsigned inl(unsigned port)
316{
317 u32 val;
318 u8 *addr = (u8 *)(port + _IO_BASE);
319
320 idma_pci9_read((u8 *)&val, (u8 *)addr, sizeof(val), sizeof(val), 0);
321 return swab32(val);
322}
323
324void insb(unsigned port, void *buf, int ns)
325{
326 u8 *addr = (u8 *)(port + _IO_BASE);
327
328 idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u8), sizeof(u8), 0);
329}
330
331void insw(unsigned port, void *buf, int ns)
332{
333 u8 *addr = (u8 *)(port + _IO_BASE);
334
335 idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u16), sizeof(u16), 0);
336}
337
338void insl(unsigned port, void *buf, int nl)
339{
340 u8 *addr = (u8 *)(port + _IO_BASE);
341
342 idma_pci9_read((u8 *)buf, (u8 *)addr, nl*sizeof(u32), sizeof(u32), 0);
343}
344
345void insw_ns(unsigned port, void *buf, int ns)
346{
347 u8 *addr = (u8 *)(port + _IO_BASE);
348
349 idma_pci9_read((u8 *)buf, (u8 *)addr, ns*sizeof(u16), sizeof(u16), 0);
350}
351
352void insl_ns(unsigned port, void *buf, int nl)
353{
354 u8 *addr = (u8 *)(port + _IO_BASE);
355
356 idma_pci9_read((u8 *)buf, (u8 *)addr, nl*sizeof(u32), sizeof(u32), 0);
357}
358
359void *memcpy_fromio(void *dest, unsigned long src, size_t count)
360{
361 unsigned long pa = iopa((unsigned long) src);
362
363 if (is_pci_mem(pa))
364 idma_pci9_read((u8 *)dest, (u8 *)pa, count, 32, 1);
365 else
366 memcpy(dest, (void *)src, count);
367 return dest;
368}
369
370EXPORT_SYMBOL(readb);
371EXPORT_SYMBOL(readw);
372EXPORT_SYMBOL(readl);
373EXPORT_SYMBOL(inb);
374EXPORT_SYMBOL(inw);
375EXPORT_SYMBOL(inl);
376EXPORT_SYMBOL(insb);
377EXPORT_SYMBOL(insw);
378EXPORT_SYMBOL(insl);
379EXPORT_SYMBOL(insw_ns);
380EXPORT_SYMBOL(insl_ns);
381EXPORT_SYMBOL(memcpy_fromio);
382
383#endif /* ifdef CONFIG_8260_PCI9 */
384
385/* Indirect PCI routines adapted from arch/ppc/kernel/indirect_pci.c.
386 * Copyright (C) 1998 Gabriel Paubert.
387 */
388#ifndef CONFIG_8260_PCI9
389#define cfg_read(val, addr, type, op) *val = op((type)(addr))
390#else
391#define cfg_read(val, addr, type, op) \
392 idma_pci9_read_le((u8*)(val),(u8*)(addr),sizeof(*(val)),sizeof(*(val)),0)
393#endif
394
395#define cfg_write(val, addr, type, op) op((type *)(addr), (val))
396
397static int indirect_write_config(struct pci_bus *pbus, unsigned int devfn, int where,
398 int size, u32 value)
399{
400 struct pci_controller *hose = pbus->sysdata;
401 u8 cfg_type = 0;
402 if (ppc_md.pci_exclude_device)
403 if (ppc_md.pci_exclude_device(pbus->number, devfn))
404 return PCIBIOS_DEVICE_NOT_FOUND;
405
406 if (hose->set_cfg_type)
407 if (pbus->number != hose->first_busno)
408 cfg_type = 1;
409
410 out_be32(hose->cfg_addr,
411 (((where & 0xfc) | cfg_type) << 24) | (devfn << 16)
412 | ((pbus->number - hose->bus_offset) << 8) | 0x80);
413
414 switch (size)
415 {
416 case 1:
417 cfg_write(value, hose->cfg_data + (where & 3), u8, out_8);
418 break;
419 case 2:
420 cfg_write(value, hose->cfg_data + (where & 2), u16, out_le16);
421 break;
422 case 4:
423 cfg_write(value, hose->cfg_data + (where & 0), u32, out_le32);
424 break;
425 }
426 return PCIBIOS_SUCCESSFUL;
427}
428
429static int indirect_read_config(struct pci_bus *pbus, unsigned int devfn, int where,
430 int size, u32 *value)
431{
432 struct pci_controller *hose = pbus->sysdata;
433 u8 cfg_type = 0;
434 if (ppc_md.pci_exclude_device)
435 if (ppc_md.pci_exclude_device(pbus->number, devfn))
436 return PCIBIOS_DEVICE_NOT_FOUND;
437
438 if (hose->set_cfg_type)
439 if (pbus->number != hose->first_busno)
440 cfg_type = 1;
441
442 out_be32(hose->cfg_addr,
443 (((where & 0xfc) | cfg_type) << 24) | (devfn << 16)
444 | ((pbus->number - hose->bus_offset) << 8) | 0x80);
445
446 switch (size)
447 {
448 case 1:
449 cfg_read(value, hose->cfg_data + (where & 3), u8 *, in_8);
450 break;
451 case 2:
452 cfg_read(value, hose->cfg_data + (where & 2), u16 *, in_le16);
453 break;
454 case 4:
455 cfg_read(value, hose->cfg_data + (where & 0), u32 *, in_le32);
456 break;
457 }
458 return PCIBIOS_SUCCESSFUL;
459}
460
461static struct pci_ops indirect_pci_ops =
462{
463 .read = indirect_read_config,
464 .write = indirect_write_config,
465};
466
467void
468setup_m8260_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
469{
470 hose->ops = &indirect_pci_ops;
471 hose->cfg_addr = (unsigned int *) ioremap(cfg_addr, 4);
472 hose->cfg_data = (unsigned char *) ioremap(cfg_data, 4);
473}
diff --git a/arch/ppc/syslib/m8260_setup.c b/arch/ppc/syslib/m8260_setup.c
new file mode 100644
index 000000000000..23ea3f694de2
--- /dev/null
+++ b/arch/ppc/syslib/m8260_setup.c
@@ -0,0 +1,264 @@
1/*
2 * arch/ppc/syslib/m8260_setup.c
3 *
4 * Copyright (C) 1995 Linus Torvalds
5 * Adapted from 'alpha' version by Gary Thomas
6 * Modified by Cort Dougan (cort@cs.nmt.edu)
7 * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
8 * Further modified for generic 8xx and 8260 by Dan.
9 */
10
11#include <linux/config.h>
12#include <linux/sched.h>
13#include <linux/kernel.h>
14#include <linux/mm.h>
15#include <linux/stddef.h>
16#include <linux/slab.h>
17#include <linux/init.h>
18#include <linux/initrd.h>
19#include <linux/root_dev.h>
20#include <linux/seq_file.h>
21#include <linux/irq.h>
22
23#include <asm/mmu.h>
24#include <asm/io.h>
25#include <asm/pgtable.h>
26#include <asm/mpc8260.h>
27#include <asm/immap_cpm2.h>
28#include <asm/machdep.h>
29#include <asm/bootinfo.h>
30#include <asm/time.h>
31
32#include "cpm2_pic.h"
33
34unsigned char __res[sizeof(bd_t)];
35
36extern void cpm2_reset(void);
37extern void m8260_find_bridges(void);
38extern void idma_pci9_init(void);
39
40/* Place-holder for board-specific init */
41void __attribute__ ((weak)) __init
42m82xx_board_setup(void)
43{
44}
45
46static void __init
47m8260_setup_arch(void)
48{
49 /* Print out Vendor and Machine info. */
50 printk(KERN_INFO "%s %s port\n", CPUINFO_VENDOR, CPUINFO_MACHINE);
51
52 /* Reset the Communication Processor Module. */
53 cpm2_reset();
54#ifdef CONFIG_8260_PCI9
55 /* Initialise IDMA for PCI erratum workaround */
56 idma_pci9_init();
57#endif
58#ifdef CONFIG_PCI_8260
59 m8260_find_bridges();
60#endif
61#ifdef CONFIG_BLK_DEV_INITRD
62 if (initrd_start)
63 ROOT_DEV = Root_RAM0;
64#endif
65 m82xx_board_setup();
66}
67
68/* The decrementer counts at the system (internal) clock frequency
69 * divided by four.
70 */
71static void __init
72m8260_calibrate_decr(void)
73{
74 bd_t *binfo = (bd_t *)__res;
75 int freq, divisor;
76
77 freq = binfo->bi_busfreq;
78 divisor = 4;
79 tb_ticks_per_jiffy = freq / HZ / divisor;
80 tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
81}
82
83/* The 8260 has an internal 1-second timer update register that
84 * we should use for this purpose.
85 */
86static uint rtc_time;
87
88static int
89m8260_set_rtc_time(unsigned long time)
90{
91 rtc_time = time;
92
93 return(0);
94}
95
96static unsigned long
97m8260_get_rtc_time(void)
98{
99 /* Get time from the RTC.
100 */
101 return((unsigned long)rtc_time);
102}
103
104#ifndef BOOTROM_RESTART_ADDR
105#warning "Using default BOOTROM_RESTART_ADDR!"
106#define BOOTROM_RESTART_ADDR 0xff000104
107#endif
108
109static void
110m8260_restart(char *cmd)
111{
112 extern void m8260_gorom(bd_t *bi, uint addr);
113 uint startaddr;
114
115 /* Most boot roms have a warmstart as the second instruction
116 * of the reset vector. If that doesn't work for you, change this
117 * or the reboot program to send a proper address.
118 */
119 startaddr = BOOTROM_RESTART_ADDR;
120 if (cmd != NULL) {
121 if (!strncmp(cmd, "startaddr=", 10))
122 startaddr = simple_strtoul(&cmd[10], NULL, 0);
123 }
124
125 m8260_gorom((void*)__pa(__res), startaddr);
126}
127
128static void
129m8260_halt(void)
130{
131 local_irq_disable();
132 while (1);
133}
134
135static void
136m8260_power_off(void)
137{
138 m8260_halt();
139}
140
141static int
142m8260_show_cpuinfo(struct seq_file *m)
143{
144 bd_t *bp = (bd_t *)__res;
145
146 seq_printf(m, "vendor\t\t: %s\n"
147 "machine\t\t: %s\n"
148 "\n"
149 "mem size\t\t: 0x%08x\n"
150 "console baud\t\t: %d\n"
151 "\n"
152 "core clock\t: %u MHz\n"
153 "CPM clock\t: %u MHz\n"
154 "bus clock\t: %u MHz\n",
155 CPUINFO_VENDOR, CPUINFO_MACHINE, bp->bi_memsize,
156 bp->bi_baudrate, bp->bi_intfreq / 1000000,
157 bp->bi_cpmfreq / 1000000, bp->bi_busfreq / 1000000);
158 return 0;
159}
160
161/* Initialize the internal interrupt controller. The number of
162 * interrupts supported can vary with the processor type, and the
163 * 8260 family can have up to 64.
164 * External interrupts can be either edge or level triggered, and
165 * need to be initialized by the appropriate driver.
166 */
167static void __init
168m8260_init_IRQ(void)
169{
170 cpm2_init_IRQ();
171
172 /* Initialize the default interrupt mapping priorities,
173 * in case the boot rom changed something on us.
174 */
175 cpm2_immr->im_intctl.ic_siprr = 0x05309770;
176}
177
178/*
179 * Same hack as 8xx
180 */
181static unsigned long __init
182m8260_find_end_of_memory(void)
183{
184 bd_t *binfo = (bd_t *)__res;
185
186 return binfo->bi_memsize;
187}
188
189/* Map the IMMR, plus anything else we can cover
190 * in that upper space according to the memory controller
191 * chip select mapping. Grab another bunch of space
192 * below that for stuff we can't cover in the upper.
193 */
194static void __init
195m8260_map_io(void)
196{
197 uint addr;
198
199 /* Map IMMR region to a 256MB BAT */
200 addr = (cpm2_immr != NULL) ? (uint)cpm2_immr : CPM_MAP_ADDR;
201 io_block_mapping(addr, addr, 0x10000000, _PAGE_IO);
202
203 /* Map I/O region to a 256MB BAT */
204 io_block_mapping(IO_VIRT_ADDR, IO_PHYS_ADDR, 0x10000000, _PAGE_IO);
205}
206
207/* Place-holder for board-specific ppc_md hooking */
208void __attribute__ ((weak)) __init
209m82xx_board_init(void)
210{
211}
212
213/* Inputs:
214 * r3 - Optional pointer to a board information structure.
215 * r4 - Optional pointer to the physical starting address of the init RAM
216 * disk.
217 * r5 - Optional pointer to the physical ending address of the init RAM
218 * disk.
219 * r6 - Optional pointer to the physical starting address of any kernel
220 * command-line parameters.
221 * r7 - Optional pointer to the physical ending address of any kernel
222 * command-line parameters.
223 */
224void __init
225platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
226 unsigned long r6, unsigned long r7)
227{
228 parse_bootinfo(find_bootinfo());
229
230 if ( r3 )
231 memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
232
233#ifdef CONFIG_BLK_DEV_INITRD
234 /* take care of initrd if we have one */
235 if ( r4 ) {
236 initrd_start = r4 + KERNELBASE;
237 initrd_end = r5 + KERNELBASE;
238 }
239#endif /* CONFIG_BLK_DEV_INITRD */
240 /* take care of cmd line */
241 if ( r6 ) {
242 *(char *)(r7+KERNELBASE) = 0;
243 strcpy(cmd_line, (char *)(r6+KERNELBASE));
244 }
245
246 ppc_md.setup_arch = m8260_setup_arch;
247 ppc_md.show_cpuinfo = m8260_show_cpuinfo;
248 ppc_md.init_IRQ = m8260_init_IRQ;
249 ppc_md.get_irq = cpm2_get_irq;
250
251 ppc_md.restart = m8260_restart;
252 ppc_md.power_off = m8260_power_off;
253 ppc_md.halt = m8260_halt;
254
255 ppc_md.set_rtc_time = m8260_set_rtc_time;
256 ppc_md.get_rtc_time = m8260_get_rtc_time;
257 ppc_md.calibrate_decr = m8260_calibrate_decr;
258
259 ppc_md.find_end_of_memory = m8260_find_end_of_memory;
260 ppc_md.setup_io_mappings = m8260_map_io;
261
262 /* Call back for board-specific settings and overrides. */
263 m82xx_board_init();
264}
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
new file mode 100644
index 000000000000..c1db2ab1d154
--- /dev/null
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -0,0 +1,433 @@
1/*
2 * arch/ppc/kernel/setup.c
3 *
4 * Copyright (C) 1995 Linus Torvalds
5 * Adapted from 'alpha' version by Gary Thomas
6 * Modified by Cort Dougan (cort@cs.nmt.edu)
7 * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
8 * Further modified for generic 8xx by Dan.
9 */
10
11/*
12 * bootup setup stuff..
13 */
14
15#include <linux/config.h>
16#include <linux/errno.h>
17#include <linux/sched.h>
18#include <linux/kernel.h>
19#include <linux/mm.h>
20#include <linux/stddef.h>
21#include <linux/unistd.h>
22#include <linux/ptrace.h>
23#include <linux/slab.h>
24#include <linux/user.h>
25#include <linux/a.out.h>
26#include <linux/tty.h>
27#include <linux/major.h>
28#include <linux/interrupt.h>
29#include <linux/reboot.h>
30#include <linux/init.h>
31#include <linux/initrd.h>
32#include <linux/ioport.h>
33#include <linux/bootmem.h>
34#include <linux/seq_file.h>
35#include <linux/root_dev.h>
36
37#include <asm/mmu.h>
38#include <asm/reg.h>
39#include <asm/residual.h>
40#include <asm/io.h>
41#include <asm/pgtable.h>
42#include <asm/mpc8xx.h>
43#include <asm/8xx_immap.h>
44#include <asm/machdep.h>
45#include <asm/bootinfo.h>
46#include <asm/time.h>
47#include <asm/xmon.h>
48
49#include "ppc8xx_pic.h"
50
51static int m8xx_set_rtc_time(unsigned long time);
52static unsigned long m8xx_get_rtc_time(void);
53void m8xx_calibrate_decr(void);
54
55unsigned char __res[sizeof(bd_t)];
56
57extern void m8xx_ide_init(void);
58
59extern unsigned long find_available_memory(void);
60extern void m8xx_cpm_reset(uint cpm_page);
61extern void m8xx_wdt_handler_install(bd_t *bp);
62extern void rpxfb_alloc_pages(void);
63extern void cpm_interrupt_init(void);
64
65void __attribute__ ((weak))
66board_init(void)
67{
68}
69
70void __init
71m8xx_setup_arch(void)
72{
73 int cpm_page;
74
75 cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
76
77 /* Reset the Communication Processor Module.
78 */
79 m8xx_cpm_reset(cpm_page);
80
81#ifdef CONFIG_FB_RPX
82 rpxfb_alloc_pages();
83#endif
84
85#ifdef notdef
86 ROOT_DEV = Root_HDA1; /* hda1 */
87#endif
88
89#ifdef CONFIG_BLK_DEV_INITRD
90#if 0
91 ROOT_DEV = Root_FD0; /* floppy */
92 rd_prompt = 1;
93 rd_doload = 1;
94 rd_image_start = 0;
95#endif
96#if 0 /* XXX this may need to be updated for the new bootmem stuff,
97 or possibly just deleted (see set_phys_avail() in init.c).
98 - paulus. */
99 /* initrd_start and size are setup by boot/head.S and kernel/head.S */
100 if ( initrd_start )
101 {
102 if (initrd_end > *memory_end_p)
103 {
104 printk("initrd extends beyond end of memory "
105 "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
106 initrd_end,*memory_end_p);
107 initrd_start = 0;
108 }
109 }
110#endif
111#endif
112 board_init();
113}
114
115void
116abort(void)
117{
118#ifdef CONFIG_XMON
119 xmon(0);
120#endif
121 machine_restart(NULL);
122
123 /* not reached */
124 for (;;);
125}
126
127/* A place holder for time base interrupts, if they are ever enabled. */
128irqreturn_t timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
129{
130 printk ("timebase_interrupt()\n");
131
132 return IRQ_HANDLED;
133}
134
135static struct irqaction tbint_irqaction = {
136 .handler = timebase_interrupt,
137 .mask = CPU_MASK_NONE,
138 .name = "tbint",
139};
140
141/* The decrementer counts at the system (internal) clock frequency divided by
142 * sixteen, or external oscillator divided by four. We force the processor
143 * to use system clock divided by sixteen.
144 */
145void __init m8xx_calibrate_decr(void)
146{
147 bd_t *binfo = (bd_t *)__res;
148 int freq, fp, divisor;
149
150 /* Unlock the SCCR. */
151 ((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = ~KAPWR_KEY;
152 ((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = KAPWR_KEY;
153
154 /* Force all 8xx processors to use divide by 16 processor clock. */
155 ((volatile immap_t *)IMAP_ADDR)->im_clkrst.car_sccr |= 0x02000000;
156
157 /* Processor frequency is MHz.
158 * The value 'fp' is the number of decrementer ticks per second.
159 */
160 fp = binfo->bi_intfreq / 16;
161 freq = fp*60; /* try to make freq/1e6 an integer */
162 divisor = 60;
163 printk("Decrementer Frequency = %d/%d\n", freq, divisor);
164 tb_ticks_per_jiffy = freq / HZ / divisor;
165 tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
166
167 /* Perform some more timer/timebase initialization. This used
168 * to be done elsewhere, but other changes caused it to get
169 * called more than once....that is a bad thing.
170 *
171 * First, unlock all of the registers we are going to modify.
172 * To protect them from corruption during power down, registers
173 * that are maintained by keep alive power are "locked". To
174 * modify these registers we have to write the key value to
175 * the key location associated with the register.
176 * Some boards power up with these unlocked, while others
177 * are locked. Writing anything (including the unlock code?)
178 * to the unlocked registers will lock them again. So, here
179 * we guarantee the registers are locked, then we unlock them
180 * for our use.
181 */
182 ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = ~KAPWR_KEY;
183 ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = ~KAPWR_KEY;
184 ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = ~KAPWR_KEY;
185 ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = KAPWR_KEY;
186 ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = KAPWR_KEY;
187 ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk = KAPWR_KEY;
188
189 /* Disable the RTC one second and alarm interrupts. */
190 ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
191 ~(RTCSC_SIE | RTCSC_ALE);
192 /* Enable the RTC */
193 ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc |=
194 (RTCSC_RTF | RTCSC_RTE);
195
196 /* Enabling the decrementer also enables the timebase interrupts
197 * (or from the other point of view, to get decrementer interrupts
198 * we have to enable the timebase). The decrementer interrupt
199 * is wired into the vector table, nothing to do here for that.
200 */
201 ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
202 ((mk_int_int_mask(DEC_INTERRUPT) << 8) |
203 (TBSCR_TBF | TBSCR_TBE));
204
205 if (setup_irq(DEC_INTERRUPT, &tbint_irqaction))
206 panic("Could not allocate timer IRQ!");
207
208#ifdef CONFIG_8xx_WDT
209 /* Install watchdog timer handler early because it might be
210 * already enabled by the bootloader
211 */
212 m8xx_wdt_handler_install(binfo);
213#endif
214}
215
216/* The RTC on the MPC8xx is an internal register.
217 * We want to protect this during power down, so we need to unlock,
218 * modify, and re-lock.
219 */
220static int
221m8xx_set_rtc_time(unsigned long time)
222{
223 ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
224 ((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
225 ((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
226 return(0);
227}
228
229static unsigned long
230m8xx_get_rtc_time(void)
231{
232 /* Get time from the RTC. */
233 return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc));
234}
235
236static void
237m8xx_restart(char *cmd)
238{
239 __volatile__ unsigned char dummy;
240
241 local_irq_disable();
242 ((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080;
243
244 /* Clear the ME bit in MSR to cause checkstop on machine check
245 */
246 mtmsr(mfmsr() & ~0x1000);
247
248 dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0];
249 printk("Restart failed\n");
250 while(1);
251}
252
253static void
254m8xx_power_off(void)
255{
256 m8xx_restart(NULL);
257}
258
259static void
260m8xx_halt(void)
261{
262 m8xx_restart(NULL);
263}
264
265
266static int
267m8xx_show_percpuinfo(struct seq_file *m, int i)
268{
269 bd_t *bp;
270
271 bp = (bd_t *)__res;
272
273 seq_printf(m, "clock\t\t: %ldMHz\n"
274 "bus clock\t: %ldMHz\n",
275 bp->bi_intfreq / 1000000,
276 bp->bi_busfreq / 1000000);
277
278 return 0;
279}
280
281#ifdef CONFIG_PCI
282static struct irqaction mbx_i8259_irqaction = {
283 .handler = mbx_i8259_action,
284 .mask = CPU_MASK_NONE,
285 .name = "i8259 cascade",
286};
287#endif
288
289/* Initialize the internal interrupt controller. The number of
290 * interrupts supported can vary with the processor type, and the
291 * 82xx family can have up to 64.
292 * External interrupts can be either edge or level triggered, and
293 * need to be initialized by the appropriate driver.
294 */
295static void __init
296m8xx_init_IRQ(void)
297{
298 int i;
299
300 for (i = SIU_IRQ_OFFSET ; i < SIU_IRQ_OFFSET + NR_SIU_INTS ; i++)
301 irq_desc[i].handler = &ppc8xx_pic;
302
303 cpm_interrupt_init();
304
305#if defined(CONFIG_PCI)
306 for (i = I8259_IRQ_OFFSET ; i < I8259_IRQ_OFFSET + NR_8259_INTS ; i++)
307 irq_desc[i].handler = &i8259_pic;
308
309 i8259_pic_irq_offset = I8259_IRQ_OFFSET;
310 i8259_init(0);
311
312 /* The i8259 cascade interrupt must be level sensitive. */
313 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_siel &=
314 ~(0x80000000 >> ISA_BRIDGE_INT);
315
316 if (setup_irq(ISA_BRIDGE_INT, &mbx_i8259_irqaction))
317 enable_irq(ISA_BRIDGE_INT);
318#endif /* CONFIG_PCI */
319}
320
321/* -------------------------------------------------------------------- */
322
323/*
324 * This is a big hack right now, but it may turn into something real
325 * someday.
326 *
327 * For the 8xx boards (at this time anyway), there is nothing to initialize
328 * associated the PROM. Rather than include all of the prom.c
329 * functions in the image just to get prom_init, all we really need right
330 * now is the initialization of the physical memory region.
331 */
332static unsigned long __init
333m8xx_find_end_of_memory(void)
334{
335 bd_t *binfo;
336 extern unsigned char __res[];
337
338 binfo = (bd_t *)__res;
339
340 return binfo->bi_memsize;
341}
342
343/*
344 * Now map in some of the I/O space that is generically needed
345 * or shared with multiple devices.
346 * All of this fits into the same 4Mbyte region, so it only
347 * requires one page table page. (or at least it used to -- paulus)
348 */
349static void __init
350m8xx_map_io(void)
351{
352 io_block_mapping(IMAP_ADDR, IMAP_ADDR, IMAP_SIZE, _PAGE_IO);
353#ifdef CONFIG_MBX
354 io_block_mapping(NVRAM_ADDR, NVRAM_ADDR, NVRAM_SIZE, _PAGE_IO);
355 io_block_mapping(MBX_CSR_ADDR, MBX_CSR_ADDR, MBX_CSR_SIZE, _PAGE_IO);
356 io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
357
358 /* Map some of the PCI/ISA I/O space to get the IDE interface.
359 */
360 io_block_mapping(PCI_ISA_IO_ADDR, PCI_ISA_IO_ADDR, 0x4000, _PAGE_IO);
361 io_block_mapping(PCI_IDE_ADDR, PCI_IDE_ADDR, 0x4000, _PAGE_IO);
362#endif
363#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
364 io_block_mapping(RPX_CSR_ADDR, RPX_CSR_ADDR, RPX_CSR_SIZE, _PAGE_IO);
365#if !defined(CONFIG_PCI)
366 io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
367#endif
368#endif
369#if defined(CONFIG_HTDMSOUND) || defined(CONFIG_RPXTOUCH) || defined(CONFIG_FB_RPX)
370 io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
371#endif
372#ifdef CONFIG_FADS
373 io_block_mapping(BCSR_ADDR, BCSR_ADDR, BCSR_SIZE, _PAGE_IO);
374#endif
375#ifdef CONFIG_PCI
376 io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
377#endif
378#if defined(CONFIG_NETTA)
379 io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
380#endif
381}
382
383void __init
384platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
385 unsigned long r6, unsigned long r7)
386{
387 parse_bootinfo(find_bootinfo());
388
389 if ( r3 )
390 memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
391
392#ifdef CONFIG_PCI
393 m8xx_setup_pci_ptrs();
394#endif
395
396#ifdef CONFIG_BLK_DEV_INITRD
397 /* take care of initrd if we have one */
398 if ( r4 )
399 {
400 initrd_start = r4 + KERNELBASE;
401 initrd_end = r5 + KERNELBASE;
402 }
403#endif /* CONFIG_BLK_DEV_INITRD */
404 /* take care of cmd line */
405 if ( r6 )
406 {
407 *(char *)(r7+KERNELBASE) = 0;
408 strcpy(cmd_line, (char *)(r6+KERNELBASE));
409 }
410
411 ppc_md.setup_arch = m8xx_setup_arch;
412 ppc_md.show_percpuinfo = m8xx_show_percpuinfo;
413 ppc_md.irq_canonicalize = NULL;
414 ppc_md.init_IRQ = m8xx_init_IRQ;
415 ppc_md.get_irq = m8xx_get_irq;
416 ppc_md.init = NULL;
417
418 ppc_md.restart = m8xx_restart;
419 ppc_md.power_off = m8xx_power_off;
420 ppc_md.halt = m8xx_halt;
421
422 ppc_md.time_init = NULL;
423 ppc_md.set_rtc_time = m8xx_set_rtc_time;
424 ppc_md.get_rtc_time = m8xx_get_rtc_time;
425 ppc_md.calibrate_decr = m8xx_calibrate_decr;
426
427 ppc_md.find_end_of_memory = m8xx_find_end_of_memory;
428 ppc_md.setup_io_mappings = m8xx_map_io;
429
430#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
431 m8xx_ide_init();
432#endif
433}
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
new file mode 100644
index 000000000000..7838a44bfd1d
--- /dev/null
+++ b/arch/ppc/syslib/m8xx_wdt.c
@@ -0,0 +1,99 @@
1/*
2 * m8xx_wdt.c - MPC8xx watchdog driver
3 *
4 * Author: Florian Schirmer <jolt@tuxbox.org>
5 *
6 * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
10 */
11
12#include <linux/init.h>
13#include <linux/interrupt.h>
14#include <linux/kernel.h>
15#include <linux/sched.h>
16#include <asm/8xx_immap.h>
17#include <syslib/m8xx_wdt.h>
18
19static int wdt_timeout;
20
21void m8xx_wdt_reset(void)
22{
23 volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
24
25 imap->im_siu_conf.sc_swsr = 0x556c; /* write magic1 */
26 imap->im_siu_conf.sc_swsr = 0xaa39; /* write magic2 */
27}
28
29static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
30{
31 volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
32
33 m8xx_wdt_reset();
34
35 imap->im_sit.sit_piscr |= PISCR_PS; /* clear irq */
36
37 return IRQ_HANDLED;
38}
39
40void __init m8xx_wdt_handler_install(bd_t * binfo)
41{
42 volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
43 u32 pitc;
44 u32 sypcr;
45 u32 pitrtclk;
46
47 sypcr = imap->im_siu_conf.sc_sypcr;
48
49 if (!(sypcr & 0x04)) {
50 printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
51 sypcr);
52 return;
53 }
54
55 m8xx_wdt_reset();
56
57 printk(KERN_NOTICE
58 "m8xx_wdt: active wdt found (SWTC: 0x%04X, SWP: 0x%01X)\n",
59 (sypcr >> 16), sypcr & 0x01);
60
61 wdt_timeout = (sypcr >> 16) & 0xFFFF;
62
63 if (!wdt_timeout)
64 wdt_timeout = 0xFFFF;
65
66 if (sypcr & 0x01)
67 wdt_timeout *= 2048;
68
69 /*
70 * Fire trigger if half of the wdt ticked down
71 */
72
73 if (imap->im_sit.sit_rtcsc & RTCSC_38K)
74 pitrtclk = 9600;
75 else
76 pitrtclk = 8192;
77
78 if ((wdt_timeout) > (UINT_MAX / pitrtclk))
79 pitc = wdt_timeout / binfo->bi_intfreq * pitrtclk / 2;
80 else
81 pitc = pitrtclk * wdt_timeout / binfo->bi_intfreq / 2;
82
83 imap->im_sit.sit_pitc = pitc << 16;
84 imap->im_sit.sit_piscr =
85 (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE;
86
87 if (request_irq(PIT_INTERRUPT, m8xx_wdt_interrupt, 0, "watchdog", NULL))
88 panic("m8xx_wdt: could not allocate watchdog irq!");
89
90 printk(KERN_NOTICE
91 "m8xx_wdt: keep-alive trigger installed (PITC: 0x%04X)\n", pitc);
92
93 wdt_timeout /= binfo->bi_intfreq;
94}
95
96int m8xx_wdt_get_timeout(void)
97{
98 return wdt_timeout;
99}
diff --git a/arch/ppc/syslib/m8xx_wdt.h b/arch/ppc/syslib/m8xx_wdt.h
new file mode 100644
index 000000000000..0d81a9f8155f
--- /dev/null
+++ b/arch/ppc/syslib/m8xx_wdt.h
@@ -0,0 +1,16 @@
1/*
2 * Author: Florian Schirmer <jolt@tuxbox.org>
3 *
4 * 2002 (c) Florian Schirmer <jolt@tuxbox.org> This file is licensed under
5 * the terms of the GNU General Public License version 2. This program
6 * is licensed "as is" without any warranty of any kind, whether express
7 * or implied.
8 */
9#ifndef _PPC_SYSLIB_M8XX_WDT_H
10#define _PPC_SYSLIB_M8XX_WDT_H
11
12extern void m8xx_wdt_handler_install(bd_t * binfo);
13extern int m8xx_wdt_get_timeout(void);
14extern void m8xx_wdt_reset(void);
15
16#endif /* _PPC_SYSLIB_M8XX_WDT_H */
diff --git a/arch/ppc/syslib/mpc10x_common.c b/arch/ppc/syslib/mpc10x_common.c
new file mode 100644
index 000000000000..fd93adfd464c
--- /dev/null
+++ b/arch/ppc/syslib/mpc10x_common.c
@@ -0,0 +1,510 @@
1/*
2 * arch/ppc/syslib/mpc10x_common.c
3 *
4 * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
5 * Mem ctlr, EPIC, etc.
6 *
7 * Author: Mark A. Greer
8 * mgreer@mvista.com
9 *
10 * 2001 (c) MontaVista, Software, Inc. This file is licensed under
11 * the terms of the GNU General Public License version 2. This program
12 * is licensed "as is" without any warranty of any kind, whether express
13 * or implied.
14 */
15
16/*
17 * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
18 */
19
20#include <linux/kernel.h>
21#include <linux/init.h>
22#include <linux/pci.h>
23#include <linux/slab.h>
24
25#include <asm/byteorder.h>
26#include <asm/io.h>
27#include <asm/irq.h>
28#include <asm/uaccess.h>
29#include <asm/machdep.h>
30#include <asm/pci-bridge.h>
31#include <asm/open_pic.h>
32#include <asm/mpc10x.h>
33#include <asm/ocp.h>
34
35/* The OCP structure is fixed by code below, before OCP initialises.
36 paddr depends on where the board places the EUMB.
37 - fixed in mpc10x_bridge_init().
38 irq depends on two things:
39 > does the board use the EPIC at all? (PCORE does not).
40 > is the EPIC in serial or parallel mode?
41 - fixed in mpc10x_set_openpic().
42*/
43
44#ifdef CONFIG_MPC10X_OPENPIC
45#ifdef CONFIG_EPIC_SERIAL_MODE
46#define EPIC_IRQ_BASE (epic_serial_mode ? 16 : 5)
47#else
48#define EPIC_IRQ_BASE 5
49#endif
50#define MPC10X_I2C_IRQ (EPIC_IRQ_BASE + NUM_8259_INTERRUPTS)
51#define MPC10X_DMA0_IRQ (EPIC_IRQ_BASE + 1 + NUM_8259_INTERRUPTS)
52#define MPC10X_DMA1_IRQ (EPIC_IRQ_BASE + 2 + NUM_8259_INTERRUPTS)
53#else
54#define MPC10X_I2C_IRQ OCP_IRQ_NA
55#define MPC10X_DMA0_IRQ OCP_IRQ_NA
56#define MPC10X_DMA1_IRQ OCP_IRQ_NA
57#endif
58
59
60struct ocp_def core_ocp[] = {
61 { .vendor = OCP_VENDOR_INVALID
62 }
63};
64
65static struct ocp_fs_i2c_data mpc10x_i2c_data = {
66 .flags = 0
67};
68static struct ocp_def mpc10x_i2c_ocp = {
69 .vendor = OCP_VENDOR_MOTOROLA,
70 .function = OCP_FUNC_IIC,
71 .index = 0,
72 .additions = &mpc10x_i2c_data
73};
74
75static struct ocp_def mpc10x_dma_ocp[2] = {
76{ .vendor = OCP_VENDOR_MOTOROLA,
77 .function = OCP_FUNC_DMA,
78 .index = 0 },
79{ .vendor = OCP_VENDOR_MOTOROLA,
80 .function = OCP_FUNC_DMA,
81 .index = 1 }
82};
83
84/* Set resources to match bridge memory map */
85void __init
86mpc10x_bridge_set_resources(int map, struct pci_controller *hose)
87{
88
89 switch (map) {
90 case MPC10X_MEM_MAP_A:
91 pci_init_resource(&hose->io_resource,
92 0x00000000,
93 0x3f7fffff,
94 IORESOURCE_IO,
95 "PCI host bridge");
96
97 pci_init_resource (&hose->mem_resources[0],
98 0xc0000000,
99 0xfeffffff,
100 IORESOURCE_MEM,
101 "PCI host bridge");
102 break;
103 case MPC10X_MEM_MAP_B:
104 pci_init_resource(&hose->io_resource,
105 0x00000000,
106 0x00bfffff,
107 IORESOURCE_IO,
108 "PCI host bridge");
109
110 pci_init_resource (&hose->mem_resources[0],
111 0x80000000,
112 0xfcffffff,
113 IORESOURCE_MEM,
114 "PCI host bridge");
115 break;
116 default:
117 printk("mpc10x_bridge_set_resources: "
118 "Invalid map specified\n");
119 if (ppc_md.progress)
120 ppc_md.progress("mpc10x:exit1", 0x100);
121 }
122}
123/*
124 * Do some initialization and put the EUMB registers at the specified address
125 * (also map the EPIC registers into virtual space--OpenPIC_Addr will be set).
126 *
127 * The EPIC is not on the 106, only the 8240 and 107.
128 */
129int __init
130mpc10x_bridge_init(struct pci_controller *hose,
131 uint current_map,
132 uint new_map,
133 uint phys_eumb_base)
134{
135 int host_bridge, picr1, picr1_bit;
136 ulong pci_config_addr, pci_config_data;
137 u_char pir, byte;
138
139 if (ppc_md.progress) ppc_md.progress("mpc10x:enter", 0x100);
140
141 /* Set up for current map so we can get at config regs */
142 switch (current_map) {
143 case MPC10X_MEM_MAP_A:
144 setup_indirect_pci(hose,
145 MPC10X_MAPA_CNFG_ADDR,
146 MPC10X_MAPA_CNFG_DATA);
147 break;
148 case MPC10X_MEM_MAP_B:
149 setup_indirect_pci(hose,
150 MPC10X_MAPB_CNFG_ADDR,
151 MPC10X_MAPB_CNFG_DATA);
152 break;
153 default:
154 printk("mpc10x_bridge_init: %s\n",
155 "Invalid current map specified");
156 if (ppc_md.progress)
157 ppc_md.progress("mpc10x:exit1", 0x100);
158 return -1;
159 }
160
161 /* Make sure it's a supported bridge */
162 early_read_config_dword(hose,
163 0,
164 PCI_DEVFN(0,0),
165 PCI_VENDOR_ID,
166 &host_bridge);
167
168 switch (host_bridge) {
169 case MPC10X_BRIDGE_106:
170 case MPC10X_BRIDGE_8240:
171 case MPC10X_BRIDGE_107:
172 case MPC10X_BRIDGE_8245:
173 break;
174 default:
175 if (ppc_md.progress)
176 ppc_md.progress("mpc10x:exit2", 0x100);
177 return -1;
178 }
179
180 switch (new_map) {
181 case MPC10X_MEM_MAP_A:
182 MPC10X_SETUP_HOSE(hose, A);
183 pci_config_addr = MPC10X_MAPA_CNFG_ADDR;
184 pci_config_data = MPC10X_MAPA_CNFG_DATA;
185 picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_A;
186 break;
187 case MPC10X_MEM_MAP_B:
188 MPC10X_SETUP_HOSE(hose, B);
189 pci_config_addr = MPC10X_MAPB_CNFG_ADDR;
190 pci_config_data = MPC10X_MAPB_CNFG_DATA;
191 picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_B;
192 break;
193 default:
194 printk("mpc10x_bridge_init: %s\n",
195 "Invalid new map specified");
196 if (ppc_md.progress)
197 ppc_md.progress("mpc10x:exit3", 0x100);
198 return -1;
199 }
200
201 /* Make bridge use the 'new_map', if not already usng it */
202 if (current_map != new_map) {
203 early_read_config_dword(hose,
204 0,
205 PCI_DEVFN(0,0),
206 MPC10X_CFG_PICR1_REG,
207 &picr1);
208
209 picr1 = (picr1 & ~MPC10X_CFG_PICR1_ADDR_MAP_MASK) |
210 picr1_bit;
211
212 early_write_config_dword(hose,
213 0,
214 PCI_DEVFN(0,0),
215 MPC10X_CFG_PICR1_REG,
216 picr1);
217
218 asm volatile("sync");
219
220 /* Undo old mappings & map in new cfg data/addr regs */
221 iounmap((void *)hose->cfg_addr);
222 iounmap((void *)hose->cfg_data);
223
224 setup_indirect_pci(hose,
225 pci_config_addr,
226 pci_config_data);
227 }
228
229 /* Setup resources to match map */
230 mpc10x_bridge_set_resources(new_map, hose);
231
232 /*
233 * Want processor accesses of 0xFDxxxxxx to be mapped
234 * to PCI memory space at 0x00000000. Do not want
235 * host bridge to respond to PCI memory accesses of
236 * 0xFDxxxxxx. Do not want host bridge to respond
237 * to PCI memory addresses 0xFD000000-0xFDFFFFFF;
238 * want processor accesses from 0x000A0000-0x000BFFFF
239 * to be forwarded to system memory.
240 *
241 * Only valid if not in agent mode and using MAP B.
242 */
243 if (new_map == MPC10X_MEM_MAP_B) {
244 early_read_config_byte(hose,
245 0,
246 PCI_DEVFN(0,0),
247 MPC10X_CFG_MAPB_OPTIONS_REG,
248 &byte);
249
250 byte &= ~(MPC10X_CFG_MAPB_OPTIONS_PFAE |
251 MPC10X_CFG_MAPB_OPTIONS_PCICH |
252 MPC10X_CFG_MAPB_OPTIONS_PROCCH);
253
254 if (host_bridge != MPC10X_BRIDGE_106) {
255 byte |= MPC10X_CFG_MAPB_OPTIONS_CFAE;
256 }
257
258 early_write_config_byte(hose,
259 0,
260 PCI_DEVFN(0,0),
261 MPC10X_CFG_MAPB_OPTIONS_REG,
262 byte);
263 }
264
265 if (host_bridge != MPC10X_BRIDGE_106) {
266 early_read_config_byte(hose,
267 0,
268 PCI_DEVFN(0,0),
269 MPC10X_CFG_PIR_REG,
270 &pir);
271
272 if (pir != MPC10X_CFG_PIR_HOST_BRIDGE) {
273 printk("Host bridge in Agent mode\n");
274 /* Read or Set LMBAR & PCSRBAR? */
275 }
276
277 /* Set base addr of the 8240/107 EUMB. */
278 early_write_config_dword(hose,
279 0,
280 PCI_DEVFN(0,0),
281 MPC10X_CFG_EUMBBAR,
282 phys_eumb_base);
283#ifdef CONFIG_MPC10X_OPENPIC
284 /* Map EPIC register part of EUMB into vitual memory - PCORE
285 uses an i8259 instead of EPIC. */
286 OpenPIC_Addr =
287 ioremap(phys_eumb_base + MPC10X_EUMB_EPIC_OFFSET,
288 MPC10X_EUMB_EPIC_SIZE);
289#endif
290 mpc10x_i2c_ocp.paddr = phys_eumb_base + MPC10X_EUMB_I2C_OFFSET;
291 mpc10x_i2c_ocp.irq = MPC10X_I2C_IRQ;
292 ocp_add_one_device(&mpc10x_i2c_ocp);
293 mpc10x_dma_ocp[0].paddr = phys_eumb_base +
294 MPC10X_EUMB_DMA_OFFSET + 0x100;
295 mpc10x_dma_ocp[0].irq = MPC10X_DMA0_IRQ;
296 ocp_add_one_device(&mpc10x_dma_ocp[0]);
297 mpc10x_dma_ocp[1].paddr = phys_eumb_base +
298 MPC10X_EUMB_DMA_OFFSET + 0x200;
299 mpc10x_dma_ocp[1].irq = MPC10X_DMA1_IRQ;
300 ocp_add_one_device(&mpc10x_dma_ocp[1]);
301 }
302
303#ifdef CONFIG_MPC10X_STORE_GATHERING
304 mpc10x_enable_store_gathering(hose);
305#else
306 mpc10x_disable_store_gathering(hose);
307#endif
308
309 /*
310 * 8240 erratum 26, 8241/8245 erratum 29, 107 erratum 23: speculative
311 * PCI reads may return stale data so turn off.
312 */
313 if ((host_bridge == MPC10X_BRIDGE_8240)
314 || (host_bridge == MPC10X_BRIDGE_8245)
315 || (host_bridge == MPC10X_BRIDGE_107)) {
316
317 early_read_config_dword(hose, 0, PCI_DEVFN(0,0),
318 MPC10X_CFG_PICR1_REG, &picr1);
319
320 picr1 &= ~MPC10X_CFG_PICR1_SPEC_PCI_RD;
321
322 early_write_config_dword(hose, 0, PCI_DEVFN(0,0),
323 MPC10X_CFG_PICR1_REG, picr1);
324 }
325
326 /*
327 * 8241/8245 erratum 28: PCI reads from local memory may return
328 * stale data. Workaround by setting PICR2[0] to disable copyback
329 * optimization. Oddly, the latest available user manual for the
330 * 8245 (Rev 2., dated 10/2003) says PICR2[0] is reserverd.
331 */
332 if (host_bridge == MPC10X_BRIDGE_8245) {
333 ulong picr2;
334
335 early_read_config_dword(hose, 0, PCI_DEVFN(0,0),
336 MPC10X_CFG_PICR2_REG, &picr2);
337
338 picr2 |= MPC10X_CFG_PICR2_COPYBACK_OPT;
339
340 early_write_config_dword(hose, 0, PCI_DEVFN(0,0),
341 MPC10X_CFG_PICR2_REG, picr2);
342 }
343
344 if (ppc_md.progress) ppc_md.progress("mpc10x:exit", 0x100);
345 return 0;
346}
347
348/*
349 * Need to make our own PCI config space access macros because
350 * mpc10x_get_mem_size() is called before the data structures are set up for
351 * the 'early_xxx' and 'indirect_xxx' routines to work.
352 * Assumes bus 0.
353 */
354#define MPC10X_CFG_read(val, addr, type, op) *val = op((type)(addr))
355#define MPC10X_CFG_write(val, addr, type, op) op((type *)(addr), (val))
356
357#define MPC10X_PCI_OP(rw, size, type, op, mask) \
358static void \
359mpc10x_##rw##_config_##size(uint *cfg_addr, uint *cfg_data, int devfn, int offset, type val) \
360{ \
361 out_be32(cfg_addr, \
362 ((offset & 0xfc) << 24) | (devfn << 16) \
363 | (0 << 8) | 0x80); \
364 MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op); \
365 return; \
366}
367
368MPC10X_PCI_OP(read, byte, u8 *, in_8, 3)
369MPC10X_PCI_OP(read, dword, u32 *, in_le32, 0)
370#if 0 /* Not used */
371MPC10X_PCI_OP(write, byte, u8, out_8, 3)
372MPC10X_PCI_OP(read, word, u16 *, in_le16, 2)
373MPC10X_PCI_OP(write, word, u16, out_le16, 2)
374MPC10X_PCI_OP(write, dword, u32, out_le32, 0)
375#endif
376
377/*
378 * Read the memory controller registers to determine the amount of memory in
379 * the system. This assumes that the firmware has correctly set up the memory
380 * controller registers.
381 */
382unsigned long __init
383mpc10x_get_mem_size(uint mem_map)
384{
385 uint *config_addr, *config_data, val;
386 ulong start, end, total, offset;
387 int i;
388 u_char bank_enables;
389
390 switch (mem_map) {
391 case MPC10X_MEM_MAP_A:
392 config_addr = (uint *)MPC10X_MAPA_CNFG_ADDR;
393 config_data = (uint *)MPC10X_MAPA_CNFG_DATA;
394 break;
395 case MPC10X_MEM_MAP_B:
396 config_addr = (uint *)MPC10X_MAPB_CNFG_ADDR;
397 config_data = (uint *)MPC10X_MAPB_CNFG_DATA;
398 break;
399 default:
400 return 0;
401 }
402
403 mpc10x_read_config_byte(config_addr,
404 config_data,
405 PCI_DEVFN(0,0),
406 MPC10X_MCTLR_MEM_BANK_ENABLES,
407 &bank_enables);
408
409 total = 0;
410
411 for (i=0; i<8; i++) {
412 if (bank_enables & (1 << i)) {
413 offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
414 mpc10x_read_config_dword(config_addr,
415 config_data,
416 PCI_DEVFN(0,0),
417 offset,
418 &val);
419 start = (val >> ((i & 3) << 3)) & 0xff;
420
421 offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
422 mpc10x_read_config_dword(config_addr,
423 config_data,
424 PCI_DEVFN(0,0),
425 offset,
426 &val);
427 val = (val >> ((i & 3) << 3)) & 0x03;
428 start = (val << 28) | (start << 20);
429
430 offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
431 mpc10x_read_config_dword(config_addr,
432 config_data,
433 PCI_DEVFN(0,0),
434 offset,
435 &val);
436 end = (val >> ((i & 3) << 3)) & 0xff;
437
438 offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
439 mpc10x_read_config_dword(config_addr,
440 config_data,
441 PCI_DEVFN(0,0),
442 offset,
443 &val);
444 val = (val >> ((i & 3) << 3)) & 0x03;
445 end = (val << 28) | (end << 20) | 0xfffff;
446
447 total += (end - start + 1);
448 }
449 }
450
451 return total;
452}
453
454int __init
455mpc10x_enable_store_gathering(struct pci_controller *hose)
456{
457 uint picr1;
458
459 early_read_config_dword(hose,
460 0,
461 PCI_DEVFN(0,0),
462 MPC10X_CFG_PICR1_REG,
463 &picr1);
464
465 picr1 |= MPC10X_CFG_PICR1_ST_GATH_EN;
466
467 early_write_config_dword(hose,
468 0,
469 PCI_DEVFN(0,0),
470 MPC10X_CFG_PICR1_REG,
471 picr1);
472
473 return 0;
474}
475
476int __init
477mpc10x_disable_store_gathering(struct pci_controller *hose)
478{
479 uint picr1;
480
481 early_read_config_dword(hose,
482 0,
483 PCI_DEVFN(0,0),
484 MPC10X_CFG_PICR1_REG,
485 &picr1);
486
487 picr1 &= ~MPC10X_CFG_PICR1_ST_GATH_EN;
488
489 early_write_config_dword(hose,
490 0,
491 PCI_DEVFN(0,0),
492 MPC10X_CFG_PICR1_REG,
493 picr1);
494
495 return 0;
496}
497
498#ifdef CONFIG_MPC10X_OPENPIC
499void __init mpc10x_set_openpic(void)
500{
501 /* Map external IRQs */
502 openpic_set_sources(0, EPIC_IRQ_BASE, OpenPIC_Addr + 0x10200);
503 /* Skip reserved space and map i2c and DMA Ch[01] */
504 openpic_set_sources(EPIC_IRQ_BASE, 3, OpenPIC_Addr + 0x11020);
505 /* Skip reserved space and map Message Unit Interrupt (I2O) */
506 openpic_set_sources(EPIC_IRQ_BASE + 3, 1, OpenPIC_Addr + 0x110C0);
507
508 openpic_init(NUM_8259_INTERRUPTS);
509}
510#endif
diff --git a/arch/ppc/syslib/mpc52xx_devices.c b/arch/ppc/syslib/mpc52xx_devices.c
new file mode 100644
index 000000000000..ad5182efca1d
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_devices.c
@@ -0,0 +1,318 @@
1/*
2 * arch/ppc/syslib/mpc52xx_devices.c
3 *
4 * Freescale MPC52xx device descriptions
5 *
6 *
7 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
8 *
9 * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
10 *
11 * This file is licensed under the terms of the GNU General Public License
12 * version 2. This program is licensed "as is" without any warranty of any
13 * kind, whether express or implied.
14 */
15
16#include <linux/fsl_devices.h>
17#include <linux/resource.h>
18#include <asm/mpc52xx.h>
19#include <asm/ppc_sys.h>
20
21
22static u64 mpc52xx_dma_mask = 0xffffffffULL;
23
24static struct fsl_i2c_platform_data mpc52xx_fsl_i2c_pdata = {
25 .device_flags = FSL_I2C_DEV_CLOCK_5200,
26};
27
28
29/* We use relative offsets for IORESOURCE_MEM to be independent from the
30 * MBAR location at compile time
31 */
32
33/* TODO Add the BestComm initiator channel to the device definitions,
34 possibly using IORESOURCE_DMA. But that's when BestComm is ready ... */
35
36struct platform_device ppc_sys_platform_devices[] = {
37 [MPC52xx_MSCAN1] = {
38 .name = "mpc52xx-mscan",
39 .id = 0,
40 .num_resources = 2,
41 .resource = (struct resource[]) {
42 {
43 .start = 0x0900,
44 .end = 0x097f,
45 .flags = IORESOURCE_MEM,
46 },
47 {
48 .start = MPC52xx_MSCAN1_IRQ,
49 .end = MPC52xx_MSCAN1_IRQ,
50 .flags = IORESOURCE_IRQ,
51 },
52 },
53 },
54 [MPC52xx_MSCAN2] = {
55 .name = "mpc52xx-mscan",
56 .id = 1,
57 .num_resources = 2,
58 .resource = (struct resource[]) {
59 {
60 .start = 0x0980,
61 .end = 0x09ff,
62 .flags = IORESOURCE_MEM,
63 },
64 {
65 .start = MPC52xx_MSCAN2_IRQ,
66 .end = MPC52xx_MSCAN2_IRQ,
67 .flags = IORESOURCE_IRQ,
68 },
69 },
70 },
71 [MPC52xx_SPI] = {
72 .name = "mpc52xx-spi",
73 .id = -1,
74 .num_resources = 3,
75 .resource = (struct resource[]) {
76 {
77 .start = 0x0f00,
78 .end = 0x0f1f,
79 .flags = IORESOURCE_MEM,
80 },
81 {
82 .name = "modf",
83 .start = MPC52xx_SPI_MODF_IRQ,
84 .end = MPC52xx_SPI_MODF_IRQ,
85 .flags = IORESOURCE_IRQ,
86 },
87 {
88 .name = "spif",
89 .start = MPC52xx_SPI_SPIF_IRQ,
90 .end = MPC52xx_SPI_SPIF_IRQ,
91 .flags = IORESOURCE_IRQ,
92 },
93 },
94 },
95 [MPC52xx_USB] = {
96 .name = "ppc-soc-ohci",
97 .id = -1,
98 .num_resources = 2,
99 .dev.dma_mask = &mpc52xx_dma_mask,
100 .dev.coherent_dma_mask = 0xffffffffULL,
101 .resource = (struct resource[]) {
102 {
103 .start = 0x1000,
104 .end = 0x10ff,
105 .flags = IORESOURCE_MEM,
106 },
107 {
108 .start = MPC52xx_USB_IRQ,
109 .end = MPC52xx_USB_IRQ,
110 .flags = IORESOURCE_IRQ,
111 },
112 },
113 },
114 [MPC52xx_BDLC] = {
115 .name = "mpc52xx-bdlc",
116 .id = -1,
117 .num_resources = 2,
118 .resource = (struct resource[]) {
119 {
120 .start = 0x1300,
121 .end = 0x130f,
122 .flags = IORESOURCE_MEM,
123 },
124 {
125 .start = MPC52xx_BDLC_IRQ,
126 .end = MPC52xx_BDLC_IRQ,
127 .flags = IORESOURCE_IRQ,
128 },
129 },
130 },
131 [MPC52xx_PSC1] = {
132 .name = "mpc52xx-psc",
133 .id = 0,
134 .num_resources = 2,
135 .resource = (struct resource[]) {
136 {
137 .start = 0x2000,
138 .end = 0x209f,
139 .flags = IORESOURCE_MEM,
140 },
141 {
142 .start = MPC52xx_PSC1_IRQ,
143 .end = MPC52xx_PSC1_IRQ,
144 .flags = IORESOURCE_IRQ,
145 },
146 },
147 },
148 [MPC52xx_PSC2] = {
149 .name = "mpc52xx-psc",
150 .id = 1,
151 .num_resources = 2,
152 .resource = (struct resource[]) {
153 {
154 .start = 0x2200,
155 .end = 0x229f,
156 .flags = IORESOURCE_MEM,
157 },
158 {
159 .start = MPC52xx_PSC2_IRQ,
160 .end = MPC52xx_PSC2_IRQ,
161 .flags = IORESOURCE_IRQ,
162 },
163 },
164 },
165 [MPC52xx_PSC3] = {
166 .name = "mpc52xx-psc",
167 .id = 2,
168 .num_resources = 2,
169 .resource = (struct resource[]) {
170 {
171 .start = 0x2400,
172 .end = 0x249f,
173 .flags = IORESOURCE_MEM,
174 },
175 {
176 .start = MPC52xx_PSC3_IRQ,
177 .end = MPC52xx_PSC3_IRQ,
178 .flags = IORESOURCE_IRQ,
179 },
180 },
181 },
182 [MPC52xx_PSC4] = {
183 .name = "mpc52xx-psc",
184 .id = 3,
185 .num_resources = 2,
186 .resource = (struct resource[]) {
187 {
188 .start = 0x2600,
189 .end = 0x269f,
190 .flags = IORESOURCE_MEM,
191 },
192 {
193 .start = MPC52xx_PSC4_IRQ,
194 .end = MPC52xx_PSC4_IRQ,
195 .flags = IORESOURCE_IRQ,
196 },
197 },
198 },
199 [MPC52xx_PSC5] = {
200 .name = "mpc52xx-psc",
201 .id = 4,
202 .num_resources = 2,
203 .resource = (struct resource[]) {
204 {
205 .start = 0x2800,
206 .end = 0x289f,
207 .flags = IORESOURCE_MEM,
208 },
209 {
210 .start = MPC52xx_PSC5_IRQ,
211 .end = MPC52xx_PSC5_IRQ,
212 .flags = IORESOURCE_IRQ,
213 },
214 },
215 },
216 [MPC52xx_PSC6] = {
217 .name = "mpc52xx-psc",
218 .id = 5,
219 .num_resources = 2,
220 .resource = (struct resource[]) {
221 {
222 .start = 0x2c00,
223 .end = 0x2c9f,
224 .flags = IORESOURCE_MEM,
225 },
226 {
227 .start = MPC52xx_PSC6_IRQ,
228 .end = MPC52xx_PSC6_IRQ,
229 .flags = IORESOURCE_IRQ,
230 },
231 },
232 },
233 [MPC52xx_FEC] = {
234 .name = "mpc52xx-fec",
235 .id = -1,
236 .num_resources = 2,
237 .resource = (struct resource[]) {
238 {
239 .start = 0x3000,
240 .end = 0x33ff,
241 .flags = IORESOURCE_MEM,
242 },
243 {
244 .start = MPC52xx_FEC_IRQ,
245 .end = MPC52xx_FEC_IRQ,
246 .flags = IORESOURCE_IRQ,
247 },
248 },
249 },
250 [MPC52xx_ATA] = {
251 .name = "mpc52xx-ata",
252 .id = -1,
253 .num_resources = 2,
254 .resource = (struct resource[]) {
255 {
256 .start = 0x3a00,
257 .end = 0x3aff,
258 .flags = IORESOURCE_MEM,
259 },
260 {
261 .start = MPC52xx_ATA_IRQ,
262 .end = MPC52xx_ATA_IRQ,
263 .flags = IORESOURCE_IRQ,
264 },
265 },
266 },
267 [MPC52xx_I2C1] = {
268 .name = "fsl-i2c",
269 .id = 0,
270 .dev.platform_data = &mpc52xx_fsl_i2c_pdata,
271 .num_resources = 2,
272 .resource = (struct resource[]) {
273 {
274 .start = 0x3d00,
275 .end = 0x3d1f,
276 .flags = IORESOURCE_MEM,
277 },
278 {
279 .start = MPC52xx_I2C1_IRQ,
280 .end = MPC52xx_I2C1_IRQ,
281 .flags = IORESOURCE_IRQ,
282 },
283 },
284 },
285 [MPC52xx_I2C2] = {
286 .name = "fsl-i2c",
287 .id = 1,
288 .dev.platform_data = &mpc52xx_fsl_i2c_pdata,
289 .num_resources = 2,
290 .resource = (struct resource[]) {
291 {
292 .start = 0x3d40,
293 .end = 0x3d5f,
294 .flags = IORESOURCE_MEM,
295 },
296 {
297 .start = MPC52xx_I2C2_IRQ,
298 .end = MPC52xx_I2C2_IRQ,
299 .flags = IORESOURCE_IRQ,
300 },
301 },
302 },
303};
304
305
306static int __init mach_mpc52xx_fixup(struct platform_device *pdev)
307{
308 ppc_sys_fixup_mem_resource(pdev, MPC52xx_MBAR);
309 return 0;
310}
311
312static int __init mach_mpc52xx_init(void)
313{
314 ppc_sys_device_fixup = mach_mpc52xx_fixup;
315 return 0;
316}
317
318postcore_initcall(mach_mpc52xx_init);
diff --git a/arch/ppc/syslib/mpc52xx_pci.c b/arch/ppc/syslib/mpc52xx_pci.c
new file mode 100644
index 000000000000..c723efd954a6
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_pci.c
@@ -0,0 +1,235 @@
1/*
2 * arch/ppc/syslib/mpc52xx_pci.c
3 *
4 * PCI code for the Freescale MPC52xx embedded CPU.
5 *
6 *
7 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
8 *
9 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
10 *
11 * This file is licensed under the terms of the GNU General Public License
12 * version 2. This program is licensed "as is" without any warranty of any
13 * kind, whether express or implied.
14 */
15
16#include <linux/config.h>
17
18#include <asm/pci.h>
19
20#include <asm/mpc52xx.h>
21#include "mpc52xx_pci.h"
22
23#include <asm/delay.h>
24
25
26static int
27mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
28 int offset, int len, u32 *val)
29{
30 struct pci_controller *hose = bus->sysdata;
31 u32 value;
32
33 if (ppc_md.pci_exclude_device)
34 if (ppc_md.pci_exclude_device(bus->number, devfn))
35 return PCIBIOS_DEVICE_NOT_FOUND;
36
37 out_be32(hose->cfg_addr,
38 (1 << 31) |
39 ((bus->number - hose->bus_offset) << 16) |
40 (devfn << 8) |
41 (offset & 0xfc));
42
43 value = in_le32(hose->cfg_data);
44
45 if (len != 4) {
46 value >>= ((offset & 0x3) << 3);
47 value &= 0xffffffff >> (32 - (len << 3));
48 }
49
50 *val = value;
51
52 out_be32(hose->cfg_addr, 0);
53
54 return PCIBIOS_SUCCESSFUL;
55}
56
57static int
58mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
59 int offset, int len, u32 val)
60{
61 struct pci_controller *hose = bus->sysdata;
62 u32 value, mask;
63
64 if (ppc_md.pci_exclude_device)
65 if (ppc_md.pci_exclude_device(bus->number, devfn))
66 return PCIBIOS_DEVICE_NOT_FOUND;
67
68 out_be32(hose->cfg_addr,
69 (1 << 31) |
70 ((bus->number - hose->bus_offset) << 16) |
71 (devfn << 8) |
72 (offset & 0xfc));
73
74 if (len != 4) {
75 value = in_le32(hose->cfg_data);
76
77 offset = (offset & 0x3) << 3;
78 mask = (0xffffffff >> (32 - (len << 3)));
79 mask <<= offset;
80
81 value &= ~mask;
82 val = value | ((val << offset) & mask);
83 }
84
85 out_le32(hose->cfg_data, val);
86
87 out_be32(hose->cfg_addr, 0);
88
89 return PCIBIOS_SUCCESSFUL;
90}
91
92static struct pci_ops mpc52xx_pci_ops = {
93 .read = mpc52xx_pci_read_config,
94 .write = mpc52xx_pci_write_config
95};
96
97
98static void __init
99mpc52xx_pci_setup(struct mpc52xx_pci __iomem *pci_regs)
100{
101
102 /* Setup control regs */
103 /* Nothing to do afaik */
104
105 /* Setup windows */
106 out_be32(&pci_regs->iw0btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
107 MPC52xx_PCI_MEM_START + MPC52xx_PCI_MEM_OFFSET,
108 MPC52xx_PCI_MEM_START,
109 MPC52xx_PCI_MEM_SIZE ));
110
111 out_be32(&pci_regs->iw1btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
112 MPC52xx_PCI_MMIO_START + MPC52xx_PCI_MEM_OFFSET,
113 MPC52xx_PCI_MMIO_START,
114 MPC52xx_PCI_MMIO_SIZE ));
115
116 out_be32(&pci_regs->iw2btar, MPC52xx_PCI_IWBTAR_TRANSLATION(
117 MPC52xx_PCI_IO_BASE,
118 MPC52xx_PCI_IO_START,
119 MPC52xx_PCI_IO_SIZE ));
120
121 out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(
122 ( MPC52xx_PCI_IWCR_ENABLE | /* iw0btar */
123 MPC52xx_PCI_IWCR_READ_MULTI |
124 MPC52xx_PCI_IWCR_MEM ),
125 ( MPC52xx_PCI_IWCR_ENABLE | /* iw1btar */
126 MPC52xx_PCI_IWCR_READ |
127 MPC52xx_PCI_IWCR_MEM ),
128 ( MPC52xx_PCI_IWCR_ENABLE | /* iw2btar */
129 MPC52xx_PCI_IWCR_IO )
130 ));
131
132
133 out_be32(&pci_regs->tbatr0,
134 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
135 out_be32(&pci_regs->tbatr1,
136 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
137
138 out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
139
140 /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
141 /* Not necessary and can be a bad thing if for example the bootloader
142 is displaying a splash screen or ... Just left here for
143 documentation purpose if anyone need it */
144#if 0
145 u32 tmp;
146 tmp = in_be32(&pci_regs->gscr);
147 out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
148 udelay(50);
149 out_be32(&pci_regs->gscr, tmp);
150#endif
151}
152
153static void __init
154mpc52xx_pci_fixup_resources(struct pci_dev *dev)
155{
156 int i;
157
158 /* We don't rely on boot loader for PCI and resets all
159 devices */
160 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
161 struct resource *res = &dev->resource[i];
162 if (res->end > res->start) { /* Only valid resources */
163 res->end -= res->start;
164 res->start = 0;
165 res->flags |= IORESOURCE_UNSET;
166 }
167 }
168
169 /* The PCI Host bridge of MPC52xx has a prefetch memory resource
170 fixed to 1Gb. Doesn't fit in the resource system so we remove it */
171 if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
172 (dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200) ) {
173 struct resource *res = &dev->resource[1];
174 res->start = res->end = res->flags = 0;
175 }
176}
177
178void __init
179mpc52xx_find_bridges(void)
180{
181 struct mpc52xx_pci __iomem *pci_regs;
182 struct pci_controller *hose;
183
184 pci_assign_all_busses = 1;
185
186 pci_regs = ioremap(MPC52xx_PA(MPC52xx_PCI_OFFSET), MPC52xx_PCI_SIZE);
187 if (!pci_regs)
188 return;
189
190 hose = pcibios_alloc_controller();
191 if (!hose) {
192 iounmap(pci_regs);
193 return;
194 }
195
196 ppc_md.pci_swizzle = common_swizzle;
197 ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
198
199 hose->first_busno = 0;
200 hose->last_busno = 0xff;
201 hose->bus_offset = 0;
202 hose->ops = &mpc52xx_pci_ops;
203
204 mpc52xx_pci_setup(pci_regs);
205
206 hose->pci_mem_offset = MPC52xx_PCI_MEM_OFFSET;
207
208 isa_io_base =
209 (unsigned long) ioremap(MPC52xx_PCI_IO_BASE,
210 MPC52xx_PCI_IO_SIZE);
211 hose->io_base_virt = (void *) isa_io_base;
212
213 hose->cfg_addr = &pci_regs->car;
214 hose->cfg_data = (void __iomem *) isa_io_base;
215
216 /* Setup resources */
217 pci_init_resource(&hose->mem_resources[0],
218 MPC52xx_PCI_MEM_START,
219 MPC52xx_PCI_MEM_STOP,
220 IORESOURCE_MEM|IORESOURCE_PREFETCH,
221 "PCI prefetchable memory");
222
223 pci_init_resource(&hose->mem_resources[1],
224 MPC52xx_PCI_MMIO_START,
225 MPC52xx_PCI_MMIO_STOP,
226 IORESOURCE_MEM,
227 "PCI memory");
228
229 pci_init_resource(&hose->io_resource,
230 MPC52xx_PCI_IO_START,
231 MPC52xx_PCI_IO_STOP,
232 IORESOURCE_IO,
233 "PCI I/O");
234
235}
diff --git a/arch/ppc/syslib/mpc52xx_pci.h b/arch/ppc/syslib/mpc52xx_pci.h
new file mode 100644
index 000000000000..04b509a02530
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_pci.h
@@ -0,0 +1,139 @@
1/*
2 * arch/ppc/syslib/mpc52xx_pci.h
3 *
4 * PCI Include file the Freescale MPC52xx embedded cpu chips
5 *
6 *
7 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
8 *
9 * Inspired from code written by Dale Farnsworth <dfarnsworth@mvista.com>
10 * for the 2.4 kernel.
11 *
12 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
13 * Copyright (C) 2003 MontaVista, Software, Inc.
14 *
15 * This file is licensed under the terms of the GNU General Public License
16 * version 2. This program is licensed "as is" without any warranty of any
17 * kind, whether express or implied.
18 */
19
20#ifndef __SYSLIB_MPC52xx_PCI_H__
21#define __SYSLIB_MPC52xx_PCI_H__
22
23/* ======================================================================== */
24/* PCI windows config */
25/* ======================================================================== */
26
27/*
28 * Master windows : MPC52xx -> PCI
29 *
30 * 0x80000000 -> 0x9FFFFFFF PCI Mem prefetchable IW0BTAR
31 * 0xA0000000 -> 0xAFFFFFFF PCI Mem IW1BTAR
32 * 0xB0000000 -> 0xB0FFFFFF PCI IO IW2BTAR
33 *
34 * Slave windows : PCI -> MPC52xx
35 *
36 * 0xF0000000 -> 0xF003FFFF MPC52xx MBAR TBATR0
37 * 0x00000000 -> 0x3FFFFFFF MPC52xx local memory TBATR1
38 */
39
40#define MPC52xx_PCI_MEM_OFFSET 0x00000000 /* Offset for MEM MMIO */
41
42#define MPC52xx_PCI_MEM_START 0x80000000
43#define MPC52xx_PCI_MEM_SIZE 0x20000000
44#define MPC52xx_PCI_MEM_STOP (MPC52xx_PCI_MEM_START+MPC52xx_PCI_MEM_SIZE-1)
45
46#define MPC52xx_PCI_MMIO_START 0xa0000000
47#define MPC52xx_PCI_MMIO_SIZE 0x10000000
48#define MPC52xx_PCI_MMIO_STOP (MPC52xx_PCI_MMIO_START+MPC52xx_PCI_MMIO_SIZE-1)
49
50#define MPC52xx_PCI_IO_BASE 0xb0000000
51
52#define MPC52xx_PCI_IO_START 0x00000000
53#define MPC52xx_PCI_IO_SIZE 0x01000000
54#define MPC52xx_PCI_IO_STOP (MPC52xx_PCI_IO_START+MPC52xx_PCI_IO_SIZE-1)
55
56
57#define MPC52xx_PCI_TARGET_IO MPC52xx_MBAR
58#define MPC52xx_PCI_TARGET_MEM 0x00000000
59
60
61/* ======================================================================== */
62/* Structures mapping & Defines for PCI Unit */
63/* ======================================================================== */
64
65#define MPC52xx_PCI_GSCR_BM 0x40000000
66#define MPC52xx_PCI_GSCR_PE 0x20000000
67#define MPC52xx_PCI_GSCR_SE 0x10000000
68#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000
69#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24
70#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000
71#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16
72#define MPC52xx_PCI_GSCR_BME 0x00004000
73#define MPC52xx_PCI_GSCR_PEE 0x00002000
74#define MPC52xx_PCI_GSCR_SEE 0x00001000
75#define MPC52xx_PCI_GSCR_PR 0x00000001
76
77
78#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \
79 ( ( (proc_ad) & 0xff000000 ) | \
80 ( (((size) - 1) >> 8) & 0x00ff0000 ) | \
81 ( ((pci_ad) >> 16) & 0x0000ff00 ) )
82
83#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \
84 ((win1) << 16) | \
85 ((win2) << 8))
86
87#define MPC52xx_PCI_IWCR_DISABLE 0x0
88#define MPC52xx_PCI_IWCR_ENABLE 0x1
89#define MPC52xx_PCI_IWCR_READ 0x0
90#define MPC52xx_PCI_IWCR_READ_LINE 0x2
91#define MPC52xx_PCI_IWCR_READ_MULTI 0x4
92#define MPC52xx_PCI_IWCR_MEM 0x0
93#define MPC52xx_PCI_IWCR_IO 0x8
94
95#define MPC52xx_PCI_TCR_P 0x01000000
96#define MPC52xx_PCI_TCR_LD 0x00010000
97
98#define MPC52xx_PCI_TBATR_DISABLE 0x0
99#define MPC52xx_PCI_TBATR_ENABLE 0x1
100
101
102#ifndef __ASSEMBLY__
103
104struct mpc52xx_pci {
105 u32 idr; /* PCI + 0x00 */
106 u32 scr; /* PCI + 0x04 */
107 u32 ccrir; /* PCI + 0x08 */
108 u32 cr1; /* PCI + 0x0C */
109 u32 bar0; /* PCI + 0x10 */
110 u32 bar1; /* PCI + 0x14 */
111 u8 reserved1[16]; /* PCI + 0x18 */
112 u32 ccpr; /* PCI + 0x28 */
113 u32 sid; /* PCI + 0x2C */
114 u32 erbar; /* PCI + 0x30 */
115 u32 cpr; /* PCI + 0x34 */
116 u8 reserved2[4]; /* PCI + 0x38 */
117 u32 cr2; /* PCI + 0x3C */
118 u8 reserved3[32]; /* PCI + 0x40 */
119 u32 gscr; /* PCI + 0x60 */
120 u32 tbatr0; /* PCI + 0x64 */
121 u32 tbatr1; /* PCI + 0x68 */
122 u32 tcr; /* PCI + 0x6C */
123 u32 iw0btar; /* PCI + 0x70 */
124 u32 iw1btar; /* PCI + 0x74 */
125 u32 iw2btar; /* PCI + 0x78 */
126 u8 reserved4[4]; /* PCI + 0x7C */
127 u32 iwcr; /* PCI + 0x80 */
128 u32 icr; /* PCI + 0x84 */
129 u32 isr; /* PCI + 0x88 */
130 u32 arb; /* PCI + 0x8C */
131 u8 reserved5[104]; /* PCI + 0x90 */
132 u32 car; /* PCI + 0xF8 */
133 u8 reserved6[4]; /* PCI + 0xFC */
134};
135
136#endif /* __ASSEMBLY__ */
137
138
139#endif /* __SYSLIB_MPC52xx_PCI_H__ */
diff --git a/arch/ppc/syslib/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c
new file mode 100644
index 000000000000..4c4497e62517
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_pic.c
@@ -0,0 +1,257 @@
1/*
2 * arch/ppc/syslib/mpc52xx_pic.c
3 *
4 * Programmable Interrupt Controller functions for the Freescale MPC52xx
5 * embedded CPU.
6 *
7 *
8 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
9 *
10 * Based on (well, mostly copied from) the code from the 2.4 kernel by
11 * Dale Farnsworth <dfarnsworth@mvista.com> and Kent Borg.
12 *
13 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
14 * Copyright (C) 2003 Montavista Software, Inc
15 *
16 * This file is licensed under the terms of the GNU General Public License
17 * version 2. This program is licensed "as is" without any warranty of any
18 * kind, whether express or implied.
19 */
20
21#include <linux/stddef.h>
22#include <linux/init.h>
23#include <linux/sched.h>
24#include <linux/signal.h>
25#include <linux/stddef.h>
26#include <linux/delay.h>
27#include <linux/irq.h>
28
29#include <asm/io.h>
30#include <asm/processor.h>
31#include <asm/system.h>
32#include <asm/irq.h>
33#include <asm/mpc52xx.h>
34
35
36static struct mpc52xx_intr __iomem *intr;
37static struct mpc52xx_sdma __iomem *sdma;
38
39static void
40mpc52xx_ic_disable(unsigned int irq)
41{
42 u32 val;
43
44 if (irq == MPC52xx_IRQ0) {
45 val = in_be32(&intr->ctrl);
46 val &= ~(1 << 11);
47 out_be32(&intr->ctrl, val);
48 }
49 else if (irq < MPC52xx_IRQ1) {
50 BUG();
51 }
52 else if (irq <= MPC52xx_IRQ3) {
53 val = in_be32(&intr->ctrl);
54 val &= ~(1 << (10 - (irq - MPC52xx_IRQ1)));
55 out_be32(&intr->ctrl, val);
56 }
57 else if (irq < MPC52xx_SDMA_IRQ_BASE) {
58 val = in_be32(&intr->main_mask);
59 val |= 1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE));
60 out_be32(&intr->main_mask, val);
61 }
62 else if (irq < MPC52xx_PERP_IRQ_BASE) {
63 val = in_be32(&sdma->IntMask);
64 val |= 1 << (irq - MPC52xx_SDMA_IRQ_BASE);
65 out_be32(&sdma->IntMask, val);
66 }
67 else {
68 val = in_be32(&intr->per_mask);
69 val |= 1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE));
70 out_be32(&intr->per_mask, val);
71 }
72}
73
74static void
75mpc52xx_ic_enable(unsigned int irq)
76{
77 u32 val;
78
79 if (irq == MPC52xx_IRQ0) {
80 val = in_be32(&intr->ctrl);
81 val |= 1 << 11;
82 out_be32(&intr->ctrl, val);
83 }
84 else if (irq < MPC52xx_IRQ1) {
85 BUG();
86 }
87 else if (irq <= MPC52xx_IRQ3) {
88 val = in_be32(&intr->ctrl);
89 val |= 1 << (10 - (irq - MPC52xx_IRQ1));
90 out_be32(&intr->ctrl, val);
91 }
92 else if (irq < MPC52xx_SDMA_IRQ_BASE) {
93 val = in_be32(&intr->main_mask);
94 val &= ~(1 << (16 - (irq - MPC52xx_MAIN_IRQ_BASE)));
95 out_be32(&intr->main_mask, val);
96 }
97 else if (irq < MPC52xx_PERP_IRQ_BASE) {
98 val = in_be32(&sdma->IntMask);
99 val &= ~(1 << (irq - MPC52xx_SDMA_IRQ_BASE));
100 out_be32(&sdma->IntMask, val);
101 }
102 else {
103 val = in_be32(&intr->per_mask);
104 val &= ~(1 << (31 - (irq - MPC52xx_PERP_IRQ_BASE)));
105 out_be32(&intr->per_mask, val);
106 }
107}
108
109static void
110mpc52xx_ic_ack(unsigned int irq)
111{
112 u32 val;
113
114 /*
115 * Only some irqs are reset here, others in interrupting hardware.
116 */
117
118 switch (irq) {
119 case MPC52xx_IRQ0:
120 val = in_be32(&intr->ctrl);
121 val |= 0x08000000;
122 out_be32(&intr->ctrl, val);
123 break;
124 case MPC52xx_CCS_IRQ:
125 val = in_be32(&intr->enc_status);
126 val |= 0x00000400;
127 out_be32(&intr->enc_status, val);
128 break;
129 case MPC52xx_IRQ1:
130 val = in_be32(&intr->ctrl);
131 val |= 0x04000000;
132 out_be32(&intr->ctrl, val);
133 break;
134 case MPC52xx_IRQ2:
135 val = in_be32(&intr->ctrl);
136 val |= 0x02000000;
137 out_be32(&intr->ctrl, val);
138 break;
139 case MPC52xx_IRQ3:
140 val = in_be32(&intr->ctrl);
141 val |= 0x01000000;
142 out_be32(&intr->ctrl, val);
143 break;
144 default:
145 if (irq >= MPC52xx_SDMA_IRQ_BASE
146 && irq < (MPC52xx_SDMA_IRQ_BASE + MPC52xx_SDMA_IRQ_NUM)) {
147 out_be32(&sdma->IntPend,
148 1 << (irq - MPC52xx_SDMA_IRQ_BASE));
149 }
150 break;
151 }
152}
153
154static void
155mpc52xx_ic_disable_and_ack(unsigned int irq)
156{
157 mpc52xx_ic_disable(irq);
158 mpc52xx_ic_ack(irq);
159}
160
161static void
162mpc52xx_ic_end(unsigned int irq)
163{
164 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
165 mpc52xx_ic_enable(irq);
166}
167
168static struct hw_interrupt_type mpc52xx_ic = {
169 .typename = " MPC52xx ",
170 .enable = mpc52xx_ic_enable,
171 .disable = mpc52xx_ic_disable,
172 .ack = mpc52xx_ic_disable_and_ack,
173 .end = mpc52xx_ic_end,
174};
175
176void __init
177mpc52xx_init_irq(void)
178{
179 int i;
180 u32 intr_ctrl;
181
182 /* Remap the necessary zones */
183 intr = ioremap(MPC52xx_PA(MPC52xx_INTR_OFFSET), MPC52xx_INTR_SIZE);
184 sdma = ioremap(MPC52xx_PA(MPC52xx_SDMA_OFFSET), MPC52xx_SDMA_SIZE);
185
186 if ((intr==NULL) || (sdma==NULL))
187 panic("Can't ioremap PIC/SDMA register for init_irq !");
188
189 /* Disable all interrupt sources. */
190 out_be32(&sdma->IntPend, 0xffffffff); /* 1 means clear pending */
191 out_be32(&sdma->IntMask, 0xffffffff); /* 1 means disabled */
192 out_be32(&intr->per_mask, 0x7ffffc00); /* 1 means disabled */
193 out_be32(&intr->main_mask, 0x00010fff); /* 1 means disabled */
194 intr_ctrl = in_be32(&intr->ctrl);
195 intr_ctrl &= 0x00ff0000; /* Keeps IRQ[0-3] config */
196 intr_ctrl |= 0x0f000000 | /* clear IRQ 0-3 */
197 0x00001000 | /* MEE master external enable */
198 0x00000000 | /* 0 means disable IRQ 0-3 */
199 0x00000001; /* CEb route critical normally */
200 out_be32(&intr->ctrl, intr_ctrl);
201
202 /* Zero a bunch of the priority settings. */
203 out_be32(&intr->per_pri1, 0);
204 out_be32(&intr->per_pri2, 0);
205 out_be32(&intr->per_pri3, 0);
206 out_be32(&intr->main_pri1, 0);
207 out_be32(&intr->main_pri2, 0);
208
209 /* Initialize irq_desc[i].handler's with mpc52xx_ic. */
210 for (i = 0; i < NR_IRQS; i++) {
211 irq_desc[i].handler = &mpc52xx_ic;
212 irq_desc[i].status = IRQ_LEVEL;
213 }
214
215 #define IRQn_MODE(intr_ctrl,irq) (((intr_ctrl) >> (22-(i<<1))) & 0x03)
216 for (i=0 ; i<4 ; i++) {
217 int mode;
218 mode = IRQn_MODE(intr_ctrl,i);
219 if ((mode == 0x1) || (mode == 0x2))
220 irq_desc[i?MPC52xx_IRQ1+i-1:MPC52xx_IRQ0].status = 0;
221 }
222}
223
224int
225mpc52xx_get_irq(struct pt_regs *regs)
226{
227 u32 status;
228 int irq = -1;
229
230 status = in_be32(&intr->enc_status);
231
232 if (status & 0x00000400) { /* critical */
233 irq = (status >> 8) & 0x3;
234 if (irq == 2) /* high priority peripheral */
235 goto peripheral;
236 irq += MPC52xx_CRIT_IRQ_BASE;
237 }
238 else if (status & 0x00200000) { /* main */
239 irq = (status >> 16) & 0x1f;
240 if (irq == 4) /* low priority peripheral */
241 goto peripheral;
242 irq += MPC52xx_MAIN_IRQ_BASE;
243 }
244 else if (status & 0x20000000) { /* peripheral */
245peripheral:
246 irq = (status >> 24) & 0x1f;
247 if (irq == 0) { /* bestcomm */
248 status = in_be32(&sdma->IntPend);
249 irq = ffs(status) + MPC52xx_SDMA_IRQ_BASE-1;
250 }
251 else
252 irq += MPC52xx_PERP_IRQ_BASE;
253 }
254
255 return irq;
256}
257
diff --git a/arch/ppc/syslib/mpc52xx_setup.c b/arch/ppc/syslib/mpc52xx_setup.c
new file mode 100644
index 000000000000..bb2374585a7b
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_setup.c
@@ -0,0 +1,230 @@
1/*
2 * arch/ppc/syslib/mpc52xx_setup.c
3 *
4 * Common code for the boards based on Freescale MPC52xx embedded CPU.
5 *
6 *
7 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
8 *
9 * Support for other bootloaders than UBoot by Dale Farnsworth
10 * <dfarnsworth@mvista.com>
11 *
12 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
13 * Copyright (C) 2003 Montavista Software, Inc
14 *
15 * This file is licensed under the terms of the GNU General Public License
16 * version 2. This program is licensed "as is" without any warranty of any
17 * kind, whether express or implied.
18 */
19
20#include <linux/config.h>
21
22#include <asm/io.h>
23#include <asm/time.h>
24#include <asm/mpc52xx.h>
25#include <asm/mpc52xx_psc.h>
26#include <asm/pgtable.h>
27#include <asm/ppcboot.h>
28
29extern bd_t __res;
30
31static int core_mult[] = { /* CPU Frequency multiplier, taken */
32 0, 0, 0, 10, 20, 20, 25, 45, /* from the datasheet used to compute */
33 30, 55, 40, 50, 0, 60, 35, 0, /* CPU frequency from XLB freq and */
34 30, 25, 65, 10, 70, 20, 75, 45, /* external jumper config */
35 0, 55, 40, 50, 80, 60, 35, 0
36};
37
38void
39mpc52xx_restart(char *cmd)
40{
41 struct mpc52xx_gpt __iomem *gpt0 = MPC52xx_VA(MPC52xx_GPTx_OFFSET(0));
42
43 local_irq_disable();
44
45 /* Turn on the watchdog and wait for it to expire. It effectively
46 does a reset */
47 out_be32(&gpt0->count, 0x000000ff);
48 out_be32(&gpt0->mode, 0x00009004);
49
50 while (1);
51}
52
53void
54mpc52xx_halt(void)
55{
56 local_irq_disable();
57
58 while (1);
59}
60
61void
62mpc52xx_power_off(void)
63{
64 /* By default we don't have any way of shut down.
65 If a specific board wants to, it can set the power down
66 code to any hardware implementation dependent code */
67 mpc52xx_halt();
68}
69
70
71void __init
72mpc52xx_set_bat(void)
73{
74 /* Set BAT 2 to map the 0xf0000000 area */
75 /* This mapping is used during mpc52xx_progress,
76 * mpc52xx_find_end_of_memory, and UARTs/GPIO access for debug
77 */
78 mb();
79 mtspr(SPRN_DBAT2U, 0xf0001ffe);
80 mtspr(SPRN_DBAT2L, 0xf000002a);
81 mb();
82}
83
84void __init
85mpc52xx_map_io(void)
86{
87 /* Here we only map the MBAR */
88 io_block_mapping(
89 MPC52xx_MBAR_VIRT, MPC52xx_MBAR, MPC52xx_MBAR_SIZE, _PAGE_IO);
90}
91
92
93#ifdef CONFIG_SERIAL_TEXT_DEBUG
94#ifndef MPC52xx_PF_CONSOLE_PORT
95#error "mpc52xx PSC for console not selected"
96#endif
97
98static void
99mpc52xx_psc_putc(struct mpc52xx_psc __iomem *psc, unsigned char c)
100{
101 while (!(in_be16(&psc->mpc52xx_psc_status) &
102 MPC52xx_PSC_SR_TXRDY));
103 out_8(&psc->mpc52xx_psc_buffer_8, c);
104}
105
106void
107mpc52xx_progress(char *s, unsigned short hex)
108{
109 char c;
110 struct mpc52xx_psc __iomem *psc;
111
112 psc = MPC52xx_VA(MPC52xx_PSCx_OFFSET(MPC52xx_PF_CONSOLE_PORT));
113
114 while ((c = *s++) != 0) {
115 if (c == '\n')
116 mpc52xx_psc_putc(psc, '\r');
117 mpc52xx_psc_putc(psc, c);
118 }
119
120 mpc52xx_psc_putc(psc, '\r');
121 mpc52xx_psc_putc(psc, '\n');
122}
123
124#endif /* CONFIG_SERIAL_TEXT_DEBUG */
125
126
127unsigned long __init
128mpc52xx_find_end_of_memory(void)
129{
130 u32 ramsize = __res.bi_memsize;
131
132 /*
133 * if bootloader passed a memsize, just use it
134 * else get size from sdram config registers
135 */
136 if (ramsize == 0) {
137 struct mpc52xx_mmap_ctl __iomem *mmap_ctl;
138 u32 sdram_config_0, sdram_config_1;
139
140 /* Temp BAT2 mapping active when this is called ! */
141 mmap_ctl = MPC52xx_VA(MPC52xx_MMAP_CTL_OFFSET);
142
143 sdram_config_0 = in_be32(&mmap_ctl->sdram0);
144 sdram_config_1 = in_be32(&mmap_ctl->sdram1);
145
146 if ((sdram_config_0 & 0x1f) >= 0x13)
147 ramsize = 1 << ((sdram_config_0 & 0xf) + 17);
148
149 if (((sdram_config_1 & 0x1f) >= 0x13) &&
150 ((sdram_config_1 & 0xfff00000) == ramsize))
151 ramsize += 1 << ((sdram_config_1 & 0xf) + 17);
152 }
153
154 return ramsize;
155}
156
157void __init
158mpc52xx_calibrate_decr(void)
159{
160 int current_time, previous_time;
161 int tbl_start, tbl_end;
162 unsigned int xlbfreq, cpufreq, ipbfreq, pcifreq, divisor;
163
164 xlbfreq = __res.bi_busfreq;
165 /* if bootloader didn't pass bus frequencies, calculate them */
166 if (xlbfreq == 0) {
167 /* Get RTC & Clock manager modules */
168 struct mpc52xx_rtc __iomem *rtc;
169 struct mpc52xx_cdm __iomem *cdm;
170
171 rtc = ioremap(MPC52xx_PA(MPC52xx_RTC_OFFSET), MPC52xx_RTC_SIZE);
172 cdm = ioremap(MPC52xx_PA(MPC52xx_CDM_OFFSET), MPC52xx_CDM_SIZE);
173
174 if ((rtc==NULL) || (cdm==NULL))
175 panic("Can't ioremap RTC/CDM while computing bus freq");
176
177 /* Count bus clock during 1/64 sec */
178 out_be32(&rtc->dividers, 0x8f1f0000); /* Set RTC 64x faster */
179 previous_time = in_be32(&rtc->time);
180 while ((current_time = in_be32(&rtc->time)) == previous_time) ;
181 tbl_start = get_tbl();
182 previous_time = current_time;
183 while ((current_time = in_be32(&rtc->time)) == previous_time) ;
184 tbl_end = get_tbl();
185 out_be32(&rtc->dividers, 0xffff0000); /* Restore RTC */
186
187 /* Compute all frequency from that & CDM settings */
188 xlbfreq = (tbl_end - tbl_start) << 8;
189 cpufreq = (xlbfreq * core_mult[in_be32(&cdm->rstcfg)&0x1f])/10;
190 ipbfreq = (in_8(&cdm->ipb_clk_sel) & 1) ?
191 xlbfreq / 2 : xlbfreq;
192 switch (in_8(&cdm->pci_clk_sel) & 3) {
193 case 0:
194 pcifreq = ipbfreq;
195 break;
196 case 1:
197 pcifreq = ipbfreq / 2;
198 break;
199 default:
200 pcifreq = xlbfreq / 4;
201 break;
202 }
203 __res.bi_busfreq = xlbfreq;
204 __res.bi_intfreq = cpufreq;
205 __res.bi_ipbfreq = ipbfreq;
206 __res.bi_pcifreq = pcifreq;
207
208 /* Release mapping */
209 iounmap(rtc);
210 iounmap(cdm);
211 }
212
213 divisor = 4;
214
215 tb_ticks_per_jiffy = xlbfreq / HZ / divisor;
216 tb_to_us = mulhwu_scale_factor(xlbfreq / divisor, 1000000);
217}
218
219int mpc52xx_match_psc_function(int psc_idx, const char *func)
220{
221 struct mpc52xx_psc_func *cf = mpc52xx_psc_functions;
222
223 while ((cf->id != -1) && (cf->func != NULL)) {
224 if ((cf->id == psc_idx) && !strcmp(cf->func,func))
225 return 1;
226 cf++;
227 }
228
229 return 0;
230}
diff --git a/arch/ppc/syslib/mpc52xx_sys.c b/arch/ppc/syslib/mpc52xx_sys.c
new file mode 100644
index 000000000000..9a0f90aa8aac
--- /dev/null
+++ b/arch/ppc/syslib/mpc52xx_sys.c
@@ -0,0 +1,38 @@
1/*
2 * arch/ppc/syslib/mpc52xx_sys.c
3 *
4 * Freescale MPC52xx system descriptions
5 *
6 *
7 * Maintainer : Sylvain Munaut <tnt@246tNt.com>
8 *
9 * Copyright (C) 2005 Sylvain Munaut <tnt@246tNt.com>
10 *
11 * This file is licensed under the terms of the GNU General Public License
12 * version 2. This program is licensed "as is" without any warranty of any
13 * kind, whether express or implied.
14 */
15
16#include <asm/ppc_sys.h>
17
18struct ppc_sys_spec *cur_ppc_sys_spec;
19struct ppc_sys_spec ppc_sys_specs[] = {
20 {
21 .ppc_sys_name = "5200",
22 .mask = 0xffff0000,
23 .value = 0x80110000,
24 .num_devices = 15,
25 .device_list = (enum ppc_sys_devices[])
26 {
27 MPC52xx_MSCAN1, MPC52xx_MSCAN2, MPC52xx_SPI,
28 MPC52xx_USB, MPC52xx_BDLC, MPC52xx_PSC1, MPC52xx_PSC2,
29 MPC52xx_PSC3, MPC52xx_PSC4, MPC52xx_PSC5, MPC52xx_PSC6,
30 MPC52xx_FEC, MPC52xx_ATA, MPC52xx_I2C1, MPC52xx_I2C2,
31 },
32 },
33 { /* default match */
34 .ppc_sys_name = "",
35 .mask = 0x00000000,
36 .value = 0x00000000,
37 },
38};
diff --git a/arch/ppc/syslib/mpc83xx_devices.c b/arch/ppc/syslib/mpc83xx_devices.c
new file mode 100644
index 000000000000..5c1a919eaabf
--- /dev/null
+++ b/arch/ppc/syslib/mpc83xx_devices.c
@@ -0,0 +1,237 @@
1/*
2 * arch/ppc/platforms/83xx/mpc83xx_devices.c
3 *
4 * MPC83xx Device descriptions
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2005 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/device.h>
19#include <linux/serial_8250.h>
20#include <linux/fsl_devices.h>
21#include <asm/mpc83xx.h>
22#include <asm/irq.h>
23#include <asm/ppc_sys.h>
24
25/* We use offsets for IORESOURCE_MEM since we do not know at compile time
26 * what IMMRBAR is, will get fixed up by mach_mpc83xx_fixup
27 */
28
29static struct gianfar_platform_data mpc83xx_tsec1_pdata = {
30 .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
31 FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
32 FSL_GIANFAR_DEV_HAS_MULTI_INTR,
33 .phy_reg_addr = 0x24000,
34};
35
36static struct gianfar_platform_data mpc83xx_tsec2_pdata = {
37 .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
38 FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
39 FSL_GIANFAR_DEV_HAS_MULTI_INTR,
40 .phy_reg_addr = 0x24000,
41};
42
43static struct fsl_i2c_platform_data mpc83xx_fsl_i2c1_pdata = {
44 .device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
45};
46
47static struct fsl_i2c_platform_data mpc83xx_fsl_i2c2_pdata = {
48 .device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
49};
50
51static struct plat_serial8250_port serial_platform_data[] = {
52 [0] = {
53 .mapbase = 0x4500,
54 .irq = MPC83xx_IRQ_UART1,
55 .iotype = UPIO_MEM,
56 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
57 },
58 [1] = {
59 .mapbase = 0x4600,
60 .irq = MPC83xx_IRQ_UART2,
61 .iotype = UPIO_MEM,
62 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
63 },
64};
65
66struct platform_device ppc_sys_platform_devices[] = {
67 [MPC83xx_TSEC1] = {
68 .name = "fsl-gianfar",
69 .id = 1,
70 .dev.platform_data = &mpc83xx_tsec1_pdata,
71 .num_resources = 4,
72 .resource = (struct resource[]) {
73 {
74 .start = 0x24000,
75 .end = 0x24fff,
76 .flags = IORESOURCE_MEM,
77 },
78 {
79 .name = "tx",
80 .start = MPC83xx_IRQ_TSEC1_TX,
81 .end = MPC83xx_IRQ_TSEC1_TX,
82 .flags = IORESOURCE_IRQ,
83 },
84 {
85 .name = "rx",
86 .start = MPC83xx_IRQ_TSEC1_RX,
87 .end = MPC83xx_IRQ_TSEC1_RX,
88 .flags = IORESOURCE_IRQ,
89 },
90 {
91 .name = "error",
92 .start = MPC83xx_IRQ_TSEC1_ERROR,
93 .end = MPC83xx_IRQ_TSEC1_ERROR,
94 .flags = IORESOURCE_IRQ,
95 },
96 },
97 },
98 [MPC83xx_TSEC2] = {
99 .name = "fsl-gianfar",
100 .id = 2,
101 .dev.platform_data = &mpc83xx_tsec2_pdata,
102 .num_resources = 4,
103 .resource = (struct resource[]) {
104 {
105 .start = 0x25000,
106 .end = 0x25fff,
107 .flags = IORESOURCE_MEM,
108 },
109 {
110 .name = "tx",
111 .start = MPC83xx_IRQ_TSEC2_TX,
112 .end = MPC83xx_IRQ_TSEC2_TX,
113 .flags = IORESOURCE_IRQ,
114 },
115 {
116 .name = "rx",
117 .start = MPC83xx_IRQ_TSEC2_RX,
118 .end = MPC83xx_IRQ_TSEC2_RX,
119 .flags = IORESOURCE_IRQ,
120 },
121 {
122 .name = "error",
123 .start = MPC83xx_IRQ_TSEC2_ERROR,
124 .end = MPC83xx_IRQ_TSEC2_ERROR,
125 .flags = IORESOURCE_IRQ,
126 },
127 },
128 },
129 [MPC83xx_IIC1] = {
130 .name = "fsl-i2c",
131 .id = 1,
132 .dev.platform_data = &mpc83xx_fsl_i2c1_pdata,
133 .num_resources = 2,
134 .resource = (struct resource[]) {
135 {
136 .start = 0x3000,
137 .end = 0x30ff,
138 .flags = IORESOURCE_MEM,
139 },
140 {
141 .start = MPC83xx_IRQ_IIC1,
142 .end = MPC83xx_IRQ_IIC1,
143 .flags = IORESOURCE_IRQ,
144 },
145 },
146 },
147 [MPC83xx_IIC2] = {
148 .name = "fsl-i2c",
149 .id = 2,
150 .dev.platform_data = &mpc83xx_fsl_i2c2_pdata,
151 .num_resources = 2,
152 .resource = (struct resource[]) {
153 {
154 .start = 0x3100,
155 .end = 0x31ff,
156 .flags = IORESOURCE_MEM,
157 },
158 {
159 .start = MPC83xx_IRQ_IIC2,
160 .end = MPC83xx_IRQ_IIC2,
161 .flags = IORESOURCE_IRQ,
162 },
163 },
164 },
165 [MPC83xx_DUART] = {
166 .name = "serial8250",
167 .id = 0,
168 .dev.platform_data = serial_platform_data,
169 },
170 [MPC83xx_SEC2] = {
171 .name = "fsl-sec2",
172 .id = 1,
173 .num_resources = 2,
174 .resource = (struct resource[]) {
175 {
176 .start = 0x30000,
177 .end = 0x3ffff,
178 .flags = IORESOURCE_MEM,
179 },
180 {
181 .start = MPC83xx_IRQ_SEC2,
182 .end = MPC83xx_IRQ_SEC2,
183 .flags = IORESOURCE_IRQ,
184 },
185 },
186 },
187 [MPC83xx_USB2_DR] = {
188 .name = "fsl-usb2-dr",
189 .id = 1,
190 .num_resources = 2,
191 .resource = (struct resource[]) {
192 {
193 .start = 0x22000,
194 .end = 0x22fff,
195 .flags = IORESOURCE_MEM,
196 },
197 {
198 .start = MPC83xx_IRQ_USB2_DR,
199 .end = MPC83xx_IRQ_USB2_DR,
200 .flags = IORESOURCE_IRQ,
201 },
202 },
203 },
204 [MPC83xx_USB2_MPH] = {
205 .name = "fsl-usb2-mph",
206 .id = 1,
207 .num_resources = 2,
208 .resource = (struct resource[]) {
209 {
210 .start = 0x23000,
211 .end = 0x23fff,
212 .flags = IORESOURCE_MEM,
213 },
214 {
215 .start = MPC83xx_IRQ_USB2_MPH,
216 .end = MPC83xx_IRQ_USB2_MPH,
217 .flags = IORESOURCE_IRQ,
218 },
219 },
220 },
221};
222
223static int __init mach_mpc83xx_fixup(struct platform_device *pdev)
224{
225 ppc_sys_fixup_mem_resource(pdev, immrbar);
226 return 0;
227}
228
229static int __init mach_mpc83xx_init(void)
230{
231 if (ppc_md.progress)
232 ppc_md.progress("mach_mpc83xx_init:enter", 0);
233 ppc_sys_device_fixup = mach_mpc83xx_fixup;
234 return 0;
235}
236
237postcore_initcall(mach_mpc83xx_init);
diff --git a/arch/ppc/syslib/mpc83xx_sys.c b/arch/ppc/syslib/mpc83xx_sys.c
new file mode 100644
index 000000000000..29aa63350025
--- /dev/null
+++ b/arch/ppc/syslib/mpc83xx_sys.c
@@ -0,0 +1,100 @@
1/*
2 * arch/ppc/platforms/83xx/mpc83xx_sys.c
3 *
4 * MPC83xx System descriptions
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2005 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/device.h>
19#include <asm/ppc_sys.h>
20
21struct ppc_sys_spec *cur_ppc_sys_spec;
22struct ppc_sys_spec ppc_sys_specs[] = {
23 {
24 .ppc_sys_name = "8349E",
25 .mask = 0xFFFF0000,
26 .value = 0x80500000,
27 .num_devices = 8,
28 .device_list = (enum ppc_sys_devices[])
29 {
30 MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
31 MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
32 MPC83xx_USB2_DR, MPC83xx_USB2_MPH
33 },
34 },
35 {
36 .ppc_sys_name = "8349",
37 .mask = 0xFFFF0000,
38 .value = 0x80510000,
39 .num_devices = 7,
40 .device_list = (enum ppc_sys_devices[])
41 {
42 MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
43 MPC83xx_IIC2, MPC83xx_DUART,
44 MPC83xx_USB2_DR, MPC83xx_USB2_MPH
45 },
46 },
47 {
48 .ppc_sys_name = "8347E",
49 .mask = 0xFFFF0000,
50 .value = 0x80520000,
51 .num_devices = 8,
52 .device_list = (enum ppc_sys_devices[])
53 {
54 MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
55 MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
56 MPC83xx_USB2_DR, MPC83xx_USB2_MPH
57 },
58 },
59 {
60 .ppc_sys_name = "8347",
61 .mask = 0xFFFF0000,
62 .value = 0x80530000,
63 .num_devices = 7,
64 .device_list = (enum ppc_sys_devices[])
65 {
66 MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
67 MPC83xx_IIC2, MPC83xx_DUART,
68 MPC83xx_USB2_DR, MPC83xx_USB2_MPH
69 },
70 },
71 {
72 .ppc_sys_name = "8343E",
73 .mask = 0xFFFF0000,
74 .value = 0x80540000,
75 .num_devices = 7,
76 .device_list = (enum ppc_sys_devices[])
77 {
78 MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
79 MPC83xx_IIC2, MPC83xx_DUART, MPC83xx_SEC2,
80 MPC83xx_USB2_DR,
81 },
82 },
83 {
84 .ppc_sys_name = "8343",
85 .mask = 0xFFFF0000,
86 .value = 0x80550000,
87 .num_devices = 6,
88 .device_list = (enum ppc_sys_devices[])
89 {
90 MPC83xx_TSEC1, MPC83xx_TSEC2, MPC83xx_IIC1,
91 MPC83xx_IIC2, MPC83xx_DUART,
92 MPC83xx_USB2_DR,
93 },
94 },
95 { /* default match */
96 .ppc_sys_name = "",
97 .mask = 0x00000000,
98 .value = 0x00000000,
99 },
100};
diff --git a/arch/ppc/syslib/mpc85xx_devices.c b/arch/ppc/syslib/mpc85xx_devices.c
new file mode 100644
index 000000000000..a231795ee26f
--- /dev/null
+++ b/arch/ppc/syslib/mpc85xx_devices.c
@@ -0,0 +1,552 @@
1/*
2 * arch/ppc/platforms/85xx/mpc85xx_devices.c
3 *
4 * MPC85xx Device descriptions
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2005 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/device.h>
19#include <linux/serial_8250.h>
20#include <linux/fsl_devices.h>
21#include <asm/mpc85xx.h>
22#include <asm/irq.h>
23#include <asm/ppc_sys.h>
24
25/* We use offsets for IORESOURCE_MEM since we do not know at compile time
26 * what CCSRBAR is, will get fixed up by mach_mpc85xx_fixup
27 */
28
29static struct gianfar_platform_data mpc85xx_tsec1_pdata = {
30 .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
31 FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
32 FSL_GIANFAR_DEV_HAS_MULTI_INTR,
33 .phy_reg_addr = MPC85xx_ENET1_OFFSET,
34};
35
36static struct gianfar_platform_data mpc85xx_tsec2_pdata = {
37 .device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT |
38 FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON |
39 FSL_GIANFAR_DEV_HAS_MULTI_INTR,
40 .phy_reg_addr = MPC85xx_ENET1_OFFSET,
41};
42
43static struct gianfar_platform_data mpc85xx_fec_pdata = {
44 .phy_reg_addr = MPC85xx_ENET1_OFFSET,
45};
46
47static struct fsl_i2c_platform_data mpc85xx_fsl_i2c_pdata = {
48 .device_flags = FSL_I2C_DEV_SEPARATE_DFSRR,
49};
50
51static struct plat_serial8250_port serial_platform_data[] = {
52 [0] = {
53 .mapbase = 0x4500,
54 .irq = MPC85xx_IRQ_DUART,
55 .iotype = UPIO_MEM,
56 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ,
57 },
58 [1] = {
59 .mapbase = 0x4600,
60 .irq = MPC85xx_IRQ_DUART,
61 .iotype = UPIO_MEM,
62 .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ,
63 },
64};
65
66struct platform_device ppc_sys_platform_devices[] = {
67 [MPC85xx_TSEC1] = {
68 .name = "fsl-gianfar",
69 .id = 1,
70 .dev.platform_data = &mpc85xx_tsec1_pdata,
71 .num_resources = 4,
72 .resource = (struct resource[]) {
73 {
74 .start = MPC85xx_ENET1_OFFSET,
75 .end = MPC85xx_ENET1_OFFSET +
76 MPC85xx_ENET1_SIZE - 1,
77 .flags = IORESOURCE_MEM,
78 },
79 {
80 .name = "tx",
81 .start = MPC85xx_IRQ_TSEC1_TX,
82 .end = MPC85xx_IRQ_TSEC1_TX,
83 .flags = IORESOURCE_IRQ,
84 },
85 {
86 .name = "rx",
87 .start = MPC85xx_IRQ_TSEC1_RX,
88 .end = MPC85xx_IRQ_TSEC1_RX,
89 .flags = IORESOURCE_IRQ,
90 },
91 {
92 .name = "error",
93 .start = MPC85xx_IRQ_TSEC1_ERROR,
94 .end = MPC85xx_IRQ_TSEC1_ERROR,
95 .flags = IORESOURCE_IRQ,
96 },
97 },
98 },
99 [MPC85xx_TSEC2] = {
100 .name = "fsl-gianfar",
101 .id = 2,
102 .dev.platform_data = &mpc85xx_tsec2_pdata,
103 .num_resources = 4,
104 .resource = (struct resource[]) {
105 {
106 .start = MPC85xx_ENET2_OFFSET,
107 .end = MPC85xx_ENET2_OFFSET +
108 MPC85xx_ENET2_SIZE - 1,
109 .flags = IORESOURCE_MEM,
110 },
111 {
112 .name = "tx",
113 .start = MPC85xx_IRQ_TSEC2_TX,
114 .end = MPC85xx_IRQ_TSEC2_TX,
115 .flags = IORESOURCE_IRQ,
116 },
117 {
118 .name = "rx",
119 .start = MPC85xx_IRQ_TSEC2_RX,
120 .end = MPC85xx_IRQ_TSEC2_RX,
121 .flags = IORESOURCE_IRQ,
122 },
123 {
124 .name = "error",
125 .start = MPC85xx_IRQ_TSEC2_ERROR,
126 .end = MPC85xx_IRQ_TSEC2_ERROR,
127 .flags = IORESOURCE_IRQ,
128 },
129 },
130 },
131 [MPC85xx_FEC] = {
132 .name = "fsl-gianfar",
133 .id = 3,
134 .dev.platform_data = &mpc85xx_fec_pdata,
135 .num_resources = 2,
136 .resource = (struct resource[]) {
137 {
138 .start = MPC85xx_ENET3_OFFSET,
139 .end = MPC85xx_ENET3_OFFSET +
140 MPC85xx_ENET3_SIZE - 1,
141 .flags = IORESOURCE_MEM,
142
143 },
144 {
145 .start = MPC85xx_IRQ_FEC,
146 .end = MPC85xx_IRQ_FEC,
147 .flags = IORESOURCE_IRQ,
148 },
149 },
150 },
151 [MPC85xx_IIC1] = {
152 .name = "fsl-i2c",
153 .id = 1,
154 .dev.platform_data = &mpc85xx_fsl_i2c_pdata,
155 .num_resources = 2,
156 .resource = (struct resource[]) {
157 {
158 .start = MPC85xx_IIC1_OFFSET,
159 .end = MPC85xx_IIC1_OFFSET +
160 MPC85xx_IIC1_SIZE - 1,
161 .flags = IORESOURCE_MEM,
162 },
163 {
164 .start = MPC85xx_IRQ_IIC1,
165 .end = MPC85xx_IRQ_IIC1,
166 .flags = IORESOURCE_IRQ,
167 },
168 },
169 },
170 [MPC85xx_DMA0] = {
171 .name = "fsl-dma",
172 .id = 0,
173 .num_resources = 2,
174 .resource = (struct resource[]) {
175 {
176 .start = MPC85xx_DMA0_OFFSET,
177 .end = MPC85xx_DMA0_OFFSET +
178 MPC85xx_DMA0_SIZE - 1,
179 .flags = IORESOURCE_MEM,
180 },
181 {
182 .start = MPC85xx_IRQ_DMA0,
183 .end = MPC85xx_IRQ_DMA0,
184 .flags = IORESOURCE_IRQ,
185 },
186 },
187 },
188 [MPC85xx_DMA1] = {
189 .name = "fsl-dma",
190 .id = 1,
191 .num_resources = 2,
192 .resource = (struct resource[]) {
193 {
194 .start = MPC85xx_DMA1_OFFSET,
195 .end = MPC85xx_DMA1_OFFSET +
196 MPC85xx_DMA1_SIZE - 1,
197 .flags = IORESOURCE_MEM,
198 },
199 {
200 .start = MPC85xx_IRQ_DMA1,
201 .end = MPC85xx_IRQ_DMA1,
202 .flags = IORESOURCE_IRQ,
203 },
204 },
205 },
206 [MPC85xx_DMA2] = {
207 .name = "fsl-dma",
208 .id = 2,
209 .num_resources = 2,
210 .resource = (struct resource[]) {
211 {
212 .start = MPC85xx_DMA2_OFFSET,
213 .end = MPC85xx_DMA2_OFFSET +
214 MPC85xx_DMA2_SIZE - 1,
215 .flags = IORESOURCE_MEM,
216 },
217 {
218 .start = MPC85xx_IRQ_DMA2,
219 .end = MPC85xx_IRQ_DMA2,
220 .flags = IORESOURCE_IRQ,
221 },
222 },
223 },
224 [MPC85xx_DMA3] = {
225 .name = "fsl-dma",
226 .id = 3,
227 .num_resources = 2,
228 .resource = (struct resource[]) {
229 {
230 .start = MPC85xx_DMA3_OFFSET,
231 .end = MPC85xx_DMA3_OFFSET +
232 MPC85xx_DMA3_SIZE - 1,
233 .flags = IORESOURCE_MEM,
234 },
235 {
236 .start = MPC85xx_IRQ_DMA3,
237 .end = MPC85xx_IRQ_DMA3,
238 .flags = IORESOURCE_IRQ,
239 },
240 },
241 },
242 [MPC85xx_DUART] = {
243 .name = "serial8250",
244 .id = 0,
245 .dev.platform_data = serial_platform_data,
246 },
247 [MPC85xx_PERFMON] = {
248 .name = "fsl-perfmon",
249 .id = 1,
250 .num_resources = 2,
251 .resource = (struct resource[]) {
252 {
253 .start = MPC85xx_PERFMON_OFFSET,
254 .end = MPC85xx_PERFMON_OFFSET +
255 MPC85xx_PERFMON_SIZE - 1,
256 .flags = IORESOURCE_MEM,
257 },
258 {
259 .start = MPC85xx_IRQ_PERFMON,
260 .end = MPC85xx_IRQ_PERFMON,
261 .flags = IORESOURCE_IRQ,
262 },
263 },
264 },
265 [MPC85xx_SEC2] = {
266 .name = "fsl-sec2",
267 .id = 1,
268 .num_resources = 2,
269 .resource = (struct resource[]) {
270 {
271 .start = MPC85xx_SEC2_OFFSET,
272 .end = MPC85xx_SEC2_OFFSET +
273 MPC85xx_SEC2_SIZE - 1,
274 .flags = IORESOURCE_MEM,
275 },
276 {
277 .start = MPC85xx_IRQ_SEC2,
278 .end = MPC85xx_IRQ_SEC2,
279 .flags = IORESOURCE_IRQ,
280 },
281 },
282 },
283#ifdef CONFIG_CPM2
284 [MPC85xx_CPM_FCC1] = {
285 .name = "fsl-cpm-fcc",
286 .id = 1,
287 .num_resources = 3,
288 .resource = (struct resource[]) {
289 {
290 .start = 0x91300,
291 .end = 0x9131F,
292 .flags = IORESOURCE_MEM,
293 },
294 {
295 .start = 0x91380,
296 .end = 0x9139F,
297 .flags = IORESOURCE_MEM,
298 },
299 {
300 .start = SIU_INT_FCC1,
301 .end = SIU_INT_FCC1,
302 .flags = IORESOURCE_IRQ,
303 },
304 },
305 },
306 [MPC85xx_CPM_FCC2] = {
307 .name = "fsl-cpm-fcc",
308 .id = 2,
309 .num_resources = 3,
310 .resource = (struct resource[]) {
311 {
312 .start = 0x91320,
313 .end = 0x9133F,
314 .flags = IORESOURCE_MEM,
315 },
316 {
317 .start = 0x913A0,
318 .end = 0x913CF,
319 .flags = IORESOURCE_MEM,
320 },
321 {
322 .start = SIU_INT_FCC2,
323 .end = SIU_INT_FCC2,
324 .flags = IORESOURCE_IRQ,
325 },
326 },
327 },
328 [MPC85xx_CPM_FCC3] = {
329 .name = "fsl-cpm-fcc",
330 .id = 3,
331 .num_resources = 3,
332 .resource = (struct resource[]) {
333 {
334 .start = 0x91340,
335 .end = 0x9135F,
336 .flags = IORESOURCE_MEM,
337 },
338 {
339 .start = 0x913D0,
340 .end = 0x913FF,
341 .flags = IORESOURCE_MEM,
342 },
343 {
344 .start = SIU_INT_FCC3,
345 .end = SIU_INT_FCC3,
346 .flags = IORESOURCE_IRQ,
347 },
348 },
349 },
350 [MPC85xx_CPM_I2C] = {
351 .name = "fsl-cpm-i2c",
352 .id = 1,
353 .num_resources = 2,
354 .resource = (struct resource[]) {
355 {
356 .start = 0x91860,
357 .end = 0x918BF,
358 .flags = IORESOURCE_MEM,
359 },
360 {
361 .start = SIU_INT_I2C,
362 .end = SIU_INT_I2C,
363 .flags = IORESOURCE_IRQ,
364 },
365 },
366 },
367 [MPC85xx_CPM_SCC1] = {
368 .name = "fsl-cpm-scc",
369 .id = 1,
370 .num_resources = 2,
371 .resource = (struct resource[]) {
372 {
373 .start = 0x91A00,
374 .end = 0x91A1F,
375 .flags = IORESOURCE_MEM,
376 },
377 {
378 .start = SIU_INT_SCC1,
379 .end = SIU_INT_SCC1,
380 .flags = IORESOURCE_IRQ,
381 },
382 },
383 },
384 [MPC85xx_CPM_SCC2] = {
385 .name = "fsl-cpm-scc",
386 .id = 2,
387 .num_resources = 2,
388 .resource = (struct resource[]) {
389 {
390 .start = 0x91A20,
391 .end = 0x91A3F,
392 .flags = IORESOURCE_MEM,
393 },
394 {
395 .start = SIU_INT_SCC2,
396 .end = SIU_INT_SCC2,
397 .flags = IORESOURCE_IRQ,
398 },
399 },
400 },
401 [MPC85xx_CPM_SCC3] = {
402 .name = "fsl-cpm-scc",
403 .id = 3,
404 .num_resources = 2,
405 .resource = (struct resource[]) {
406 {
407 .start = 0x91A40,
408 .end = 0x91A5F,
409 .flags = IORESOURCE_MEM,
410 },
411 {
412 .start = SIU_INT_SCC3,
413 .end = SIU_INT_SCC3,
414 .flags = IORESOURCE_IRQ,
415 },
416 },
417 },
418 [MPC85xx_CPM_SCC4] = {
419 .name = "fsl-cpm-scc",
420 .id = 4,
421 .num_resources = 2,
422 .resource = (struct resource[]) {
423 {
424 .start = 0x91A60,
425 .end = 0x91A7F,
426 .flags = IORESOURCE_MEM,
427 },
428 {
429 .start = SIU_INT_SCC4,
430 .end = SIU_INT_SCC4,
431 .flags = IORESOURCE_IRQ,
432 },
433 },
434 },
435 [MPC85xx_CPM_SPI] = {
436 .name = "fsl-cpm-spi",
437 .id = 1,
438 .num_resources = 2,
439 .resource = (struct resource[]) {
440 {
441 .start = 0x91AA0,
442 .end = 0x91AFF,
443 .flags = IORESOURCE_MEM,
444 },
445 {
446 .start = SIU_INT_SPI,
447 .end = SIU_INT_SPI,
448 .flags = IORESOURCE_IRQ,
449 },
450 },
451 },
452 [MPC85xx_CPM_MCC1] = {
453 .name = "fsl-cpm-mcc",
454 .id = 1,
455 .num_resources = 2,
456 .resource = (struct resource[]) {
457 {
458 .start = 0x91B30,
459 .end = 0x91B3F,
460 .flags = IORESOURCE_MEM,
461 },
462 {
463 .start = SIU_INT_MCC1,
464 .end = SIU_INT_MCC1,
465 .flags = IORESOURCE_IRQ,
466 },
467 },
468 },
469 [MPC85xx_CPM_MCC2] = {
470 .name = "fsl-cpm-mcc",
471 .id = 2,
472 .num_resources = 2,
473 .resource = (struct resource[]) {
474 {
475 .start = 0x91B50,
476 .end = 0x91B5F,
477 .flags = IORESOURCE_MEM,
478 },
479 {
480 .start = SIU_INT_MCC2,
481 .end = SIU_INT_MCC2,
482 .flags = IORESOURCE_IRQ,
483 },
484 },
485 },
486 [MPC85xx_CPM_SMC1] = {
487 .name = "fsl-cpm-smc",
488 .id = 1,
489 .num_resources = 2,
490 .resource = (struct resource[]) {
491 {
492 .start = 0x91A80,
493 .end = 0x91A8F,
494 .flags = IORESOURCE_MEM,
495 },
496 {
497 .start = SIU_INT_SMC1,
498 .end = SIU_INT_SMC1,
499 .flags = IORESOURCE_IRQ,
500 },
501 },
502 },
503 [MPC85xx_CPM_SMC2] = {
504 .name = "fsl-cpm-smc",
505 .id = 2,
506 .num_resources = 2,
507 .resource = (struct resource[]) {
508 {
509 .start = 0x91A90,
510 .end = 0x91A9F,
511 .flags = IORESOURCE_MEM,
512 },
513 {
514 .start = SIU_INT_SMC2,
515 .end = SIU_INT_SMC2,
516 .flags = IORESOURCE_IRQ,
517 },
518 },
519 },
520 [MPC85xx_CPM_USB] = {
521 .name = "fsl-cpm-usb",
522 .id = 2,
523 .num_resources = 2,
524 .resource = (struct resource[]) {
525 {
526 .start = 0x91B60,
527 .end = 0x91B7F,
528 .flags = IORESOURCE_MEM,
529 },
530 {
531 .start = SIU_INT_USB,
532 .end = SIU_INT_USB,
533 .flags = IORESOURCE_IRQ,
534 },
535 },
536 },
537#endif /* CONFIG_CPM2 */
538};
539
540static int __init mach_mpc85xx_fixup(struct platform_device *pdev)
541{
542 ppc_sys_fixup_mem_resource(pdev, CCSRBAR);
543 return 0;
544}
545
546static int __init mach_mpc85xx_init(void)
547{
548 ppc_sys_device_fixup = mach_mpc85xx_fixup;
549 return 0;
550}
551
552postcore_initcall(mach_mpc85xx_init);
diff --git a/arch/ppc/syslib/mpc85xx_sys.c b/arch/ppc/syslib/mpc85xx_sys.c
new file mode 100644
index 000000000000..d806a92a9401
--- /dev/null
+++ b/arch/ppc/syslib/mpc85xx_sys.c
@@ -0,0 +1,118 @@
1/*
2 * arch/ppc/platforms/85xx/mpc85xx_sys.c
3 *
4 * MPC85xx System descriptions
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2005 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/init.h>
17#include <linux/module.h>
18#include <linux/device.h>
19#include <asm/ppc_sys.h>
20
21struct ppc_sys_spec *cur_ppc_sys_spec;
22struct ppc_sys_spec ppc_sys_specs[] = {
23 {
24 .ppc_sys_name = "8540",
25 .mask = 0xFFFF0000,
26 .value = 0x80300000,
27 .num_devices = 10,
28 .device_list = (enum ppc_sys_devices[])
29 {
30 MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_FEC, MPC85xx_IIC1,
31 MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
32 MPC85xx_PERFMON, MPC85xx_DUART,
33 },
34 },
35 {
36 .ppc_sys_name = "8560",
37 .mask = 0xFFFF0000,
38 .value = 0x80700000,
39 .num_devices = 19,
40 .device_list = (enum ppc_sys_devices[])
41 {
42 MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
43 MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
44 MPC85xx_PERFMON,
45 MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1,
46 MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3, MPC85xx_CPM_SCC4,
47 MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2, MPC85xx_CPM_FCC3,
48 MPC85xx_CPM_MCC1, MPC85xx_CPM_MCC2,
49 },
50 },
51 {
52 .ppc_sys_name = "8541",
53 .mask = 0xFFFF0000,
54 .value = 0x80720000,
55 .num_devices = 13,
56 .device_list = (enum ppc_sys_devices[])
57 {
58 MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
59 MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
60 MPC85xx_PERFMON, MPC85xx_DUART,
61 MPC85xx_CPM_SPI, MPC85xx_CPM_I2C,
62 MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
63 },
64 },
65 {
66 .ppc_sys_name = "8541E",
67 .mask = 0xFFFF0000,
68 .value = 0x807A0000,
69 .num_devices = 14,
70 .device_list = (enum ppc_sys_devices[])
71 {
72 MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
73 MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
74 MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
75 MPC85xx_CPM_SPI, MPC85xx_CPM_I2C,
76 MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
77 },
78 },
79 {
80 .ppc_sys_name = "8555",
81 .mask = 0xFFFF0000,
82 .value = 0x80710000,
83 .num_devices = 19,
84 .device_list = (enum ppc_sys_devices[])
85 {
86 MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
87 MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
88 MPC85xx_PERFMON, MPC85xx_DUART,
89 MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1,
90 MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3,
91 MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
92 MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2,
93 MPC85xx_CPM_USB,
94 },
95 },
96 {
97 .ppc_sys_name = "8555E",
98 .mask = 0xFFFF0000,
99 .value = 0x80790000,
100 .num_devices = 20,
101 .device_list = (enum ppc_sys_devices[])
102 {
103 MPC85xx_TSEC1, MPC85xx_TSEC2, MPC85xx_IIC1,
104 MPC85xx_DMA0, MPC85xx_DMA1, MPC85xx_DMA2, MPC85xx_DMA3,
105 MPC85xx_PERFMON, MPC85xx_DUART, MPC85xx_SEC2,
106 MPC85xx_CPM_SPI, MPC85xx_CPM_I2C, MPC85xx_CPM_SCC1,
107 MPC85xx_CPM_SCC2, MPC85xx_CPM_SCC3,
108 MPC85xx_CPM_FCC1, MPC85xx_CPM_FCC2,
109 MPC85xx_CPM_SMC1, MPC85xx_CPM_SMC2,
110 MPC85xx_CPM_USB,
111 },
112 },
113 { /* default match */
114 .ppc_sys_name = "",
115 .mask = 0x00000000,
116 .value = 0x00000000,
117 },
118};
diff --git a/arch/ppc/syslib/mv64360_pic.c b/arch/ppc/syslib/mv64360_pic.c
new file mode 100644
index 000000000000..74d8996418e9
--- /dev/null
+++ b/arch/ppc/syslib/mv64360_pic.c
@@ -0,0 +1,426 @@
1/*
2 * arch/ppc/kernel/mv64360_pic.c
3 *
4 * Interrupt controller support for Marvell's MV64360.
5 *
6 * Author: Rabeeh Khoury <rabeeh@galileo.co.il>
7 * Based on MV64360 PIC written by
8 * Chris Zankel <chris@mvista.com>
9 * Mark A. Greer <mgreer@mvista.com>
10 *
11 * Copyright 2004 MontaVista Software, Inc.
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 */
18
19/*
20 * This file contains the specific functions to support the MV64360
21 * interrupt controller.
22 *
23 * The MV64360 has two main interrupt registers (high and low) that
24 * summarizes the interrupts generated by the units of the MV64360.
25 * Each bit is assigned to an interrupt number, where the low register
26 * are assigned from IRQ0 to IRQ31 and the high cause register
27 * from IRQ32 to IRQ63
28 * The GPP (General Purpose Pins) interrupts are assigned from IRQ64 (GPP0)
29 * to IRQ95 (GPP31).
30 * get_irq() returns the lowest interrupt number that is currently asserted.
31 *
32 * Note:
33 * - This driver does not initialize the GPP when used as an interrupt
34 * input.
35 */
36
37#include <linux/stddef.h>
38#include <linux/init.h>
39#include <linux/sched.h>
40#include <linux/signal.h>
41#include <linux/stddef.h>
42#include <linux/delay.h>
43#include <linux/irq.h>
44#include <linux/interrupt.h>
45
46#include <asm/io.h>
47#include <asm/processor.h>
48#include <asm/system.h>
49#include <asm/irq.h>
50#include <asm/mv64x60.h>
51
52#ifdef CONFIG_IRQ_ALL_CPUS
53#error "The mv64360 does not support distribution of IRQs on all CPUs"
54#endif
55/* ========================== forward declaration ========================== */
56
57static void mv64360_unmask_irq(unsigned int);
58static void mv64360_mask_irq(unsigned int);
59static irqreturn_t mv64360_cpu_error_int_handler(int, void *, struct pt_regs *);
60static irqreturn_t mv64360_sram_error_int_handler(int, void *,
61 struct pt_regs *);
62static irqreturn_t mv64360_pci_error_int_handler(int, void *, struct pt_regs *);
63
64/* ========================== local declarations =========================== */
65
66struct hw_interrupt_type mv64360_pic = {
67 .typename = " mv64360 ",
68 .enable = mv64360_unmask_irq,
69 .disable = mv64360_mask_irq,
70 .ack = mv64360_mask_irq,
71 .end = mv64360_unmask_irq,
72};
73
74#define CPU_INTR_STR "mv64360 cpu interface error"
75#define SRAM_INTR_STR "mv64360 internal sram error"
76#define PCI0_INTR_STR "mv64360 pci 0 error"
77#define PCI1_INTR_STR "mv64360 pci 1 error"
78
79static struct mv64x60_handle bh;
80
81u32 mv64360_irq_base = 0; /* MV64360 handles the next 96 IRQs from here */
82
83/* mv64360_init_irq()
84 *
85 * This function initializes the interrupt controller. It assigns
86 * all interrupts from IRQ0 to IRQ95 to the mv64360 interrupt controller.
87 *
88 * Input Variable(s):
89 * None.
90 *
91 * Outpu. Variable(s):
92 * None.
93 *
94 * Returns:
95 * void
96 *
97 * Note:
98 * We register all GPP inputs as interrupt source, but disable them.
99 */
100void __init
101mv64360_init_irq(void)
102{
103 int i;
104
105 if (ppc_md.progress)
106 ppc_md.progress("mv64360_init_irq: enter", 0x0);
107
108 bh.v_base = mv64x60_get_bridge_vbase();
109
110 ppc_cached_irq_mask[0] = 0;
111 ppc_cached_irq_mask[1] = 0x0f000000; /* Enable GPP intrs */
112 ppc_cached_irq_mask[2] = 0;
113
114 /* disable all interrupts and clear current interrupts */
115 mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, 0);
116 mv64x60_write(&bh, MV64x60_GPP_INTR_MASK, ppc_cached_irq_mask[2]);
117 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_LO,ppc_cached_irq_mask[0]);
118 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_HI,ppc_cached_irq_mask[1]);
119
120 /* All interrupts are level interrupts */
121 for (i = mv64360_irq_base; i < (mv64360_irq_base + 96); i++) {
122 irq_desc[i].status |= IRQ_LEVEL;
123 irq_desc[i].handler = &mv64360_pic;
124 }
125
126 if (ppc_md.progress)
127 ppc_md.progress("mv64360_init_irq: exit", 0x0);
128}
129
130/* mv64360_get_irq()
131 *
132 * This function returns the lowest interrupt number of all interrupts that
133 * are currently asserted.
134 *
135 * Input Variable(s):
136 * struct pt_regs* not used
137 *
138 * Output Variable(s):
139 * None.
140 *
141 * Returns:
142 * int <interrupt number> or -2 (bogus interrupt)
143 *
144 */
145int
146mv64360_get_irq(struct pt_regs *regs)
147{
148 int irq;
149 int irq_gpp;
150
151#ifdef CONFIG_SMP
152 /*
153 * Second CPU gets only doorbell (message) interrupts.
154 * The doorbell interrupt is BIT28 in the main interrupt low cause reg.
155 */
156 int cpu_nr = smp_processor_id();
157 if (cpu_nr == 1) {
158 if (!(mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_LO) &
159 (1 << MV64x60_IRQ_DOORBELL)))
160 return -1;
161 return mv64360_irq_base + MV64x60_IRQ_DOORBELL;
162 }
163#endif
164
165 irq = mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_LO);
166 irq = __ilog2((irq & 0x3dfffffe) & ppc_cached_irq_mask[0]);
167
168 if (irq == -1) {
169 irq = mv64x60_read(&bh, MV64360_IC_MAIN_CAUSE_HI);
170 irq = __ilog2((irq & 0x1f0003f7) & ppc_cached_irq_mask[1]);
171
172 if (irq == -1)
173 irq = -2; /* bogus interrupt, should never happen */
174 else {
175 if ((irq >= 24) && (irq < MV64x60_IRQ_DOORBELL)) {
176 irq_gpp = mv64x60_read(&bh,
177 MV64x60_GPP_INTR_CAUSE);
178 irq_gpp = __ilog2(irq_gpp &
179 ppc_cached_irq_mask[2]);
180
181 if (irq_gpp == -1)
182 irq = -2;
183 else {
184 irq = irq_gpp + 64;
185 mv64x60_write(&bh,
186 MV64x60_GPP_INTR_CAUSE,
187 ~(1 << (irq - 64)));
188 }
189 }
190 else
191 irq += 32;
192 }
193 }
194
195 (void)mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE);
196
197 if (irq < 0)
198 return (irq);
199 else
200 return (mv64360_irq_base + irq);
201}
202
203/* mv64360_unmask_irq()
204 *
205 * This function enables an interrupt.
206 *
207 * Input Variable(s):
208 * unsigned int interrupt number (IRQ0...IRQ95).
209 *
210 * Output Variable(s):
211 * None.
212 *
213 * Returns:
214 * void
215 */
216static void
217mv64360_unmask_irq(unsigned int irq)
218{
219#ifdef CONFIG_SMP
220 /* second CPU gets only doorbell interrupts */
221 if ((irq - mv64360_irq_base) == MV64x60_IRQ_DOORBELL) {
222 mv64x60_set_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO,
223 (1 << MV64x60_IRQ_DOORBELL));
224 return;
225 }
226#endif
227 irq -= mv64360_irq_base;
228
229 if (irq > 31) {
230 if (irq > 63) /* unmask GPP irq */
231 mv64x60_write(&bh, MV64x60_GPP_INTR_MASK,
232 ppc_cached_irq_mask[2] |= (1 << (irq - 64)));
233 else /* mask high interrupt register */
234 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_HI,
235 ppc_cached_irq_mask[1] |= (1 << (irq - 32)));
236 }
237 else /* mask low interrupt register */
238 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_LO,
239 ppc_cached_irq_mask[0] |= (1 << irq));
240
241 (void)mv64x60_read(&bh, MV64x60_GPP_INTR_MASK);
242 return;
243}
244
245/* mv64360_mask_irq()
246 *
247 * This function disables the requested interrupt.
248 *
249 * Input Variable(s):
250 * unsigned int interrupt number (IRQ0...IRQ95).
251 *
252 * Output Variable(s):
253 * None.
254 *
255 * Returns:
256 * void
257 */
258static void
259mv64360_mask_irq(unsigned int irq)
260{
261#ifdef CONFIG_SMP
262 if ((irq - mv64360_irq_base) == MV64x60_IRQ_DOORBELL) {
263 mv64x60_clr_bits(&bh, MV64360_IC_CPU1_INTR_MASK_LO,
264 (1 << MV64x60_IRQ_DOORBELL));
265 return;
266 }
267#endif
268 irq -= mv64360_irq_base;
269
270 if (irq > 31) {
271 if (irq > 63) /* mask GPP irq */
272 mv64x60_write(&bh, MV64x60_GPP_INTR_MASK,
273 ppc_cached_irq_mask[2] &= ~(1 << (irq - 64)));
274 else /* mask high interrupt register */
275 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_HI,
276 ppc_cached_irq_mask[1] &= ~(1 << (irq - 32)));
277 }
278 else /* mask low interrupt register */
279 mv64x60_write(&bh, MV64360_IC_CPU0_INTR_MASK_LO,
280 ppc_cached_irq_mask[0] &= ~(1 << irq));
281
282 (void)mv64x60_read(&bh, MV64x60_GPP_INTR_MASK);
283 return;
284}
285
286static irqreturn_t
287mv64360_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
288{
289 printk(KERN_ERR "mv64360_cpu_error_int_handler: %s 0x%08x\n",
290 "Error on CPU interface - Cause regiser",
291 mv64x60_read(&bh, MV64x60_CPU_ERR_CAUSE));
292 printk(KERN_ERR "\tCPU error register dump:\n");
293 printk(KERN_ERR "\tAddress low 0x%08x\n",
294 mv64x60_read(&bh, MV64x60_CPU_ERR_ADDR_LO));
295 printk(KERN_ERR "\tAddress high 0x%08x\n",
296 mv64x60_read(&bh, MV64x60_CPU_ERR_ADDR_HI));
297 printk(KERN_ERR "\tData low 0x%08x\n",
298 mv64x60_read(&bh, MV64x60_CPU_ERR_DATA_LO));
299 printk(KERN_ERR "\tData high 0x%08x\n",
300 mv64x60_read(&bh, MV64x60_CPU_ERR_DATA_HI));
301 printk(KERN_ERR "\tParity 0x%08x\n",
302 mv64x60_read(&bh, MV64x60_CPU_ERR_PARITY));
303 mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0);
304 return IRQ_HANDLED;
305}
306
307static irqreturn_t
308mv64360_sram_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
309{
310 printk(KERN_ERR "mv64360_sram_error_int_handler: %s 0x%08x\n",
311 "Error in internal SRAM - Cause register",
312 mv64x60_read(&bh, MV64360_SRAM_ERR_CAUSE));
313 printk(KERN_ERR "\tSRAM error register dump:\n");
314 printk(KERN_ERR "\tAddress Low 0x%08x\n",
315 mv64x60_read(&bh, MV64360_SRAM_ERR_ADDR_LO));
316 printk(KERN_ERR "\tAddress High 0x%08x\n",
317 mv64x60_read(&bh, MV64360_SRAM_ERR_ADDR_HI));
318 printk(KERN_ERR "\tData Low 0x%08x\n",
319 mv64x60_read(&bh, MV64360_SRAM_ERR_DATA_LO));
320 printk(KERN_ERR "\tData High 0x%08x\n",
321 mv64x60_read(&bh, MV64360_SRAM_ERR_DATA_HI));
322 printk(KERN_ERR "\tParity 0x%08x\n",
323 mv64x60_read(&bh, MV64360_SRAM_ERR_PARITY));
324 mv64x60_write(&bh, MV64360_SRAM_ERR_CAUSE, 0);
325 return IRQ_HANDLED;
326}
327
328static irqreturn_t
329mv64360_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
330{
331 u32 val;
332 unsigned int pci_bus = (unsigned int)dev_id;
333
334 if (pci_bus == 0) { /* Error on PCI 0 */
335 val = mv64x60_read(&bh, MV64x60_PCI0_ERR_CAUSE);
336 printk(KERN_ERR "%s: Error in PCI %d Interface\n",
337 "mv64360_pci_error_int_handler", pci_bus);
338 printk(KERN_ERR "\tPCI %d error register dump:\n", pci_bus);
339 printk(KERN_ERR "\tCause register 0x%08x\n", val);
340 printk(KERN_ERR "\tAddress Low 0x%08x\n",
341 mv64x60_read(&bh, MV64x60_PCI0_ERR_ADDR_LO));
342 printk(KERN_ERR "\tAddress High 0x%08x\n",
343 mv64x60_read(&bh, MV64x60_PCI0_ERR_ADDR_HI));
344 printk(KERN_ERR "\tAttribute 0x%08x\n",
345 mv64x60_read(&bh, MV64x60_PCI0_ERR_DATA_LO));
346 printk(KERN_ERR "\tCommand 0x%08x\n",
347 mv64x60_read(&bh, MV64x60_PCI0_ERR_CMD));
348 mv64x60_write(&bh, MV64x60_PCI0_ERR_CAUSE, ~val);
349 }
350 if (pci_bus == 1) { /* Error on PCI 1 */
351 val = mv64x60_read(&bh, MV64x60_PCI1_ERR_CAUSE);
352 printk(KERN_ERR "%s: Error in PCI %d Interface\n",
353 "mv64360_pci_error_int_handler", pci_bus);
354 printk(KERN_ERR "\tPCI %d error register dump:\n", pci_bus);
355 printk(KERN_ERR "\tCause register 0x%08x\n", val);
356 printk(KERN_ERR "\tAddress Low 0x%08x\n",
357 mv64x60_read(&bh, MV64x60_PCI1_ERR_ADDR_LO));
358 printk(KERN_ERR "\tAddress High 0x%08x\n",
359 mv64x60_read(&bh, MV64x60_PCI1_ERR_ADDR_HI));
360 printk(KERN_ERR "\tAttribute 0x%08x\n",
361 mv64x60_read(&bh, MV64x60_PCI1_ERR_DATA_LO));
362 printk(KERN_ERR "\tCommand 0x%08x\n",
363 mv64x60_read(&bh, MV64x60_PCI1_ERR_CMD));
364 mv64x60_write(&bh, MV64x60_PCI1_ERR_CAUSE, ~val);
365 }
366 return IRQ_HANDLED;
367}
368
369static int __init
370mv64360_register_hdlrs(void)
371{
372 u32 mask;
373 int rc;
374
375 /* Clear old errors and register CPU interface error intr handler */
376 mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0);
377 if ((rc = request_irq(MV64x60_IRQ_CPU_ERR + mv64360_irq_base,
378 mv64360_cpu_error_int_handler, SA_INTERRUPT, CPU_INTR_STR, 0)))
379 printk(KERN_WARNING "Can't register cpu error handler: %d", rc);
380
381 mv64x60_write(&bh, MV64x60_CPU_ERR_MASK, 0);
382 mv64x60_write(&bh, MV64x60_CPU_ERR_MASK, 0x000000ff);
383
384 /* Clear old errors and register internal SRAM error intr handler */
385 mv64x60_write(&bh, MV64360_SRAM_ERR_CAUSE, 0);
386 if ((rc = request_irq(MV64360_IRQ_SRAM_PAR_ERR + mv64360_irq_base,
387 mv64360_sram_error_int_handler,SA_INTERRUPT,SRAM_INTR_STR, 0)))
388 printk(KERN_WARNING "Can't register SRAM error handler: %d",rc);
389
390 /*
391 * Bit 0 reserved on 64360 and erratum FEr PCI-#11 (PCI internal
392 * data parity error set incorrectly) on rev 0 & 1 of 64460 requires
393 * bit 0 to be cleared.
394 */
395 mask = 0x00a50c24;
396
397 if ((mv64x60_get_bridge_type() == MV64x60_TYPE_MV64460) &&
398 (mv64x60_get_bridge_rev() > 1))
399 mask |= 0x1; /* enable DPErr on 64460 */
400
401 /* Clear old errors and register PCI 0 error intr handler */
402 mv64x60_write(&bh, MV64x60_PCI0_ERR_CAUSE, 0);
403 if ((rc = request_irq(MV64360_IRQ_PCI0 + mv64360_irq_base,
404 mv64360_pci_error_int_handler,
405 SA_INTERRUPT, PCI0_INTR_STR, (void *)0)))
406 printk(KERN_WARNING "Can't register pci 0 error handler: %d",
407 rc);
408
409 mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, 0);
410 mv64x60_write(&bh, MV64x60_PCI0_ERR_MASK, mask);
411
412 /* Clear old errors and register PCI 1 error intr handler */
413 mv64x60_write(&bh, MV64x60_PCI1_ERR_CAUSE, 0);
414 if ((rc = request_irq(MV64360_IRQ_PCI1 + mv64360_irq_base,
415 mv64360_pci_error_int_handler,
416 SA_INTERRUPT, PCI1_INTR_STR, (void *)1)))
417 printk(KERN_WARNING "Can't register pci 1 error handler: %d",
418 rc);
419
420 mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, 0);
421 mv64x60_write(&bh, MV64x60_PCI1_ERR_MASK, mask);
422
423 return 0;
424}
425
426arch_initcall(mv64360_register_hdlrs);
diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c
new file mode 100644
index 000000000000..7b241e7876bd
--- /dev/null
+++ b/arch/ppc/syslib/mv64x60.c
@@ -0,0 +1,2392 @@
1/*
2 * arch/ppc/syslib/mv64x60.c
3 *
4 * Common routines for the Marvell/Galileo Discovery line of host bridges
5 * (gt64260, mv64360, mv64460, ...).
6 *
7 * Author: Mark A. Greer <mgreer@mvista.com>
8 *
9 * 2004 (c) MontaVista, Software, Inc. This file is licensed under
10 * the terms of the GNU General Public License version 2. This program
11 * is licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 */
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/pci.h>
17#include <linux/slab.h>
18#include <linux/module.h>
19#include <linux/string.h>
20#include <linux/bootmem.h>
21#include <linux/spinlock.h>
22#include <linux/mv643xx.h>
23
24#include <asm/byteorder.h>
25#include <asm/io.h>
26#include <asm/irq.h>
27#include <asm/uaccess.h>
28#include <asm/machdep.h>
29#include <asm/pci-bridge.h>
30#include <asm/delay.h>
31#include <asm/mv64x60.h>
32
33
34u8 mv64x60_pci_exclude_bridge = 1;
35spinlock_t mv64x60_lock = SPIN_LOCK_UNLOCKED;
36
37static phys_addr_t mv64x60_bridge_pbase = 0;
38static void *mv64x60_bridge_vbase = 0;
39static u32 mv64x60_bridge_type = MV64x60_TYPE_INVALID;
40static u32 mv64x60_bridge_rev = 0;
41
42static u32 gt64260_translate_size(u32 base, u32 size, u32 num_bits);
43static u32 gt64260_untranslate_size(u32 base, u32 size, u32 num_bits);
44static void gt64260_set_pci2mem_window(struct pci_controller *hose, u32 bus,
45 u32 window, u32 base);
46static void gt64260_set_pci2regs_window(struct mv64x60_handle *bh,
47 struct pci_controller *hose, u32 bus, u32 base);
48static u32 gt64260_is_enabled_32bit(struct mv64x60_handle *bh, u32 window);
49static void gt64260_enable_window_32bit(struct mv64x60_handle *bh, u32 window);
50static void gt64260_disable_window_32bit(struct mv64x60_handle *bh, u32 window);
51static void gt64260_enable_window_64bit(struct mv64x60_handle *bh, u32 window);
52static void gt64260_disable_window_64bit(struct mv64x60_handle *bh, u32 window);
53static void gt64260_disable_all_windows(struct mv64x60_handle *bh,
54 struct mv64x60_setup_info *si);
55static void gt64260a_chip_specific_init(struct mv64x60_handle *bh,
56 struct mv64x60_setup_info *si);
57static void gt64260b_chip_specific_init(struct mv64x60_handle *bh,
58 struct mv64x60_setup_info *si);
59
60static u32 mv64360_translate_size(u32 base, u32 size, u32 num_bits);
61static u32 mv64360_untranslate_size(u32 base, u32 size, u32 num_bits);
62static void mv64360_set_pci2mem_window(struct pci_controller *hose, u32 bus,
63 u32 window, u32 base);
64static void mv64360_set_pci2regs_window(struct mv64x60_handle *bh,
65 struct pci_controller *hose, u32 bus, u32 base);
66static u32 mv64360_is_enabled_32bit(struct mv64x60_handle *bh, u32 window);
67static void mv64360_enable_window_32bit(struct mv64x60_handle *bh, u32 window);
68static void mv64360_disable_window_32bit(struct mv64x60_handle *bh, u32 window);
69static void mv64360_enable_window_64bit(struct mv64x60_handle *bh, u32 window);
70static void mv64360_disable_window_64bit(struct mv64x60_handle *bh, u32 window);
71static void mv64360_disable_all_windows(struct mv64x60_handle *bh,
72 struct mv64x60_setup_info *si);
73static void mv64360_config_io2mem_windows(struct mv64x60_handle *bh,
74 struct mv64x60_setup_info *si,
75 u32 mem_windows[MV64x60_CPU2MEM_WINDOWS][2]);
76static void mv64360_set_mpsc2regs_window(struct mv64x60_handle *bh, u32 base);
77static void mv64360_chip_specific_init(struct mv64x60_handle *bh,
78 struct mv64x60_setup_info *si);
79static void mv64460_chip_specific_init(struct mv64x60_handle *bh,
80 struct mv64x60_setup_info *si);
81
82
83/*
84 * Define tables that have the chip-specific info for each type of
85 * Marvell bridge chip.
86 */
87static struct mv64x60_chip_info gt64260a_ci __initdata = { /* GT64260A */
88 .translate_size = gt64260_translate_size,
89 .untranslate_size = gt64260_untranslate_size,
90 .set_pci2mem_window = gt64260_set_pci2mem_window,
91 .set_pci2regs_window = gt64260_set_pci2regs_window,
92 .is_enabled_32bit = gt64260_is_enabled_32bit,
93 .enable_window_32bit = gt64260_enable_window_32bit,
94 .disable_window_32bit = gt64260_disable_window_32bit,
95 .enable_window_64bit = gt64260_enable_window_64bit,
96 .disable_window_64bit = gt64260_disable_window_64bit,
97 .disable_all_windows = gt64260_disable_all_windows,
98 .chip_specific_init = gt64260a_chip_specific_init,
99 .window_tab_32bit = gt64260_32bit_windows,
100 .window_tab_64bit = gt64260_64bit_windows,
101};
102
103static struct mv64x60_chip_info gt64260b_ci __initdata = { /* GT64260B */
104 .translate_size = gt64260_translate_size,
105 .untranslate_size = gt64260_untranslate_size,
106 .set_pci2mem_window = gt64260_set_pci2mem_window,
107 .set_pci2regs_window = gt64260_set_pci2regs_window,
108 .is_enabled_32bit = gt64260_is_enabled_32bit,
109 .enable_window_32bit = gt64260_enable_window_32bit,
110 .disable_window_32bit = gt64260_disable_window_32bit,
111 .enable_window_64bit = gt64260_enable_window_64bit,
112 .disable_window_64bit = gt64260_disable_window_64bit,
113 .disable_all_windows = gt64260_disable_all_windows,
114 .chip_specific_init = gt64260b_chip_specific_init,
115 .window_tab_32bit = gt64260_32bit_windows,
116 .window_tab_64bit = gt64260_64bit_windows,
117};
118
119static struct mv64x60_chip_info mv64360_ci __initdata = { /* MV64360 */
120 .translate_size = mv64360_translate_size,
121 .untranslate_size = mv64360_untranslate_size,
122 .set_pci2mem_window = mv64360_set_pci2mem_window,
123 .set_pci2regs_window = mv64360_set_pci2regs_window,
124 .is_enabled_32bit = mv64360_is_enabled_32bit,
125 .enable_window_32bit = mv64360_enable_window_32bit,
126 .disable_window_32bit = mv64360_disable_window_32bit,
127 .enable_window_64bit = mv64360_enable_window_64bit,
128 .disable_window_64bit = mv64360_disable_window_64bit,
129 .disable_all_windows = mv64360_disable_all_windows,
130 .config_io2mem_windows = mv64360_config_io2mem_windows,
131 .set_mpsc2regs_window = mv64360_set_mpsc2regs_window,
132 .chip_specific_init = mv64360_chip_specific_init,
133 .window_tab_32bit = mv64360_32bit_windows,
134 .window_tab_64bit = mv64360_64bit_windows,
135};
136
137static struct mv64x60_chip_info mv64460_ci __initdata = { /* MV64460 */
138 .translate_size = mv64360_translate_size,
139 .untranslate_size = mv64360_untranslate_size,
140 .set_pci2mem_window = mv64360_set_pci2mem_window,
141 .set_pci2regs_window = mv64360_set_pci2regs_window,
142 .is_enabled_32bit = mv64360_is_enabled_32bit,
143 .enable_window_32bit = mv64360_enable_window_32bit,
144 .disable_window_32bit = mv64360_disable_window_32bit,
145 .enable_window_64bit = mv64360_enable_window_64bit,
146 .disable_window_64bit = mv64360_disable_window_64bit,
147 .disable_all_windows = mv64360_disable_all_windows,
148 .config_io2mem_windows = mv64360_config_io2mem_windows,
149 .set_mpsc2regs_window = mv64360_set_mpsc2regs_window,
150 .chip_specific_init = mv64460_chip_specific_init,
151 .window_tab_32bit = mv64360_32bit_windows,
152 .window_tab_64bit = mv64360_64bit_windows,
153};
154
155/*
156 *****************************************************************************
157 *
158 * Platform Device Definitions
159 *
160 *****************************************************************************
161 */
162#ifdef CONFIG_SERIAL_MPSC
163static struct mpsc_shared_pdata mv64x60_mpsc_shared_pdata = {
164 .mrr_val = 0x3ffffe38,
165 .rcrr_val = 0,
166 .tcrr_val = 0,
167 .intr_cause_val = 0,
168 .intr_mask_val = 0,
169};
170
171static struct resource mv64x60_mpsc_shared_resources[] = {
172 /* Do not change the order of the IORESOURCE_MEM resources */
173 [0] = {
174 .name = "mpsc routing base",
175 .start = MV64x60_MPSC_ROUTING_OFFSET,
176 .end = MV64x60_MPSC_ROUTING_OFFSET +
177 MPSC_ROUTING_REG_BLOCK_SIZE - 1,
178 .flags = IORESOURCE_MEM,
179 },
180 [1] = {
181 .name = "sdma intr base",
182 .start = MV64x60_SDMA_INTR_OFFSET,
183 .end = MV64x60_SDMA_INTR_OFFSET +
184 MPSC_SDMA_INTR_REG_BLOCK_SIZE - 1,
185 .flags = IORESOURCE_MEM,
186 },
187};
188
189static struct platform_device mpsc_shared_device = { /* Shared device */
190 .name = MPSC_SHARED_NAME,
191 .id = 0,
192 .num_resources = ARRAY_SIZE(mv64x60_mpsc_shared_resources),
193 .resource = mv64x60_mpsc_shared_resources,
194 .dev = {
195 .platform_data = &mv64x60_mpsc_shared_pdata,
196 },
197};
198
199static struct mpsc_pdata mv64x60_mpsc0_pdata = {
200 .mirror_regs = 0,
201 .cache_mgmt = 0,
202 .max_idle = 0,
203 .default_baud = 9600,
204 .default_bits = 8,
205 .default_parity = 'n',
206 .default_flow = 'n',
207 .chr_1_val = 0x00000000,
208 .chr_2_val = 0x00000000,
209 .chr_10_val = 0x00000003,
210 .mpcr_val = 0,
211 .bcr_val = 0,
212 .brg_can_tune = 0,
213 .brg_clk_src = 8, /* Default to TCLK */
214 .brg_clk_freq = 100000000, /* Default to 100 MHz */
215};
216
217static struct resource mv64x60_mpsc0_resources[] = {
218 /* Do not change the order of the IORESOURCE_MEM resources */
219 [0] = {
220 .name = "mpsc 0 base",
221 .start = MV64x60_MPSC_0_OFFSET,
222 .end = MV64x60_MPSC_0_OFFSET + MPSC_REG_BLOCK_SIZE - 1,
223 .flags = IORESOURCE_MEM,
224 },
225 [1] = {
226 .name = "sdma 0 base",
227 .start = MV64x60_SDMA_0_OFFSET,
228 .end = MV64x60_SDMA_0_OFFSET + MPSC_SDMA_REG_BLOCK_SIZE - 1,
229 .flags = IORESOURCE_MEM,
230 },
231 [2] = {
232 .name = "brg 0 base",
233 .start = MV64x60_BRG_0_OFFSET,
234 .end = MV64x60_BRG_0_OFFSET + MPSC_BRG_REG_BLOCK_SIZE - 1,
235 .flags = IORESOURCE_MEM,
236 },
237 [3] = {
238 .name = "sdma 0 irq",
239 .start = MV64x60_IRQ_SDMA_0,
240 .end = MV64x60_IRQ_SDMA_0,
241 .flags = IORESOURCE_IRQ,
242 },
243};
244
245static struct platform_device mpsc0_device = {
246 .name = MPSC_CTLR_NAME,
247 .id = 0,
248 .num_resources = ARRAY_SIZE(mv64x60_mpsc0_resources),
249 .resource = mv64x60_mpsc0_resources,
250 .dev = {
251 .platform_data = &mv64x60_mpsc0_pdata,
252 },
253};
254
255static struct mpsc_pdata mv64x60_mpsc1_pdata = {
256 .mirror_regs = 0,
257 .cache_mgmt = 0,
258 .max_idle = 0,
259 .default_baud = 9600,
260 .default_bits = 8,
261 .default_parity = 'n',
262 .default_flow = 'n',
263 .chr_1_val = 0x00000000,
264 .chr_1_val = 0x00000000,
265 .chr_2_val = 0x00000000,
266 .chr_10_val = 0x00000003,
267 .mpcr_val = 0,
268 .bcr_val = 0,
269 .brg_can_tune = 0,
270 .brg_clk_src = 8, /* Default to TCLK */
271 .brg_clk_freq = 100000000, /* Default to 100 MHz */
272};
273
274static struct resource mv64x60_mpsc1_resources[] = {
275 /* Do not change the order of the IORESOURCE_MEM resources */
276 [0] = {
277 .name = "mpsc 1 base",
278 .start = MV64x60_MPSC_1_OFFSET,
279 .end = MV64x60_MPSC_1_OFFSET + MPSC_REG_BLOCK_SIZE - 1,
280 .flags = IORESOURCE_MEM,
281 },
282 [1] = {
283 .name = "sdma 1 base",
284 .start = MV64x60_SDMA_1_OFFSET,
285 .end = MV64x60_SDMA_1_OFFSET + MPSC_SDMA_REG_BLOCK_SIZE - 1,
286 .flags = IORESOURCE_MEM,
287 },
288 [2] = {
289 .name = "brg 1 base",
290 .start = MV64x60_BRG_1_OFFSET,
291 .end = MV64x60_BRG_1_OFFSET + MPSC_BRG_REG_BLOCK_SIZE - 1,
292 .flags = IORESOURCE_MEM,
293 },
294 [3] = {
295 .name = "sdma 1 irq",
296 .start = MV64360_IRQ_SDMA_1,
297 .end = MV64360_IRQ_SDMA_1,
298 .flags = IORESOURCE_IRQ,
299 },
300};
301
302static struct platform_device mpsc1_device = {
303 .name = MPSC_CTLR_NAME,
304 .id = 1,
305 .num_resources = ARRAY_SIZE(mv64x60_mpsc1_resources),
306 .resource = mv64x60_mpsc1_resources,
307 .dev = {
308 .platform_data = &mv64x60_mpsc1_pdata,
309 },
310};
311#endif
312
313#ifdef CONFIG_MV643XX_ETH
314static struct resource mv64x60_eth_shared_resources[] = {
315 [0] = {
316 .name = "ethernet shared base",
317 .start = MV643XX_ETH_SHARED_REGS,
318 .end = MV643XX_ETH_SHARED_REGS +
319 MV643XX_ETH_SHARED_REGS_SIZE - 1,
320 .flags = IORESOURCE_MEM,
321 },
322};
323
324static struct platform_device mv64x60_eth_shared_device = {
325 .name = MV643XX_ETH_SHARED_NAME,
326 .id = 0,
327 .num_resources = ARRAY_SIZE(mv64x60_eth_shared_resources),
328 .resource = mv64x60_eth_shared_resources,
329};
330
331#ifdef CONFIG_MV643XX_ETH_0
332static struct resource mv64x60_eth0_resources[] = {
333 [0] = {
334 .name = "eth0 irq",
335 .start = MV64x60_IRQ_ETH_0,
336 .end = MV64x60_IRQ_ETH_0,
337 .flags = IORESOURCE_IRQ,
338 },
339};
340
341static struct mv643xx_eth_platform_data eth0_pd;
342
343static struct platform_device eth0_device = {
344 .name = MV643XX_ETH_NAME,
345 .id = 0,
346 .num_resources = ARRAY_SIZE(mv64x60_eth0_resources),
347 .resource = mv64x60_eth0_resources,
348 .dev = {
349 .platform_data = &eth0_pd,
350 },
351};
352#endif
353
354#ifdef CONFIG_MV643XX_ETH_1
355static struct resource mv64x60_eth1_resources[] = {
356 [0] = {
357 .name = "eth1 irq",
358 .start = MV64x60_IRQ_ETH_1,
359 .end = MV64x60_IRQ_ETH_1,
360 .flags = IORESOURCE_IRQ,
361 },
362};
363
364static struct mv643xx_eth_platform_data eth1_pd;
365
366static struct platform_device eth1_device = {
367 .name = MV643XX_ETH_NAME,
368 .id = 1,
369 .num_resources = ARRAY_SIZE(mv64x60_eth1_resources),
370 .resource = mv64x60_eth1_resources,
371 .dev = {
372 .platform_data = &eth1_pd,
373 },
374};
375#endif
376
377#ifdef CONFIG_MV643XX_ETH_2
378static struct resource mv64x60_eth2_resources[] = {
379 [0] = {
380 .name = "eth2 irq",
381 .start = MV64x60_IRQ_ETH_2,
382 .end = MV64x60_IRQ_ETH_2,
383 .flags = IORESOURCE_IRQ,
384 },
385};
386
387static struct mv643xx_eth_platform_data eth2_pd;
388
389static struct platform_device eth2_device = {
390 .name = MV643XX_ETH_NAME,
391 .id = 2,
392 .num_resources = ARRAY_SIZE(mv64x60_eth2_resources),
393 .resource = mv64x60_eth2_resources,
394 .dev = {
395 .platform_data = &eth2_pd,
396 },
397};
398#endif
399#endif
400
401#ifdef CONFIG_I2C_MV64XXX
402static struct mv64xxx_i2c_pdata mv64xxx_i2c_pdata = {
403 .freq_m = 8,
404 .freq_n = 3,
405 .timeout = 1000, /* Default timeout of 1 second */
406 .retries = 1,
407};
408
409static struct resource mv64xxx_i2c_resources[] = {
410 /* Do not change the order of the IORESOURCE_MEM resources */
411 [0] = {
412 .name = "mv64xxx i2c base",
413 .start = MV64XXX_I2C_OFFSET,
414 .end = MV64XXX_I2C_OFFSET + MV64XXX_I2C_REG_BLOCK_SIZE - 1,
415 .flags = IORESOURCE_MEM,
416 },
417 [1] = {
418 .name = "mv64xxx i2c irq",
419 .start = MV64x60_IRQ_I2C,
420 .end = MV64x60_IRQ_I2C,
421 .flags = IORESOURCE_IRQ,
422 },
423};
424
425static struct platform_device i2c_device = {
426 .name = MV64XXX_I2C_CTLR_NAME,
427 .id = 0,
428 .num_resources = ARRAY_SIZE(mv64xxx_i2c_resources),
429 .resource = mv64xxx_i2c_resources,
430 .dev = {
431 .platform_data = &mv64xxx_i2c_pdata,
432 },
433};
434#endif
435
436static struct platform_device *mv64x60_pd_devs[] __initdata = {
437#ifdef CONFIG_SERIAL_MPSC
438 &mpsc_shared_device,
439 &mpsc0_device,
440 &mpsc1_device,
441#endif
442#ifdef CONFIG_MV643XX_ETH
443 &mv64x60_eth_shared_device,
444#endif
445#ifdef CONFIG_MV643XX_ETH_0
446 &eth0_device,
447#endif
448#ifdef CONFIG_MV643XX_ETH_1
449 &eth1_device,
450#endif
451#ifdef CONFIG_MV643XX_ETH_2
452 &eth2_device,
453#endif
454#ifdef CONFIG_I2C_MV64XXX
455 &i2c_device,
456#endif
457};
458
459/*
460 *****************************************************************************
461 *
462 * Bridge Initialization Routines
463 *
464 *****************************************************************************
465 */
466/*
467 * mv64x60_init()
468 *
469 * Initialze the bridge based on setting passed in via 'si'. The bridge
470 * handle, 'bh', will be set so that it can be used to make subsequent
471 * calls to routines in this file.
472 */
473int __init
474mv64x60_init(struct mv64x60_handle *bh, struct mv64x60_setup_info *si)
475{
476 u32 mem_windows[MV64x60_CPU2MEM_WINDOWS][2];
477
478 if (ppc_md.progress)
479 ppc_md.progress("mv64x60 initialization", 0x0);
480
481 spin_lock_init(&mv64x60_lock);
482 mv64x60_early_init(bh, si);
483
484 if (mv64x60_get_type(bh) || mv64x60_setup_for_chip(bh)) {
485 iounmap(bh->v_base);
486 bh->v_base = 0;
487 if (ppc_md.progress)
488 ppc_md.progress("mv64x60_init: Can't determine chip",0);
489 return -1;
490 }
491
492 bh->ci->disable_all_windows(bh, si);
493 mv64x60_get_mem_windows(bh, mem_windows);
494 mv64x60_config_cpu2mem_windows(bh, si, mem_windows);
495
496 if (bh->ci->config_io2mem_windows)
497 bh->ci->config_io2mem_windows(bh, si, mem_windows);
498 if (bh->ci->set_mpsc2regs_window)
499 bh->ci->set_mpsc2regs_window(bh, si->phys_reg_base);
500
501 if (si->pci_1.enable_bus) {
502 bh->io_base_b = (u32)ioremap(si->pci_1.pci_io.cpu_base,
503 si->pci_1.pci_io.size);
504 isa_io_base = bh->io_base_b;
505 }
506
507 if (si->pci_0.enable_bus) {
508 bh->io_base_a = (u32)ioremap(si->pci_0.pci_io.cpu_base,
509 si->pci_0.pci_io.size);
510 isa_io_base = bh->io_base_a;
511
512 mv64x60_alloc_hose(bh, MV64x60_PCI0_CONFIG_ADDR,
513 MV64x60_PCI0_CONFIG_DATA, &bh->hose_a);
514 mv64x60_config_resources(bh->hose_a, &si->pci_0, bh->io_base_a);
515 mv64x60_config_pci_params(bh->hose_a, &si->pci_0);
516
517 mv64x60_config_cpu2pci_windows(bh, &si->pci_0, 0);
518 mv64x60_config_pci2mem_windows(bh, bh->hose_a, &si->pci_0, 0,
519 mem_windows);
520 bh->ci->set_pci2regs_window(bh, bh->hose_a, 0,
521 si->phys_reg_base);
522 }
523
524 if (si->pci_1.enable_bus) {
525 mv64x60_alloc_hose(bh, MV64x60_PCI1_CONFIG_ADDR,
526 MV64x60_PCI1_CONFIG_DATA, &bh->hose_b);
527 mv64x60_config_resources(bh->hose_b, &si->pci_1, bh->io_base_b);
528 mv64x60_config_pci_params(bh->hose_b, &si->pci_1);
529
530 mv64x60_config_cpu2pci_windows(bh, &si->pci_1, 1);
531 mv64x60_config_pci2mem_windows(bh, bh->hose_b, &si->pci_1, 1,
532 mem_windows);
533 bh->ci->set_pci2regs_window(bh, bh->hose_b, 1,
534 si->phys_reg_base);
535 }
536
537 bh->ci->chip_specific_init(bh, si);
538 mv64x60_pd_fixup(bh, mv64x60_pd_devs, ARRAY_SIZE(mv64x60_pd_devs));
539
540 return 0;
541}
542
543/*
544 * mv64x60_early_init()
545 *
546 * Do some bridge work that must take place before we start messing with
547 * the bridge for real.
548 */
549void __init
550mv64x60_early_init(struct mv64x60_handle *bh, struct mv64x60_setup_info *si)
551{
552 struct pci_controller hose_a, hose_b;
553
554 memset(bh, 0, sizeof(*bh));
555
556 bh->p_base = si->phys_reg_base;
557 bh->v_base = ioremap(bh->p_base, MV64x60_INTERNAL_SPACE_SIZE);
558
559 mv64x60_bridge_pbase = bh->p_base;
560 mv64x60_bridge_vbase = bh->v_base;
561
562 /* Assuming pci mode [reserved] bits 4:5 on 64260 are 0 */
563 bh->pci_mode_a = mv64x60_read(bh, MV64x60_PCI0_MODE) &
564 MV64x60_PCIMODE_MASK;
565 bh->pci_mode_b = mv64x60_read(bh, MV64x60_PCI1_MODE) &
566 MV64x60_PCIMODE_MASK;
567
568 /* Need temporary hose structs to call mv64x60_set_bus() */
569 memset(&hose_a, 0, sizeof(hose_a));
570 memset(&hose_b, 0, sizeof(hose_b));
571 setup_indirect_pci_nomap(&hose_a, bh->v_base + MV64x60_PCI0_CONFIG_ADDR,
572 bh->v_base + MV64x60_PCI0_CONFIG_DATA);
573 setup_indirect_pci_nomap(&hose_b, bh->v_base + MV64x60_PCI1_CONFIG_ADDR,
574 bh->v_base + MV64x60_PCI1_CONFIG_DATA);
575 bh->hose_a = &hose_a;
576 bh->hose_b = &hose_b;
577
578 mv64x60_set_bus(bh, 0, 0);
579 mv64x60_set_bus(bh, 1, 0);
580
581 bh->hose_a = NULL;
582 bh->hose_b = NULL;
583
584 /* Clear bit 0 of PCI addr decode control so PCI->CPU remap 1:1 */
585 mv64x60_clr_bits(bh, MV64x60_PCI0_PCI_DECODE_CNTL, 0x00000001);
586 mv64x60_clr_bits(bh, MV64x60_PCI1_PCI_DECODE_CNTL, 0x00000001);
587
588 /* Bit 12 MUST be 0; set bit 27--don't auto-update cpu remap regs */
589 mv64x60_clr_bits(bh, MV64x60_CPU_CONFIG, (1<<12));
590 mv64x60_set_bits(bh, MV64x60_CPU_CONFIG, (1<<27));
591
592 mv64x60_set_bits(bh, MV64x60_PCI0_TO_RETRY, 0xffff);
593 mv64x60_set_bits(bh, MV64x60_PCI1_TO_RETRY, 0xffff);
594
595 return;
596}
597
598/*
599 *****************************************************************************
600 *
601 * Window Config Routines
602 *
603 *****************************************************************************
604 */
605/*
606 * mv64x60_get_32bit_window()
607 *
608 * Determine the base address and size of a 32-bit window on the bridge.
609 */
610void __init
611mv64x60_get_32bit_window(struct mv64x60_handle *bh, u32 window,
612 u32 *base, u32 *size)
613{
614 u32 val, base_reg, size_reg, base_bits, size_bits;
615 u32 (*get_from_field)(u32 val, u32 num_bits);
616
617 base_reg = bh->ci->window_tab_32bit[window].base_reg;
618
619 if (base_reg != 0) {
620 size_reg = bh->ci->window_tab_32bit[window].size_reg;
621 base_bits = bh->ci->window_tab_32bit[window].base_bits;
622 size_bits = bh->ci->window_tab_32bit[window].size_bits;
623 get_from_field= bh->ci->window_tab_32bit[window].get_from_field;
624
625 val = mv64x60_read(bh, base_reg);
626 *base = get_from_field(val, base_bits);
627
628 if (size_reg != 0) {
629 val = mv64x60_read(bh, size_reg);
630 val = get_from_field(val, size_bits);
631 *size = bh->ci->untranslate_size(*base, val, size_bits);
632 }
633 else
634 *size = 0;
635 }
636 else {
637 *base = 0;
638 *size = 0;
639 }
640
641 pr_debug("get 32bit window: %d, base: 0x%x, size: 0x%x\n",
642 window, *base, *size);
643
644 return;
645}
646
647/*
648 * mv64x60_set_32bit_window()
649 *
650 * Set the base address and size of a 32-bit window on the bridge.
651 */
652void __init
653mv64x60_set_32bit_window(struct mv64x60_handle *bh, u32 window,
654 u32 base, u32 size, u32 other_bits)
655{
656 u32 val, base_reg, size_reg, base_bits, size_bits;
657 u32 (*map_to_field)(u32 val, u32 num_bits);
658
659 pr_debug("set 32bit window: %d, base: 0x%x, size: 0x%x, other: 0x%x\n",
660 window, base, size, other_bits);
661
662 base_reg = bh->ci->window_tab_32bit[window].base_reg;
663
664 if (base_reg != 0) {
665 size_reg = bh->ci->window_tab_32bit[window].size_reg;
666 base_bits = bh->ci->window_tab_32bit[window].base_bits;
667 size_bits = bh->ci->window_tab_32bit[window].size_bits;
668 map_to_field = bh->ci->window_tab_32bit[window].map_to_field;
669
670 val = map_to_field(base, base_bits) | other_bits;
671 mv64x60_write(bh, base_reg, val);
672
673 if (size_reg != 0) {
674 val = bh->ci->translate_size(base, size, size_bits);
675 val = map_to_field(val, size_bits);
676 mv64x60_write(bh, size_reg, val);
677 }
678
679 (void)mv64x60_read(bh, base_reg); /* Flush FIFO */
680 }
681
682 return;
683}
684
685/*
686 * mv64x60_get_64bit_window()
687 *
688 * Determine the base address and size of a 64-bit window on the bridge.
689 */
690void __init
691mv64x60_get_64bit_window(struct mv64x60_handle *bh, u32 window,
692 u32 *base_hi, u32 *base_lo, u32 *size)
693{
694 u32 val, base_lo_reg, size_reg, base_lo_bits, size_bits;
695 u32 (*get_from_field)(u32 val, u32 num_bits);
696
697 base_lo_reg = bh->ci->window_tab_64bit[window].base_lo_reg;
698
699 if (base_lo_reg != 0) {
700 size_reg = bh->ci->window_tab_64bit[window].size_reg;
701 base_lo_bits = bh->ci->window_tab_64bit[window].base_lo_bits;
702 size_bits = bh->ci->window_tab_64bit[window].size_bits;
703 get_from_field= bh->ci->window_tab_64bit[window].get_from_field;
704
705 *base_hi = mv64x60_read(bh,
706 bh->ci->window_tab_64bit[window].base_hi_reg);
707
708 val = mv64x60_read(bh, base_lo_reg);
709 *base_lo = get_from_field(val, base_lo_bits);
710
711 if (size_reg != 0) {
712 val = mv64x60_read(bh, size_reg);
713 val = get_from_field(val, size_bits);
714 *size = bh->ci->untranslate_size(*base_lo, val,
715 size_bits);
716 }
717 else
718 *size = 0;
719 }
720 else {
721 *base_hi = 0;
722 *base_lo = 0;
723 *size = 0;
724 }
725
726 pr_debug("get 64bit window: %d, base hi: 0x%x, base lo: 0x%x, "
727 "size: 0x%x\n", window, *base_hi, *base_lo, *size);
728
729 return;
730}
731
732/*
733 * mv64x60_set_64bit_window()
734 *
735 * Set the base address and size of a 64-bit window on the bridge.
736 */
737void __init
738mv64x60_set_64bit_window(struct mv64x60_handle *bh, u32 window,
739 u32 base_hi, u32 base_lo, u32 size, u32 other_bits)
740{
741 u32 val, base_lo_reg, size_reg, base_lo_bits, size_bits;
742 u32 (*map_to_field)(u32 val, u32 num_bits);
743
744 pr_debug("set 64bit window: %d, base hi: 0x%x, base lo: 0x%x, "
745 "size: 0x%x, other: 0x%x\n",
746 window, base_hi, base_lo, size, other_bits);
747
748 base_lo_reg = bh->ci->window_tab_64bit[window].base_lo_reg;
749
750 if (base_lo_reg != 0) {
751 size_reg = bh->ci->window_tab_64bit[window].size_reg;
752 base_lo_bits = bh->ci->window_tab_64bit[window].base_lo_bits;
753 size_bits = bh->ci->window_tab_64bit[window].size_bits;
754 map_to_field = bh->ci->window_tab_64bit[window].map_to_field;
755
756 mv64x60_write(bh, bh->ci->window_tab_64bit[window].base_hi_reg,
757 base_hi);
758
759 val = map_to_field(base_lo, base_lo_bits) | other_bits;
760 mv64x60_write(bh, base_lo_reg, val);
761
762 if (size_reg != 0) {
763 val = bh->ci->translate_size(base_lo, size, size_bits);
764 val = map_to_field(val, size_bits);
765 mv64x60_write(bh, size_reg, val);
766 }
767
768 (void)mv64x60_read(bh, base_lo_reg); /* Flush FIFO */
769 }
770
771 return;
772}
773
774/*
775 * mv64x60_mask()
776 *
777 * Take the high-order 'num_bits' of 'val' & mask off low bits.
778 */
779u32 __init
780mv64x60_mask(u32 val, u32 num_bits)
781{
782 return val & (0xffffffff << (32 - num_bits));
783}
784
785/*
786 * mv64x60_shift_left()
787 *
788 * Take the low-order 'num_bits' of 'val', shift left to align at bit 31 (MSB).
789 */
790u32 __init
791mv64x60_shift_left(u32 val, u32 num_bits)
792{
793 return val << (32 - num_bits);
794}
795
796/*
797 * mv64x60_shift_right()
798 *
799 * Take the high-order 'num_bits' of 'val', shift right to align at bit 0 (LSB).
800 */
801u32 __init
802mv64x60_shift_right(u32 val, u32 num_bits)
803{
804 return val >> (32 - num_bits);
805}
806
807/*
808 *****************************************************************************
809 *
810 * Chip Identification Routines
811 *
812 *****************************************************************************
813 */
814/*
815 * mv64x60_get_type()
816 *
817 * Determine the type of bridge chip we have.
818 */
819int __init
820mv64x60_get_type(struct mv64x60_handle *bh)
821{
822 struct pci_controller hose;
823 u16 val;
824 u8 save_exclude;
825
826 memset(&hose, 0, sizeof(hose));
827 setup_indirect_pci_nomap(&hose, bh->v_base + MV64x60_PCI0_CONFIG_ADDR,
828 bh->v_base + MV64x60_PCI0_CONFIG_DATA);
829
830 save_exclude = mv64x60_pci_exclude_bridge;
831 mv64x60_pci_exclude_bridge = 0;
832 /* Sanity check of bridge's Vendor ID */
833 early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID, &val);
834
835 if (val != PCI_VENDOR_ID_MARVELL) {
836 mv64x60_pci_exclude_bridge = save_exclude;
837 return -1;
838 }
839
840 /* Get the revision of the chip */
841 early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), PCI_CLASS_REVISION,
842 &val);
843 bh->rev = (u32)(val & 0xff);
844
845 /* Figure out the type of Marvell bridge it is */
846 early_read_config_word(&hose, 0, PCI_DEVFN(0, 0), PCI_DEVICE_ID, &val);
847 mv64x60_pci_exclude_bridge = save_exclude;
848
849 switch (val) {
850 case PCI_DEVICE_ID_MARVELL_GT64260:
851 switch (bh->rev) {
852 case GT64260_REV_A:
853 bh->type = MV64x60_TYPE_GT64260A;
854 break;
855
856 default:
857 printk(KERN_WARNING "Unsupported GT64260 rev %04x\n",
858 bh->rev);
859 /* Assume its similar to a 'B' rev and fallthru */
860 case GT64260_REV_B:
861 bh->type = MV64x60_TYPE_GT64260B;
862 break;
863 }
864 break;
865
866 case PCI_DEVICE_ID_MARVELL_MV64360:
867 /* Marvell won't tell me how to distinguish a 64361 & 64362 */
868 bh->type = MV64x60_TYPE_MV64360;
869 break;
870
871 case PCI_DEVICE_ID_MARVELL_MV64460:
872 bh->type = MV64x60_TYPE_MV64460;
873 break;
874
875 default:
876 printk(KERN_ERR "Unknown Marvell bridge type %04x\n", val);
877 return -1;
878 }
879
880 /* Hang onto bridge type & rev for PIC code */
881 mv64x60_bridge_type = bh->type;
882 mv64x60_bridge_rev = bh->rev;
883
884 return 0;
885}
886
887/*
888 * mv64x60_setup_for_chip()
889 *
890 * Set 'bh' to use the proper set of routine for the bridge chip that we have.
891 */
892int __init
893mv64x60_setup_for_chip(struct mv64x60_handle *bh)
894{
895 int rc = 0;
896
897 /* Set up chip-specific info based on the chip/bridge type */
898 switch(bh->type) {
899 case MV64x60_TYPE_GT64260A:
900 bh->ci = &gt64260a_ci;
901 break;
902
903 case MV64x60_TYPE_GT64260B:
904 bh->ci = &gt64260b_ci;
905 break;
906
907 case MV64x60_TYPE_MV64360:
908 bh->ci = &mv64360_ci;
909 break;
910
911 case MV64x60_TYPE_MV64460:
912 bh->ci = &mv64460_ci;
913 break;
914
915 case MV64x60_TYPE_INVALID:
916 default:
917 if (ppc_md.progress)
918 ppc_md.progress("mv64x60: Unsupported bridge", 0x0);
919 printk(KERN_ERR "mv64x60: Unsupported bridge\n");
920 rc = -1;
921 }
922
923 return rc;
924}
925
926/*
927 * mv64x60_get_bridge_vbase()
928 *
929 * Return the virtual address of the bridge's registers.
930 */
931void *
932mv64x60_get_bridge_vbase(void)
933{
934 return mv64x60_bridge_vbase;
935}
936
937/*
938 * mv64x60_get_bridge_type()
939 *
940 * Return the type of bridge on the platform.
941 */
942u32
943mv64x60_get_bridge_type(void)
944{
945 return mv64x60_bridge_type;
946}
947
948/*
949 * mv64x60_get_bridge_rev()
950 *
951 * Return the revision of the bridge on the platform.
952 */
953u32
954mv64x60_get_bridge_rev(void)
955{
956 return mv64x60_bridge_rev;
957}
958
959/*
960 *****************************************************************************
961 *
962 * System Memory Window Related Routines
963 *
964 *****************************************************************************
965 */
966/*
967 * mv64x60_get_mem_size()
968 *
969 * Calculate the amount of memory that the memory controller is set up for.
970 * This should only be used by board-specific code if there is no other
971 * way to determine the amount of memory in the system.
972 */
973u32 __init
974mv64x60_get_mem_size(u32 bridge_base, u32 chip_type)
975{
976 struct mv64x60_handle bh;
977 u32 mem_windows[MV64x60_CPU2MEM_WINDOWS][2];
978 u32 rc = 0;
979
980 memset(&bh, 0, sizeof(bh));
981
982 bh.type = chip_type;
983 bh.v_base = (void *)bridge_base;
984
985 if (!mv64x60_setup_for_chip(&bh)) {
986 mv64x60_get_mem_windows(&bh, mem_windows);
987 rc = mv64x60_calc_mem_size(&bh, mem_windows);
988 }
989
990 return rc;
991}
992
993/*
994 * mv64x60_get_mem_windows()
995 *
996 * Get the values in the memory controller & return in the 'mem_windows' array.
997 */
998void __init
999mv64x60_get_mem_windows(struct mv64x60_handle *bh,
1000 u32 mem_windows[MV64x60_CPU2MEM_WINDOWS][2])
1001{
1002 u32 i, win;
1003
1004 for (win=MV64x60_CPU2MEM_0_WIN,i=0;win<=MV64x60_CPU2MEM_3_WIN;win++,i++)
1005 if (bh->ci->is_enabled_32bit(bh, win))
1006 mv64x60_get_32bit_window(bh, win,
1007 &mem_windows[i][0], &mem_windows[i][1]);
1008 else {
1009 mem_windows[i][0] = 0;
1010 mem_windows[i][1] = 0;
1011 }
1012
1013 return;
1014}
1015
1016/*
1017 * mv64x60_calc_mem_size()
1018 *
1019 * Using the memory controller register values in 'mem_windows', determine
1020 * how much memory it is set up for.
1021 */
1022u32 __init
1023mv64x60_calc_mem_size(struct mv64x60_handle *bh,
1024 u32 mem_windows[MV64x60_CPU2MEM_WINDOWS][2])
1025{
1026 u32 i, total = 0;
1027
1028 for (i=0; i<MV64x60_CPU2MEM_WINDOWS; i++)
1029 total += mem_windows[i][1];
1030
1031 return total;
1032}
1033
1034/*
1035 *****************************************************************************
1036 *
1037 * CPU->System MEM, PCI Config Routines
1038 *
1039 *****************************************************************************
1040 */
1041/*
1042 * mv64x60_config_cpu2mem_windows()
1043 *
1044 * Configure CPU->Memory windows on the bridge.
1045 */
1046static u32 prot_tab[] __initdata = {
1047 MV64x60_CPU_PROT_0_WIN, MV64x60_CPU_PROT_1_WIN,
1048 MV64x60_CPU_PROT_2_WIN, MV64x60_CPU_PROT_3_WIN
1049};
1050
1051static u32 cpu_snoop_tab[] __initdata = {
1052 MV64x60_CPU_SNOOP_0_WIN, MV64x60_CPU_SNOOP_1_WIN,
1053 MV64x60_CPU_SNOOP_2_WIN, MV64x60_CPU_SNOOP_3_WIN
1054};
1055
1056void __init
1057mv64x60_config_cpu2mem_windows(struct mv64x60_handle *bh,
1058 struct mv64x60_setup_info *si,
1059 u32 mem_windows[MV64x60_CPU2MEM_WINDOWS][2])
1060{
1061 u32 i, win;
1062
1063 /* Set CPU protection & snoop windows */
1064 for (win=MV64x60_CPU2MEM_0_WIN,i=0;win<=MV64x60_CPU2MEM_3_WIN;win++,i++)
1065 if (bh->ci->is_enabled_32bit(bh, win)) {
1066 mv64x60_set_32bit_window(bh, prot_tab[i],
1067 mem_windows[i][0], mem_windows[i][1],
1068 si->cpu_prot_options[i]);
1069 bh->ci->enable_window_32bit(bh, prot_tab[i]);
1070
1071 if (bh->ci->window_tab_32bit[cpu_snoop_tab[i]].
1072 base_reg != 0) {
1073 mv64x60_set_32bit_window(bh, cpu_snoop_tab[i],
1074 mem_windows[i][0], mem_windows[i][1],
1075 si->cpu_snoop_options[i]);
1076 bh->ci->enable_window_32bit(bh,
1077 cpu_snoop_tab[i]);
1078 }
1079
1080 }
1081
1082 return;
1083}
1084
1085/*
1086 * mv64x60_config_cpu2pci_windows()
1087 *
1088 * Configure the CPU->PCI windows for one of the PCI buses.
1089 */
1090static u32 win_tab[2][4] __initdata = {
1091 { MV64x60_CPU2PCI0_IO_WIN, MV64x60_CPU2PCI0_MEM_0_WIN,
1092 MV64x60_CPU2PCI0_MEM_1_WIN, MV64x60_CPU2PCI0_MEM_2_WIN },
1093 { MV64x60_CPU2PCI1_IO_WIN, MV64x60_CPU2PCI1_MEM_0_WIN,
1094 MV64x60_CPU2PCI1_MEM_1_WIN, MV64x60_CPU2PCI1_MEM_2_WIN },
1095};
1096
1097static u32 remap_tab[2][4] __initdata = {
1098 { MV64x60_CPU2PCI0_IO_REMAP_WIN, MV64x60_CPU2PCI0_MEM_0_REMAP_WIN,
1099 MV64x60_CPU2PCI0_MEM_1_REMAP_WIN, MV64x60_CPU2PCI0_MEM_2_REMAP_WIN },
1100 { MV64x60_CPU2PCI1_IO_REMAP_WIN, MV64x60_CPU2PCI1_MEM_0_REMAP_WIN,
1101 MV64x60_CPU2PCI1_MEM_1_REMAP_WIN, MV64x60_CPU2PCI1_MEM_2_REMAP_WIN }
1102};
1103
1104void __init
1105mv64x60_config_cpu2pci_windows(struct mv64x60_handle *bh,
1106 struct mv64x60_pci_info *pi, u32 bus)
1107{
1108 int i;
1109
1110 if (pi->pci_io.size > 0) {
1111 mv64x60_set_32bit_window(bh, win_tab[bus][0],
1112 pi->pci_io.cpu_base, pi->pci_io.size, pi->pci_io.swap);
1113 mv64x60_set_32bit_window(bh, remap_tab[bus][0],
1114 pi->pci_io.pci_base_lo, 0, 0);
1115 bh->ci->enable_window_32bit(bh, win_tab[bus][0]);
1116 }
1117 else /* Actually, the window should already be disabled */
1118 bh->ci->disable_window_32bit(bh, win_tab[bus][0]);
1119
1120 for (i=0; i<3; i++)
1121 if (pi->pci_mem[i].size > 0) {
1122 mv64x60_set_32bit_window(bh, win_tab[bus][i+1],
1123 pi->pci_mem[i].cpu_base, pi->pci_mem[i].size,
1124 pi->pci_mem[i].swap);
1125 mv64x60_set_64bit_window(bh, remap_tab[bus][i+1],
1126 pi->pci_mem[i].pci_base_hi,
1127 pi->pci_mem[i].pci_base_lo, 0, 0);
1128 bh->ci->enable_window_32bit(bh, win_tab[bus][i+1]);
1129 }
1130 else /* Actually, the window should already be disabled */
1131 bh->ci->disable_window_32bit(bh, win_tab[bus][i+1]);
1132
1133 return;
1134}
1135
1136/*
1137 *****************************************************************************
1138 *
1139 * PCI->System MEM Config Routines
1140 *
1141 *****************************************************************************
1142 */
1143/*
1144 * mv64x60_config_pci2mem_windows()
1145 *
1146 * Configure the PCI->Memory windows on the bridge.
1147 */
1148static u32 pci_acc_tab[2][4] __initdata = {
1149 { MV64x60_PCI02MEM_ACC_CNTL_0_WIN, MV64x60_PCI02MEM_ACC_CNTL_1_WIN,
1150 MV64x60_PCI02MEM_ACC_CNTL_2_WIN, MV64x60_PCI02MEM_ACC_CNTL_3_WIN },
1151 { MV64x60_PCI12MEM_ACC_CNTL_0_WIN, MV64x60_PCI12MEM_ACC_CNTL_1_WIN,
1152 MV64x60_PCI12MEM_ACC_CNTL_2_WIN, MV64x60_PCI12MEM_ACC_CNTL_3_WIN }
1153};
1154
1155static u32 pci_snoop_tab[2][4] __initdata = {
1156 { MV64x60_PCI02MEM_SNOOP_0_WIN, MV64x60_PCI02MEM_SNOOP_1_WIN,
1157 MV64x60_PCI02MEM_SNOOP_2_WIN, MV64x60_PCI02MEM_SNOOP_3_WIN },
1158 { MV64x60_PCI12MEM_SNOOP_0_WIN, MV64x60_PCI12MEM_SNOOP_1_WIN,
1159 MV64x60_PCI12MEM_SNOOP_2_WIN, MV64x60_PCI12MEM_SNOOP_3_WIN }
1160};
1161
1162static u32 pci_size_tab[2][4] __initdata = {
1163 { MV64x60_PCI0_MEM_0_SIZE, MV64x60_PCI0_MEM_1_SIZE,
1164 MV64x60_PCI0_MEM_2_SIZE, MV64x60_PCI0_MEM_3_SIZE },
1165 { MV64x60_PCI1_MEM_0_SIZE, MV64x60_PCI1_MEM_1_SIZE,
1166 MV64x60_PCI1_MEM_2_SIZE, MV64x60_PCI1_MEM_3_SIZE }
1167};
1168
1169void __init
1170mv64x60_config_pci2mem_windows(struct mv64x60_handle *bh,
1171 struct pci_controller *hose, struct mv64x60_pci_info *pi,
1172 u32 bus, u32 mem_windows[MV64x60_CPU2MEM_WINDOWS][2])
1173{
1174 u32 i, win;
1175
1176 /*
1177 * Set the access control, snoop, BAR size, and window base addresses.
1178 * PCI->MEM windows base addresses will match exactly what the
1179 * CPU->MEM windows are.
1180 */
1181 for (win=MV64x60_CPU2MEM_0_WIN,i=0;win<=MV64x60_CPU2MEM_3_WIN;win++,i++)
1182 if (bh->ci->is_enabled_32bit(bh, win)) {
1183 mv64x60_set_64bit_window(bh,
1184 pci_acc_tab[bus][i], 0,
1185 mem_windows[i][0], mem_windows[i][1],
1186 pi->acc_cntl_options[i]);
1187 bh->ci->enable_window_64bit(bh, pci_acc_tab[bus][i]);
1188
1189 if (bh->ci->window_tab_64bit[
1190 pci_snoop_tab[bus][i]].base_lo_reg != 0) {
1191
1192 mv64x60_set_64bit_window(bh,
1193 pci_snoop_tab[bus][i], 0,
1194 mem_windows[i][0], mem_windows[i][1],
1195 pi->snoop_options[i]);
1196 bh->ci->enable_window_64bit(bh,
1197 pci_snoop_tab[bus][i]);
1198 }
1199
1200 bh->ci->set_pci2mem_window(hose, bus, i,
1201 mem_windows[i][0]);
1202 mv64x60_write(bh, pci_size_tab[bus][i],
1203 mv64x60_mask(mem_windows[i][1] - 1, 20));
1204
1205 /* Enable the window */
1206 mv64x60_clr_bits(bh, ((bus == 0) ?
1207 MV64x60_PCI0_BAR_ENABLE :
1208 MV64x60_PCI1_BAR_ENABLE), (1 << i));
1209 }
1210
1211 return;
1212}
1213
1214/*
1215 *****************************************************************************
1216 *
1217 * Hose & Resource Alloc/Init Routines
1218 *
1219 *****************************************************************************
1220 */
1221/*
1222 * mv64x60_alloc_hoses()
1223 *
1224 * Allocate the PCI hose structures for the bridge's PCI buses.
1225 */
1226void __init
1227mv64x60_alloc_hose(struct mv64x60_handle *bh, u32 cfg_addr, u32 cfg_data,
1228 struct pci_controller **hose)
1229{
1230 *hose = pcibios_alloc_controller();
1231 setup_indirect_pci_nomap(*hose, bh->v_base + cfg_addr,
1232 bh->v_base + cfg_data);
1233 return;
1234}
1235
1236/*
1237 * mv64x60_config_resources()
1238 *
1239 * Calculate the offsets, etc. for the hose structures to reflect all of
1240 * the address remapping that happens as you go from CPU->PCI and PCI->MEM.
1241 */
1242void __init
1243mv64x60_config_resources(struct pci_controller *hose,
1244 struct mv64x60_pci_info *pi, u32 io_base)
1245{
1246 int i;
1247 /* 2 hoses; 4 resources/hose; string <= 64 bytes */
1248 static char s[2][4][64];
1249
1250 if (pi->pci_io.size != 0) {
1251 sprintf(s[hose->index][0], "PCI hose %d I/O Space",
1252 hose->index);
1253 pci_init_resource(&hose->io_resource, io_base - isa_io_base,
1254 io_base - isa_io_base + pi->pci_io.size - 1,
1255 IORESOURCE_IO, s[hose->index][0]);
1256 hose->io_space.start = pi->pci_io.pci_base_lo;
1257 hose->io_space.end = pi->pci_io.pci_base_lo + pi->pci_io.size-1;
1258 hose->io_base_phys = pi->pci_io.cpu_base;
1259 hose->io_base_virt = (void *)isa_io_base;
1260 }
1261
1262 for (i=0; i<3; i++)
1263 if (pi->pci_mem[i].size != 0) {
1264 sprintf(s[hose->index][i+1], "PCI hose %d MEM Space %d",
1265 hose->index, i);
1266 pci_init_resource(&hose->mem_resources[i],
1267 pi->pci_mem[i].cpu_base,
1268 pi->pci_mem[i].cpu_base + pi->pci_mem[i].size-1,
1269 IORESOURCE_MEM, s[hose->index][i+1]);
1270 }
1271
1272 hose->mem_space.end = pi->pci_mem[0].pci_base_lo +
1273 pi->pci_mem[0].size - 1;
1274 hose->pci_mem_offset = pi->pci_mem[0].cpu_base -
1275 pi->pci_mem[0].pci_base_lo;
1276 return;
1277}
1278
1279/*
1280 * mv64x60_config_pci_params()
1281 *
1282 * Configure a hose's PCI config space parameters.
1283 */
1284void __init
1285mv64x60_config_pci_params(struct pci_controller *hose,
1286 struct mv64x60_pci_info *pi)
1287{
1288 u32 devfn;
1289 u16 u16_val;
1290 u8 save_exclude;
1291
1292 devfn = PCI_DEVFN(0,0);
1293
1294 save_exclude = mv64x60_pci_exclude_bridge;
1295 mv64x60_pci_exclude_bridge = 0;
1296
1297 /* Set class code to indicate host bridge */
1298 u16_val = PCI_CLASS_BRIDGE_HOST; /* 0x0600 (host bridge) */
1299 early_write_config_word(hose, 0, devfn, PCI_CLASS_DEVICE, u16_val);
1300
1301 /* Enable bridge to be PCI master & respond to PCI MEM cycles */
1302 early_read_config_word(hose, 0, devfn, PCI_COMMAND, &u16_val);
1303 u16_val &= ~(PCI_COMMAND_IO | PCI_COMMAND_INVALIDATE |
1304 PCI_COMMAND_PARITY | PCI_COMMAND_SERR | PCI_COMMAND_FAST_BACK);
1305 u16_val |= pi->pci_cmd_bits | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
1306 early_write_config_word(hose, 0, devfn, PCI_COMMAND, u16_val);
1307
1308 /* Set latency timer, cache line size, clear BIST */
1309 u16_val = (pi->latency_timer << 8) | (L1_CACHE_LINE_SIZE >> 2);
1310 early_write_config_word(hose, 0, devfn, PCI_CACHE_LINE_SIZE, u16_val);
1311
1312 mv64x60_pci_exclude_bridge = save_exclude;
1313 return;
1314}
1315
1316/*
1317 *****************************************************************************
1318 *
1319 * PCI Related Routine
1320 *
1321 *****************************************************************************
1322 */
1323/*
1324 * mv64x60_set_bus()
1325 *
1326 * Set the bus number for the hose directly under the bridge.
1327 */
1328void __init
1329mv64x60_set_bus(struct mv64x60_handle *bh, u32 bus, u32 child_bus)
1330{
1331 struct pci_controller *hose;
1332 u32 pci_mode, p2p_cfg, pci_cfg_offset, val;
1333 u8 save_exclude;
1334
1335 if (bus == 0) {
1336 pci_mode = bh->pci_mode_a;
1337 p2p_cfg = MV64x60_PCI0_P2P_CONFIG;
1338 pci_cfg_offset = 0x64;
1339 hose = bh->hose_a;
1340 }
1341 else {
1342 pci_mode = bh->pci_mode_b;
1343 p2p_cfg = MV64x60_PCI1_P2P_CONFIG;
1344 pci_cfg_offset = 0xe4;
1345 hose = bh->hose_b;
1346 }
1347
1348 child_bus &= 0xff;
1349 val = mv64x60_read(bh, p2p_cfg);
1350
1351 if (pci_mode == MV64x60_PCIMODE_CONVENTIONAL) {
1352 val &= 0xe0000000; /* Force dev num to 0, turn off P2P bridge */
1353 val |= (child_bus << 16) | 0xff;
1354 mv64x60_write(bh, p2p_cfg, val);
1355 (void)mv64x60_read(bh, p2p_cfg); /* Flush FIFO */
1356 }
1357 else { /* PCI-X */
1358 /*
1359 * Need to use the current bus/dev number (that's in the
1360 * P2P CONFIG reg) to access the bridge's pci config space.
1361 */
1362 save_exclude = mv64x60_pci_exclude_bridge;
1363 mv64x60_pci_exclude_bridge = 0;
1364 early_write_config_dword(hose, (val & 0x00ff0000) >> 16,
1365 PCI_DEVFN(((val & 0x1f000000) >> 24), 0),
1366 pci_cfg_offset, child_bus << 8);
1367 mv64x60_pci_exclude_bridge = save_exclude;
1368 }
1369
1370 return;
1371}
1372
1373/*
1374 * mv64x60_pci_exclude_device()
1375 *
1376 * This routine is used to make the bridge not appear when the
1377 * PCI subsystem is accessing PCI devices (in PCI config space).
1378 */
1379int
1380mv64x60_pci_exclude_device(u8 bus, u8 devfn)
1381{
1382 struct pci_controller *hose;
1383
1384 hose = pci_bus_to_hose(bus);
1385
1386 /* Skip slot 0 on both hoses */
1387 if ((mv64x60_pci_exclude_bridge == 1) && (PCI_SLOT(devfn) == 0) &&
1388 (hose->first_busno == bus))
1389
1390 return PCIBIOS_DEVICE_NOT_FOUND;
1391 else
1392 return PCIBIOS_SUCCESSFUL;
1393} /* mv64x60_pci_exclude_device() */
1394
1395/*
1396 *****************************************************************************
1397 *
1398 * Platform Device Routines
1399 *
1400 *****************************************************************************
1401 */
1402
1403/*
1404 * mv64x60_pd_fixup()
1405 *
1406 * Need to add the base addr of where the bridge's regs are mapped in the
1407 * physical addr space so drivers can ioremap() them.
1408 */
1409void __init
1410mv64x60_pd_fixup(struct mv64x60_handle *bh, struct platform_device *pd_devs[],
1411 u32 entries)
1412{
1413 struct resource *r;
1414 u32 i, j;
1415
1416 for (i=0; i<entries; i++) {
1417 j = 0;
1418
1419 while ((r = platform_get_resource(pd_devs[i],IORESOURCE_MEM,j))
1420 != NULL) {
1421
1422 r->start += bh->p_base;
1423 r->end += bh->p_base;
1424 j++;
1425 }
1426 }
1427
1428 return;
1429}
1430
1431/*
1432 * mv64x60_add_pds()
1433 *
1434 * Add the mv64x60 platform devices to the list of platform devices.
1435 */
1436static int __init
1437mv64x60_add_pds(void)
1438{
1439 return platform_add_devices(mv64x60_pd_devs,
1440 ARRAY_SIZE(mv64x60_pd_devs));
1441}
1442arch_initcall(mv64x60_add_pds);
1443
1444/*
1445 *****************************************************************************
1446 *
1447 * GT64260-Specific Routines
1448 *
1449 *****************************************************************************
1450 */
1451/*
1452 * gt64260_translate_size()
1453 *
1454 * On the GT64260, the size register is really the "top" address of the window.
1455 */
1456static u32 __init
1457gt64260_translate_size(u32 base, u32 size, u32 num_bits)
1458{
1459 return base + mv64x60_mask(size - 1, num_bits);
1460}
1461
1462/*
1463 * gt64260_untranslate_size()
1464 *
1465 * Translate the top address of a window into a window size.
1466 */
1467static u32 __init
1468gt64260_untranslate_size(u32 base, u32 size, u32 num_bits)
1469{
1470 if (size >= base)
1471 size = size - base + (1 << (32 - num_bits));
1472 else
1473 size = 0;
1474
1475 return size;
1476}
1477
1478/*
1479 * gt64260_set_pci2mem_window()
1480 *
1481 * The PCI->MEM window registers are actually in PCI config space so need
1482 * to set them by setting the correct config space BARs.
1483 */
1484static u32 gt64260_reg_addrs[2][4] __initdata = {
1485 { 0x10, 0x14, 0x18, 0x1c }, { 0x90, 0x94, 0x98, 0x9c }
1486};
1487
1488static void __init
1489gt64260_set_pci2mem_window(struct pci_controller *hose, u32 bus, u32 window,
1490 u32 base)
1491{
1492 u8 save_exclude;
1493
1494 pr_debug("set pci->mem window: %d, hose: %d, base: 0x%x\n", window,
1495 hose->index, base);
1496
1497 save_exclude = mv64x60_pci_exclude_bridge;
1498 mv64x60_pci_exclude_bridge = 0;
1499 early_write_config_dword(hose, 0, PCI_DEVFN(0, 0),
1500 gt64260_reg_addrs[bus][window], mv64x60_mask(base, 20) | 0x8);
1501 mv64x60_pci_exclude_bridge = save_exclude;
1502
1503 return;
1504}
1505
1506/*
1507 * gt64260_set_pci2regs_window()
1508 *
1509 * Set where the bridge's registers appear in PCI MEM space.
1510 */
1511static u32 gt64260_offset[2] __initdata = {0x20, 0xa0};
1512
1513static void __init
1514gt64260_set_pci2regs_window(struct mv64x60_handle *bh,
1515 struct pci_controller *hose, u32 bus, u32 base)
1516{
1517 u8 save_exclude;
1518
1519 pr_debug("set pci->internal regs hose: %d, base: 0x%x\n", hose->index,
1520 base);
1521
1522 save_exclude = mv64x60_pci_exclude_bridge;
1523 mv64x60_pci_exclude_bridge = 0;
1524 early_write_config_dword(hose, 0, PCI_DEVFN(0,0), gt64260_offset[bus],
1525 (base << 16));
1526 mv64x60_pci_exclude_bridge = save_exclude;
1527
1528 return;
1529}
1530
1531/*
1532 * gt64260_is_enabled_32bit()
1533 *
1534 * On a GT64260, a window is enabled iff its top address is >= to its base
1535 * address.
1536 */
1537static u32 __init
1538gt64260_is_enabled_32bit(struct mv64x60_handle *bh, u32 window)
1539{
1540 u32 rc = 0;
1541
1542 if ((gt64260_32bit_windows[window].base_reg != 0) &&
1543 (gt64260_32bit_windows[window].size_reg != 0) &&
1544 ((mv64x60_read(bh, gt64260_32bit_windows[window].size_reg) &
1545 ((1 << gt64260_32bit_windows[window].size_bits) - 1)) >=
1546 (mv64x60_read(bh, gt64260_32bit_windows[window].base_reg) &
1547 ((1 << gt64260_32bit_windows[window].base_bits) - 1))))
1548
1549 rc = 1;
1550
1551 return rc;
1552}
1553
1554/*
1555 * gt64260_enable_window_32bit()
1556 *
1557 * On the GT64260, a window is enabled iff the top address is >= to the base
1558 * address of the window. Since the window has already been configured by
1559 * the time this routine is called, we have nothing to do here.
1560 */
1561static void __init
1562gt64260_enable_window_32bit(struct mv64x60_handle *bh, u32 window)
1563{
1564 pr_debug("enable 32bit window: %d\n", window);
1565 return;
1566}
1567
1568/*
1569 * gt64260_disable_window_32bit()
1570 *
1571 * On a GT64260, you disable a window by setting its top address to be less
1572 * than its base address.
1573 */
1574static void __init
1575gt64260_disable_window_32bit(struct mv64x60_handle *bh, u32 window)
1576{
1577 pr_debug("disable 32bit window: %d, base_reg: 0x%x, size_reg: 0x%x\n",
1578 window, gt64260_32bit_windows[window].base_reg,
1579 gt64260_32bit_windows[window].size_reg);
1580
1581 if ((gt64260_32bit_windows[window].base_reg != 0) &&
1582 (gt64260_32bit_windows[window].size_reg != 0)) {
1583
1584 /* To disable, make bottom reg higher than top reg */
1585 mv64x60_write(bh, gt64260_32bit_windows[window].base_reg,0xfff);
1586 mv64x60_write(bh, gt64260_32bit_windows[window].size_reg, 0);
1587 }
1588
1589 return;
1590}
1591
1592/*
1593 * gt64260_enable_window_64bit()
1594 *
1595 * On the GT64260, a window is enabled iff the top address is >= to the base
1596 * address of the window. Since the window has already been configured by
1597 * the time this routine is called, we have nothing to do here.
1598 */
1599static void __init
1600gt64260_enable_window_64bit(struct mv64x60_handle *bh, u32 window)
1601{
1602 pr_debug("enable 64bit window: %d\n", window);
1603 return; /* Enabled when window configured (i.e., when top >= base) */
1604}
1605
1606/*
1607 * gt64260_disable_window_64bit()
1608 *
1609 * On a GT64260, you disable a window by setting its top address to be less
1610 * than its base address.
1611 */
1612static void __init
1613gt64260_disable_window_64bit(struct mv64x60_handle *bh, u32 window)
1614{
1615 pr_debug("disable 64bit window: %d, base_reg: 0x%x, size_reg: 0x%x\n",
1616 window, gt64260_64bit_windows[window].base_lo_reg,
1617 gt64260_64bit_windows[window].size_reg);
1618
1619 if ((gt64260_64bit_windows[window].base_lo_reg != 0) &&
1620 (gt64260_64bit_windows[window].size_reg != 0)) {
1621
1622 /* To disable, make bottom reg higher than top reg */
1623 mv64x60_write(bh, gt64260_64bit_windows[window].base_lo_reg,
1624 0xfff);
1625 mv64x60_write(bh, gt64260_64bit_windows[window].base_hi_reg, 0);
1626 mv64x60_write(bh, gt64260_64bit_windows[window].size_reg, 0);
1627 }
1628
1629 return;
1630}
1631
1632/*
1633 * gt64260_disable_all_windows()
1634 *
1635 * The GT64260 has several windows that aren't represented in the table of
1636 * windows at the top of this file. This routine turns all of them off
1637 * except for the memory controller windows, of course.
1638 */
1639static void __init
1640gt64260_disable_all_windows(struct mv64x60_handle *bh,
1641 struct mv64x60_setup_info *si)
1642{
1643 u32 i, preserve;
1644
1645 /* Disable 32bit windows (don't disable cpu->mem windows) */
1646 for (i=MV64x60_CPU2DEV_0_WIN; i<MV64x60_32BIT_WIN_COUNT; i++) {
1647 if (i < 32)
1648 preserve = si->window_preserve_mask_32_lo & (1 << i);
1649 else
1650 preserve = si->window_preserve_mask_32_hi & (1<<(i-32));
1651
1652 if (!preserve)
1653 gt64260_disable_window_32bit(bh, i);
1654 }
1655
1656 /* Disable 64bit windows */
1657 for (i=0; i<MV64x60_64BIT_WIN_COUNT; i++)
1658 if (!(si->window_preserve_mask_64 & (1<<i)))
1659 gt64260_disable_window_64bit(bh, i);
1660
1661 /* Turn off cpu protection windows not in gt64260_32bit_windows[] */
1662 mv64x60_write(bh, GT64260_CPU_PROT_BASE_4, 0xfff);
1663 mv64x60_write(bh, GT64260_CPU_PROT_SIZE_4, 0);
1664 mv64x60_write(bh, GT64260_CPU_PROT_BASE_5, 0xfff);
1665 mv64x60_write(bh, GT64260_CPU_PROT_SIZE_5, 0);
1666 mv64x60_write(bh, GT64260_CPU_PROT_BASE_6, 0xfff);
1667 mv64x60_write(bh, GT64260_CPU_PROT_SIZE_6, 0);
1668 mv64x60_write(bh, GT64260_CPU_PROT_BASE_7, 0xfff);
1669 mv64x60_write(bh, GT64260_CPU_PROT_SIZE_7, 0);
1670
1671 /* Turn off PCI->MEM access cntl wins not in gt64260_64bit_windows[] */
1672 mv64x60_write(bh, MV64x60_PCI0_ACC_CNTL_4_BASE_LO, 0xfff);
1673 mv64x60_write(bh, MV64x60_PCI0_ACC_CNTL_4_BASE_HI, 0);
1674 mv64x60_write(bh, MV64x60_PCI0_ACC_CNTL_4_SIZE, 0);
1675 mv64x60_write(bh, MV64x60_PCI0_ACC_CNTL_5_BASE_LO, 0xfff);
1676 mv64x60_write(bh, MV64x60_PCI0_ACC_CNTL_5_BASE_HI, 0);
1677 mv64x60_write(bh, MV64x60_PCI0_ACC_CNTL_5_SIZE, 0);
1678 mv64x60_write(bh, GT64260_PCI0_ACC_CNTL_6_BASE_LO, 0xfff);
1679 mv64x60_write(bh, GT64260_PCI0_ACC_CNTL_6_BASE_HI, 0);
1680 mv64x60_write(bh, GT64260_PCI0_ACC_CNTL_6_SIZE, 0);
1681 mv64x60_write(bh, GT64260_PCI0_ACC_CNTL_7_BASE_LO, 0xfff);
1682 mv64x60_write(bh, GT64260_PCI0_ACC_CNTL_7_BASE_HI, 0);
1683 mv64x60_write(bh, GT64260_PCI0_ACC_CNTL_7_SIZE, 0);
1684
1685 mv64x60_write(bh, MV64x60_PCI1_ACC_CNTL_4_BASE_LO, 0xfff);
1686 mv64x60_write(bh, MV64x60_PCI1_ACC_CNTL_4_BASE_HI, 0);
1687 mv64x60_write(bh, MV64x60_PCI1_ACC_CNTL_4_SIZE, 0);
1688 mv64x60_write(bh, MV64x60_PCI1_ACC_CNTL_5_BASE_LO, 0xfff);
1689 mv64x60_write(bh, MV64x60_PCI1_ACC_CNTL_5_BASE_HI, 0);
1690 mv64x60_write(bh, MV64x60_PCI1_ACC_CNTL_5_SIZE, 0);
1691 mv64x60_write(bh, GT64260_PCI1_ACC_CNTL_6_BASE_LO, 0xfff);
1692 mv64x60_write(bh, GT64260_PCI1_ACC_CNTL_6_BASE_HI, 0);
1693 mv64x60_write(bh, GT64260_PCI1_ACC_CNTL_6_SIZE, 0);
1694 mv64x60_write(bh, GT64260_PCI1_ACC_CNTL_7_BASE_LO, 0xfff);
1695 mv64x60_write(bh, GT64260_PCI1_ACC_CNTL_7_BASE_HI, 0);
1696 mv64x60_write(bh, GT64260_PCI1_ACC_CNTL_7_SIZE, 0);
1697
1698 /* Disable all PCI-><whatever> windows */
1699 mv64x60_set_bits(bh, MV64x60_PCI0_BAR_ENABLE, 0x07fffdff);
1700 mv64x60_set_bits(bh, MV64x60_PCI1_BAR_ENABLE, 0x07fffdff);
1701
1702 /*
1703 * Some firmwares enable a bunch of intr sources
1704 * for the PCI INT output pins.
1705 */
1706 mv64x60_write(bh, GT64260_IC_CPU_INTR_MASK_LO, 0);
1707 mv64x60_write(bh, GT64260_IC_CPU_INTR_MASK_HI, 0);
1708 mv64x60_write(bh, GT64260_IC_PCI0_INTR_MASK_LO, 0);
1709 mv64x60_write(bh, GT64260_IC_PCI0_INTR_MASK_HI, 0);
1710 mv64x60_write(bh, GT64260_IC_PCI1_INTR_MASK_LO, 0);
1711 mv64x60_write(bh, GT64260_IC_PCI1_INTR_MASK_HI, 0);
1712 mv64x60_write(bh, GT64260_IC_CPU_INT_0_MASK, 0);
1713 mv64x60_write(bh, GT64260_IC_CPU_INT_1_MASK, 0);
1714 mv64x60_write(bh, GT64260_IC_CPU_INT_2_MASK, 0);
1715 mv64x60_write(bh, GT64260_IC_CPU_INT_3_MASK, 0);
1716
1717 return;
1718}
1719
1720/*
1721 * gt64260a_chip_specific_init()
1722 *
1723 * Implement errata work arounds for the GT64260A.
1724 */
1725static void __init
1726gt64260a_chip_specific_init(struct mv64x60_handle *bh,
1727 struct mv64x60_setup_info *si)
1728{
1729#ifdef CONFIG_SERIAL_MPSC
1730 struct resource *r;
1731#endif
1732#if !defined(CONFIG_NOT_COHERENT_CACHE)
1733 u32 val;
1734 u8 save_exclude;
1735#endif
1736
1737 if (si->pci_0.enable_bus)
1738 mv64x60_set_bits(bh, MV64x60_PCI0_CMD,
1739 ((1<<4) | (1<<5) | (1<<9) | (1<<13)));
1740
1741 if (si->pci_1.enable_bus)
1742 mv64x60_set_bits(bh, MV64x60_PCI1_CMD,
1743 ((1<<4) | (1<<5) | (1<<9) | (1<<13)));
1744
1745 /*
1746 * Dave Wilhardt found that bit 4 in the PCI Command registers must
1747 * be set if you are using cache coherency.
1748 */
1749#if !defined(CONFIG_NOT_COHERENT_CACHE)
1750 /* Res #MEM-4 -- cpu read buffer to buffer 1 */
1751 if ((mv64x60_read(bh, MV64x60_CPU_MODE) & 0xf0) == 0x40)
1752 mv64x60_set_bits(bh, GT64260_SDRAM_CONFIG, (1<<26));
1753
1754 save_exclude = mv64x60_pci_exclude_bridge;
1755 mv64x60_pci_exclude_bridge = 0;
1756 if (si->pci_0.enable_bus) {
1757 early_read_config_dword(bh->hose_a, 0, PCI_DEVFN(0,0),
1758 PCI_COMMAND, &val);
1759 val |= PCI_COMMAND_INVALIDATE;
1760 early_write_config_dword(bh->hose_a, 0, PCI_DEVFN(0,0),
1761 PCI_COMMAND, val);
1762 }
1763
1764 if (si->pci_1.enable_bus) {
1765 early_read_config_dword(bh->hose_b, 0, PCI_DEVFN(0,0),
1766 PCI_COMMAND, &val);
1767 val |= PCI_COMMAND_INVALIDATE;
1768 early_write_config_dword(bh->hose_b, 0, PCI_DEVFN(0,0),
1769 PCI_COMMAND, val);
1770 }
1771 mv64x60_pci_exclude_bridge = save_exclude;
1772#endif
1773
1774 /* Disable buffer/descriptor snooping */
1775 mv64x60_clr_bits(bh, 0xf280, (1<< 6) | (1<<14) | (1<<22) | (1<<30));
1776 mv64x60_clr_bits(bh, 0xf2c0, (1<< 6) | (1<<14) | (1<<22) | (1<<30));
1777
1778#ifdef CONFIG_SERIAL_MPSC
1779 mv64x60_mpsc0_pdata.mirror_regs = 1;
1780 mv64x60_mpsc0_pdata.cache_mgmt = 1;
1781 mv64x60_mpsc1_pdata.mirror_regs = 1;
1782 mv64x60_mpsc1_pdata.cache_mgmt = 1;
1783
1784 if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 0))
1785 != NULL) {
1786
1787 r->start = MV64x60_IRQ_SDMA_0;
1788 r->end = MV64x60_IRQ_SDMA_0;
1789 }
1790#endif
1791
1792 return;
1793}
1794
1795/*
1796 * gt64260b_chip_specific_init()
1797 *
1798 * Implement errata work arounds for the GT64260B.
1799 */
1800static void __init
1801gt64260b_chip_specific_init(struct mv64x60_handle *bh,
1802 struct mv64x60_setup_info *si)
1803{
1804#ifdef CONFIG_SERIAL_MPSC
1805 struct resource *r;
1806#endif
1807#if !defined(CONFIG_NOT_COHERENT_CACHE)
1808 u32 val;
1809 u8 save_exclude;
1810#endif
1811
1812 if (si->pci_0.enable_bus)
1813 mv64x60_set_bits(bh, MV64x60_PCI0_CMD,
1814 ((1<<4) | (1<<5) | (1<<9) | (1<<13)));
1815
1816 if (si->pci_1.enable_bus)
1817 mv64x60_set_bits(bh, MV64x60_PCI1_CMD,
1818 ((1<<4) | (1<<5) | (1<<9) | (1<<13)));
1819
1820 /*
1821 * Dave Wilhardt found that bit 4 in the PCI Command registers must
1822 * be set if you are using cache coherency.
1823 */
1824#if !defined(CONFIG_NOT_COHERENT_CACHE)
1825 mv64x60_set_bits(bh, GT64260_CPU_WB_PRIORITY_BUFFER_DEPTH, 0xf);
1826
1827 /* Res #MEM-4 -- cpu read buffer to buffer 1 */
1828 if ((mv64x60_read(bh, MV64x60_CPU_MODE) & 0xf0) == 0x40)
1829 mv64x60_set_bits(bh, GT64260_SDRAM_CONFIG, (1<<26));
1830
1831 save_exclude = mv64x60_pci_exclude_bridge;
1832 mv64x60_pci_exclude_bridge = 0;
1833 if (si->pci_0.enable_bus) {
1834 early_read_config_dword(bh->hose_a, 0, PCI_DEVFN(0,0),
1835 PCI_COMMAND, &val);
1836 val |= PCI_COMMAND_INVALIDATE;
1837 early_write_config_dword(bh->hose_a, 0, PCI_DEVFN(0,0),
1838 PCI_COMMAND, val);
1839 }
1840
1841 if (si->pci_1.enable_bus) {
1842 early_read_config_dword(bh->hose_b, 0, PCI_DEVFN(0,0),
1843 PCI_COMMAND, &val);
1844 val |= PCI_COMMAND_INVALIDATE;
1845 early_write_config_dword(bh->hose_b, 0, PCI_DEVFN(0,0),
1846 PCI_COMMAND, val);
1847 }
1848 mv64x60_pci_exclude_bridge = save_exclude;
1849#endif
1850
1851 /* Disable buffer/descriptor snooping */
1852 mv64x60_clr_bits(bh, 0xf280, (1<< 6) | (1<<14) | (1<<22) | (1<<30));
1853 mv64x60_clr_bits(bh, 0xf2c0, (1<< 6) | (1<<14) | (1<<22) | (1<<30));
1854
1855#ifdef CONFIG_SERIAL_MPSC
1856 /*
1857 * The 64260B is not supposed to have the bug where the MPSC & ENET
1858 * can't access cache coherent regions. However, testing has shown
1859 * that the MPSC, at least, still has this bug.
1860 */
1861 mv64x60_mpsc0_pdata.cache_mgmt = 1;
1862 mv64x60_mpsc1_pdata.cache_mgmt = 1;
1863
1864 if ((r = platform_get_resource(&mpsc1_device, IORESOURCE_IRQ, 0))
1865 != NULL) {
1866
1867 r->start = MV64x60_IRQ_SDMA_0;
1868 r->end = MV64x60_IRQ_SDMA_0;
1869 }
1870#endif
1871
1872 return;
1873}
1874
1875/*
1876 *****************************************************************************
1877 *
1878 * MV64360-Specific Routines
1879 *
1880 *****************************************************************************
1881 */
1882/*
1883 * mv64360_translate_size()
1884 *
1885 * On the MV64360, the size register is set similar to the size you get
1886 * from a pci config space BAR register. That is, programmed from LSB to MSB
1887 * as a sequence of 1's followed by a sequence of 0's. IOW, "size -1" with the
1888 * assumption that the size is a power of 2.
1889 */
1890static u32 __init
1891mv64360_translate_size(u32 base_addr, u32 size, u32 num_bits)
1892{
1893 return mv64x60_mask(size - 1, num_bits);
1894}
1895
1896/*
1897 * mv64360_untranslate_size()
1898 *
1899 * Translate the size register value of a window into a window size.
1900 */
1901static u32 __init
1902mv64360_untranslate_size(u32 base_addr, u32 size, u32 num_bits)
1903{
1904 if (size > 0) {
1905 size >>= (32 - num_bits);
1906 size++;
1907 size <<= (32 - num_bits);
1908 }
1909
1910 return size;
1911}
1912
1913/*
1914 * mv64360_set_pci2mem_window()
1915 *
1916 * The PCI->MEM window registers are actually in PCI config space so need
1917 * to set them by setting the correct config space BARs.
1918 */
1919struct {
1920 u32 fcn;
1921 u32 base_hi_bar;
1922 u32 base_lo_bar;
1923} static mv64360_reg_addrs[2][4] __initdata = {
1924 {{ 0, 0x14, 0x10 }, { 0, 0x1c, 0x18 },
1925 { 1, 0x14, 0x10 }, { 1, 0x1c, 0x18 }},
1926 {{ 0, 0x94, 0x90 }, { 0, 0x9c, 0x98 },
1927 { 1, 0x94, 0x90 }, { 1, 0x9c, 0x98 }}
1928};
1929
1930static void __init
1931mv64360_set_pci2mem_window(struct pci_controller *hose, u32 bus, u32 window,
1932 u32 base)
1933{
1934 u8 save_exclude;
1935
1936 pr_debug("set pci->mem window: %d, hose: %d, base: 0x%x\n", window,
1937 hose->index, base);
1938
1939 save_exclude = mv64x60_pci_exclude_bridge;
1940 mv64x60_pci_exclude_bridge = 0;
1941 early_write_config_dword(hose, 0,
1942 PCI_DEVFN(0, mv64360_reg_addrs[bus][window].fcn),
1943 mv64360_reg_addrs[bus][window].base_hi_bar, 0);
1944 early_write_config_dword(hose, 0,
1945 PCI_DEVFN(0, mv64360_reg_addrs[bus][window].fcn),
1946 mv64360_reg_addrs[bus][window].base_lo_bar,
1947 mv64x60_mask(base,20) | 0xc);
1948 mv64x60_pci_exclude_bridge = save_exclude;
1949
1950 return;
1951}
1952
1953/*
1954 * mv64360_set_pci2regs_window()
1955 *
1956 * Set where the bridge's registers appear in PCI MEM space.
1957 */
1958static u32 mv64360_offset[2][2] __initdata = {{0x20, 0x24}, {0xa0, 0xa4}};
1959
1960static void __init
1961mv64360_set_pci2regs_window(struct mv64x60_handle *bh,
1962 struct pci_controller *hose, u32 bus, u32 base)
1963{
1964 u8 save_exclude;
1965
1966 pr_debug("set pci->internal regs hose: %d, base: 0x%x\n", hose->index,
1967 base);
1968
1969 save_exclude = mv64x60_pci_exclude_bridge;
1970 mv64x60_pci_exclude_bridge = 0;
1971 early_write_config_dword(hose, 0, PCI_DEVFN(0,0),
1972 mv64360_offset[bus][0], (base << 16));
1973 early_write_config_dword(hose, 0, PCI_DEVFN(0,0),
1974 mv64360_offset[bus][1], 0);
1975 mv64x60_pci_exclude_bridge = save_exclude;
1976
1977 return;
1978}
1979
1980/*
1981 * mv64360_is_enabled_32bit()
1982 *
1983 * On a MV64360, a window is enabled by either clearing a bit in the
1984 * CPU BAR Enable reg or setting a bit in the window's base reg.
1985 * Note that this doesn't work for windows on the PCI slave side but we don't
1986 * check those so its okay.
1987 */
1988static u32 __init
1989mv64360_is_enabled_32bit(struct mv64x60_handle *bh, u32 window)
1990{
1991 u32 extra, rc = 0;
1992
1993 if (((mv64360_32bit_windows[window].base_reg != 0) &&
1994 (mv64360_32bit_windows[window].size_reg != 0)) ||
1995 (window == MV64x60_CPU2SRAM_WIN)) {
1996
1997 extra = mv64360_32bit_windows[window].extra;
1998
1999 switch (extra & MV64x60_EXTRA_MASK) {
2000 case MV64x60_EXTRA_CPUWIN_ENAB:
2001 rc = (mv64x60_read(bh, MV64360_CPU_BAR_ENABLE) &
2002 (1 << (extra & 0x1f))) == 0;
2003 break;
2004
2005 case MV64x60_EXTRA_CPUPROT_ENAB:
2006 rc = (mv64x60_read(bh,
2007 mv64360_32bit_windows[window].base_reg) &
2008 (1 << (extra & 0x1f))) != 0;
2009 break;
2010
2011 case MV64x60_EXTRA_ENET_ENAB:
2012 rc = (mv64x60_read(bh, MV64360_ENET2MEM_BAR_ENABLE) &
2013 (1 << (extra & 0x7))) == 0;
2014 break;
2015
2016 case MV64x60_EXTRA_MPSC_ENAB:
2017 rc = (mv64x60_read(bh, MV64360_MPSC2MEM_BAR_ENABLE) &
2018 (1 << (extra & 0x3))) == 0;
2019 break;
2020
2021 case MV64x60_EXTRA_IDMA_ENAB:
2022 rc = (mv64x60_read(bh, MV64360_IDMA2MEM_BAR_ENABLE) &
2023 (1 << (extra & 0x7))) == 0;
2024 break;
2025
2026 default:
2027 printk(KERN_ERR "mv64360_is_enabled: %s\n",
2028 "32bit table corrupted");
2029 }
2030 }
2031
2032 return rc;
2033}
2034
2035/*
2036 * mv64360_enable_window_32bit()
2037 *
2038 * On a MV64360, a window is enabled by either clearing a bit in the
2039 * CPU BAR Enable reg or setting a bit in the window's base reg.
2040 */
2041static void __init
2042mv64360_enable_window_32bit(struct mv64x60_handle *bh, u32 window)
2043{
2044 u32 extra;
2045
2046 pr_debug("enable 32bit window: %d\n", window);
2047
2048 if (((mv64360_32bit_windows[window].base_reg != 0) &&
2049 (mv64360_32bit_windows[window].size_reg != 0)) ||
2050 (window == MV64x60_CPU2SRAM_WIN)) {
2051
2052 extra = mv64360_32bit_windows[window].extra;
2053
2054 switch (extra & MV64x60_EXTRA_MASK) {
2055 case MV64x60_EXTRA_CPUWIN_ENAB:
2056 mv64x60_clr_bits(bh, MV64360_CPU_BAR_ENABLE,
2057 (1 << (extra & 0x1f)));
2058 break;
2059
2060 case MV64x60_EXTRA_CPUPROT_ENAB:
2061 mv64x60_set_bits(bh,
2062 mv64360_32bit_windows[window].base_reg,
2063 (1 << (extra & 0x1f)));
2064 break;
2065
2066 case MV64x60_EXTRA_ENET_ENAB:
2067 mv64x60_clr_bits(bh, MV64360_ENET2MEM_BAR_ENABLE,
2068 (1 << (extra & 0x7)));
2069 break;
2070
2071 case MV64x60_EXTRA_MPSC_ENAB:
2072 mv64x60_clr_bits(bh, MV64360_MPSC2MEM_BAR_ENABLE,
2073 (1 << (extra & 0x3)));
2074 break;
2075
2076 case MV64x60_EXTRA_IDMA_ENAB:
2077 mv64x60_clr_bits(bh, MV64360_IDMA2MEM_BAR_ENABLE,
2078 (1 << (extra & 0x7)));
2079 break;
2080
2081 default:
2082 printk(KERN_ERR "mv64360_enable: %s\n",
2083 "32bit table corrupted");
2084 }
2085 }
2086
2087 return;
2088}
2089
2090/*
2091 * mv64360_disable_window_32bit()
2092 *
2093 * On a MV64360, a window is disabled by either setting a bit in the
2094 * CPU BAR Enable reg or clearing a bit in the window's base reg.
2095 */
2096static void __init
2097mv64360_disable_window_32bit(struct mv64x60_handle *bh, u32 window)
2098{
2099 u32 extra;
2100
2101 pr_debug("disable 32bit window: %d, base_reg: 0x%x, size_reg: 0x%x\n",
2102 window, mv64360_32bit_windows[window].base_reg,
2103 mv64360_32bit_windows[window].size_reg);
2104
2105 if (((mv64360_32bit_windows[window].base_reg != 0) &&
2106 (mv64360_32bit_windows[window].size_reg != 0)) ||
2107 (window == MV64x60_CPU2SRAM_WIN)) {
2108
2109 extra = mv64360_32bit_windows[window].extra;
2110
2111 switch (extra & MV64x60_EXTRA_MASK) {
2112 case MV64x60_EXTRA_CPUWIN_ENAB:
2113 mv64x60_set_bits(bh, MV64360_CPU_BAR_ENABLE,
2114 (1 << (extra & 0x1f)));
2115 break;
2116
2117 case MV64x60_EXTRA_CPUPROT_ENAB:
2118 mv64x60_clr_bits(bh,
2119 mv64360_32bit_windows[window].base_reg,
2120 (1 << (extra & 0x1f)));
2121 break;
2122
2123 case MV64x60_EXTRA_ENET_ENAB:
2124 mv64x60_set_bits(bh, MV64360_ENET2MEM_BAR_ENABLE,
2125 (1 << (extra & 0x7)));
2126 break;
2127
2128 case MV64x60_EXTRA_MPSC_ENAB:
2129 mv64x60_set_bits(bh, MV64360_MPSC2MEM_BAR_ENABLE,
2130 (1 << (extra & 0x3)));
2131 break;
2132
2133 case MV64x60_EXTRA_IDMA_ENAB:
2134 mv64x60_set_bits(bh, MV64360_IDMA2MEM_BAR_ENABLE,
2135 (1 << (extra & 0x7)));
2136 break;
2137
2138 default:
2139 printk(KERN_ERR "mv64360_disable: %s\n",
2140 "32bit table corrupted");
2141 }
2142 }
2143
2144 return;
2145}
2146
2147/*
2148 * mv64360_enable_window_64bit()
2149 *
2150 * On the MV64360, a 64-bit window is enabled by setting a bit in the window's
2151 * base reg.
2152 */
2153static void __init
2154mv64360_enable_window_64bit(struct mv64x60_handle *bh, u32 window)
2155{
2156 pr_debug("enable 64bit window: %d\n", window);
2157
2158 if ((mv64360_64bit_windows[window].base_lo_reg!= 0) &&
2159 (mv64360_64bit_windows[window].size_reg != 0)) {
2160
2161 if ((mv64360_64bit_windows[window].extra & MV64x60_EXTRA_MASK)
2162 == MV64x60_EXTRA_PCIACC_ENAB)
2163
2164 mv64x60_set_bits(bh,
2165 mv64360_64bit_windows[window].base_lo_reg,
2166 (1 << (mv64360_64bit_windows[window].extra &
2167 0x1f)));
2168 else
2169 printk(KERN_ERR "mv64360_enable: %s\n",
2170 "64bit table corrupted");
2171 }
2172
2173 return;
2174}
2175
2176/*
2177 * mv64360_disable_window_64bit()
2178 *
2179 * On a MV64360, a 64-bit window is disabled by clearing a bit in the window's
2180 * base reg.
2181 */
2182static void __init
2183mv64360_disable_window_64bit(struct mv64x60_handle *bh, u32 window)
2184{
2185 pr_debug("disable 64bit window: %d, base_reg: 0x%x, size_reg: 0x%x\n",
2186 window, mv64360_64bit_windows[window].base_lo_reg,
2187 mv64360_64bit_windows[window].size_reg);
2188
2189 if ((mv64360_64bit_windows[window].base_lo_reg != 0) &&
2190 (mv64360_64bit_windows[window].size_reg != 0)) {
2191
2192 if ((mv64360_64bit_windows[window].extra & MV64x60_EXTRA_MASK)
2193 == MV64x60_EXTRA_PCIACC_ENAB)
2194
2195 mv64x60_clr_bits(bh,
2196 mv64360_64bit_windows[window].base_lo_reg,
2197 (1 << (mv64360_64bit_windows[window].extra &
2198 0x1f)));
2199 else
2200 printk(KERN_ERR "mv64360_disable: %s\n",
2201 "64bit table corrupted");
2202 }
2203
2204 return;
2205}
2206
2207/*
2208 * mv64360_disable_all_windows()
2209 *
2210 * The MV64360 has a few windows that aren't represented in the table of
2211 * windows at the top of this file. This routine turns all of them off
2212 * except for the memory controller windows, of course.
2213 */
2214static void __init
2215mv64360_disable_all_windows(struct mv64x60_handle *bh,
2216 struct mv64x60_setup_info *si)
2217{
2218 u32 preserve, i;
2219
2220 /* Disable 32bit windows (don't disable cpu->mem windows) */
2221 for (i=MV64x60_CPU2DEV_0_WIN; i<MV64x60_32BIT_WIN_COUNT; i++) {
2222 if (i < 32)
2223 preserve = si->window_preserve_mask_32_lo & (1 << i);
2224 else
2225 preserve = si->window_preserve_mask_32_hi & (1<<(i-32));
2226
2227 if (!preserve)
2228 mv64360_disable_window_32bit(bh, i);
2229 }
2230
2231 /* Disable 64bit windows */
2232 for (i=0; i<MV64x60_64BIT_WIN_COUNT; i++)
2233 if (!(si->window_preserve_mask_64 & (1<<i)))
2234 mv64360_disable_window_64bit(bh, i);
2235
2236 /* Turn off PCI->MEM access cntl wins not in mv64360_64bit_windows[] */
2237 mv64x60_clr_bits(bh, MV64x60_PCI0_ACC_CNTL_4_BASE_LO, 0);
2238 mv64x60_clr_bits(bh, MV64x60_PCI0_ACC_CNTL_5_BASE_LO, 0);
2239 mv64x60_clr_bits(bh, MV64x60_PCI1_ACC_CNTL_4_BASE_LO, 0);
2240 mv64x60_clr_bits(bh, MV64x60_PCI1_ACC_CNTL_5_BASE_LO, 0);
2241
2242 /* Disable all PCI-><whatever> windows */
2243 mv64x60_set_bits(bh, MV64x60_PCI0_BAR_ENABLE, 0x0000f9ff);
2244 mv64x60_set_bits(bh, MV64x60_PCI1_BAR_ENABLE, 0x0000f9ff);
2245
2246 return;
2247}
2248
2249/*
2250 * mv64360_config_io2mem_windows()
2251 *
2252 * ENET, MPSC, and IDMA ctlrs on the MV64[34]60 have separate windows that
2253 * must be set up so that the respective ctlr can access system memory.
2254 */
2255static u32 enet_tab[MV64x60_CPU2MEM_WINDOWS] __initdata = {
2256 MV64x60_ENET2MEM_0_WIN, MV64x60_ENET2MEM_1_WIN,
2257 MV64x60_ENET2MEM_2_WIN, MV64x60_ENET2MEM_3_WIN,
2258};
2259
2260static u32 mpsc_tab[MV64x60_CPU2MEM_WINDOWS] __initdata = {
2261 MV64x60_MPSC2MEM_0_WIN, MV64x60_MPSC2MEM_1_WIN,
2262 MV64x60_MPSC2MEM_2_WIN, MV64x60_MPSC2MEM_3_WIN,
2263};
2264
2265static u32 idma_tab[MV64x60_CPU2MEM_WINDOWS] __initdata = {
2266 MV64x60_IDMA2MEM_0_WIN, MV64x60_IDMA2MEM_1_WIN,
2267 MV64x60_IDMA2MEM_2_WIN, MV64x60_IDMA2MEM_3_WIN,
2268};
2269
2270static u32 dram_selects[MV64x60_CPU2MEM_WINDOWS] __initdata =
2271 { 0xe, 0xd, 0xb, 0x7 };
2272
2273static void __init
2274mv64360_config_io2mem_windows(struct mv64x60_handle *bh,
2275 struct mv64x60_setup_info *si,
2276 u32 mem_windows[MV64x60_CPU2MEM_WINDOWS][2])
2277{
2278 u32 i, win;
2279
2280 pr_debug("config_io2regs_windows: enet, mpsc, idma -> bridge regs\n");
2281
2282 mv64x60_write(bh, MV64360_ENET2MEM_ACC_PROT_0, 0);
2283 mv64x60_write(bh, MV64360_ENET2MEM_ACC_PROT_1, 0);
2284 mv64x60_write(bh, MV64360_ENET2MEM_ACC_PROT_2, 0);
2285
2286 mv64x60_write(bh, MV64360_MPSC2MEM_ACC_PROT_0, 0);
2287 mv64x60_write(bh, MV64360_MPSC2MEM_ACC_PROT_1, 0);
2288
2289 mv64x60_write(bh, MV64360_IDMA2MEM_ACC_PROT_0, 0);
2290 mv64x60_write(bh, MV64360_IDMA2MEM_ACC_PROT_1, 0);
2291 mv64x60_write(bh, MV64360_IDMA2MEM_ACC_PROT_2, 0);
2292 mv64x60_write(bh, MV64360_IDMA2MEM_ACC_PROT_3, 0);
2293
2294 /* Assume that mem ctlr has no more windows than embedded I/O ctlr */
2295 for (win=MV64x60_CPU2MEM_0_WIN,i=0;win<=MV64x60_CPU2MEM_3_WIN;win++,i++)
2296 if (bh->ci->is_enabled_32bit(bh, win)) {
2297 mv64x60_set_32bit_window(bh, enet_tab[i],
2298 mem_windows[i][0], mem_windows[i][1],
2299 (dram_selects[i] << 8) |
2300 (si->enet_options[i] & 0x3000));
2301 bh->ci->enable_window_32bit(bh, enet_tab[i]);
2302
2303 /* Give enet r/w access to memory region */
2304 mv64x60_set_bits(bh, MV64360_ENET2MEM_ACC_PROT_0,
2305 (0x3 << (i << 1)));
2306 mv64x60_set_bits(bh, MV64360_ENET2MEM_ACC_PROT_1,
2307 (0x3 << (i << 1)));
2308 mv64x60_set_bits(bh, MV64360_ENET2MEM_ACC_PROT_2,
2309 (0x3 << (i << 1)));
2310
2311 mv64x60_set_32bit_window(bh, mpsc_tab[i],
2312 mem_windows[i][0], mem_windows[i][1],
2313 (dram_selects[i] << 8) |
2314 (si->mpsc_options[i] & 0x3000));
2315 bh->ci->enable_window_32bit(bh, mpsc_tab[i]);
2316
2317 /* Give mpsc r/w access to memory region */
2318 mv64x60_set_bits(bh, MV64360_MPSC2MEM_ACC_PROT_0,
2319 (0x3 << (i << 1)));
2320 mv64x60_set_bits(bh, MV64360_MPSC2MEM_ACC_PROT_1,
2321 (0x3 << (i << 1)));
2322
2323 mv64x60_set_32bit_window(bh, idma_tab[i],
2324 mem_windows[i][0], mem_windows[i][1],
2325 (dram_selects[i] << 8) |
2326 (si->idma_options[i] & 0x3000));
2327 bh->ci->enable_window_32bit(bh, idma_tab[i]);
2328
2329 /* Give idma r/w access to memory region */
2330 mv64x60_set_bits(bh, MV64360_IDMA2MEM_ACC_PROT_0,
2331 (0x3 << (i << 1)));
2332 mv64x60_set_bits(bh, MV64360_IDMA2MEM_ACC_PROT_1,
2333 (0x3 << (i << 1)));
2334 mv64x60_set_bits(bh, MV64360_IDMA2MEM_ACC_PROT_2,
2335 (0x3 << (i << 1)));
2336 mv64x60_set_bits(bh, MV64360_IDMA2MEM_ACC_PROT_3,
2337 (0x3 << (i << 1)));
2338 }
2339
2340 return;
2341}
2342
2343/*
2344 * mv64360_set_mpsc2regs_window()
2345 *
2346 * MPSC has a window to the bridge's internal registers. Call this routine
2347 * to change that window so it doesn't conflict with the windows mapping the
2348 * mpsc to system memory.
2349 */
2350static void __init
2351mv64360_set_mpsc2regs_window(struct mv64x60_handle *bh, u32 base)
2352{
2353 pr_debug("set mpsc->internal regs, base: 0x%x\n", base);
2354
2355 mv64x60_write(bh, MV64360_MPSC2REGS_BASE, base & 0xffff0000);
2356 return;
2357}
2358
2359/*
2360 * mv64360_chip_specific_init()
2361 *
2362 * No errata work arounds for the MV64360 implemented at this point.
2363 */
2364static void __init
2365mv64360_chip_specific_init(struct mv64x60_handle *bh,
2366 struct mv64x60_setup_info *si)
2367{
2368#ifdef CONFIG_SERIAL_MPSC
2369 mv64x60_mpsc0_pdata.brg_can_tune = 1;
2370 mv64x60_mpsc0_pdata.cache_mgmt = 1;
2371 mv64x60_mpsc1_pdata.brg_can_tune = 1;
2372 mv64x60_mpsc1_pdata.cache_mgmt = 1;
2373#endif
2374
2375 return;
2376}
2377
2378/*
2379 * mv64460_chip_specific_init()
2380 *
2381 * No errata work arounds for the MV64460 implemented at this point.
2382 */
2383static void __init
2384mv64460_chip_specific_init(struct mv64x60_handle *bh,
2385 struct mv64x60_setup_info *si)
2386{
2387#ifdef CONFIG_SERIAL_MPSC
2388 mv64x60_mpsc0_pdata.brg_can_tune = 1;
2389 mv64x60_mpsc1_pdata.brg_can_tune = 1;
2390#endif
2391 return;
2392}
diff --git a/arch/ppc/syslib/mv64x60_dbg.c b/arch/ppc/syslib/mv64x60_dbg.c
new file mode 100644
index 000000000000..2927c7adf5e5
--- /dev/null
+++ b/arch/ppc/syslib/mv64x60_dbg.c
@@ -0,0 +1,123 @@
1/*
2 * arch/ppc/syslib/mv64x60_dbg.c
3 *
4 * KGDB and progress routines for the Marvell/Galileo MV64x60 (Discovery).
5 *
6 * Author: Mark A. Greer <mgreer@mvista.com>
7 *
8 * 2003 (c) MontaVista Software, Inc. This file is licensed under
9 * the terms of the GNU General Public License version 2. This program
10 * is licensed "as is" without any warranty of any kind, whether express
11 * or implied.
12 */
13
14/*
15 *****************************************************************************
16 *
17 * Low-level MPSC/UART I/O routines
18 *
19 *****************************************************************************
20 */
21
22
23#include <linux/config.h>
24#include <linux/irq.h>
25#include <asm/delay.h>
26#include <asm/mv64x60.h>
27
28
29#if defined(CONFIG_SERIAL_TEXT_DEBUG)
30
31#define MPSC_CHR_1 0x000c
32#define MPSC_CHR_2 0x0010
33
34static struct mv64x60_handle mv64x60_dbg_bh;
35
36void
37mv64x60_progress_init(u32 base)
38{
39 mv64x60_dbg_bh.v_base = base;
40 return;
41}
42
43static void
44mv64x60_polled_putc(int chan, char c)
45{
46 u32 offset;
47
48 if (chan == 0)
49 offset = 0x8000;
50 else
51 offset = 0x9000;
52
53 mv64x60_write(&mv64x60_dbg_bh, offset + MPSC_CHR_1, (u32)c);
54 mv64x60_write(&mv64x60_dbg_bh, offset + MPSC_CHR_2, 0x200);
55 udelay(2000);
56}
57
58void
59mv64x60_mpsc_progress(char *s, unsigned short hex)
60{
61 volatile char c;
62
63 mv64x60_polled_putc(0, '\r');
64
65 while ((c = *s++) != 0)
66 mv64x60_polled_putc(0, c);
67
68 mv64x60_polled_putc(0, '\n');
69 mv64x60_polled_putc(0, '\r');
70
71 return;
72}
73#endif /* CONFIG_SERIAL_TEXT_DEBUG */
74
75
76#if defined(CONFIG_KGDB)
77
78#if defined(CONFIG_KGDB_TTYS0)
79#define KGDB_PORT 0
80#elif defined(CONFIG_KGDB_TTYS1)
81#define KGDB_PORT 1
82#else
83#error "Invalid kgdb_tty port"
84#endif
85
86void
87putDebugChar(unsigned char c)
88{
89 mv64x60_polled_putc(KGDB_PORT, (char)c);
90}
91
92int
93getDebugChar(void)
94{
95 unsigned char c;
96
97 while (!mv64x60_polled_getc(KGDB_PORT, &c));
98 return (int)c;
99}
100
101void
102putDebugString(char* str)
103{
104 while (*str != '\0') {
105 putDebugChar(*str);
106 str++;
107 }
108 putDebugChar('\r');
109 return;
110}
111
112void
113kgdb_interruptible(int enable)
114{
115}
116
117void
118kgdb_map_scc(void)
119{
120 if (ppc_md.early_serial_map)
121 ppc_md.early_serial_map();
122}
123#endif /* CONFIG_KGDB */
diff --git a/arch/ppc/syslib/mv64x60_win.c b/arch/ppc/syslib/mv64x60_win.c
new file mode 100644
index 000000000000..b6f0f5dcf6ee
--- /dev/null
+++ b/arch/ppc/syslib/mv64x60_win.c
@@ -0,0 +1,1168 @@
1/*
2 * arch/ppc/syslib/mv64x60_win.c
3 *
4 * Tables with info on how to manipulate the 32 & 64 bit windows on the
5 * various types of Marvell bridge chips.
6 *
7 * Author: Mark A. Greer <mgreer@mvista.com>
8 *
9 * 2004 (c) MontaVista, Software, Inc. This file is licensed under
10 * the terms of the GNU General Public License version 2. This program
11 * is licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 */
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/pci.h>
17#include <linux/slab.h>
18#include <linux/module.h>
19#include <linux/string.h>
20#include <linux/bootmem.h>
21#include <linux/mv643xx.h>
22
23#include <asm/byteorder.h>
24#include <asm/io.h>
25#include <asm/irq.h>
26#include <asm/uaccess.h>
27#include <asm/machdep.h>
28#include <asm/pci-bridge.h>
29#include <asm/delay.h>
30#include <asm/mv64x60.h>
31
32
33/*
34 *****************************************************************************
35 *
36 * Tables describing how to set up windows on each type of bridge
37 *
38 *****************************************************************************
39 */
40struct mv64x60_32bit_window
41 gt64260_32bit_windows[MV64x60_32BIT_WIN_COUNT] __initdata = {
42 /* CPU->MEM Windows */
43 [MV64x60_CPU2MEM_0_WIN] = {
44 .base_reg = MV64x60_CPU2MEM_0_BASE,
45 .size_reg = MV64x60_CPU2MEM_0_SIZE,
46 .base_bits = 12,
47 .size_bits = 12,
48 .get_from_field = mv64x60_shift_left,
49 .map_to_field = mv64x60_shift_right,
50 .extra = 0 },
51 [MV64x60_CPU2MEM_1_WIN] = {
52 .base_reg = MV64x60_CPU2MEM_1_BASE,
53 .size_reg = MV64x60_CPU2MEM_1_SIZE,
54 .base_bits = 12,
55 .size_bits = 12,
56 .get_from_field = mv64x60_shift_left,
57 .map_to_field = mv64x60_shift_right,
58 .extra = 0 },
59 [MV64x60_CPU2MEM_2_WIN] = {
60 .base_reg = MV64x60_CPU2MEM_2_BASE,
61 .size_reg = MV64x60_CPU2MEM_2_SIZE,
62 .base_bits = 12,
63 .size_bits = 12,
64 .get_from_field = mv64x60_shift_left,
65 .map_to_field = mv64x60_shift_right,
66 .extra = 0 },
67 [MV64x60_CPU2MEM_3_WIN] = {
68 .base_reg = MV64x60_CPU2MEM_3_BASE,
69 .size_reg = MV64x60_CPU2MEM_3_SIZE,
70 .base_bits = 12,
71 .size_bits = 12,
72 .get_from_field = mv64x60_shift_left,
73 .map_to_field = mv64x60_shift_right,
74 .extra = 0 },
75 /* CPU->Device Windows */
76 [MV64x60_CPU2DEV_0_WIN] = {
77 .base_reg = MV64x60_CPU2DEV_0_BASE,
78 .size_reg = MV64x60_CPU2DEV_0_SIZE,
79 .base_bits = 12,
80 .size_bits = 12,
81 .get_from_field = mv64x60_shift_left,
82 .map_to_field = mv64x60_shift_right,
83 .extra = 0 },
84 [MV64x60_CPU2DEV_1_WIN] = {
85 .base_reg = MV64x60_CPU2DEV_1_BASE,
86 .size_reg = MV64x60_CPU2DEV_1_SIZE,
87 .base_bits = 12,
88 .size_bits = 12,
89 .get_from_field = mv64x60_shift_left,
90 .map_to_field = mv64x60_shift_right,
91 .extra = 0 },
92 [MV64x60_CPU2DEV_2_WIN] = {
93 .base_reg = MV64x60_CPU2DEV_2_BASE,
94 .size_reg = MV64x60_CPU2DEV_2_SIZE,
95 .base_bits = 12,
96 .size_bits = 12,
97 .get_from_field = mv64x60_shift_left,
98 .map_to_field = mv64x60_shift_right,
99 .extra = 0 },
100 [MV64x60_CPU2DEV_3_WIN] = {
101 .base_reg = MV64x60_CPU2DEV_3_BASE,
102 .size_reg = MV64x60_CPU2DEV_3_SIZE,
103 .base_bits = 12,
104 .size_bits = 12,
105 .get_from_field = mv64x60_shift_left,
106 .map_to_field = mv64x60_shift_right,
107 .extra = 0 },
108 /* CPU->Boot Window */
109 [MV64x60_CPU2BOOT_WIN] = {
110 .base_reg = MV64x60_CPU2BOOT_0_BASE,
111 .size_reg = MV64x60_CPU2BOOT_0_SIZE,
112 .base_bits = 12,
113 .size_bits = 12,
114 .get_from_field = mv64x60_shift_left,
115 .map_to_field = mv64x60_shift_right,
116 .extra = 0 },
117 /* CPU->PCI 0 Windows */
118 [MV64x60_CPU2PCI0_IO_WIN] = {
119 .base_reg = MV64x60_CPU2PCI0_IO_BASE,
120 .size_reg = MV64x60_CPU2PCI0_IO_SIZE,
121 .base_bits = 12,
122 .size_bits = 12,
123 .get_from_field = mv64x60_shift_left,
124 .map_to_field = mv64x60_shift_right,
125 .extra = 0 },
126 [MV64x60_CPU2PCI0_MEM_0_WIN] = {
127 .base_reg = MV64x60_CPU2PCI0_MEM_0_BASE,
128 .size_reg = MV64x60_CPU2PCI0_MEM_0_SIZE,
129 .base_bits = 12,
130 .size_bits = 12,
131 .get_from_field = mv64x60_shift_left,
132 .map_to_field = mv64x60_shift_right,
133 .extra = 0 },
134 [MV64x60_CPU2PCI0_MEM_1_WIN] = {
135 .base_reg = MV64x60_CPU2PCI0_MEM_1_BASE,
136 .size_reg = MV64x60_CPU2PCI0_MEM_1_SIZE,
137 .base_bits = 12,
138 .size_bits = 12,
139 .get_from_field = mv64x60_shift_left,
140 .map_to_field = mv64x60_shift_right,
141 .extra = 0 },
142 [MV64x60_CPU2PCI0_MEM_2_WIN] = {
143 .base_reg = MV64x60_CPU2PCI0_MEM_2_BASE,
144 .size_reg = MV64x60_CPU2PCI0_MEM_2_SIZE,
145 .base_bits = 12,
146 .size_bits = 12,
147 .get_from_field = mv64x60_shift_left,
148 .map_to_field = mv64x60_shift_right,
149 .extra = 0 },
150 [MV64x60_CPU2PCI0_MEM_3_WIN] = {
151 .base_reg = MV64x60_CPU2PCI0_MEM_3_BASE,
152 .size_reg = MV64x60_CPU2PCI0_MEM_3_SIZE,
153 .base_bits = 12,
154 .size_bits = 12,
155 .get_from_field = mv64x60_shift_left,
156 .map_to_field = mv64x60_shift_right,
157 .extra = 0 },
158 /* CPU->PCI 1 Windows */
159 [MV64x60_CPU2PCI1_IO_WIN] = {
160 .base_reg = MV64x60_CPU2PCI1_IO_BASE,
161 .size_reg = MV64x60_CPU2PCI1_IO_SIZE,
162 .base_bits = 12,
163 .size_bits = 12,
164 .get_from_field = mv64x60_shift_left,
165 .map_to_field = mv64x60_shift_right,
166 .extra = 0 },
167 [MV64x60_CPU2PCI1_MEM_0_WIN] = {
168 .base_reg = MV64x60_CPU2PCI1_MEM_0_BASE,
169 .size_reg = MV64x60_CPU2PCI1_MEM_0_SIZE,
170 .base_bits = 12,
171 .size_bits = 12,
172 .get_from_field = mv64x60_shift_left,
173 .map_to_field = mv64x60_shift_right,
174 .extra = 0 },
175 [MV64x60_CPU2PCI1_MEM_1_WIN] = {
176 .base_reg = MV64x60_CPU2PCI1_MEM_1_BASE,
177 .size_reg = MV64x60_CPU2PCI1_MEM_1_SIZE,
178 .base_bits = 12,
179 .size_bits = 12,
180 .get_from_field = mv64x60_shift_left,
181 .map_to_field = mv64x60_shift_right,
182 .extra = 0 },
183 [MV64x60_CPU2PCI1_MEM_2_WIN] = {
184 .base_reg = MV64x60_CPU2PCI1_MEM_2_BASE,
185 .size_reg = MV64x60_CPU2PCI1_MEM_2_SIZE,
186 .base_bits = 12,
187 .size_bits = 12,
188 .get_from_field = mv64x60_shift_left,
189 .map_to_field = mv64x60_shift_right,
190 .extra = 0 },
191 [MV64x60_CPU2PCI1_MEM_3_WIN] = {
192 .base_reg = MV64x60_CPU2PCI1_MEM_3_BASE,
193 .size_reg = MV64x60_CPU2PCI1_MEM_3_SIZE,
194 .base_bits = 12,
195 .size_bits = 12,
196 .get_from_field = mv64x60_shift_left,
197 .map_to_field = mv64x60_shift_right,
198 .extra = 0 },
199 /* CPU->SRAM Window (64260 has no integrated SRAM) */
200 /* CPU->PCI 0 Remap I/O Window */
201 [MV64x60_CPU2PCI0_IO_REMAP_WIN] = {
202 .base_reg = MV64x60_CPU2PCI0_IO_REMAP,
203 .size_reg = 0,
204 .base_bits = 12,
205 .size_bits = 0,
206 .get_from_field = mv64x60_shift_left,
207 .map_to_field = mv64x60_shift_right,
208 .extra = 0 },
209 /* CPU->PCI 1 Remap I/O Window */
210 [MV64x60_CPU2PCI1_IO_REMAP_WIN] = {
211 .base_reg = MV64x60_CPU2PCI1_IO_REMAP,
212 .size_reg = 0,
213 .base_bits = 12,
214 .size_bits = 0,
215 .get_from_field = mv64x60_shift_left,
216 .map_to_field = mv64x60_shift_right,
217 .extra = 0 },
218 /* CPU Memory Protection Windows */
219 [MV64x60_CPU_PROT_0_WIN] = {
220 .base_reg = MV64x60_CPU_PROT_BASE_0,
221 .size_reg = MV64x60_CPU_PROT_SIZE_0,
222 .base_bits = 12,
223 .size_bits = 12,
224 .get_from_field = mv64x60_shift_left,
225 .map_to_field = mv64x60_shift_right,
226 .extra = 0 },
227 [MV64x60_CPU_PROT_1_WIN] = {
228 .base_reg = MV64x60_CPU_PROT_BASE_1,
229 .size_reg = MV64x60_CPU_PROT_SIZE_1,
230 .base_bits = 12,
231 .size_bits = 12,
232 .get_from_field = mv64x60_shift_left,
233 .map_to_field = mv64x60_shift_right,
234 .extra = 0 },
235 [MV64x60_CPU_PROT_2_WIN] = {
236 .base_reg = MV64x60_CPU_PROT_BASE_2,
237 .size_reg = MV64x60_CPU_PROT_SIZE_2,
238 .base_bits = 12,
239 .size_bits = 12,
240 .get_from_field = mv64x60_shift_left,
241 .map_to_field = mv64x60_shift_right,
242 .extra = 0 },
243 [MV64x60_CPU_PROT_3_WIN] = {
244 .base_reg = MV64x60_CPU_PROT_BASE_3,
245 .size_reg = MV64x60_CPU_PROT_SIZE_3,
246 .base_bits = 12,
247 .size_bits = 12,
248 .get_from_field = mv64x60_shift_left,
249 .map_to_field = mv64x60_shift_right,
250 .extra = 0 },
251 /* CPU Snoop Windows */
252 [MV64x60_CPU_SNOOP_0_WIN] = {
253 .base_reg = GT64260_CPU_SNOOP_BASE_0,
254 .size_reg = GT64260_CPU_SNOOP_SIZE_0,
255 .base_bits = 12,
256 .size_bits = 12,
257 .get_from_field = mv64x60_shift_left,
258 .map_to_field = mv64x60_shift_right,
259 .extra = 0 },
260 [MV64x60_CPU_SNOOP_1_WIN] = {
261 .base_reg = GT64260_CPU_SNOOP_BASE_1,
262 .size_reg = GT64260_CPU_SNOOP_SIZE_1,
263 .base_bits = 12,
264 .size_bits = 12,
265 .get_from_field = mv64x60_shift_left,
266 .map_to_field = mv64x60_shift_right,
267 .extra = 0 },
268 [MV64x60_CPU_SNOOP_2_WIN] = {
269 .base_reg = GT64260_CPU_SNOOP_BASE_2,
270 .size_reg = GT64260_CPU_SNOOP_SIZE_2,
271 .base_bits = 12,
272 .size_bits = 12,
273 .get_from_field = mv64x60_shift_left,
274 .map_to_field = mv64x60_shift_right,
275 .extra = 0 },
276 [MV64x60_CPU_SNOOP_3_WIN] = {
277 .base_reg = GT64260_CPU_SNOOP_BASE_3,
278 .size_reg = GT64260_CPU_SNOOP_SIZE_3,
279 .base_bits = 12,
280 .size_bits = 12,
281 .get_from_field = mv64x60_shift_left,
282 .map_to_field = mv64x60_shift_right,
283 .extra = 0 },
284 /* PCI 0->System Memory Remap Windows */
285 [MV64x60_PCI02MEM_REMAP_0_WIN] = {
286 .base_reg = MV64x60_PCI0_SLAVE_MEM_0_REMAP,
287 .size_reg = 0,
288 .base_bits = 20,
289 .size_bits = 0,
290 .get_from_field = mv64x60_mask,
291 .map_to_field = mv64x60_mask,
292 .extra = 0 },
293 [MV64x60_PCI02MEM_REMAP_1_WIN] = {
294 .base_reg = MV64x60_PCI0_SLAVE_MEM_1_REMAP,
295 .size_reg = 0,
296 .base_bits = 20,
297 .size_bits = 0,
298 .get_from_field = mv64x60_mask,
299 .map_to_field = mv64x60_mask,
300 .extra = 0 },
301 [MV64x60_PCI02MEM_REMAP_2_WIN] = {
302 .base_reg = MV64x60_PCI0_SLAVE_MEM_1_REMAP,
303 .size_reg = 0,
304 .base_bits = 20,
305 .size_bits = 0,
306 .get_from_field = mv64x60_mask,
307 .map_to_field = mv64x60_mask,
308 .extra = 0 },
309 [MV64x60_PCI02MEM_REMAP_3_WIN] = {
310 .base_reg = MV64x60_PCI0_SLAVE_MEM_1_REMAP,
311 .size_reg = 0,
312 .base_bits = 20,
313 .size_bits = 0,
314 .get_from_field = mv64x60_mask,
315 .map_to_field = mv64x60_mask,
316 .extra = 0 },
317 /* PCI 1->System Memory Remap Windows */
318 [MV64x60_PCI12MEM_REMAP_0_WIN] = {
319 .base_reg = MV64x60_PCI1_SLAVE_MEM_0_REMAP,
320 .size_reg = 0,
321 .base_bits = 20,
322 .size_bits = 0,
323 .get_from_field = mv64x60_mask,
324 .map_to_field = mv64x60_mask,
325 .extra = 0 },
326 [MV64x60_PCI12MEM_REMAP_1_WIN] = {
327 .base_reg = MV64x60_PCI1_SLAVE_MEM_1_REMAP,
328 .size_reg = 0,
329 .base_bits = 20,
330 .size_bits = 0,
331 .get_from_field = mv64x60_mask,
332 .map_to_field = mv64x60_mask,
333 .extra = 0 },
334 [MV64x60_PCI12MEM_REMAP_2_WIN] = {
335 .base_reg = MV64x60_PCI1_SLAVE_MEM_1_REMAP,
336 .size_reg = 0,
337 .base_bits = 20,
338 .size_bits = 0,
339 .get_from_field = mv64x60_mask,
340 .map_to_field = mv64x60_mask,
341 .extra = 0 },
342 [MV64x60_PCI12MEM_REMAP_3_WIN] = {
343 .base_reg = MV64x60_PCI1_SLAVE_MEM_1_REMAP,
344 .size_reg = 0,
345 .base_bits = 20,
346 .size_bits = 0,
347 .get_from_field = mv64x60_mask,
348 .map_to_field = mv64x60_mask,
349 .extra = 0 },
350 /* ENET->SRAM Window (64260 doesn't have separate windows) */
351 /* MPSC->SRAM Window (64260 doesn't have separate windows) */
352 /* IDMA->SRAM Window (64260 doesn't have separate windows) */
353};
354
355struct mv64x60_64bit_window
356 gt64260_64bit_windows[MV64x60_64BIT_WIN_COUNT] __initdata = {
357 /* CPU->PCI 0 MEM Remap Windows */
358 [MV64x60_CPU2PCI0_MEM_0_REMAP_WIN] = {
359 .base_hi_reg = MV64x60_CPU2PCI0_MEM_0_REMAP_HI,
360 .base_lo_reg = MV64x60_CPU2PCI0_MEM_0_REMAP_LO,
361 .size_reg = 0,
362 .base_lo_bits = 12,
363 .size_bits = 0,
364 .get_from_field = mv64x60_shift_left,
365 .map_to_field = mv64x60_shift_right,
366 .extra = 0 },
367 [MV64x60_CPU2PCI0_MEM_1_REMAP_WIN] = {
368 .base_hi_reg = MV64x60_CPU2PCI0_MEM_1_REMAP_HI,
369 .base_lo_reg = MV64x60_CPU2PCI0_MEM_1_REMAP_LO,
370 .size_reg = 0,
371 .base_lo_bits = 12,
372 .size_bits = 0,
373 .get_from_field = mv64x60_shift_left,
374 .map_to_field = mv64x60_shift_right,
375 .extra = 0 },
376 [MV64x60_CPU2PCI0_MEM_2_REMAP_WIN] = {
377 .base_hi_reg = MV64x60_CPU2PCI0_MEM_2_REMAP_HI,
378 .base_lo_reg = MV64x60_CPU2PCI0_MEM_2_REMAP_LO,
379 .size_reg = 0,
380 .base_lo_bits = 12,
381 .size_bits = 0,
382 .get_from_field = mv64x60_shift_left,
383 .map_to_field = mv64x60_shift_right,
384 .extra = 0 },
385 [MV64x60_CPU2PCI0_MEM_3_REMAP_WIN] = {
386 .base_hi_reg = MV64x60_CPU2PCI0_MEM_3_REMAP_HI,
387 .base_lo_reg = MV64x60_CPU2PCI0_MEM_3_REMAP_LO,
388 .size_reg = 0,
389 .base_lo_bits = 12,
390 .size_bits = 0,
391 .get_from_field = mv64x60_shift_left,
392 .map_to_field = mv64x60_shift_right,
393 .extra = 0 },
394 /* CPU->PCI 1 MEM Remap Windows */
395 [MV64x60_CPU2PCI1_MEM_0_REMAP_WIN] = {
396 .base_hi_reg = MV64x60_CPU2PCI1_MEM_0_REMAP_HI,
397 .base_lo_reg = MV64x60_CPU2PCI1_MEM_0_REMAP_LO,
398 .size_reg = 0,
399 .base_lo_bits = 12,
400 .size_bits = 0,
401 .get_from_field = mv64x60_shift_left,
402 .map_to_field = mv64x60_shift_right,
403 .extra = 0 },
404 [MV64x60_CPU2PCI1_MEM_1_REMAP_WIN] = {
405 .base_hi_reg = MV64x60_CPU2PCI1_MEM_1_REMAP_HI,
406 .base_lo_reg = MV64x60_CPU2PCI1_MEM_1_REMAP_LO,
407 .size_reg = 0,
408 .base_lo_bits = 12,
409 .size_bits = 0,
410 .get_from_field = mv64x60_shift_left,
411 .map_to_field = mv64x60_shift_right,
412 .extra = 0 },
413 [MV64x60_CPU2PCI1_MEM_2_REMAP_WIN] = {
414 .base_hi_reg = MV64x60_CPU2PCI1_MEM_2_REMAP_HI,
415 .base_lo_reg = MV64x60_CPU2PCI1_MEM_2_REMAP_LO,
416 .size_reg = 0,
417 .base_lo_bits = 12,
418 .size_bits = 0,
419 .get_from_field = mv64x60_shift_left,
420 .map_to_field = mv64x60_shift_right,
421 .extra = 0 },
422 [MV64x60_CPU2PCI1_MEM_3_REMAP_WIN] = {
423 .base_hi_reg = MV64x60_CPU2PCI1_MEM_3_REMAP_HI,
424 .base_lo_reg = MV64x60_CPU2PCI1_MEM_3_REMAP_LO,
425 .size_reg = 0,
426 .base_lo_bits = 12,
427 .size_bits = 0,
428 .get_from_field = mv64x60_shift_left,
429 .map_to_field = mv64x60_shift_right,
430 .extra = 0 },
431 /* PCI 0->MEM Access Control Windows */
432 [MV64x60_PCI02MEM_ACC_CNTL_0_WIN] = {
433 .base_hi_reg = MV64x60_PCI0_ACC_CNTL_0_BASE_HI,
434 .base_lo_reg = MV64x60_PCI0_ACC_CNTL_0_BASE_LO,
435 .size_reg = MV64x60_PCI0_ACC_CNTL_0_SIZE,
436 .base_lo_bits = 12,
437 .size_bits = 12,
438 .get_from_field = mv64x60_shift_left,
439 .map_to_field = mv64x60_shift_right,
440 .extra = 0 },
441 [MV64x60_PCI02MEM_ACC_CNTL_1_WIN] = {
442 .base_hi_reg = MV64x60_PCI0_ACC_CNTL_1_BASE_HI,
443 .base_lo_reg = MV64x60_PCI0_ACC_CNTL_1_BASE_LO,
444 .size_reg = MV64x60_PCI0_ACC_CNTL_1_SIZE,
445 .base_lo_bits = 12,
446 .size_bits = 12,
447 .get_from_field = mv64x60_shift_left,
448 .map_to_field = mv64x60_shift_right,
449 .extra = 0 },
450 [MV64x60_PCI02MEM_ACC_CNTL_2_WIN] = {
451 .base_hi_reg = MV64x60_PCI0_ACC_CNTL_2_BASE_HI,
452 .base_lo_reg = MV64x60_PCI0_ACC_CNTL_2_BASE_LO,
453 .size_reg = MV64x60_PCI0_ACC_CNTL_2_SIZE,
454 .base_lo_bits = 12,
455 .size_bits = 12,
456 .get_from_field = mv64x60_shift_left,
457 .map_to_field = mv64x60_shift_right,
458 .extra = 0 },
459 [MV64x60_PCI02MEM_ACC_CNTL_3_WIN] = {
460 .base_hi_reg = MV64x60_PCI0_ACC_CNTL_3_BASE_HI,
461 .base_lo_reg = MV64x60_PCI0_ACC_CNTL_3_BASE_LO,
462 .size_reg = MV64x60_PCI0_ACC_CNTL_3_SIZE,
463 .base_lo_bits = 12,
464 .size_bits = 12,
465 .get_from_field = mv64x60_shift_left,
466 .map_to_field = mv64x60_shift_right,
467 .extra = 0 },
468 /* PCI 1->MEM Access Control Windows */
469 [MV64x60_PCI12MEM_ACC_CNTL_0_WIN] = {
470 .base_hi_reg = MV64x60_PCI1_ACC_CNTL_0_BASE_HI,
471 .base_lo_reg = MV64x60_PCI1_ACC_CNTL_0_BASE_LO,
472 .size_reg = MV64x60_PCI1_ACC_CNTL_0_SIZE,
473 .base_lo_bits = 12,
474 .size_bits = 12,
475 .get_from_field = mv64x60_shift_left,
476 .map_to_field = mv64x60_shift_right,
477 .extra = 0 },
478 [MV64x60_PCI12MEM_ACC_CNTL_1_WIN] = {
479 .base_hi_reg = MV64x60_PCI1_ACC_CNTL_1_BASE_HI,
480 .base_lo_reg = MV64x60_PCI1_ACC_CNTL_1_BASE_LO,
481 .size_reg = MV64x60_PCI1_ACC_CNTL_1_SIZE,
482 .base_lo_bits = 12,
483 .size_bits = 12,
484 .get_from_field = mv64x60_shift_left,
485 .map_to_field = mv64x60_shift_right,
486 .extra = 0 },
487 [MV64x60_PCI12MEM_ACC_CNTL_2_WIN] = {
488 .base_hi_reg = MV64x60_PCI1_ACC_CNTL_2_BASE_HI,
489 .base_lo_reg = MV64x60_PCI1_ACC_CNTL_2_BASE_LO,
490 .size_reg = MV64x60_PCI1_ACC_CNTL_2_SIZE,
491 .base_lo_bits = 12,
492 .size_bits = 12,
493 .get_from_field = mv64x60_shift_left,
494 .map_to_field = mv64x60_shift_right,
495 .extra = 0 },
496 [MV64x60_PCI12MEM_ACC_CNTL_3_WIN] = {
497 .base_hi_reg = MV64x60_PCI1_ACC_CNTL_3_BASE_HI,
498 .base_lo_reg = MV64x60_PCI1_ACC_CNTL_3_BASE_LO,
499 .size_reg = MV64x60_PCI1_ACC_CNTL_3_SIZE,
500 .base_lo_bits = 12,
501 .size_bits = 12,
502 .get_from_field = mv64x60_shift_left,
503 .map_to_field = mv64x60_shift_right,
504 .extra = 0 },
505 /* PCI 0->MEM Snoop Windows */
506 [MV64x60_PCI02MEM_SNOOP_0_WIN] = {
507 .base_hi_reg = GT64260_PCI0_SNOOP_0_BASE_HI,
508 .base_lo_reg = GT64260_PCI0_SNOOP_0_BASE_LO,
509 .size_reg = GT64260_PCI0_SNOOP_0_SIZE,
510 .base_lo_bits = 12,
511 .size_bits = 12,
512 .get_from_field = mv64x60_shift_left,
513 .map_to_field = mv64x60_shift_right,
514 .extra = 0 },
515 [MV64x60_PCI02MEM_SNOOP_1_WIN] = {
516 .base_hi_reg = GT64260_PCI0_SNOOP_1_BASE_HI,
517 .base_lo_reg = GT64260_PCI0_SNOOP_1_BASE_LO,
518 .size_reg = GT64260_PCI0_SNOOP_1_SIZE,
519 .base_lo_bits = 12,
520 .size_bits = 12,
521 .get_from_field = mv64x60_shift_left,
522 .map_to_field = mv64x60_shift_right,
523 .extra = 0 },
524 [MV64x60_PCI02MEM_SNOOP_2_WIN] = {
525 .base_hi_reg = GT64260_PCI0_SNOOP_2_BASE_HI,
526 .base_lo_reg = GT64260_PCI0_SNOOP_2_BASE_LO,
527 .size_reg = GT64260_PCI0_SNOOP_2_SIZE,
528 .base_lo_bits = 12,
529 .size_bits = 12,
530 .get_from_field = mv64x60_shift_left,
531 .map_to_field = mv64x60_shift_right,
532 .extra = 0 },
533 [MV64x60_PCI02MEM_SNOOP_3_WIN] = {
534 .base_hi_reg = GT64260_PCI0_SNOOP_3_BASE_HI,
535 .base_lo_reg = GT64260_PCI0_SNOOP_3_BASE_LO,
536 .size_reg = GT64260_PCI0_SNOOP_3_SIZE,
537 .base_lo_bits = 12,
538 .size_bits = 12,
539 .get_from_field = mv64x60_shift_left,
540 .map_to_field = mv64x60_shift_right,
541 .extra = 0 },
542 /* PCI 1->MEM Snoop Windows */
543 [MV64x60_PCI12MEM_SNOOP_0_WIN] = {
544 .base_hi_reg = GT64260_PCI1_SNOOP_0_BASE_HI,
545 .base_lo_reg = GT64260_PCI1_SNOOP_0_BASE_LO,
546 .size_reg = GT64260_PCI1_SNOOP_0_SIZE,
547 .base_lo_bits = 12,
548 .size_bits = 12,
549 .get_from_field = mv64x60_shift_left,
550 .map_to_field = mv64x60_shift_right,
551 .extra = 0 },
552 [MV64x60_PCI12MEM_SNOOP_1_WIN] = {
553 .base_hi_reg = GT64260_PCI1_SNOOP_1_BASE_HI,
554 .base_lo_reg = GT64260_PCI1_SNOOP_1_BASE_LO,
555 .size_reg = GT64260_PCI1_SNOOP_1_SIZE,
556 .base_lo_bits = 12,
557 .size_bits = 12,
558 .get_from_field = mv64x60_shift_left,
559 .map_to_field = mv64x60_shift_right,
560 .extra = 0 },
561 [MV64x60_PCI12MEM_SNOOP_2_WIN] = {
562 .base_hi_reg = GT64260_PCI1_SNOOP_2_BASE_HI,
563 .base_lo_reg = GT64260_PCI1_SNOOP_2_BASE_LO,
564 .size_reg = GT64260_PCI1_SNOOP_2_SIZE,
565 .base_lo_bits = 12,
566 .size_bits = 12,
567 .get_from_field = mv64x60_shift_left,
568 .map_to_field = mv64x60_shift_right,
569 .extra = 0 },
570 [MV64x60_PCI12MEM_SNOOP_3_WIN] = {
571 .base_hi_reg = GT64260_PCI1_SNOOP_3_BASE_HI,
572 .base_lo_reg = GT64260_PCI1_SNOOP_3_BASE_LO,
573 .size_reg = GT64260_PCI1_SNOOP_3_SIZE,
574 .base_lo_bits = 12,
575 .size_bits = 12,
576 .get_from_field = mv64x60_shift_left,
577 .map_to_field = mv64x60_shift_right,
578 .extra = 0 },
579};
580
581struct mv64x60_32bit_window
582 mv64360_32bit_windows[MV64x60_32BIT_WIN_COUNT] __initdata = {
583 /* CPU->MEM Windows */
584 [MV64x60_CPU2MEM_0_WIN] = {
585 .base_reg = MV64x60_CPU2MEM_0_BASE,
586 .size_reg = MV64x60_CPU2MEM_0_SIZE,
587 .base_bits = 16,
588 .size_bits = 16,
589 .get_from_field = mv64x60_shift_left,
590 .map_to_field = mv64x60_shift_right,
591 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 0 },
592 [MV64x60_CPU2MEM_1_WIN] = {
593 .base_reg = MV64x60_CPU2MEM_1_BASE,
594 .size_reg = MV64x60_CPU2MEM_1_SIZE,
595 .base_bits = 16,
596 .size_bits = 16,
597 .get_from_field = mv64x60_shift_left,
598 .map_to_field = mv64x60_shift_right,
599 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 1 },
600 [MV64x60_CPU2MEM_2_WIN] = {
601 .base_reg = MV64x60_CPU2MEM_2_BASE,
602 .size_reg = MV64x60_CPU2MEM_2_SIZE,
603 .base_bits = 16,
604 .size_bits = 16,
605 .get_from_field = mv64x60_shift_left,
606 .map_to_field = mv64x60_shift_right,
607 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 2 },
608 [MV64x60_CPU2MEM_3_WIN] = {
609 .base_reg = MV64x60_CPU2MEM_3_BASE,
610 .size_reg = MV64x60_CPU2MEM_3_SIZE,
611 .base_bits = 16,
612 .size_bits = 16,
613 .get_from_field = mv64x60_shift_left,
614 .map_to_field = mv64x60_shift_right,
615 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 3 },
616 /* CPU->Device Windows */
617 [MV64x60_CPU2DEV_0_WIN] = {
618 .base_reg = MV64x60_CPU2DEV_0_BASE,
619 .size_reg = MV64x60_CPU2DEV_0_SIZE,
620 .base_bits = 16,
621 .size_bits = 16,
622 .get_from_field = mv64x60_shift_left,
623 .map_to_field = mv64x60_shift_right,
624 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 4 },
625 [MV64x60_CPU2DEV_1_WIN] = {
626 .base_reg = MV64x60_CPU2DEV_1_BASE,
627 .size_reg = MV64x60_CPU2DEV_1_SIZE,
628 .base_bits = 16,
629 .size_bits = 16,
630 .get_from_field = mv64x60_shift_left,
631 .map_to_field = mv64x60_shift_right,
632 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 5 },
633 [MV64x60_CPU2DEV_2_WIN] = {
634 .base_reg = MV64x60_CPU2DEV_2_BASE,
635 .size_reg = MV64x60_CPU2DEV_2_SIZE,
636 .base_bits = 16,
637 .size_bits = 16,
638 .get_from_field = mv64x60_shift_left,
639 .map_to_field = mv64x60_shift_right,
640 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 6 },
641 [MV64x60_CPU2DEV_3_WIN] = {
642 .base_reg = MV64x60_CPU2DEV_3_BASE,
643 .size_reg = MV64x60_CPU2DEV_3_SIZE,
644 .base_bits = 16,
645 .size_bits = 16,
646 .get_from_field = mv64x60_shift_left,
647 .map_to_field = mv64x60_shift_right,
648 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 7 },
649 /* CPU->Boot Window */
650 [MV64x60_CPU2BOOT_WIN] = {
651 .base_reg = MV64x60_CPU2BOOT_0_BASE,
652 .size_reg = MV64x60_CPU2BOOT_0_SIZE,
653 .base_bits = 16,
654 .size_bits = 16,
655 .get_from_field = mv64x60_shift_left,
656 .map_to_field = mv64x60_shift_right,
657 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 8 },
658 /* CPU->PCI 0 Windows */
659 [MV64x60_CPU2PCI0_IO_WIN] = {
660 .base_reg = MV64x60_CPU2PCI0_IO_BASE,
661 .size_reg = MV64x60_CPU2PCI0_IO_SIZE,
662 .base_bits = 16,
663 .size_bits = 16,
664 .get_from_field = mv64x60_shift_left,
665 .map_to_field = mv64x60_shift_right,
666 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 9 },
667 [MV64x60_CPU2PCI0_MEM_0_WIN] = {
668 .base_reg = MV64x60_CPU2PCI0_MEM_0_BASE,
669 .size_reg = MV64x60_CPU2PCI0_MEM_0_SIZE,
670 .base_bits = 16,
671 .size_bits = 16,
672 .get_from_field = mv64x60_shift_left,
673 .map_to_field = mv64x60_shift_right,
674 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 10 },
675 [MV64x60_CPU2PCI0_MEM_1_WIN] = {
676 .base_reg = MV64x60_CPU2PCI0_MEM_1_BASE,
677 .size_reg = MV64x60_CPU2PCI0_MEM_1_SIZE,
678 .base_bits = 16,
679 .size_bits = 16,
680 .get_from_field = mv64x60_shift_left,
681 .map_to_field = mv64x60_shift_right,
682 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 11 },
683 [MV64x60_CPU2PCI0_MEM_2_WIN] = {
684 .base_reg = MV64x60_CPU2PCI0_MEM_2_BASE,
685 .size_reg = MV64x60_CPU2PCI0_MEM_2_SIZE,
686 .base_bits = 16,
687 .size_bits = 16,
688 .get_from_field = mv64x60_shift_left,
689 .map_to_field = mv64x60_shift_right,
690 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 12 },
691 [MV64x60_CPU2PCI0_MEM_3_WIN] = {
692 .base_reg = MV64x60_CPU2PCI0_MEM_3_BASE,
693 .size_reg = MV64x60_CPU2PCI0_MEM_3_SIZE,
694 .base_bits = 16,
695 .size_bits = 16,
696 .get_from_field = mv64x60_shift_left,
697 .map_to_field = mv64x60_shift_right,
698 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 13 },
699 /* CPU->PCI 1 Windows */
700 [MV64x60_CPU2PCI1_IO_WIN] = {
701 .base_reg = MV64x60_CPU2PCI1_IO_BASE,
702 .size_reg = MV64x60_CPU2PCI1_IO_SIZE,
703 .base_bits = 16,
704 .size_bits = 16,
705 .get_from_field = mv64x60_shift_left,
706 .map_to_field = mv64x60_shift_right,
707 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 14 },
708 [MV64x60_CPU2PCI1_MEM_0_WIN] = {
709 .base_reg = MV64x60_CPU2PCI1_MEM_0_BASE,
710 .size_reg = MV64x60_CPU2PCI1_MEM_0_SIZE,
711 .base_bits = 16,
712 .size_bits = 16,
713 .get_from_field = mv64x60_shift_left,
714 .map_to_field = mv64x60_shift_right,
715 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 15 },
716 [MV64x60_CPU2PCI1_MEM_1_WIN] = {
717 .base_reg = MV64x60_CPU2PCI1_MEM_1_BASE,
718 .size_reg = MV64x60_CPU2PCI1_MEM_1_SIZE,
719 .base_bits = 16,
720 .size_bits = 16,
721 .get_from_field = mv64x60_shift_left,
722 .map_to_field = mv64x60_shift_right,
723 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 16 },
724 [MV64x60_CPU2PCI1_MEM_2_WIN] = {
725 .base_reg = MV64x60_CPU2PCI1_MEM_2_BASE,
726 .size_reg = MV64x60_CPU2PCI1_MEM_2_SIZE,
727 .base_bits = 16,
728 .size_bits = 16,
729 .get_from_field = mv64x60_shift_left,
730 .map_to_field = mv64x60_shift_right,
731 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 17 },
732 [MV64x60_CPU2PCI1_MEM_3_WIN] = {
733 .base_reg = MV64x60_CPU2PCI1_MEM_3_BASE,
734 .size_reg = MV64x60_CPU2PCI1_MEM_3_SIZE,
735 .base_bits = 16,
736 .size_bits = 16,
737 .get_from_field = mv64x60_shift_left,
738 .map_to_field = mv64x60_shift_right,
739 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 18 },
740 /* CPU->SRAM Window */
741 [MV64x60_CPU2SRAM_WIN] = {
742 .base_reg = MV64360_CPU2SRAM_BASE,
743 .size_reg = 0,
744 .base_bits = 16,
745 .size_bits = 0,
746 .get_from_field = mv64x60_shift_left,
747 .map_to_field = mv64x60_shift_right,
748 .extra = MV64x60_EXTRA_CPUWIN_ENAB | 19 },
749 /* CPU->PCI 0 Remap I/O Window */
750 [MV64x60_CPU2PCI0_IO_REMAP_WIN] = {
751 .base_reg = MV64x60_CPU2PCI0_IO_REMAP,
752 .size_reg = 0,
753 .base_bits = 16,
754 .size_bits = 0,
755 .get_from_field = mv64x60_shift_left,
756 .map_to_field = mv64x60_shift_right,
757 .extra = 0 },
758 /* CPU->PCI 1 Remap I/O Window */
759 [MV64x60_CPU2PCI1_IO_REMAP_WIN] = {
760 .base_reg = MV64x60_CPU2PCI1_IO_REMAP,
761 .size_reg = 0,
762 .base_bits = 16,
763 .size_bits = 0,
764 .get_from_field = mv64x60_shift_left,
765 .map_to_field = mv64x60_shift_right,
766 .extra = 0 },
767 /* CPU Memory Protection Windows */
768 [MV64x60_CPU_PROT_0_WIN] = {
769 .base_reg = MV64x60_CPU_PROT_BASE_0,
770 .size_reg = MV64x60_CPU_PROT_SIZE_0,
771 .base_bits = 16,
772 .size_bits = 16,
773 .get_from_field = mv64x60_shift_left,
774 .map_to_field = mv64x60_shift_right,
775 .extra = MV64x60_EXTRA_CPUPROT_ENAB | 31 },
776 [MV64x60_CPU_PROT_1_WIN] = {
777 .base_reg = MV64x60_CPU_PROT_BASE_1,
778 .size_reg = MV64x60_CPU_PROT_SIZE_1,
779 .base_bits = 16,
780 .size_bits = 16,
781 .get_from_field = mv64x60_shift_left,
782 .map_to_field = mv64x60_shift_right,
783 .extra = MV64x60_EXTRA_CPUPROT_ENAB | 31 },
784 [MV64x60_CPU_PROT_2_WIN] = {
785 .base_reg = MV64x60_CPU_PROT_BASE_2,
786 .size_reg = MV64x60_CPU_PROT_SIZE_2,
787 .base_bits = 16,
788 .size_bits = 16,
789 .get_from_field = mv64x60_shift_left,
790 .map_to_field = mv64x60_shift_right,
791 .extra = MV64x60_EXTRA_CPUPROT_ENAB | 31 },
792 [MV64x60_CPU_PROT_3_WIN] = {
793 .base_reg = MV64x60_CPU_PROT_BASE_3,
794 .size_reg = MV64x60_CPU_PROT_SIZE_3,
795 .base_bits = 16,
796 .size_bits = 16,
797 .get_from_field = mv64x60_shift_left,
798 .map_to_field = mv64x60_shift_right,
799 .extra = MV64x60_EXTRA_CPUPROT_ENAB | 31 },
800 /* CPU Snoop Windows -- don't exist on 64360 */
801 /* PCI 0->System Memory Remap Windows */
802 [MV64x60_PCI02MEM_REMAP_0_WIN] = {
803 .base_reg = MV64x60_PCI0_SLAVE_MEM_0_REMAP,
804 .size_reg = 0,
805 .base_bits = 20,
806 .size_bits = 0,
807 .get_from_field = mv64x60_mask,
808 .map_to_field = mv64x60_mask,
809 .extra = 0 },
810 [MV64x60_PCI02MEM_REMAP_1_WIN] = {
811 .base_reg = MV64x60_PCI0_SLAVE_MEM_1_REMAP,
812 .size_reg = 0,
813 .base_bits = 20,
814 .size_bits = 0,
815 .get_from_field = mv64x60_mask,
816 .map_to_field = mv64x60_mask,
817 .extra = 0 },
818 [MV64x60_PCI02MEM_REMAP_2_WIN] = {
819 .base_reg = MV64x60_PCI0_SLAVE_MEM_1_REMAP,
820 .size_reg = 0,
821 .base_bits = 20,
822 .size_bits = 0,
823 .get_from_field = mv64x60_mask,
824 .map_to_field = mv64x60_mask,
825 .extra = 0 },
826 [MV64x60_PCI02MEM_REMAP_3_WIN] = {
827 .base_reg = MV64x60_PCI0_SLAVE_MEM_1_REMAP,
828 .size_reg = 0,
829 .base_bits = 20,
830 .size_bits = 0,
831 .get_from_field = mv64x60_mask,
832 .map_to_field = mv64x60_mask,
833 .extra = 0 },
834 /* PCI 1->System Memory Remap Windows */
835 [MV64x60_PCI12MEM_REMAP_0_WIN] = {
836 .base_reg = MV64x60_PCI1_SLAVE_MEM_0_REMAP,
837 .size_reg = 0,
838 .base_bits = 20,
839 .size_bits = 0,
840 .get_from_field = mv64x60_mask,
841 .map_to_field = mv64x60_mask,
842 .extra = 0 },
843 [MV64x60_PCI12MEM_REMAP_1_WIN] = {
844 .base_reg = MV64x60_PCI1_SLAVE_MEM_1_REMAP,
845 .size_reg = 0,
846 .base_bits = 20,
847 .size_bits = 0,
848 .get_from_field = mv64x60_mask,
849 .map_to_field = mv64x60_mask,
850 .extra = 0 },
851 [MV64x60_PCI12MEM_REMAP_2_WIN] = {
852 .base_reg = MV64x60_PCI1_SLAVE_MEM_1_REMAP,
853 .size_reg = 0,
854 .base_bits = 20,
855 .size_bits = 0,
856 .get_from_field = mv64x60_mask,
857 .map_to_field = mv64x60_mask,
858 .extra = 0 },
859 [MV64x60_PCI12MEM_REMAP_3_WIN] = {
860 .base_reg = MV64x60_PCI1_SLAVE_MEM_1_REMAP,
861 .size_reg = 0,
862 .base_bits = 20,
863 .size_bits = 0,
864 .get_from_field = mv64x60_mask,
865 .map_to_field = mv64x60_mask,
866 .extra = 0 },
867 /* ENET->System Memory Windows */
868 [MV64x60_ENET2MEM_0_WIN] = {
869 .base_reg = MV64360_ENET2MEM_0_BASE,
870 .size_reg = MV64360_ENET2MEM_0_SIZE,
871 .base_bits = 16,
872 .size_bits = 16,
873 .get_from_field = mv64x60_mask,
874 .map_to_field = mv64x60_mask,
875 .extra = MV64x60_EXTRA_ENET_ENAB | 0 },
876 [MV64x60_ENET2MEM_1_WIN] = {
877 .base_reg = MV64360_ENET2MEM_1_BASE,
878 .size_reg = MV64360_ENET2MEM_1_SIZE,
879 .base_bits = 16,
880 .size_bits = 16,
881 .get_from_field = mv64x60_mask,
882 .map_to_field = mv64x60_mask,
883 .extra = MV64x60_EXTRA_ENET_ENAB | 1 },
884 [MV64x60_ENET2MEM_2_WIN] = {
885 .base_reg = MV64360_ENET2MEM_2_BASE,
886 .size_reg = MV64360_ENET2MEM_2_SIZE,
887 .base_bits = 16,
888 .size_bits = 16,
889 .get_from_field = mv64x60_mask,
890 .map_to_field = mv64x60_mask,
891 .extra = MV64x60_EXTRA_ENET_ENAB | 2 },
892 [MV64x60_ENET2MEM_3_WIN] = {
893 .base_reg = MV64360_ENET2MEM_3_BASE,
894 .size_reg = MV64360_ENET2MEM_3_SIZE,
895 .base_bits = 16,
896 .size_bits = 16,
897 .get_from_field = mv64x60_mask,
898 .map_to_field = mv64x60_mask,
899 .extra = MV64x60_EXTRA_ENET_ENAB | 3 },
900 [MV64x60_ENET2MEM_4_WIN] = {
901 .base_reg = MV64360_ENET2MEM_4_BASE,
902 .size_reg = MV64360_ENET2MEM_4_SIZE,
903 .base_bits = 16,
904 .size_bits = 16,
905 .get_from_field = mv64x60_mask,
906 .map_to_field = mv64x60_mask,
907 .extra = MV64x60_EXTRA_ENET_ENAB | 4 },
908 [MV64x60_ENET2MEM_5_WIN] = {
909 .base_reg = MV64360_ENET2MEM_5_BASE,
910 .size_reg = MV64360_ENET2MEM_5_SIZE,
911 .base_bits = 16,
912 .size_bits = 16,
913 .get_from_field = mv64x60_mask,
914 .map_to_field = mv64x60_mask,
915 .extra = MV64x60_EXTRA_ENET_ENAB | 5 },
916 /* MPSC->System Memory Windows */
917 [MV64x60_MPSC2MEM_0_WIN] = {
918 .base_reg = MV64360_MPSC2MEM_0_BASE,
919 .size_reg = MV64360_MPSC2MEM_0_SIZE,
920 .base_bits = 16,
921 .size_bits = 16,
922 .get_from_field = mv64x60_mask,
923 .map_to_field = mv64x60_mask,
924 .extra = MV64x60_EXTRA_MPSC_ENAB | 0 },
925 [MV64x60_MPSC2MEM_1_WIN] = {
926 .base_reg = MV64360_MPSC2MEM_1_BASE,
927 .size_reg = MV64360_MPSC2MEM_1_SIZE,
928 .base_bits = 16,
929 .size_bits = 16,
930 .get_from_field = mv64x60_mask,
931 .map_to_field = mv64x60_mask,
932 .extra = MV64x60_EXTRA_MPSC_ENAB | 1 },
933 [MV64x60_MPSC2MEM_2_WIN] = {
934 .base_reg = MV64360_MPSC2MEM_2_BASE,
935 .size_reg = MV64360_MPSC2MEM_2_SIZE,
936 .base_bits = 16,
937 .size_bits = 16,
938 .get_from_field = mv64x60_mask,
939 .map_to_field = mv64x60_mask,
940 .extra = MV64x60_EXTRA_MPSC_ENAB | 2 },
941 [MV64x60_MPSC2MEM_3_WIN] = {
942 .base_reg = MV64360_MPSC2MEM_3_BASE,
943 .size_reg = MV64360_MPSC2MEM_3_SIZE,
944 .base_bits = 16,
945 .size_bits = 16,
946 .get_from_field = mv64x60_mask,
947 .map_to_field = mv64x60_mask,
948 .extra = MV64x60_EXTRA_MPSC_ENAB | 3 },
949 /* IDMA->System Memory Windows */
950 [MV64x60_IDMA2MEM_0_WIN] = {
951 .base_reg = MV64360_IDMA2MEM_0_BASE,
952 .size_reg = MV64360_IDMA2MEM_0_SIZE,
953 .base_bits = 16,
954 .size_bits = 16,
955 .get_from_field = mv64x60_mask,
956 .map_to_field = mv64x60_mask,
957 .extra = MV64x60_EXTRA_IDMA_ENAB | 0 },
958 [MV64x60_IDMA2MEM_1_WIN] = {
959 .base_reg = MV64360_IDMA2MEM_1_BASE,
960 .size_reg = MV64360_IDMA2MEM_1_SIZE,
961 .base_bits = 16,
962 .size_bits = 16,
963 .get_from_field = mv64x60_mask,
964 .map_to_field = mv64x60_mask,
965 .extra = MV64x60_EXTRA_IDMA_ENAB | 1 },
966 [MV64x60_IDMA2MEM_2_WIN] = {
967 .base_reg = MV64360_IDMA2MEM_2_BASE,
968 .size_reg = MV64360_IDMA2MEM_2_SIZE,
969 .base_bits = 16,
970 .size_bits = 16,
971 .get_from_field = mv64x60_mask,
972 .map_to_field = mv64x60_mask,
973 .extra = MV64x60_EXTRA_IDMA_ENAB | 2 },
974 [MV64x60_IDMA2MEM_3_WIN] = {
975 .base_reg = MV64360_IDMA2MEM_3_BASE,
976 .size_reg = MV64360_IDMA2MEM_3_SIZE,
977 .base_bits = 16,
978 .size_bits = 16,
979 .get_from_field = mv64x60_mask,
980 .map_to_field = mv64x60_mask,
981 .extra = MV64x60_EXTRA_IDMA_ENAB | 3 },
982 [MV64x60_IDMA2MEM_4_WIN] = {
983 .base_reg = MV64360_IDMA2MEM_4_BASE,
984 .size_reg = MV64360_IDMA2MEM_4_SIZE,
985 .base_bits = 16,
986 .size_bits = 16,
987 .get_from_field = mv64x60_mask,
988 .map_to_field = mv64x60_mask,
989 .extra = MV64x60_EXTRA_IDMA_ENAB | 4 },
990 [MV64x60_IDMA2MEM_5_WIN] = {
991 .base_reg = MV64360_IDMA2MEM_5_BASE,
992 .size_reg = MV64360_IDMA2MEM_5_SIZE,
993 .base_bits = 16,
994 .size_bits = 16,
995 .get_from_field = mv64x60_mask,
996 .map_to_field = mv64x60_mask,
997 .extra = MV64x60_EXTRA_IDMA_ENAB | 5 },
998 [MV64x60_IDMA2MEM_6_WIN] = {
999 .base_reg = MV64360_IDMA2MEM_6_BASE,
1000 .size_reg = MV64360_IDMA2MEM_6_SIZE,
1001 .base_bits = 16,
1002 .size_bits = 16,
1003 .get_from_field = mv64x60_mask,
1004 .map_to_field = mv64x60_mask,
1005 .extra = MV64x60_EXTRA_IDMA_ENAB | 6 },
1006 [MV64x60_IDMA2MEM_7_WIN] = {
1007 .base_reg = MV64360_IDMA2MEM_7_BASE,
1008 .size_reg = MV64360_IDMA2MEM_7_SIZE,
1009 .base_bits = 16,
1010 .size_bits = 16,
1011 .get_from_field = mv64x60_mask,
1012 .map_to_field = mv64x60_mask,
1013 .extra = MV64x60_EXTRA_IDMA_ENAB | 7 },
1014};
1015
1016struct mv64x60_64bit_window
1017 mv64360_64bit_windows[MV64x60_64BIT_WIN_COUNT] __initdata = {
1018 /* CPU->PCI 0 MEM Remap Windows */
1019 [MV64x60_CPU2PCI0_MEM_0_REMAP_WIN] = {
1020 .base_hi_reg = MV64x60_CPU2PCI0_MEM_0_REMAP_HI,
1021 .base_lo_reg = MV64x60_CPU2PCI0_MEM_0_REMAP_LO,
1022 .size_reg = 0,
1023 .base_lo_bits = 16,
1024 .size_bits = 0,
1025 .get_from_field = mv64x60_shift_left,
1026 .map_to_field = mv64x60_shift_right,
1027 .extra = 0 },
1028 [MV64x60_CPU2PCI0_MEM_1_REMAP_WIN] = {
1029 .base_hi_reg = MV64x60_CPU2PCI0_MEM_1_REMAP_HI,
1030 .base_lo_reg = MV64x60_CPU2PCI0_MEM_1_REMAP_LO,
1031 .size_reg = 0,
1032 .base_lo_bits = 16,
1033 .size_bits = 0,
1034 .get_from_field = mv64x60_shift_left,
1035 .map_to_field = mv64x60_shift_right,
1036 .extra = 0 },
1037 [MV64x60_CPU2PCI0_MEM_2_REMAP_WIN] = {
1038 .base_hi_reg = MV64x60_CPU2PCI0_MEM_2_REMAP_HI,
1039 .base_lo_reg = MV64x60_CPU2PCI0_MEM_2_REMAP_LO,
1040 .size_reg = 0,
1041 .base_lo_bits = 16,
1042 .size_bits = 0,
1043 .get_from_field = mv64x60_shift_left,
1044 .map_to_field = mv64x60_shift_right,
1045 .extra = 0 },
1046 [MV64x60_CPU2PCI0_MEM_3_REMAP_WIN] = {
1047 .base_hi_reg = MV64x60_CPU2PCI0_MEM_3_REMAP_HI,
1048 .base_lo_reg = MV64x60_CPU2PCI0_MEM_3_REMAP_LO,
1049 .size_reg = 0,
1050 .base_lo_bits = 16,
1051 .size_bits = 0,
1052 .get_from_field = mv64x60_shift_left,
1053 .map_to_field = mv64x60_shift_right,
1054 .extra = 0 },
1055 /* CPU->PCI 1 MEM Remap Windows */
1056 [MV64x60_CPU2PCI1_MEM_0_REMAP_WIN] = {
1057 .base_hi_reg = MV64x60_CPU2PCI1_MEM_0_REMAP_HI,
1058 .base_lo_reg = MV64x60_CPU2PCI1_MEM_0_REMAP_LO,
1059 .size_reg = 0,
1060 .base_lo_bits = 16,
1061 .size_bits = 0,
1062 .get_from_field = mv64x60_shift_left,
1063 .map_to_field = mv64x60_shift_right,
1064 .extra = 0 },
1065 [MV64x60_CPU2PCI1_MEM_1_REMAP_WIN] = {
1066 .base_hi_reg = MV64x60_CPU2PCI1_MEM_1_REMAP_HI,
1067 .base_lo_reg = MV64x60_CPU2PCI1_MEM_1_REMAP_LO,
1068 .size_reg = 0,
1069 .base_lo_bits = 16,
1070 .size_bits = 0,
1071 .get_from_field = mv64x60_shift_left,
1072 .map_to_field = mv64x60_shift_right,
1073 .extra = 0 },
1074 [MV64x60_CPU2PCI1_MEM_2_REMAP_WIN] = {
1075 .base_hi_reg = MV64x60_CPU2PCI1_MEM_2_REMAP_HI,
1076 .base_lo_reg = MV64x60_CPU2PCI1_MEM_2_REMAP_LO,
1077 .size_reg = 0,
1078 .base_lo_bits = 16,
1079 .size_bits = 0,
1080 .get_from_field = mv64x60_shift_left,
1081 .map_to_field = mv64x60_shift_right,
1082 .extra = 0 },
1083 [MV64x60_CPU2PCI1_MEM_3_REMAP_WIN] = {
1084 .base_hi_reg = MV64x60_CPU2PCI1_MEM_3_REMAP_HI,
1085 .base_lo_reg = MV64x60_CPU2PCI1_MEM_3_REMAP_LO,
1086 .size_reg = 0,
1087 .base_lo_bits = 16,
1088 .size_bits = 0,
1089 .get_from_field = mv64x60_shift_left,
1090 .map_to_field = mv64x60_shift_right,
1091 .extra = 0 },
1092 /* PCI 0->MEM Access Control Windows */
1093 [MV64x60_PCI02MEM_ACC_CNTL_0_WIN] = {
1094 .base_hi_reg = MV64x60_PCI0_ACC_CNTL_0_BASE_HI,
1095 .base_lo_reg = MV64x60_PCI0_ACC_CNTL_0_BASE_LO,
1096 .size_reg = MV64x60_PCI0_ACC_CNTL_0_SIZE,
1097 .base_lo_bits = 20,
1098 .size_bits = 20,
1099 .get_from_field = mv64x60_mask,
1100 .map_to_field = mv64x60_mask,
1101 .extra = MV64x60_EXTRA_PCIACC_ENAB | 0 },
1102 [MV64x60_PCI02MEM_ACC_CNTL_1_WIN] = {
1103 .base_hi_reg = MV64x60_PCI0_ACC_CNTL_1_BASE_HI,
1104 .base_lo_reg = MV64x60_PCI0_ACC_CNTL_1_BASE_LO,
1105 .size_reg = MV64x60_PCI0_ACC_CNTL_1_SIZE,
1106 .base_lo_bits = 20,
1107 .size_bits = 20,
1108 .get_from_field = mv64x60_mask,
1109 .map_to_field = mv64x60_mask,
1110 .extra = MV64x60_EXTRA_PCIACC_ENAB | 0 },
1111 [MV64x60_PCI02MEM_ACC_CNTL_2_WIN] = {
1112 .base_hi_reg = MV64x60_PCI0_ACC_CNTL_2_BASE_HI,
1113 .base_lo_reg = MV64x60_PCI0_ACC_CNTL_2_BASE_LO,
1114 .size_reg = MV64x60_PCI0_ACC_CNTL_2_SIZE,
1115 .base_lo_bits = 20,
1116 .size_bits = 20,
1117 .get_from_field = mv64x60_mask,
1118 .map_to_field = mv64x60_mask,
1119 .extra = MV64x60_EXTRA_PCIACC_ENAB | 0 },
1120 [MV64x60_PCI02MEM_ACC_CNTL_3_WIN] = {
1121 .base_hi_reg = MV64x60_PCI0_ACC_CNTL_3_BASE_HI,
1122 .base_lo_reg = MV64x60_PCI0_ACC_CNTL_3_BASE_LO,
1123 .size_reg = MV64x60_PCI0_ACC_CNTL_3_SIZE,
1124 .base_lo_bits = 20,
1125 .size_bits = 20,
1126 .get_from_field = mv64x60_mask,
1127 .map_to_field = mv64x60_mask,
1128 .extra = MV64x60_EXTRA_PCIACC_ENAB | 0 },
1129 /* PCI 1->MEM Access Control Windows */
1130 [MV64x60_PCI12MEM_ACC_CNTL_0_WIN] = {
1131 .base_hi_reg = MV64x60_PCI1_ACC_CNTL_0_BASE_HI,
1132 .base_lo_reg = MV64x60_PCI1_ACC_CNTL_0_BASE_LO,
1133 .size_reg = MV64x60_PCI1_ACC_CNTL_0_SIZE,
1134 .base_lo_bits = 20,
1135 .size_bits = 20,
1136 .get_from_field = mv64x60_mask,
1137 .map_to_field = mv64x60_mask,
1138 .extra = MV64x60_EXTRA_PCIACC_ENAB | 0 },
1139 [MV64x60_PCI12MEM_ACC_CNTL_1_WIN] = {
1140 .base_hi_reg = MV64x60_PCI1_ACC_CNTL_1_BASE_HI,
1141 .base_lo_reg = MV64x60_PCI1_ACC_CNTL_1_BASE_LO,
1142 .size_reg = MV64x60_PCI1_ACC_CNTL_1_SIZE,
1143 .base_lo_bits = 20,
1144 .size_bits = 20,
1145 .get_from_field = mv64x60_mask,
1146 .map_to_field = mv64x60_mask,
1147 .extra = MV64x60_EXTRA_PCIACC_ENAB | 0 },
1148 [MV64x60_PCI12MEM_ACC_CNTL_2_WIN] = {
1149 .base_hi_reg = MV64x60_PCI1_ACC_CNTL_2_BASE_HI,
1150 .base_lo_reg = MV64x60_PCI1_ACC_CNTL_2_BASE_LO,
1151 .size_reg = MV64x60_PCI1_ACC_CNTL_2_SIZE,
1152 .base_lo_bits = 20,
1153 .size_bits = 20,
1154 .get_from_field = mv64x60_mask,
1155 .map_to_field = mv64x60_mask,
1156 .extra = MV64x60_EXTRA_PCIACC_ENAB | 0 },
1157 [MV64x60_PCI12MEM_ACC_CNTL_3_WIN] = {
1158 .base_hi_reg = MV64x60_PCI1_ACC_CNTL_3_BASE_HI,
1159 .base_lo_reg = MV64x60_PCI1_ACC_CNTL_3_BASE_LO,
1160 .size_reg = MV64x60_PCI1_ACC_CNTL_3_SIZE,
1161 .base_lo_bits = 20,
1162 .size_bits = 20,
1163 .get_from_field = mv64x60_mask,
1164 .map_to_field = mv64x60_mask,
1165 .extra = MV64x60_EXTRA_PCIACC_ENAB | 0 },
1166 /* PCI 0->MEM Snoop Windows -- don't exist on 64360 */
1167 /* PCI 1->MEM Snoop Windows -- don't exist on 64360 */
1168};
diff --git a/arch/ppc/syslib/ocp.c b/arch/ppc/syslib/ocp.c
new file mode 100644
index 000000000000..a5156c5179a6
--- /dev/null
+++ b/arch/ppc/syslib/ocp.c
@@ -0,0 +1,485 @@
1/*
2 * ocp.c
3 *
4 * (c) Benjamin Herrenschmidt (benh@kernel.crashing.org)
5 * Mipsys - France
6 *
7 * Derived from work (c) Armin Kuster akuster@pacbell.net
8 *
9 * Additional support and port to 2.6 LDM/sysfs by
10 * Matt Porter <mporter@kernel.crashing.org>
11 * Copyright 2004 MontaVista Software, Inc.
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17 *
18 * OCP (On Chip Peripheral) is a software emulated "bus" with a
19 * pseudo discovery method for dumb peripherals. Usually these type
20 * of peripherals are found on embedded SoC (System On a Chip)
21 * processors or highly integrated system controllers that have
22 * a host bridge and many peripherals. Common examples where
23 * this is already used include the PPC4xx, PPC85xx, MPC52xx,
24 * and MV64xxx parts.
25 *
26 * This subsystem creates a standard OCP bus type within the
27 * device model. The devices on the OCP bus are seeded by an
28 * an initial OCP device array created by the arch-specific
29 * Device entries can be added/removed/modified through OCP
30 * helper functions to accomodate system and board-specific
31 * parameters commonly found in embedded systems. OCP also
32 * provides a standard method for devices to describe extended
33 * attributes about themselves to the system. A standard access
34 * method allows OCP drivers to obtain the information, both
35 * SoC-specific and system/board-specific, needed for operation.
36 */
37
38#include <linux/module.h>
39#include <linux/config.h>
40#include <linux/list.h>
41#include <linux/miscdevice.h>
42#include <linux/slab.h>
43#include <linux/types.h>
44#include <linux/init.h>
45#include <linux/pm.h>
46#include <linux/bootmem.h>
47#include <linux/device.h>
48
49#include <asm/io.h>
50#include <asm/ocp.h>
51#include <asm/errno.h>
52#include <asm/rwsem.h>
53#include <asm/semaphore.h>
54
55//#define DBG(x) printk x
56#define DBG(x)
57
58extern int mem_init_done;
59
60extern struct ocp_def core_ocp[]; /* Static list of devices, provided by
61 CPU core */
62
63LIST_HEAD(ocp_devices); /* List of all OCP devices */
64DECLARE_RWSEM(ocp_devices_sem); /* Global semaphores for those lists */
65
66static int ocp_inited;
67
68/* Sysfs support */
69#define OCP_DEF_ATTR(field, format_string) \
70static ssize_t \
71show_##field(struct device *dev, char *buf) \
72{ \
73 struct ocp_device *odev = to_ocp_dev(dev); \
74 \
75 return sprintf(buf, format_string, odev->def->field); \
76} \
77static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
78
79OCP_DEF_ATTR(vendor, "0x%04x\n");
80OCP_DEF_ATTR(function, "0x%04x\n");
81OCP_DEF_ATTR(index, "0x%04x\n");
82#ifdef CONFIG_PTE_64BIT
83OCP_DEF_ATTR(paddr, "0x%016Lx\n");
84#else
85OCP_DEF_ATTR(paddr, "0x%08lx\n");
86#endif
87OCP_DEF_ATTR(irq, "%d\n");
88OCP_DEF_ATTR(pm, "%lu\n");
89
90void ocp_create_sysfs_dev_files(struct ocp_device *odev)
91{
92 struct device *dev = &odev->dev;
93
94 /* Current OCP device def attributes */
95 device_create_file(dev, &dev_attr_vendor);
96 device_create_file(dev, &dev_attr_function);
97 device_create_file(dev, &dev_attr_index);
98 device_create_file(dev, &dev_attr_paddr);
99 device_create_file(dev, &dev_attr_irq);
100 device_create_file(dev, &dev_attr_pm);
101 /* Current OCP device additions attributes */
102 if (odev->def->additions && odev->def->show)
103 odev->def->show(dev);
104}
105
106/**
107 * ocp_device_match - Match one driver to one device
108 * @drv: driver to match
109 * @dev: device to match
110 *
111 * This function returns 0 if the driver and device don't match
112 */
113static int
114ocp_device_match(struct device *dev, struct device_driver *drv)
115{
116 struct ocp_device *ocp_dev = to_ocp_dev(dev);
117 struct ocp_driver *ocp_drv = to_ocp_drv(drv);
118 const struct ocp_device_id *ids = ocp_drv->id_table;
119
120 if (!ids)
121 return 0;
122
123 while (ids->vendor || ids->function) {
124 if ((ids->vendor == OCP_ANY_ID
125 || ids->vendor == ocp_dev->def->vendor)
126 && (ids->function == OCP_ANY_ID
127 || ids->function == ocp_dev->def->function))
128 return 1;
129 ids++;
130 }
131 return 0;
132}
133
134static int
135ocp_device_probe(struct device *dev)
136{
137 int error = 0;
138 struct ocp_driver *drv;
139 struct ocp_device *ocp_dev;
140
141 drv = to_ocp_drv(dev->driver);
142 ocp_dev = to_ocp_dev(dev);
143
144 if (drv->probe) {
145 error = drv->probe(ocp_dev);
146 if (error >= 0) {
147 ocp_dev->driver = drv;
148 error = 0;
149 }
150 }
151 return error;
152}
153
154static int
155ocp_device_remove(struct device *dev)
156{
157 struct ocp_device *ocp_dev = to_ocp_dev(dev);
158
159 if (ocp_dev->driver) {
160 if (ocp_dev->driver->remove)
161 ocp_dev->driver->remove(ocp_dev);
162 ocp_dev->driver = NULL;
163 }
164 return 0;
165}
166
167static int
168ocp_device_suspend(struct device *dev, u32 state)
169{
170 struct ocp_device *ocp_dev = to_ocp_dev(dev);
171 struct ocp_driver *ocp_drv = to_ocp_drv(dev->driver);
172
173 if (dev->driver && ocp_drv->suspend)
174 return ocp_drv->suspend(ocp_dev, state);
175 return 0;
176}
177
178static int
179ocp_device_resume(struct device *dev)
180{
181 struct ocp_device *ocp_dev = to_ocp_dev(dev);
182 struct ocp_driver *ocp_drv = to_ocp_drv(dev->driver);
183
184 if (dev->driver && ocp_drv->resume)
185 return ocp_drv->resume(ocp_dev);
186 return 0;
187}
188
189struct bus_type ocp_bus_type = {
190 .name = "ocp",
191 .match = ocp_device_match,
192 .suspend = ocp_device_suspend,
193 .resume = ocp_device_resume,
194};
195
196/**
197 * ocp_register_driver - Register an OCP driver
198 * @drv: pointer to statically defined ocp_driver structure
199 *
200 * The driver's probe() callback is called either recursively
201 * by this function or upon later call of ocp_driver_init
202 *
203 * NOTE: Detection of devices is a 2 pass step on this implementation,
204 * hotswap isn't supported. First, all OCP devices are put in the device
205 * list, _then_ all drivers are probed on each match.
206 */
207int
208ocp_register_driver(struct ocp_driver *drv)
209{
210 /* initialize common driver fields */
211 drv->driver.name = drv->name;
212 drv->driver.bus = &ocp_bus_type;
213 drv->driver.probe = ocp_device_probe;
214 drv->driver.remove = ocp_device_remove;
215
216 /* register with core */
217 return driver_register(&drv->driver);
218}
219
220/**
221 * ocp_unregister_driver - Unregister an OCP driver
222 * @drv: pointer to statically defined ocp_driver structure
223 *
224 * The driver's remove() callback is called recursively
225 * by this function for any device already registered
226 */
227void
228ocp_unregister_driver(struct ocp_driver *drv)
229{
230 DBG(("ocp: ocp_unregister_driver(%s)...\n", drv->name));
231
232 driver_unregister(&drv->driver);
233
234 DBG(("ocp: ocp_unregister_driver(%s)... done.\n", drv->name));
235}
236
237/* Core of ocp_find_device(). Caller must hold ocp_devices_sem */
238static struct ocp_device *
239__ocp_find_device(unsigned int vendor, unsigned int function, int index)
240{
241 struct list_head *entry;
242 struct ocp_device *dev, *found = NULL;
243
244 DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index));
245
246 list_for_each(entry, &ocp_devices) {
247 dev = list_entry(entry, struct ocp_device, link);
248 if (vendor != OCP_ANY_ID && vendor != dev->def->vendor)
249 continue;
250 if (function != OCP_ANY_ID && function != dev->def->function)
251 continue;
252 if (index != OCP_ANY_INDEX && index != dev->def->index)
253 continue;
254 found = dev;
255 break;
256 }
257
258 DBG(("ocp: __ocp_find_device(vendor: %x, function: %x, index: %d)... done\n", vendor, function, index));
259
260 return found;
261}
262
263/**
264 * ocp_find_device - Find a device by function & index
265 * @vendor: vendor ID of the device (or OCP_ANY_ID)
266 * @function: function code of the device (or OCP_ANY_ID)
267 * @idx: index of the device (or OCP_ANY_INDEX)
268 *
269 * This function allows a lookup of a given function by it's
270 * index, it's typically used to find the MAL or ZMII associated
271 * with an EMAC or similar horrors.
272 * You can pass vendor, though you usually want OCP_ANY_ID there...
273 */
274struct ocp_device *
275ocp_find_device(unsigned int vendor, unsigned int function, int index)
276{
277 struct ocp_device *dev;
278
279 down_read(&ocp_devices_sem);
280 dev = __ocp_find_device(vendor, function, index);
281 up_read(&ocp_devices_sem);
282
283 return dev;
284}
285
286/**
287 * ocp_get_one_device - Find a def by function & index
288 * @vendor: vendor ID of the device (or OCP_ANY_ID)
289 * @function: function code of the device (or OCP_ANY_ID)
290 * @idx: index of the device (or OCP_ANY_INDEX)
291 *
292 * This function allows a lookup of a given ocp_def by it's
293 * vendor, function, and index. The main purpose for is to
294 * allow modification of the def before binding to the driver
295 */
296struct ocp_def *
297ocp_get_one_device(unsigned int vendor, unsigned int function, int index)
298{
299 struct ocp_device *dev;
300 struct ocp_def *found = NULL;
301
302 DBG(("ocp: ocp_get_one_device(vendor: %x, function: %x, index: %d)...\n",
303 vendor, function, index));
304
305 dev = ocp_find_device(vendor, function, index);
306
307 if (dev)
308 found = dev->def;
309
310 DBG(("ocp: ocp_get_one_device(vendor: %x, function: %x, index: %d)... done.\n",
311 vendor, function, index));
312
313 return found;
314}
315
316/**
317 * ocp_add_one_device - Add a device
318 * @def: static device definition structure
319 *
320 * This function adds a device definition to the
321 * device list. It may only be called before
322 * ocp_driver_init() and will return an error
323 * otherwise.
324 */
325int
326ocp_add_one_device(struct ocp_def *def)
327{
328 struct ocp_device *dev;
329
330 DBG(("ocp: ocp_add_one_device()...\n"));
331
332 /* Can't be called after ocp driver init */
333 if (ocp_inited)
334 return 1;
335
336 if (mem_init_done)
337 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
338 else
339 dev = alloc_bootmem(sizeof(*dev));
340
341 if (dev == NULL)
342 return 1;
343 memset(dev, 0, sizeof(*dev));
344 dev->def = def;
345 dev->current_state = 4;
346 sprintf(dev->name, "OCP device %04x:%04x:%04x",
347 dev->def->vendor, dev->def->function, dev->def->index);
348 down_write(&ocp_devices_sem);
349 list_add_tail(&dev->link, &ocp_devices);
350 up_write(&ocp_devices_sem);
351
352 DBG(("ocp: ocp_add_one_device()...done\n"));
353
354 return 0;
355}
356
357/**
358 * ocp_remove_one_device - Remove a device by function & index
359 * @vendor: vendor ID of the device (or OCP_ANY_ID)
360 * @function: function code of the device (or OCP_ANY_ID)
361 * @idx: index of the device (or OCP_ANY_INDEX)
362 *
363 * This function allows removal of a given function by its
364 * index. It may only be called before ocp_driver_init()
365 * and will return an error otherwise.
366 */
367int
368ocp_remove_one_device(unsigned int vendor, unsigned int function, int index)
369{
370 struct ocp_device *dev;
371
372 DBG(("ocp: ocp_remove_one_device(vendor: %x, function: %x, index: %d)...\n", vendor, function, index));
373
374 /* Can't be called after ocp driver init */
375 if (ocp_inited)
376 return 1;
377
378 down_write(&ocp_devices_sem);
379 dev = __ocp_find_device(vendor, function, index);
380 list_del((struct list_head *)dev);
381 up_write(&ocp_devices_sem);
382
383 DBG(("ocp: ocp_remove_one_device(vendor: %x, function: %x, index: %d)... done.\n", vendor, function, index));
384
385 return 0;
386}
387
388/**
389 * ocp_for_each_device - Iterate over OCP devices
390 * @callback: routine to execute for each ocp device.
391 * @arg: user data to be passed to callback routine.
392 *
393 * This routine holds the ocp_device semaphore, so the
394 * callback routine cannot modify the ocp_device list.
395 */
396void
397ocp_for_each_device(void(*callback)(struct ocp_device *, void *arg), void *arg)
398{
399 struct list_head *entry;
400
401 if (callback) {
402 down_read(&ocp_devices_sem);
403 list_for_each(entry, &ocp_devices)
404 callback(list_entry(entry, struct ocp_device, link),
405 arg);
406 up_read(&ocp_devices_sem);
407 }
408}
409
410/**
411 * ocp_early_init - Init OCP device management
412 *
413 * This function builds the list of devices before setup_arch.
414 * This allows platform code to modify the device lists before
415 * they are bound to drivers (changes to paddr, removing devices
416 * etc)
417 */
418int __init
419ocp_early_init(void)
420{
421 struct ocp_def *def;
422
423 DBG(("ocp: ocp_early_init()...\n"));
424
425 /* Fill the devices list */
426 for (def = core_ocp; def->vendor != OCP_VENDOR_INVALID; def++)
427 ocp_add_one_device(def);
428
429 DBG(("ocp: ocp_early_init()... done.\n"));
430
431 return 0;
432}
433
434/**
435 * ocp_driver_init - Init OCP device management
436 *
437 * This function is meant to be called via OCP bus registration.
438 */
439static int __init
440ocp_driver_init(void)
441{
442 int ret = 0, index = 0;
443 struct device *ocp_bus;
444 struct list_head *entry;
445 struct ocp_device *dev;
446
447 if (ocp_inited)
448 return ret;
449 ocp_inited = 1;
450
451 DBG(("ocp: ocp_driver_init()...\n"));
452
453 /* Allocate/register primary OCP bus */
454 ocp_bus = kmalloc(sizeof(struct device), GFP_KERNEL);
455 if (ocp_bus == NULL)
456 return 1;
457 memset(ocp_bus, 0, sizeof(struct device));
458 strcpy(ocp_bus->bus_id, "ocp");
459
460 bus_register(&ocp_bus_type);
461
462 device_register(ocp_bus);
463
464 /* Put each OCP device into global device list */
465 list_for_each(entry, &ocp_devices) {
466 dev = list_entry(entry, struct ocp_device, link);
467 sprintf(dev->dev.bus_id, "%2.2x", index);
468 dev->dev.parent = ocp_bus;
469 dev->dev.bus = &ocp_bus_type;
470 device_register(&dev->dev);
471 ocp_create_sysfs_dev_files(dev);
472 index++;
473 }
474
475 DBG(("ocp: ocp_driver_init()... done.\n"));
476
477 return 0;
478}
479
480postcore_initcall(ocp_driver_init);
481
482EXPORT_SYMBOL(ocp_bus_type);
483EXPORT_SYMBOL(ocp_find_device);
484EXPORT_SYMBOL(ocp_register_driver);
485EXPORT_SYMBOL(ocp_unregister_driver);
diff --git a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c
new file mode 100644
index 000000000000..46269ed21aee
--- /dev/null
+++ b/arch/ppc/syslib/of_device.c
@@ -0,0 +1,273 @@
1#include <linux/config.h>
2#include <linux/string.h>
3#include <linux/kernel.h>
4#include <linux/init.h>
5#include <linux/module.h>
6#include <asm/errno.h>
7#include <asm/of_device.h>
8
9/**
10 * of_match_device - Tell if an of_device structure has a matching
11 * of_match structure
12 * @ids: array of of device match structures to search in
13 * @dev: the of device structure to match against
14 *
15 * Used by a driver to check whether an of_device present in the
16 * system is in its list of supported devices.
17 */
18const struct of_match * of_match_device(const struct of_match *matches,
19 const struct of_device *dev)
20{
21 if (!dev->node)
22 return NULL;
23 while (matches->name || matches->type || matches->compatible) {
24 int match = 1;
25 if (matches->name && matches->name != OF_ANY_MATCH)
26 match &= dev->node->name
27 && !strcmp(matches->name, dev->node->name);
28 if (matches->type && matches->type != OF_ANY_MATCH)
29 match &= dev->node->type
30 && !strcmp(matches->type, dev->node->type);
31 if (matches->compatible && matches->compatible != OF_ANY_MATCH)
32 match &= device_is_compatible(dev->node,
33 matches->compatible);
34 if (match)
35 return matches;
36 matches++;
37 }
38 return NULL;
39}
40
41static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
42{
43 struct of_device * of_dev = to_of_device(dev);
44 struct of_platform_driver * of_drv = to_of_platform_driver(drv);
45 const struct of_match * matches = of_drv->match_table;
46
47 if (!matches)
48 return 0;
49
50 return of_match_device(matches, of_dev) != NULL;
51}
52
53struct of_device *of_dev_get(struct of_device *dev)
54{
55 struct device *tmp;
56
57 if (!dev)
58 return NULL;
59 tmp = get_device(&dev->dev);
60 if (tmp)
61 return to_of_device(tmp);
62 else
63 return NULL;
64}
65
66void of_dev_put(struct of_device *dev)
67{
68 if (dev)
69 put_device(&dev->dev);
70}
71
72
73static int of_device_probe(struct device *dev)
74{
75 int error = -ENODEV;
76 struct of_platform_driver *drv;
77 struct of_device *of_dev;
78 const struct of_match *match;
79
80 drv = to_of_platform_driver(dev->driver);
81 of_dev = to_of_device(dev);
82
83 if (!drv->probe)
84 return error;
85
86 of_dev_get(of_dev);
87
88 match = of_match_device(drv->match_table, of_dev);
89 if (match)
90 error = drv->probe(of_dev, match);
91 if (error)
92 of_dev_put(of_dev);
93
94 return error;
95}
96
97static int of_device_remove(struct device *dev)
98{
99 struct of_device * of_dev = to_of_device(dev);
100 struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
101
102 if (dev->driver && drv->remove)
103 drv->remove(of_dev);
104 return 0;
105}
106
107static int of_device_suspend(struct device *dev, u32 state)
108{
109 struct of_device * of_dev = to_of_device(dev);
110 struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
111 int error = 0;
112
113 if (dev->driver && drv->suspend)
114 error = drv->suspend(of_dev, state);
115 return error;
116}
117
118static int of_device_resume(struct device * dev)
119{
120 struct of_device * of_dev = to_of_device(dev);
121 struct of_platform_driver * drv = to_of_platform_driver(dev->driver);
122 int error = 0;
123
124 if (dev->driver && drv->resume)
125 error = drv->resume(of_dev);
126 return error;
127}
128
129struct bus_type of_platform_bus_type = {
130 .name = "of_platform",
131 .match = of_platform_bus_match,
132 .suspend = of_device_suspend,
133 .resume = of_device_resume,
134};
135
136static int __init of_bus_driver_init(void)
137{
138 return bus_register(&of_platform_bus_type);
139}
140
141postcore_initcall(of_bus_driver_init);
142
143int of_register_driver(struct of_platform_driver *drv)
144{
145 int count = 0;
146
147 /* initialize common driver fields */
148 drv->driver.name = drv->name;
149 drv->driver.bus = &of_platform_bus_type;
150 drv->driver.probe = of_device_probe;
151 drv->driver.remove = of_device_remove;
152
153 /* register with core */
154 count = driver_register(&drv->driver);
155 return count ? count : 1;
156}
157
158void of_unregister_driver(struct of_platform_driver *drv)
159{
160 driver_unregister(&drv->driver);
161}
162
163
164static ssize_t dev_show_devspec(struct device *dev, char *buf)
165{
166 struct of_device *ofdev;
167
168 ofdev = to_of_device(dev);
169 return sprintf(buf, "%s", ofdev->node->full_name);
170}
171
172static DEVICE_ATTR(devspec, S_IRUGO, dev_show_devspec, NULL);
173
174/**
175 * of_release_dev - free an of device structure when all users of it are finished.
176 * @dev: device that's been disconnected
177 *
178 * Will be called only by the device core when all users of this of device are
179 * done.
180 */
181void of_release_dev(struct device *dev)
182{
183 struct of_device *ofdev;
184
185 ofdev = to_of_device(dev);
186 of_node_put(ofdev->node);
187 kfree(ofdev);
188}
189
190int of_device_register(struct of_device *ofdev)
191{
192 int rc;
193 struct of_device **odprop;
194
195 BUG_ON(ofdev->node == NULL);
196
197 odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL);
198 if (!odprop) {
199 struct property *new_prop;
200
201 new_prop = kmalloc(sizeof(struct property) + sizeof(struct of_device *),
202 GFP_KERNEL);
203 if (new_prop == NULL)
204 return -ENOMEM;
205 new_prop->name = "linux,device";
206 new_prop->length = sizeof(sizeof(struct of_device *));
207 new_prop->value = (unsigned char *)&new_prop[1];
208 odprop = (struct of_device **)new_prop->value;
209 *odprop = NULL;
210 prom_add_property(ofdev->node, new_prop);
211 }
212 *odprop = ofdev;
213
214 rc = device_register(&ofdev->dev);
215 if (rc)
216 return rc;
217
218 device_create_file(&ofdev->dev, &dev_attr_devspec);
219
220 return 0;
221}
222
223void of_device_unregister(struct of_device *ofdev)
224{
225 struct of_device **odprop;
226
227 device_remove_file(&ofdev->dev, &dev_attr_devspec);
228
229 odprop = (struct of_device **)get_property(ofdev->node, "linux,device", NULL);
230 if (odprop)
231 *odprop = NULL;
232
233 device_unregister(&ofdev->dev);
234}
235
236struct of_device* of_platform_device_create(struct device_node *np, const char *bus_id)
237{
238 struct of_device *dev;
239 u32 *reg;
240
241 dev = kmalloc(sizeof(*dev), GFP_KERNEL);
242 if (!dev)
243 return NULL;
244 memset(dev, 0, sizeof(*dev));
245
246 dev->node = of_node_get(np);
247 dev->dma_mask = 0xffffffffUL;
248 dev->dev.dma_mask = &dev->dma_mask;
249 dev->dev.parent = NULL;
250 dev->dev.bus = &of_platform_bus_type;
251 dev->dev.release = of_release_dev;
252
253 reg = (u32 *)get_property(np, "reg", NULL);
254 strlcpy(dev->dev.bus_id, bus_id, BUS_ID_SIZE);
255
256 if (of_device_register(dev) != 0) {
257 kfree(dev);
258 return NULL;
259 }
260
261 return dev;
262}
263
264EXPORT_SYMBOL(of_match_device);
265EXPORT_SYMBOL(of_platform_bus_type);
266EXPORT_SYMBOL(of_register_driver);
267EXPORT_SYMBOL(of_unregister_driver);
268EXPORT_SYMBOL(of_device_register);
269EXPORT_SYMBOL(of_device_unregister);
270EXPORT_SYMBOL(of_dev_get);
271EXPORT_SYMBOL(of_dev_put);
272EXPORT_SYMBOL(of_platform_device_create);
273EXPORT_SYMBOL(of_release_dev);
diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
new file mode 100644
index 000000000000..406f36a8a681
--- /dev/null
+++ b/arch/ppc/syslib/open_pic.c
@@ -0,0 +1,1083 @@
1/*
2 * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
3 *
4 * Copyright (C) 1997 Geert Uytterhoeven
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/config.h>
12#include <linux/types.h>
13#include <linux/kernel.h>
14#include <linux/sched.h>
15#include <linux/init.h>
16#include <linux/irq.h>
17#include <linux/interrupt.h>
18#include <linux/sysdev.h>
19#include <linux/errno.h>
20#include <asm/ptrace.h>
21#include <asm/signal.h>
22#include <asm/io.h>
23#include <asm/irq.h>
24#include <asm/prom.h>
25#include <asm/sections.h>
26#include <asm/open_pic.h>
27#include <asm/i8259.h>
28
29#include "open_pic_defs.h"
30
31#if defined(CONFIG_PRPMC800) || defined(CONFIG_85xx)
32#define OPENPIC_BIG_ENDIAN
33#endif
34
35void __iomem *OpenPIC_Addr;
36static volatile struct OpenPIC __iomem *OpenPIC = NULL;
37
38/*
39 * We define OpenPIC_InitSenses table thusly:
40 * bit 0x1: sense, 0 for edge and 1 for level.
41 * bit 0x2: polarity, 0 for negative, 1 for positive.
42 */
43u_int OpenPIC_NumInitSenses __initdata = 0;
44u_char *OpenPIC_InitSenses __initdata = NULL;
45extern int use_of_interrupt_tree;
46
47static u_int NumProcessors;
48static u_int NumSources;
49static int open_pic_irq_offset;
50static volatile OpenPIC_Source __iomem *ISR[NR_IRQS];
51static int openpic_cascade_irq = -1;
52static int (*openpic_cascade_fn)(struct pt_regs *);
53
54/* Global Operations */
55static void openpic_disable_8259_pass_through(void);
56static void openpic_set_spurious(u_int vector);
57
58#ifdef CONFIG_SMP
59/* Interprocessor Interrupts */
60static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
61static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *);
62#endif
63
64/* Timer Interrupts */
65static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
66static void openpic_maptimer(u_int timer, cpumask_t cpumask);
67
68/* Interrupt Sources */
69static void openpic_enable_irq(u_int irq);
70static void openpic_disable_irq(u_int irq);
71static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
72 int is_level);
73static void openpic_mapirq(u_int irq, cpumask_t cpumask, cpumask_t keepmask);
74
75/*
76 * These functions are not used but the code is kept here
77 * for completeness and future reference.
78 */
79#ifdef notused
80static void openpic_enable_8259_pass_through(void);
81static u_int openpic_get_priority(void);
82static u_int openpic_get_spurious(void);
83static void openpic_set_sense(u_int irq, int sense);
84#endif /* notused */
85
86/*
87 * Description of the openpic for the higher-level irq code
88 */
89static void openpic_end_irq(unsigned int irq_nr);
90static void openpic_ack_irq(unsigned int irq_nr);
91static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask);
92
93struct hw_interrupt_type open_pic = {
94 .typename = " OpenPIC ",
95 .enable = openpic_enable_irq,
96 .disable = openpic_disable_irq,
97 .ack = openpic_ack_irq,
98 .end = openpic_end_irq,
99 .set_affinity = openpic_set_affinity,
100};
101
102#ifdef CONFIG_SMP
103static void openpic_end_ipi(unsigned int irq_nr);
104static void openpic_ack_ipi(unsigned int irq_nr);
105static void openpic_enable_ipi(unsigned int irq_nr);
106static void openpic_disable_ipi(unsigned int irq_nr);
107
108struct hw_interrupt_type open_pic_ipi = {
109 .typename = " OpenPIC ",
110 .enable = openpic_enable_ipi,
111 .disable = openpic_disable_ipi,
112 .ack = openpic_ack_ipi,
113 .end = openpic_end_ipi,
114};
115#endif /* CONFIG_SMP */
116
117/*
118 * Accesses to the current processor's openpic registers
119 */
120#ifdef CONFIG_SMP
121#define THIS_CPU Processor[cpu]
122#define DECL_THIS_CPU int cpu = smp_hw_index[smp_processor_id()]
123#define CHECK_THIS_CPU check_arg_cpu(cpu)
124#else
125#define THIS_CPU Processor[0]
126#define DECL_THIS_CPU
127#define CHECK_THIS_CPU
128#endif /* CONFIG_SMP */
129
130#if 1
131#define check_arg_ipi(ipi) \
132 if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
133 printk("open_pic.c:%d: invalid ipi %d\n", __LINE__, ipi);
134#define check_arg_timer(timer) \
135 if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
136 printk("open_pic.c:%d: invalid timer %d\n", __LINE__, timer);
137#define check_arg_vec(vec) \
138 if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
139 printk("open_pic.c:%d: invalid vector %d\n", __LINE__, vec);
140#define check_arg_pri(pri) \
141 if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
142 printk("open_pic.c:%d: invalid priority %d\n", __LINE__, pri);
143/*
144 * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
145 * data has probably been corrupted and we're going to panic or deadlock later
146 * anyway --Troy
147 */
148#define check_arg_irq(irq) \
149 if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \
150 || ISR[irq - open_pic_irq_offset] == 0) { \
151 printk("open_pic.c:%d: invalid irq %d\n", __LINE__, irq); \
152 dump_stack(); }
153#define check_arg_cpu(cpu) \
154 if (cpu < 0 || cpu >= NumProcessors){ \
155 printk("open_pic.c:%d: invalid cpu %d\n", __LINE__, cpu); \
156 dump_stack(); }
157#else
158#define check_arg_ipi(ipi) do {} while (0)
159#define check_arg_timer(timer) do {} while (0)
160#define check_arg_vec(vec) do {} while (0)
161#define check_arg_pri(pri) do {} while (0)
162#define check_arg_irq(irq) do {} while (0)
163#define check_arg_cpu(cpu) do {} while (0)
164#endif
165
166u_int openpic_read(volatile u_int __iomem *addr)
167{
168 u_int val;
169
170#ifdef OPENPIC_BIG_ENDIAN
171 val = in_be32(addr);
172#else
173 val = in_le32(addr);
174#endif
175 return val;
176}
177
178static inline void openpic_write(volatile u_int __iomem *addr, u_int val)
179{
180#ifdef OPENPIC_BIG_ENDIAN
181 out_be32(addr, val);
182#else
183 out_le32(addr, val);
184#endif
185}
186
187static inline u_int openpic_readfield(volatile u_int __iomem *addr, u_int mask)
188{
189 u_int val = openpic_read(addr);
190 return val & mask;
191}
192
193inline void openpic_writefield(volatile u_int __iomem *addr, u_int mask,
194 u_int field)
195{
196 u_int val = openpic_read(addr);
197 openpic_write(addr, (val & ~mask) | (field & mask));
198}
199
200static inline void openpic_clearfield(volatile u_int __iomem *addr, u_int mask)
201{
202 openpic_writefield(addr, mask, 0);
203}
204
205static inline void openpic_setfield(volatile u_int __iomem *addr, u_int mask)
206{
207 openpic_writefield(addr, mask, mask);
208}
209
210static void openpic_safe_writefield(volatile u_int __iomem *addr, u_int mask,
211 u_int field)
212{
213 openpic_setfield(addr, OPENPIC_MASK);
214 while (openpic_read(addr) & OPENPIC_ACTIVITY);
215 openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
216}
217
218#ifdef CONFIG_SMP
219/* yes this is right ... bug, feature, you decide! -- tgall */
220u_int openpic_read_IPI(volatile u_int __iomem * addr)
221{
222 u_int val = 0;
223#if defined(OPENPIC_BIG_ENDIAN) || defined(CONFIG_POWER3)
224 val = in_be32(addr);
225#else
226 val = in_le32(addr);
227#endif
228 return val;
229}
230
231/* because of the power3 be / le above, this is needed */
232inline void openpic_writefield_IPI(volatile u_int __iomem * addr, u_int mask, u_int field)
233{
234 u_int val = openpic_read_IPI(addr);
235 openpic_write(addr, (val & ~mask) | (field & mask));
236}
237
238static inline void openpic_clearfield_IPI(volatile u_int __iomem *addr, u_int mask)
239{
240 openpic_writefield_IPI(addr, mask, 0);
241}
242
243static inline void openpic_setfield_IPI(volatile u_int __iomem *addr, u_int mask)
244{
245 openpic_writefield_IPI(addr, mask, mask);
246}
247
248static void openpic_safe_writefield_IPI(volatile u_int __iomem *addr, u_int mask, u_int field)
249{
250 openpic_setfield_IPI(addr, OPENPIC_MASK);
251
252 /* wait until it's not in use */
253 /* BenH: Is this code really enough ? I would rather check the result
254 * and eventually retry ...
255 */
256 while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY);
257
258 openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
259}
260#endif /* CONFIG_SMP */
261
262#ifdef CONFIG_EPIC_SERIAL_MODE
263/* On platforms that may use EPIC serial mode, the default is enabled. */
264int epic_serial_mode = 1;
265
266static void __init openpic_eicr_set_clk(u_int clkval)
267{
268 openpic_writefield(&OpenPIC->Global.Global_Configuration1,
269 OPENPIC_EICR_S_CLK_MASK, (clkval << 28));
270}
271
272static void __init openpic_enable_sie(void)
273{
274 openpic_setfield(&OpenPIC->Global.Global_Configuration1,
275 OPENPIC_EICR_SIE);
276}
277#endif
278
279#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PM)
280static void openpic_reset(void)
281{
282 openpic_setfield(&OpenPIC->Global.Global_Configuration0,
283 OPENPIC_CONFIG_RESET);
284 while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
285 OPENPIC_CONFIG_RESET))
286 mb();
287}
288#endif
289
290void __init openpic_set_sources(int first_irq, int num_irqs, void __iomem *first_ISR)
291{
292 volatile OpenPIC_Source __iomem *src = first_ISR;
293 int i, last_irq;
294
295 last_irq = first_irq + num_irqs;
296 if (last_irq > NumSources)
297 NumSources = last_irq;
298 if (src == 0)
299 src = &((struct OpenPIC __iomem *)OpenPIC_Addr)->Source[first_irq];
300 for (i = first_irq; i < last_irq; ++i, ++src)
301 ISR[i] = src;
302}
303
304/*
305 * The `offset' parameter defines where the interrupts handled by the
306 * OpenPIC start in the space of interrupt numbers that the kernel knows
307 * about. In other words, the OpenPIC's IRQ0 is numbered `offset' in the
308 * kernel's interrupt numbering scheme.
309 * We assume there is only one OpenPIC.
310 */
311void __init openpic_init(int offset)
312{
313 u_int t, i;
314 u_int timerfreq;
315 const char *version;
316
317 if (!OpenPIC_Addr) {
318 printk("No OpenPIC found !\n");
319 return;
320 }
321 OpenPIC = (volatile struct OpenPIC __iomem *)OpenPIC_Addr;
322
323#ifdef CONFIG_EPIC_SERIAL_MODE
324 /* Have to start from ground zero.
325 */
326 openpic_reset();
327#endif
328
329 if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
330
331 t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
332 switch (t & OPENPIC_FEATURE_VERSION_MASK) {
333 case 1:
334 version = "1.0";
335 break;
336 case 2:
337 version = "1.2";
338 break;
339 case 3:
340 version = "1.3";
341 break;
342 default:
343 version = "?";
344 break;
345 }
346 NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
347 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
348 if (NumSources == 0)
349 openpic_set_sources(0,
350 ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
351 OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1,
352 NULL);
353 printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
354 version, NumProcessors, NumSources, OpenPIC);
355 timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
356 if (timerfreq)
357 printk("OpenPIC timer frequency is %d.%06d MHz\n",
358 timerfreq / 1000000, timerfreq % 1000000);
359
360 open_pic_irq_offset = offset;
361
362 /* Initialize timer interrupts */
363 if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba);
364 for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
365 /* Disabled, Priority 0 */
366 openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+offset);
367 /* No processor */
368 openpic_maptimer(i, CPU_MASK_NONE);
369 }
370
371#ifdef CONFIG_SMP
372 /* Initialize IPI interrupts */
373 if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
374 for (i = 0; i < OPENPIC_NUM_IPI; i++) {
375 /* Disabled, Priority 10..13 */
376 openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
377 /* IPIs are per-CPU */
378 irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
379 irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
380 }
381#endif
382
383 /* Initialize external interrupts */
384 if (ppc_md.progress) ppc_md.progress("openpic: external",0x3bc);
385
386 openpic_set_priority(0xf);
387
388 /* Init all external sources, including possibly the cascade. */
389 for (i = 0; i < NumSources; i++) {
390 int sense;
391
392 if (ISR[i] == 0)
393 continue;
394
395 /* the bootloader may have left it enabled (bad !) */
396 openpic_disable_irq(i+offset);
397
398 sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \
399 (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
400
401 if (sense & IRQ_SENSE_MASK)
402 irq_desc[i+offset].status = IRQ_LEVEL;
403
404 /* Enabled, Priority 8 */
405 openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
406 (sense & IRQ_SENSE_MASK));
407 /* Processor 0 */
408 openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
409 }
410
411 /* Init descriptors */
412 for (i = offset; i < NumSources + offset; i++)
413 irq_desc[i].handler = &open_pic;
414
415 /* Initialize the spurious interrupt */
416 if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
417 openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
418 openpic_disable_8259_pass_through();
419#ifdef CONFIG_EPIC_SERIAL_MODE
420 if (epic_serial_mode) {
421 openpic_eicr_set_clk(7); /* Slowest value until we know better */
422 openpic_enable_sie();
423 }
424#endif
425 openpic_set_priority(0);
426
427 if (ppc_md.progress) ppc_md.progress("openpic: exit",0x222);
428}
429
430#ifdef notused
431static void openpic_enable_8259_pass_through(void)
432{
433 openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
434 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
435}
436#endif /* notused */
437
438static void openpic_disable_8259_pass_through(void)
439{
440 openpic_setfield(&OpenPIC->Global.Global_Configuration0,
441 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
442}
443
444/*
445 * Find out the current interrupt
446 */
447u_int openpic_irq(void)
448{
449 u_int vec;
450 DECL_THIS_CPU;
451
452 CHECK_THIS_CPU;
453 vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
454 OPENPIC_VECTOR_MASK);
455 return vec;
456}
457
458void openpic_eoi(void)
459{
460 DECL_THIS_CPU;
461
462 CHECK_THIS_CPU;
463 openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
464 /* Handle PCI write posting */
465 (void)openpic_read(&OpenPIC->THIS_CPU.EOI);
466}
467
468#ifdef notused
469static u_int openpic_get_priority(void)
470{
471 DECL_THIS_CPU;
472
473 CHECK_THIS_CPU;
474 return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
475 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
476}
477#endif /* notused */
478
479void openpic_set_priority(u_int pri)
480{
481 DECL_THIS_CPU;
482
483 CHECK_THIS_CPU;
484 check_arg_pri(pri);
485 openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
486 OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
487}
488
489/*
490 * Get/set the spurious vector
491 */
492#ifdef notused
493static u_int openpic_get_spurious(void)
494{
495 return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
496 OPENPIC_VECTOR_MASK);
497}
498#endif /* notused */
499
500static void openpic_set_spurious(u_int vec)
501{
502 check_arg_vec(vec);
503 openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
504 vec);
505}
506
507#ifdef CONFIG_SMP
508/*
509 * Convert a cpu mask from logical to physical cpu numbers.
510 */
511static inline cpumask_t physmask(cpumask_t cpumask)
512{
513 int i;
514 cpumask_t mask = CPU_MASK_NONE;
515
516 cpus_and(cpumask, cpu_online_map, cpumask);
517
518 for (i = 0; i < NR_CPUS; i++)
519 if (cpu_isset(i, cpumask))
520 cpu_set(smp_hw_index[i], mask);
521
522 return mask;
523}
524#else
525#define physmask(cpumask) (cpumask)
526#endif
527
528void openpic_reset_processor_phys(u_int mask)
529{
530 openpic_write(&OpenPIC->Global.Processor_Initialization, mask);
531}
532
533#if defined(CONFIG_SMP) || defined(CONFIG_PM)
534static DEFINE_SPINLOCK(openpic_setup_lock);
535#endif
536
537#ifdef CONFIG_SMP
538/*
539 * Initialize an interprocessor interrupt (and disable it)
540 *
541 * ipi: OpenPIC interprocessor interrupt number
542 * pri: interrupt source priority
543 * vec: the vector it will produce
544 */
545static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
546{
547 check_arg_ipi(ipi);
548 check_arg_pri(pri);
549 check_arg_vec(vec);
550 openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
551 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
552 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
553}
554
555/*
556 * Send an IPI to one or more CPUs
557 *
558 * Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
559 * and not a system-wide interrupt number
560 */
561void openpic_cause_IPI(u_int ipi, cpumask_t cpumask)
562{
563 cpumask_t phys;
564 DECL_THIS_CPU;
565
566 CHECK_THIS_CPU;
567 check_arg_ipi(ipi);
568 phys = physmask(cpumask);
569 openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
570 cpus_addr(physmask(cpumask))[0]);
571}
572
573void openpic_request_IPIs(void)
574{
575 int i;
576
577 /*
578 * Make sure this matches what is defined in smp.c for
579 * smp_message_{pass|recv}() or what shows up in
580 * /proc/interrupts will be wrong!!! --Troy */
581
582 if (OpenPIC == NULL)
583 return;
584
585 /* IPIs are marked SA_INTERRUPT as they must run with irqs disabled */
586 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset,
587 openpic_ipi_action, SA_INTERRUPT,
588 "IPI0 (call function)", NULL);
589 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1,
590 openpic_ipi_action, SA_INTERRUPT,
591 "IPI1 (reschedule)", NULL);
592 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2,
593 openpic_ipi_action, SA_INTERRUPT,
594 "IPI2 (invalidate tlb)", NULL);
595 request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3,
596 openpic_ipi_action, SA_INTERRUPT,
597 "IPI3 (xmon break)", NULL);
598
599 for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
600 openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i);
601}
602
603/*
604 * Do per-cpu setup for SMP systems.
605 *
606 * Get IPI's working and start taking interrupts.
607 * -- Cort
608 */
609
610void __devinit do_openpic_setup_cpu(void)
611{
612#ifdef CONFIG_IRQ_ALL_CPUS
613 int i;
614 cpumask_t msk = CPU_MASK_NONE;
615#endif
616 spin_lock(&openpic_setup_lock);
617
618#ifdef CONFIG_IRQ_ALL_CPUS
619 cpu_set(smp_hw_index[smp_processor_id()], msk);
620
621 /* let the openpic know we want intrs. default affinity
622 * is 0xffffffff until changed via /proc
623 * That's how it's done on x86. If we want it differently, then
624 * we should make sure we also change the default values of irq_affinity
625 * in irq.c.
626 */
627 for (i = 0; i < NumSources; i++)
628 openpic_mapirq(i, msk, CPU_MASK_ALL);
629#endif /* CONFIG_IRQ_ALL_CPUS */
630 openpic_set_priority(0);
631
632 spin_unlock(&openpic_setup_lock);
633}
634#endif /* CONFIG_SMP */
635
636/*
637 * Initialize a timer interrupt (and disable it)
638 *
639 * timer: OpenPIC timer number
640 * pri: interrupt source priority
641 * vec: the vector it will produce
642 */
643static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
644{
645 check_arg_timer(timer);
646 check_arg_pri(pri);
647 check_arg_vec(vec);
648 openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
649 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
650 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
651}
652
653/*
654 * Map a timer interrupt to one or more CPUs
655 */
656static void __init openpic_maptimer(u_int timer, cpumask_t cpumask)
657{
658 cpumask_t phys = physmask(cpumask);
659 check_arg_timer(timer);
660 openpic_write(&OpenPIC->Global.Timer[timer].Destination,
661 cpus_addr(phys)[0]);
662}
663
664/*
665 * Initalize the interrupt source which will generate an NMI.
666 * This raises the interrupt's priority from 8 to 9.
667 *
668 * irq: The logical IRQ which generates an NMI.
669 */
670void __init
671openpic_init_nmi_irq(u_int irq)
672{
673 check_arg_irq(irq);
674 openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
675 OPENPIC_PRIORITY_MASK,
676 9 << OPENPIC_PRIORITY_SHIFT);
677}
678
679/*
680 *
681 * All functions below take an offset'ed irq argument
682 *
683 */
684
685/*
686 * Hookup a cascade to the OpenPIC.
687 */
688
689static struct irqaction openpic_cascade_irqaction = {
690 .handler = no_action,
691 .flags = SA_INTERRUPT,
692 .mask = CPU_MASK_NONE,
693};
694
695void __init
696openpic_hookup_cascade(u_int irq, char *name,
697 int (*cascade_fn)(struct pt_regs *))
698{
699 openpic_cascade_irq = irq;
700 openpic_cascade_fn = cascade_fn;
701
702 if (setup_irq(irq, &openpic_cascade_irqaction))
703 printk("Unable to get OpenPIC IRQ %d for cascade\n",
704 irq - open_pic_irq_offset);
705}
706
707/*
708 * Enable/disable an external interrupt source
709 *
710 * Externally called, irq is an offseted system-wide interrupt number
711 */
712static void openpic_enable_irq(u_int irq)
713{
714 volatile u_int __iomem *vpp;
715
716 check_arg_irq(irq);
717 vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
718 openpic_clearfield(vpp, OPENPIC_MASK);
719 /* make sure mask gets to controller before we return to user */
720 do {
721 mb(); /* sync is probably useless here */
722 } while (openpic_readfield(vpp, OPENPIC_MASK));
723}
724
725static void openpic_disable_irq(u_int irq)
726{
727 volatile u_int __iomem *vpp;
728 u32 vp;
729
730 check_arg_irq(irq);
731 vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
732 openpic_setfield(vpp, OPENPIC_MASK);
733 /* make sure mask gets to controller before we return to user */
734 do {
735 mb(); /* sync is probably useless here */
736 vp = openpic_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY);
737 } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
738}
739
740#ifdef CONFIG_SMP
741/*
742 * Enable/disable an IPI interrupt source
743 *
744 * Externally called, irq is an offseted system-wide interrupt number
745 */
746void openpic_enable_ipi(u_int irq)
747{
748 irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
749 check_arg_ipi(irq);
750 openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
751
752}
753
754void openpic_disable_ipi(u_int irq)
755{
756 irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
757 check_arg_ipi(irq);
758 openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
759}
760#endif
761
762/*
763 * Initialize an interrupt source (and disable it!)
764 *
765 * irq: OpenPIC interrupt number
766 * pri: interrupt source priority
767 * vec: the vector it will produce
768 * pol: polarity (1 for positive, 0 for negative)
769 * sense: 1 for level, 0 for edge
770 */
771static void __init
772openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
773{
774 openpic_safe_writefield(&ISR[irq]->Vector_Priority,
775 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
776 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
777 (pri << OPENPIC_PRIORITY_SHIFT) | vec |
778 (pol ? OPENPIC_POLARITY_POSITIVE :
779 OPENPIC_POLARITY_NEGATIVE) |
780 (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
781}
782
783/*
784 * Map an interrupt source to one or more CPUs
785 */
786static void openpic_mapirq(u_int irq, cpumask_t physmask, cpumask_t keepmask)
787{
788 if (ISR[irq] == 0)
789 return;
790 if (!cpus_empty(keepmask)) {
791 cpumask_t irqdest = { .bits[0] = openpic_read(&ISR[irq]->Destination) };
792 cpus_and(irqdest, irqdest, keepmask);
793 cpus_or(physmask, physmask, irqdest);
794 }
795 openpic_write(&ISR[irq]->Destination, cpus_addr(physmask)[0]);
796}
797
798#ifdef notused
799/*
800 * Set the sense for an interrupt source (and disable it!)
801 *
802 * sense: 1 for level, 0 for edge
803 */
804static void openpic_set_sense(u_int irq, int sense)
805{
806 if (ISR[irq] != 0)
807 openpic_safe_writefield(&ISR[irq]->Vector_Priority,
808 OPENPIC_SENSE_LEVEL,
809 (sense ? OPENPIC_SENSE_LEVEL : 0));
810}
811#endif /* notused */
812
813/* No spinlocks, should not be necessary with the OpenPIC
814 * (1 register = 1 interrupt and we have the desc lock).
815 */
816static void openpic_ack_irq(unsigned int irq_nr)
817{
818#ifdef __SLOW_VERSION__
819 openpic_disable_irq(irq_nr);
820 openpic_eoi();
821#else
822 if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0)
823 openpic_eoi();
824#endif
825}
826
827static void openpic_end_irq(unsigned int irq_nr)
828{
829#ifdef __SLOW_VERSION__
830 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
831 && irq_desc[irq_nr].action)
832 openpic_enable_irq(irq_nr);
833#else
834 if ((irq_desc[irq_nr].status & IRQ_LEVEL) != 0)
835 openpic_eoi();
836#endif
837}
838
839static void openpic_set_affinity(unsigned int irq_nr, cpumask_t cpumask)
840{
841 openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), CPU_MASK_NONE);
842}
843
844#ifdef CONFIG_SMP
845static void openpic_ack_ipi(unsigned int irq_nr)
846{
847 openpic_eoi();
848}
849
850static void openpic_end_ipi(unsigned int irq_nr)
851{
852}
853
854static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
855{
856 smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs);
857 return IRQ_HANDLED;
858}
859
860#endif /* CONFIG_SMP */
861
862int
863openpic_get_irq(struct pt_regs *regs)
864{
865 int irq = openpic_irq();
866
867 /*
868 * Check for the cascade interrupt and call the cascaded
869 * interrupt controller function (usually i8259_irq) if so.
870 * This should move to irq.c eventually. -- paulus
871 */
872 if (irq == openpic_cascade_irq && openpic_cascade_fn != NULL) {
873 int cirq = openpic_cascade_fn(regs);
874
875 /* Allow for the cascade being shared with other devices */
876 if (cirq != -1) {
877 irq = cirq;
878 openpic_eoi();
879 }
880 } else if (irq == OPENPIC_VEC_SPURIOUS)
881 irq = -1;
882 return irq;
883}
884
885#ifdef CONFIG_SMP
886void
887smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
888{
889 cpumask_t mask = CPU_MASK_ALL;
890 /* make sure we're sending something that translates to an IPI */
891 if (msg > 0x3) {
892 printk("SMP %d: smp_message_pass: unknown msg %d\n",
893 smp_processor_id(), msg);
894 return;
895 }
896 switch (target) {
897 case MSG_ALL:
898 openpic_cause_IPI(msg, mask);
899 break;
900 case MSG_ALL_BUT_SELF:
901 cpu_clear(smp_processor_id(), mask);
902 openpic_cause_IPI(msg, mask);
903 break;
904 default:
905 openpic_cause_IPI(msg, cpumask_of_cpu(target));
906 break;
907 }
908}
909#endif /* CONFIG_SMP */
910
911#ifdef CONFIG_PM
912
913/*
914 * We implement the IRQ controller as a sysdev and put it
915 * to sleep at powerdown stage (the callback is named suspend,
916 * but it's old semantics, for the Device Model, it's really
917 * powerdown). The possible problem is that another sysdev that
918 * happens to be suspend after this one will have interrupts off,
919 * that may be an issue... For now, this isn't an issue on pmac
920 * though...
921 */
922
923static u32 save_ipi_vp[OPENPIC_NUM_IPI];
924static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
925static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
926static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
927static int openpic_suspend_count;
928
929static void openpic_cached_enable_irq(u_int irq)
930{
931 check_arg_irq(irq);
932 save_irq_src_vp[irq - open_pic_irq_offset] &= ~OPENPIC_MASK;
933}
934
935static void openpic_cached_disable_irq(u_int irq)
936{
937 check_arg_irq(irq);
938 save_irq_src_vp[irq - open_pic_irq_offset] |= OPENPIC_MASK;
939}
940
941/* WARNING: Can be called directly by the cpufreq code with NULL parameter,
942 * we need something better to deal with that... Maybe switch to S1 for
943 * cpufreq changes
944 */
945int openpic_suspend(struct sys_device *sysdev, u32 state)
946{
947 int i;
948 unsigned long flags;
949
950 spin_lock_irqsave(&openpic_setup_lock, flags);
951
952 if (openpic_suspend_count++ > 0) {
953 spin_unlock_irqrestore(&openpic_setup_lock, flags);
954 return 0;
955 }
956
957 openpic_set_priority(0xf);
958
959 open_pic.enable = openpic_cached_enable_irq;
960 open_pic.disable = openpic_cached_disable_irq;
961
962 for (i=0; i<NumProcessors; i++) {
963 save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
964 openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority,
965 OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
966 }
967
968 for (i=0; i<OPENPIC_NUM_IPI; i++)
969 save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
970 for (i=0; i<NumSources; i++) {
971 if (ISR[i] == 0)
972 continue;
973 save_irq_src_vp[i] = openpic_read(&ISR[i]->Vector_Priority) & ~OPENPIC_ACTIVITY;
974 save_irq_src_dest[i] = openpic_read(&ISR[i]->Destination);
975 }
976
977 spin_unlock_irqrestore(&openpic_setup_lock, flags);
978
979 return 0;
980}
981
982/* WARNING: Can be called directly by the cpufreq code with NULL parameter,
983 * we need something better to deal with that... Maybe switch to S1 for
984 * cpufreq changes
985 */
986int openpic_resume(struct sys_device *sysdev)
987{
988 int i;
989 unsigned long flags;
990 u32 vppmask = OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
991 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK |
992 OPENPIC_MASK;
993
994 spin_lock_irqsave(&openpic_setup_lock, flags);
995
996 if ((--openpic_suspend_count) > 0) {
997 spin_unlock_irqrestore(&openpic_setup_lock, flags);
998 return 0;
999 }
1000
1001 openpic_reset();
1002
1003 /* OpenPIC sometimes seem to need some time to be fully back up... */
1004 do {
1005 openpic_set_spurious(OPENPIC_VEC_SPURIOUS);
1006 } while(openpic_readfield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK)
1007 != OPENPIC_VEC_SPURIOUS);
1008
1009 openpic_disable_8259_pass_through();
1010
1011 for (i=0; i<OPENPIC_NUM_IPI; i++)
1012 openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i),
1013 save_ipi_vp[i]);
1014 for (i=0; i<NumSources; i++) {
1015 if (ISR[i] == 0)
1016 continue;
1017 openpic_write(&ISR[i]->Destination, save_irq_src_dest[i]);
1018 openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
1019 /* make sure mask gets to controller before we return to user */
1020 do {
1021 openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
1022 } while (openpic_readfield(&ISR[i]->Vector_Priority, vppmask)
1023 != (save_irq_src_vp[i] & vppmask));
1024 }
1025 for (i=0; i<NumProcessors; i++)
1026 openpic_write(&OpenPIC->Processor[i].Current_Task_Priority,
1027 save_cpu_task_pri[i]);
1028
1029 open_pic.enable = openpic_enable_irq;
1030 open_pic.disable = openpic_disable_irq;
1031
1032 openpic_set_priority(0);
1033
1034 spin_unlock_irqrestore(&openpic_setup_lock, flags);
1035
1036 return 0;
1037}
1038
1039#endif /* CONFIG_PM */
1040
1041static struct sysdev_class openpic_sysclass = {
1042 set_kset_name("openpic"),
1043};
1044
1045static struct sys_device device_openpic = {
1046 .id = 0,
1047 .cls = &openpic_sysclass,
1048};
1049
1050static struct sysdev_driver driver_openpic = {
1051#ifdef CONFIG_PM
1052 .suspend = &openpic_suspend,
1053 .resume = &openpic_resume,
1054#endif /* CONFIG_PM */
1055};
1056
1057static int __init init_openpic_sysfs(void)
1058{
1059 int rc;
1060
1061 if (!OpenPIC_Addr)
1062 return -ENODEV;
1063 printk(KERN_DEBUG "Registering openpic with sysfs...\n");
1064 rc = sysdev_class_register(&openpic_sysclass);
1065 if (rc) {
1066 printk(KERN_ERR "Failed registering openpic sys class\n");
1067 return -ENODEV;
1068 }
1069 rc = sysdev_register(&device_openpic);
1070 if (rc) {
1071 printk(KERN_ERR "Failed registering openpic sys device\n");
1072 return -ENODEV;
1073 }
1074 rc = sysdev_driver_register(&openpic_sysclass, &driver_openpic);
1075 if (rc) {
1076 printk(KERN_ERR "Failed registering openpic sys driver\n");
1077 return -ENODEV;
1078 }
1079 return 0;
1080}
1081
1082subsys_initcall(init_openpic_sysfs);
1083
diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c
new file mode 100644
index 000000000000..ea26da0d8b6b
--- /dev/null
+++ b/arch/ppc/syslib/open_pic2.c
@@ -0,0 +1,716 @@
1/*
2 * arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
3 *
4 * Copyright (C) 1997 Geert Uytterhoeven
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file COPYING in the main directory of this archive
8 * for more details.
9 *
10 * This is a duplicate of open_pic.c that deals with U3s MPIC on
11 * G5 PowerMacs. It's the same file except it's using big endian
12 * register accesses
13 */
14
15#include <linux/config.h>
16#include <linux/types.h>
17#include <linux/kernel.h>
18#include <linux/sched.h>
19#include <linux/init.h>
20#include <linux/irq.h>
21#include <linux/interrupt.h>
22#include <linux/sysdev.h>
23#include <linux/errno.h>
24#include <asm/ptrace.h>
25#include <asm/signal.h>
26#include <asm/io.h>
27#include <asm/irq.h>
28#include <asm/prom.h>
29#include <asm/sections.h>
30#include <asm/open_pic.h>
31#include <asm/i8259.h>
32
33#include "open_pic_defs.h"
34
35void *OpenPIC2_Addr;
36static volatile struct OpenPIC *OpenPIC2 = NULL;
37/*
38 * We define OpenPIC_InitSenses table thusly:
39 * bit 0x1: sense, 0 for edge and 1 for level.
40 * bit 0x2: polarity, 0 for negative, 1 for positive.
41 */
42extern u_int OpenPIC_NumInitSenses;
43extern u_char *OpenPIC_InitSenses;
44extern int use_of_interrupt_tree;
45
46static u_int NumProcessors;
47static u_int NumSources;
48static int open_pic2_irq_offset;
49static volatile OpenPIC_Source *ISR[NR_IRQS];
50
51/* Global Operations */
52static void openpic2_disable_8259_pass_through(void);
53static void openpic2_set_priority(u_int pri);
54static void openpic2_set_spurious(u_int vector);
55
56/* Timer Interrupts */
57static void openpic2_inittimer(u_int timer, u_int pri, u_int vector);
58static void openpic2_maptimer(u_int timer, u_int cpumask);
59
60/* Interrupt Sources */
61static void openpic2_enable_irq(u_int irq);
62static void openpic2_disable_irq(u_int irq);
63static void openpic2_initirq(u_int irq, u_int pri, u_int vector, int polarity,
64 int is_level);
65static void openpic2_mapirq(u_int irq, u_int cpumask, u_int keepmask);
66
67/*
68 * These functions are not used but the code is kept here
69 * for completeness and future reference.
70 */
71static void openpic2_reset(void);
72#ifdef notused
73static void openpic2_enable_8259_pass_through(void);
74static u_int openpic2_get_priority(void);
75static u_int openpic2_get_spurious(void);
76static void openpic2_set_sense(u_int irq, int sense);
77#endif /* notused */
78
79/*
80 * Description of the openpic for the higher-level irq code
81 */
82static void openpic2_end_irq(unsigned int irq_nr);
83static void openpic2_ack_irq(unsigned int irq_nr);
84
85struct hw_interrupt_type open_pic2 = {
86 " OpenPIC2 ",
87 NULL,
88 NULL,
89 openpic2_enable_irq,
90 openpic2_disable_irq,
91 openpic2_ack_irq,
92 openpic2_end_irq,
93};
94
95/*
96 * Accesses to the current processor's openpic registers
97 * On cascaded controller, this is only CPU 0
98 */
99#define THIS_CPU Processor[0]
100#define DECL_THIS_CPU
101#define CHECK_THIS_CPU
102
103#if 1
104#define check_arg_ipi(ipi) \
105 if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
106 printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
107#define check_arg_timer(timer) \
108 if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
109 printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
110#define check_arg_vec(vec) \
111 if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
112 printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
113#define check_arg_pri(pri) \
114 if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
115 printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
116/*
117 * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
118 * data has probably been corrupted and we're going to panic or deadlock later
119 * anyway --Troy
120 */
121extern unsigned long* _get_SP(void);
122#define check_arg_irq(irq) \
123 if (irq < open_pic2_irq_offset || irq >= NumSources+open_pic2_irq_offset \
124 || ISR[irq - open_pic2_irq_offset] == 0) { \
125 printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
126 /*print_backtrace(_get_SP());*/ }
127#define check_arg_cpu(cpu) \
128 if (cpu < 0 || cpu >= NumProcessors){ \
129 printk("open_pic2.c:%d: illegal cpu %d\n", __LINE__, cpu); \
130 /*print_backtrace(_get_SP());*/ }
131#else
132#define check_arg_ipi(ipi) do {} while (0)
133#define check_arg_timer(timer) do {} while (0)
134#define check_arg_vec(vec) do {} while (0)
135#define check_arg_pri(pri) do {} while (0)
136#define check_arg_irq(irq) do {} while (0)
137#define check_arg_cpu(cpu) do {} while (0)
138#endif
139
140static u_int openpic2_read(volatile u_int *addr)
141{
142 u_int val;
143
144 val = in_be32(addr);
145 return val;
146}
147
148static inline void openpic2_write(volatile u_int *addr, u_int val)
149{
150 out_be32(addr, val);
151}
152
153static inline u_int openpic2_readfield(volatile u_int *addr, u_int mask)
154{
155 u_int val = openpic2_read(addr);
156 return val & mask;
157}
158
159inline void openpic2_writefield(volatile u_int *addr, u_int mask,
160 u_int field)
161{
162 u_int val = openpic2_read(addr);
163 openpic2_write(addr, (val & ~mask) | (field & mask));
164}
165
166static inline void openpic2_clearfield(volatile u_int *addr, u_int mask)
167{
168 openpic2_writefield(addr, mask, 0);
169}
170
171static inline void openpic2_setfield(volatile u_int *addr, u_int mask)
172{
173 openpic2_writefield(addr, mask, mask);
174}
175
176static void openpic2_safe_writefield(volatile u_int *addr, u_int mask,
177 u_int field)
178{
179 openpic2_setfield(addr, OPENPIC_MASK);
180 while (openpic2_read(addr) & OPENPIC_ACTIVITY);
181 openpic2_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
182}
183
184static void openpic2_reset(void)
185{
186 openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
187 OPENPIC_CONFIG_RESET);
188 while (openpic2_readfield(&OpenPIC2->Global.Global_Configuration0,
189 OPENPIC_CONFIG_RESET))
190 mb();
191}
192
193void __init openpic2_set_sources(int first_irq, int num_irqs, void *first_ISR)
194{
195 volatile OpenPIC_Source *src = first_ISR;
196 int i, last_irq;
197
198 last_irq = first_irq + num_irqs;
199 if (last_irq > NumSources)
200 NumSources = last_irq;
201 if (src == 0)
202 src = &((struct OpenPIC *)OpenPIC2_Addr)->Source[first_irq];
203 for (i = first_irq; i < last_irq; ++i, ++src)
204 ISR[i] = src;
205}
206
207/*
208 * The `offset' parameter defines where the interrupts handled by the
209 * OpenPIC start in the space of interrupt numbers that the kernel knows
210 * about. In other words, the OpenPIC's IRQ0 is numbered `offset' in the
211 * kernel's interrupt numbering scheme.
212 * We assume there is only one OpenPIC.
213 */
214void __init openpic2_init(int offset)
215{
216 u_int t, i;
217 u_int timerfreq;
218 const char *version;
219
220 if (!OpenPIC2_Addr) {
221 printk("No OpenPIC2 found !\n");
222 return;
223 }
224 OpenPIC2 = (volatile struct OpenPIC *)OpenPIC2_Addr;
225
226 if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
227
228 t = openpic2_read(&OpenPIC2->Global.Feature_Reporting0);
229 switch (t & OPENPIC_FEATURE_VERSION_MASK) {
230 case 1:
231 version = "1.0";
232 break;
233 case 2:
234 version = "1.2";
235 break;
236 case 3:
237 version = "1.3";
238 break;
239 default:
240 version = "?";
241 break;
242 }
243 NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
244 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
245 if (NumSources == 0)
246 openpic2_set_sources(0,
247 ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
248 OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1,
249 NULL);
250 printk("OpenPIC (2) Version %s (%d CPUs and %d IRQ sources) at %p\n",
251 version, NumProcessors, NumSources, OpenPIC2);
252 timerfreq = openpic2_read(&OpenPIC2->Global.Timer_Frequency);
253 if (timerfreq)
254 printk("OpenPIC timer frequency is %d.%06d MHz\n",
255 timerfreq / 1000000, timerfreq % 1000000);
256
257 open_pic2_irq_offset = offset;
258
259 /* Initialize timer interrupts */
260 if ( ppc_md.progress ) ppc_md.progress("openpic2: timer",0x3ba);
261 for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
262 /* Disabled, Priority 0 */
263 openpic2_inittimer(i, 0, OPENPIC2_VEC_TIMER+i+offset);
264 /* No processor */
265 openpic2_maptimer(i, 0);
266 }
267
268 /* Initialize external interrupts */
269 if (ppc_md.progress) ppc_md.progress("openpic2: external",0x3bc);
270
271 openpic2_set_priority(0xf);
272
273 /* Init all external sources, including possibly the cascade. */
274 for (i = 0; i < NumSources; i++) {
275 int sense;
276
277 if (ISR[i] == 0)
278 continue;
279
280 /* the bootloader may have left it enabled (bad !) */
281 openpic2_disable_irq(i+offset);
282
283 sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: \
284 (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
285
286 if (sense & IRQ_SENSE_MASK)
287 irq_desc[i+offset].status = IRQ_LEVEL;
288
289 /* Enabled, Priority 8 */
290 openpic2_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
291 (sense & IRQ_SENSE_MASK));
292 /* Processor 0 */
293 openpic2_mapirq(i, 1<<0, 0);
294 }
295
296 /* Init descriptors */
297 for (i = offset; i < NumSources + offset; i++)
298 irq_desc[i].handler = &open_pic2;
299
300 /* Initialize the spurious interrupt */
301 if (ppc_md.progress) ppc_md.progress("openpic2: spurious",0x3bd);
302 openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS+offset);
303
304 openpic2_disable_8259_pass_through();
305 openpic2_set_priority(0);
306
307 if (ppc_md.progress) ppc_md.progress("openpic2: exit",0x222);
308}
309
310#ifdef notused
311static void openpic2_enable_8259_pass_through(void)
312{
313 openpic2_clearfield(&OpenPIC2->Global.Global_Configuration0,
314 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
315}
316#endif /* notused */
317
318/* This can't be __init, it is used in openpic_sleep_restore_intrs */
319static void openpic2_disable_8259_pass_through(void)
320{
321 openpic2_setfield(&OpenPIC2->Global.Global_Configuration0,
322 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
323}
324
325/*
326 * Find out the current interrupt
327 */
328u_int openpic2_irq(void)
329{
330 u_int vec;
331 DECL_THIS_CPU;
332
333 CHECK_THIS_CPU;
334 vec = openpic2_readfield(&OpenPIC2->THIS_CPU.Interrupt_Acknowledge,
335 OPENPIC_VECTOR_MASK);
336 return vec;
337}
338
339void openpic2_eoi(void)
340{
341 DECL_THIS_CPU;
342
343 CHECK_THIS_CPU;
344 openpic2_write(&OpenPIC2->THIS_CPU.EOI, 0);
345 /* Handle PCI write posting */
346 (void)openpic2_read(&OpenPIC2->THIS_CPU.EOI);
347}
348
349#ifdef notused
350static u_int openpic2_get_priority(void)
351{
352 DECL_THIS_CPU;
353
354 CHECK_THIS_CPU;
355 return openpic2_readfield(&OpenPIC2->THIS_CPU.Current_Task_Priority,
356 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
357}
358#endif /* notused */
359
360static void __init openpic2_set_priority(u_int pri)
361{
362 DECL_THIS_CPU;
363
364 CHECK_THIS_CPU;
365 check_arg_pri(pri);
366 openpic2_writefield(&OpenPIC2->THIS_CPU.Current_Task_Priority,
367 OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
368}
369
370/*
371 * Get/set the spurious vector
372 */
373#ifdef notused
374static u_int openpic2_get_spurious(void)
375{
376 return openpic2_readfield(&OpenPIC2->Global.Spurious_Vector,
377 OPENPIC_VECTOR_MASK);
378}
379#endif /* notused */
380
381/* This can't be __init, it is used in openpic_sleep_restore_intrs */
382static void openpic2_set_spurious(u_int vec)
383{
384 check_arg_vec(vec);
385 openpic2_writefield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
386 vec);
387}
388
389static DEFINE_SPINLOCK(openpic2_setup_lock);
390
391/*
392 * Initialize a timer interrupt (and disable it)
393 *
394 * timer: OpenPIC timer number
395 * pri: interrupt source priority
396 * vec: the vector it will produce
397 */
398static void __init openpic2_inittimer(u_int timer, u_int pri, u_int vec)
399{
400 check_arg_timer(timer);
401 check_arg_pri(pri);
402 check_arg_vec(vec);
403 openpic2_safe_writefield(&OpenPIC2->Global.Timer[timer].Vector_Priority,
404 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
405 (pri << OPENPIC_PRIORITY_SHIFT) | vec);
406}
407
408/*
409 * Map a timer interrupt to one or more CPUs
410 */
411static void __init openpic2_maptimer(u_int timer, u_int cpumask)
412{
413 check_arg_timer(timer);
414 openpic2_write(&OpenPIC2->Global.Timer[timer].Destination,
415 cpumask);
416}
417
418/*
419 * Initalize the interrupt source which will generate an NMI.
420 * This raises the interrupt's priority from 8 to 9.
421 *
422 * irq: The logical IRQ which generates an NMI.
423 */
424void __init
425openpic2_init_nmi_irq(u_int irq)
426{
427 check_arg_irq(irq);
428 openpic2_safe_writefield(&ISR[irq - open_pic2_irq_offset]->Vector_Priority,
429 OPENPIC_PRIORITY_MASK,
430 9 << OPENPIC_PRIORITY_SHIFT);
431}
432
433/*
434 *
435 * All functions below take an offset'ed irq argument
436 *
437 */
438
439
440/*
441 * Enable/disable an external interrupt source
442 *
443 * Externally called, irq is an offseted system-wide interrupt number
444 */
445static void openpic2_enable_irq(u_int irq)
446{
447 volatile u_int *vpp;
448
449 check_arg_irq(irq);
450 vpp = &ISR[irq - open_pic2_irq_offset]->Vector_Priority;
451 openpic2_clearfield(vpp, OPENPIC_MASK);
452 /* make sure mask gets to controller before we return to user */
453 do {
454 mb(); /* sync is probably useless here */
455 } while (openpic2_readfield(vpp, OPENPIC_MASK));
456}
457
458static void openpic2_disable_irq(u_int irq)
459{
460 volatile u_int *vpp;
461 u32 vp;
462
463 check_arg_irq(irq);
464 vpp = &ISR[irq - open_pic2_irq_offset]->Vector_Priority;
465 openpic2_setfield(vpp, OPENPIC_MASK);
466 /* make sure mask gets to controller before we return to user */
467 do {
468 mb(); /* sync is probably useless here */
469 vp = openpic2_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY);
470 } while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
471}
472
473
474/*
475 * Initialize an interrupt source (and disable it!)
476 *
477 * irq: OpenPIC interrupt number
478 * pri: interrupt source priority
479 * vec: the vector it will produce
480 * pol: polarity (1 for positive, 0 for negative)
481 * sense: 1 for level, 0 for edge
482 */
483static void __init
484openpic2_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
485{
486 openpic2_safe_writefield(&ISR[irq]->Vector_Priority,
487 OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
488 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
489 (pri << OPENPIC_PRIORITY_SHIFT) | vec |
490 (pol ? OPENPIC_POLARITY_POSITIVE :
491 OPENPIC_POLARITY_NEGATIVE) |
492 (sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
493}
494
495/*
496 * Map an interrupt source to one or more CPUs
497 */
498static void openpic2_mapirq(u_int irq, u_int physmask, u_int keepmask)
499{
500 if (ISR[irq] == 0)
501 return;
502 if (keepmask != 0)
503 physmask |= openpic2_read(&ISR[irq]->Destination) & keepmask;
504 openpic2_write(&ISR[irq]->Destination, physmask);
505}
506
507#ifdef notused
508/*
509 * Set the sense for an interrupt source (and disable it!)
510 *
511 * sense: 1 for level, 0 for edge
512 */
513static void openpic2_set_sense(u_int irq, int sense)
514{
515 if (ISR[irq] != 0)
516 openpic2_safe_writefield(&ISR[irq]->Vector_Priority,
517 OPENPIC_SENSE_LEVEL,
518 (sense ? OPENPIC_SENSE_LEVEL : 0));
519}
520#endif /* notused */
521
522/* No spinlocks, should not be necessary with the OpenPIC
523 * (1 register = 1 interrupt and we have the desc lock).
524 */
525static void openpic2_ack_irq(unsigned int irq_nr)
526{
527 openpic2_disable_irq(irq_nr);
528 openpic2_eoi();
529}
530
531static void openpic2_end_irq(unsigned int irq_nr)
532{
533 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
534 openpic2_enable_irq(irq_nr);
535}
536
537int
538openpic2_get_irq(struct pt_regs *regs)
539{
540 int irq = openpic2_irq();
541
542 if (irq == (OPENPIC2_VEC_SPURIOUS + open_pic2_irq_offset))
543 irq = -1;
544 return irq;
545}
546
547#ifdef CONFIG_PM
548
549/*
550 * We implement the IRQ controller as a sysdev and put it
551 * to sleep at powerdown stage (the callback is named suspend,
552 * but it's old semantics, for the Device Model, it's really
553 * powerdown). The possible problem is that another sysdev that
554 * happens to be suspend after this one will have interrupts off,
555 * that may be an issue... For now, this isn't an issue on pmac
556 * though...
557 */
558
559static u32 save_ipi_vp[OPENPIC_NUM_IPI];
560static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
561static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
562static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
563static int openpic_suspend_count;
564
565static void openpic2_cached_enable_irq(u_int irq)
566{
567 check_arg_irq(irq);
568 save_irq_src_vp[irq - open_pic2_irq_offset] &= ~OPENPIC_MASK;
569}
570
571static void openpic2_cached_disable_irq(u_int irq)
572{
573 check_arg_irq(irq);
574 save_irq_src_vp[irq - open_pic2_irq_offset] |= OPENPIC_MASK;
575}
576
577/* WARNING: Can be called directly by the cpufreq code with NULL parameter,
578 * we need something better to deal with that... Maybe switch to S1 for
579 * cpufreq changes
580 */
581int openpic2_suspend(struct sys_device *sysdev, u32 state)
582{
583 int i;
584 unsigned long flags;
585
586 spin_lock_irqsave(&openpic2_setup_lock, flags);
587
588 if (openpic_suspend_count++ > 0) {
589 spin_unlock_irqrestore(&openpic2_setup_lock, flags);
590 return 0;
591 }
592
593 open_pic2.enable = openpic2_cached_enable_irq;
594 open_pic2.disable = openpic2_cached_disable_irq;
595
596 for (i=0; i<NumProcessors; i++) {
597 save_cpu_task_pri[i] = openpic2_read(&OpenPIC2->Processor[i].Current_Task_Priority);
598 openpic2_writefield(&OpenPIC2->Processor[i].Current_Task_Priority,
599 OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
600 }
601
602 for (i=0; i<OPENPIC_NUM_IPI; i++)
603 save_ipi_vp[i] = openpic2_read(&OpenPIC2->Global.IPI_Vector_Priority(i));
604 for (i=0; i<NumSources; i++) {
605 if (ISR[i] == 0)
606 continue;
607 save_irq_src_vp[i] = openpic2_read(&ISR[i]->Vector_Priority) & ~OPENPIC_ACTIVITY;
608 save_irq_src_dest[i] = openpic2_read(&ISR[i]->Destination);
609 }
610
611 spin_unlock_irqrestore(&openpic2_setup_lock, flags);
612
613 return 0;
614}
615
616/* WARNING: Can be called directly by the cpufreq code with NULL parameter,
617 * we need something better to deal with that... Maybe switch to S1 for
618 * cpufreq changes
619 */
620int openpic2_resume(struct sys_device *sysdev)
621{
622 int i;
623 unsigned long flags;
624 u32 vppmask = OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
625 OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK |
626 OPENPIC_MASK;
627
628 spin_lock_irqsave(&openpic2_setup_lock, flags);
629
630 if ((--openpic_suspend_count) > 0) {
631 spin_unlock_irqrestore(&openpic2_setup_lock, flags);
632 return 0;
633 }
634
635 openpic2_reset();
636
637 /* OpenPIC sometimes seem to need some time to be fully back up... */
638 do {
639 openpic2_set_spurious(OPENPIC2_VEC_SPURIOUS+open_pic2_irq_offset);
640 } while(openpic2_readfield(&OpenPIC2->Global.Spurious_Vector, OPENPIC_VECTOR_MASK)
641 != (OPENPIC2_VEC_SPURIOUS + open_pic2_irq_offset));
642
643 openpic2_disable_8259_pass_through();
644
645 for (i=0; i<OPENPIC_NUM_IPI; i++)
646 openpic2_write(&OpenPIC2->Global.IPI_Vector_Priority(i),
647 save_ipi_vp[i]);
648 for (i=0; i<NumSources; i++) {
649 if (ISR[i] == 0)
650 continue;
651 openpic2_write(&ISR[i]->Destination, save_irq_src_dest[i]);
652 openpic2_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
653 /* make sure mask gets to controller before we return to user */
654 do {
655 openpic2_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
656 } while (openpic2_readfield(&ISR[i]->Vector_Priority, vppmask)
657 != (save_irq_src_vp[i] & vppmask));
658 }
659 for (i=0; i<NumProcessors; i++)
660 openpic2_write(&OpenPIC2->Processor[i].Current_Task_Priority,
661 save_cpu_task_pri[i]);
662
663 open_pic2.enable = openpic2_enable_irq;
664 open_pic2.disable = openpic2_disable_irq;
665
666 spin_unlock_irqrestore(&openpic2_setup_lock, flags);
667
668 return 0;
669}
670
671#endif /* CONFIG_PM */
672
673/* HACK ALERT */
674static struct sysdev_class openpic2_sysclass = {
675 set_kset_name("openpic2"),
676};
677
678static struct sys_device device_openpic2 = {
679 .id = 0,
680 .cls = &openpic2_sysclass,
681};
682
683static struct sysdev_driver driver_openpic2 = {
684#ifdef CONFIG_PM
685 .suspend = &openpic2_suspend,
686 .resume = &openpic2_resume,
687#endif /* CONFIG_PM */
688};
689
690static int __init init_openpic2_sysfs(void)
691{
692 int rc;
693
694 if (!OpenPIC2_Addr)
695 return -ENODEV;
696 printk(KERN_DEBUG "Registering openpic2 with sysfs...\n");
697 rc = sysdev_class_register(&openpic2_sysclass);
698 if (rc) {
699 printk(KERN_ERR "Failed registering openpic sys class\n");
700 return -ENODEV;
701 }
702 rc = sysdev_register(&device_openpic2);
703 if (rc) {
704 printk(KERN_ERR "Failed registering openpic sys device\n");
705 return -ENODEV;
706 }
707 rc = sysdev_driver_register(&openpic2_sysclass, &driver_openpic2);
708 if (rc) {
709 printk(KERN_ERR "Failed registering openpic sys driver\n");
710 return -ENODEV;
711 }
712 return 0;
713}
714
715subsys_initcall(init_openpic2_sysfs);
716
diff --git a/arch/ppc/syslib/open_pic_defs.h b/arch/ppc/syslib/open_pic_defs.h
new file mode 100644
index 000000000000..4f05624b249e
--- /dev/null
+++ b/arch/ppc/syslib/open_pic_defs.h
@@ -0,0 +1,292 @@
1/*
2 * arch/ppc/kernel/open_pic_defs.h -- OpenPIC definitions
3 *
4 * Copyright (C) 1997 Geert Uytterhoeven
5 *
6 * This file is based on the following documentation:
7 *
8 * The Open Programmable Interrupt Controller (PIC)
9 * Register Interface Specification Revision 1.2
10 *
11 * Issue Date: October 1995
12 *
13 * Issued jointly by Advanced Micro Devices and Cyrix Corporation
14 *
15 * AMD is a registered trademark of Advanced Micro Devices, Inc.
16 * Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc.
17 * All Rights Reserved.
18 *
19 * To receive a copy of this documentation, send an email to openpic@amd.com.
20 *
21 * This file is subject to the terms and conditions of the GNU General Public
22 * License. See the file COPYING in the main directory of this archive
23 * for more details.
24 */
25
26#ifndef _LINUX_OPENPIC_H
27#define _LINUX_OPENPIC_H
28
29#ifdef __KERNEL__
30
31 /*
32 * OpenPIC supports up to 2048 interrupt sources and up to 32 processors
33 */
34
35#define OPENPIC_MAX_SOURCES 2048
36#define OPENPIC_MAX_PROCESSORS 32
37#define OPENPIC_MAX_ISU 16
38
39#define OPENPIC_NUM_TIMERS 4
40#define OPENPIC_NUM_IPI 4
41#define OPENPIC_NUM_PRI 16
42#define OPENPIC_NUM_VECTORS 256
43
44
45
46 /*
47 * OpenPIC Registers are 32 bits and aligned on 128 bit boundaries
48 */
49
50typedef struct _OpenPIC_Reg {
51 u_int Reg; /* Little endian! */
52 char Pad[0xc];
53} OpenPIC_Reg;
54
55
56 /*
57 * Per Processor Registers
58 */
59
60typedef struct _OpenPIC_Processor {
61 /*
62 * Private Shadow Registers (for SLiC backwards compatibility)
63 */
64 u_int IPI0_Dispatch_Shadow; /* Write Only */
65 char Pad1[0x4];
66 u_int IPI0_Vector_Priority_Shadow; /* Read/Write */
67 char Pad2[0x34];
68 /*
69 * Interprocessor Interrupt Command Ports
70 */
71 OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI]; /* Write Only */
72 /*
73 * Current Task Priority Register
74 */
75 OpenPIC_Reg _Current_Task_Priority; /* Read/Write */
76 char Pad3[0x10];
77 /*
78 * Interrupt Acknowledge Register
79 */
80 OpenPIC_Reg _Interrupt_Acknowledge; /* Read Only */
81 /*
82 * End of Interrupt (EOI) Register
83 */
84 OpenPIC_Reg _EOI; /* Read/Write */
85 char Pad5[0xf40];
86} OpenPIC_Processor;
87
88
89 /*
90 * Timer Registers
91 */
92
93typedef struct _OpenPIC_Timer {
94 OpenPIC_Reg _Current_Count; /* Read Only */
95 OpenPIC_Reg _Base_Count; /* Read/Write */
96 OpenPIC_Reg _Vector_Priority; /* Read/Write */
97 OpenPIC_Reg _Destination; /* Read/Write */
98} OpenPIC_Timer;
99
100
101 /*
102 * Global Registers
103 */
104
105typedef struct _OpenPIC_Global {
106 /*
107 * Feature Reporting Registers
108 */
109 OpenPIC_Reg _Feature_Reporting0; /* Read Only */
110 OpenPIC_Reg _Feature_Reporting1; /* Future Expansion */
111 /*
112 * Global Configuration Registers
113 */
114 OpenPIC_Reg _Global_Configuration0; /* Read/Write */
115 OpenPIC_Reg _Global_Configuration1; /* Future Expansion */
116 /*
117 * Vendor Specific Registers
118 */
119 OpenPIC_Reg _Vendor_Specific[4];
120 /*
121 * Vendor Identification Register
122 */
123 OpenPIC_Reg _Vendor_Identification; /* Read Only */
124 /*
125 * Processor Initialization Register
126 */
127 OpenPIC_Reg _Processor_Initialization; /* Read/Write */
128 /*
129 * IPI Vector/Priority Registers
130 */
131 OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI]; /* Read/Write */
132 /*
133 * Spurious Vector Register
134 */
135 OpenPIC_Reg _Spurious_Vector; /* Read/Write */
136 /*
137 * Global Timer Registers
138 */
139 OpenPIC_Reg _Timer_Frequency; /* Read/Write */
140 OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS];
141 char Pad1[0xee00];
142} OpenPIC_Global;
143
144
145 /*
146 * Interrupt Source Registers
147 */
148
149typedef struct _OpenPIC_Source {
150 OpenPIC_Reg _Vector_Priority; /* Read/Write */
151 OpenPIC_Reg _Destination; /* Read/Write */
152} OpenPIC_Source, *OpenPIC_SourcePtr;
153
154
155 /*
156 * OpenPIC Register Map
157 */
158
159struct OpenPIC {
160 char Pad1[0x1000];
161 /*
162 * Global Registers
163 */
164 OpenPIC_Global Global;
165 /*
166 * Interrupt Source Configuration Registers
167 */
168 OpenPIC_Source Source[OPENPIC_MAX_SOURCES];
169 /*
170 * Per Processor Registers
171 */
172 OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
173};
174
175extern volatile struct OpenPIC __iomem *OpenPIC;
176
177
178 /*
179 * Current Task Priority Register
180 */
181
182#define OPENPIC_CURRENT_TASK_PRIORITY_MASK 0x0000000f
183
184 /*
185 * Who Am I Register
186 */
187
188#define OPENPIC_WHO_AM_I_ID_MASK 0x0000001f
189
190 /*
191 * Feature Reporting Register 0
192 */
193
194#define OPENPIC_FEATURE_LAST_SOURCE_MASK 0x07ff0000
195#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT 16
196#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK 0x00001f00
197#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT 8
198#define OPENPIC_FEATURE_VERSION_MASK 0x000000ff
199
200 /*
201 * Global Configuration Register 0
202 */
203
204#define OPENPIC_CONFIG_RESET 0x80000000
205#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE 0x20000000
206#define OPENPIC_CONFIG_BASE_MASK 0x000fffff
207
208 /*
209 * Global Configuration Register 1
210 * This is the EICR on EPICs.
211 */
212
213#define OPENPIC_EICR_S_CLK_MASK 0x70000000
214#define OPENPIC_EICR_SIE 0x08000000
215
216 /*
217 * Vendor Identification Register
218 */
219
220#define OPENPIC_VENDOR_ID_STEPPING_MASK 0x00ff0000
221#define OPENPIC_VENDOR_ID_STEPPING_SHIFT 16
222#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK 0x0000ff00
223#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT 8
224#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK 0x000000ff
225
226 /*
227 * Vector/Priority Registers
228 */
229
230#define OPENPIC_MASK 0x80000000
231#define OPENPIC_ACTIVITY 0x40000000 /* Read Only */
232#define OPENPIC_PRIORITY_MASK 0x000f0000
233#define OPENPIC_PRIORITY_SHIFT 16
234#define OPENPIC_VECTOR_MASK 0x000000ff
235
236
237 /*
238 * Interrupt Source Registers
239 */
240
241#define OPENPIC_POLARITY_POSITIVE 0x00800000
242#define OPENPIC_POLARITY_NEGATIVE 0x00000000
243#define OPENPIC_POLARITY_MASK 0x00800000
244#define OPENPIC_SENSE_LEVEL 0x00400000
245#define OPENPIC_SENSE_EDGE 0x00000000
246#define OPENPIC_SENSE_MASK 0x00400000
247
248
249 /*
250 * Timer Registers
251 */
252
253#define OPENPIC_COUNT_MASK 0x7fffffff
254#define OPENPIC_TIMER_TOGGLE 0x80000000
255#define OPENPIC_TIMER_COUNT_INHIBIT 0x80000000
256
257
258 /*
259 * Aliases to make life simpler
260 */
261
262/* Per Processor Registers */
263#define IPI_Dispatch(i) _IPI_Dispatch[i].Reg
264#define Current_Task_Priority _Current_Task_Priority.Reg
265#define Interrupt_Acknowledge _Interrupt_Acknowledge.Reg
266#define EOI _EOI.Reg
267
268/* Global Registers */
269#define Feature_Reporting0 _Feature_Reporting0.Reg
270#define Feature_Reporting1 _Feature_Reporting1.Reg
271#define Global_Configuration0 _Global_Configuration0.Reg
272#define Global_Configuration1 _Global_Configuration1.Reg
273#define Vendor_Specific(i) _Vendor_Specific[i].Reg
274#define Vendor_Identification _Vendor_Identification.Reg
275#define Processor_Initialization _Processor_Initialization.Reg
276#define IPI_Vector_Priority(i) _IPI_Vector_Priority[i].Reg
277#define Spurious_Vector _Spurious_Vector.Reg
278#define Timer_Frequency _Timer_Frequency.Reg
279
280/* Timer Registers */
281#define Current_Count _Current_Count.Reg
282#define Base_Count _Base_Count.Reg
283#define Vector_Priority _Vector_Priority.Reg
284#define Destination _Destination.Reg
285
286/* Interrupt Source Registers */
287#define Vector_Priority _Vector_Priority.Reg
288#define Destination _Destination.Reg
289
290#endif /* __KERNEL__ */
291
292#endif /* _LINUX_OPENPIC_H */
diff --git a/arch/ppc/syslib/pci_auto.c b/arch/ppc/syslib/pci_auto.c
new file mode 100644
index 000000000000..d64207c2a972
--- /dev/null
+++ b/arch/ppc/syslib/pci_auto.c
@@ -0,0 +1,517 @@
1/*
2 * arch/ppc/syslib/pci_auto.c
3 *
4 * PCI autoconfiguration library
5 *
6 * Author: Matt Porter <mporter@mvista.com>
7 *
8 * 2001 (c) MontaVista, Software, Inc. This file is licensed under
9 * the terms of the GNU General Public License version 2. This program
10 * is licensed "as is" without any warranty of any kind, whether express
11 * or implied.
12 */
13
14/*
15 * The CardBus support is very preliminary. Preallocating space is
16 * the way to go but will require some change in card services to
17 * make it useful. Eventually this will ensure that we can put
18 * multiple CB bridges behind multiple P2P bridges. For now, at
19 * least it ensures that we place the CB bridge BAR and assigned
20 * initial bus numbers. I definitely need to do something about
21 * the lack of 16-bit I/O support. -MDP
22 */
23
24#include <linux/kernel.h>
25#include <linux/init.h>
26#include <linux/pci.h>
27
28#include <asm/pci-bridge.h>
29
30#define PCIAUTO_IDE_MODE_MASK 0x05
31
32#undef DEBUG
33
34#ifdef DEBUG
35#define DBG(x...) printk(x)
36#else
37#define DBG(x...)
38#endif /* DEBUG */
39
40static int pciauto_upper_iospc;
41static int pciauto_upper_memspc;
42
43void __init pciauto_setup_bars(struct pci_controller *hose,
44 int current_bus,
45 int pci_devfn,
46 int bar_limit)
47{
48 int bar_response, bar_size, bar_value;
49 int bar, addr_mask;
50 int * upper_limit;
51 int found_mem64 = 0;
52
53 DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n",
54 current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) );
55
56 for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
57 /* Tickle the BAR and get the response */
58 early_write_config_dword(hose,
59 current_bus,
60 pci_devfn,
61 bar,
62 0xffffffff);
63 early_read_config_dword(hose,
64 current_bus,
65 pci_devfn,
66 bar,
67 &bar_response);
68
69 /* If BAR is not implemented go to the next BAR */
70 if (!bar_response)
71 continue;
72
73 /* Check the BAR type and set our address mask */
74 if (bar_response & PCI_BASE_ADDRESS_SPACE) {
75 addr_mask = PCI_BASE_ADDRESS_IO_MASK;
76 upper_limit = &pciauto_upper_iospc;
77 DBG("PCI Autoconfig: BAR 0x%x, I/O, ", bar);
78 } else {
79 if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
80 PCI_BASE_ADDRESS_MEM_TYPE_64)
81 found_mem64 = 1;
82
83 addr_mask = PCI_BASE_ADDRESS_MEM_MASK;
84 upper_limit = &pciauto_upper_memspc;
85 DBG("PCI Autoconfig: BAR 0x%x, Mem ", bar);
86 }
87
88 /* Calculate requested size */
89 bar_size = ~(bar_response & addr_mask) + 1;
90
91 /* Allocate a base address */
92 bar_value = (*upper_limit - bar_size) & ~(bar_size - 1);
93
94 /* Write it out and update our limit */
95 early_write_config_dword(hose,
96 current_bus,
97 pci_devfn,
98 bar,
99 bar_value);
100
101 *upper_limit = bar_value;
102
103 /*
104 * If we are a 64-bit decoder then increment to the
105 * upper 32 bits of the bar and force it to locate
106 * in the lower 4GB of memory.
107 */
108 if (found_mem64) {
109 bar += 4;
110 early_write_config_dword(hose,
111 current_bus,
112 pci_devfn,
113 bar,
114 0x00000000);
115 found_mem64 = 0;
116 }
117
118 DBG("size=0x%x, address=0x%x\n",
119 bar_size, bar_value);
120 }
121
122}
123
124void __init pciauto_prescan_setup_bridge(struct pci_controller *hose,
125 int current_bus,
126 int pci_devfn,
127 int sub_bus,
128 int *iosave,
129 int *memsave)
130{
131 /* Configure bus number registers */
132 early_write_config_byte(hose,
133 current_bus,
134 pci_devfn,
135 PCI_PRIMARY_BUS,
136 current_bus);
137 early_write_config_byte(hose,
138 current_bus,
139 pci_devfn,
140 PCI_SECONDARY_BUS,
141 sub_bus + 1);
142 early_write_config_byte(hose,
143 current_bus,
144 pci_devfn,
145 PCI_SUBORDINATE_BUS,
146 0xff);
147
148 /* Round memory allocator to 1MB boundary */
149 pciauto_upper_memspc &= ~(0x100000 - 1);
150 *memsave = pciauto_upper_memspc;
151
152 /* Round I/O allocator to 4KB boundary */
153 pciauto_upper_iospc &= ~(0x1000 - 1);
154 *iosave = pciauto_upper_iospc;
155
156 /* Set up memory and I/O filter limits, assume 32-bit I/O space */
157 early_write_config_word(hose,
158 current_bus,
159 pci_devfn,
160 PCI_MEMORY_LIMIT,
161 ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
162 early_write_config_byte(hose,
163 current_bus,
164 pci_devfn,
165 PCI_IO_LIMIT,
166 ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8);
167 early_write_config_word(hose,
168 current_bus,
169 pci_devfn,
170 PCI_IO_LIMIT_UPPER16,
171 ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16);
172
173 /* Zero upper 32 bits of prefetchable base/limit */
174 early_write_config_dword(hose,
175 current_bus,
176 pci_devfn,
177 PCI_PREF_BASE_UPPER32,
178 0);
179 early_write_config_dword(hose,
180 current_bus,
181 pci_devfn,
182 PCI_PREF_LIMIT_UPPER32,
183 0);
184}
185
186void __init pciauto_postscan_setup_bridge(struct pci_controller *hose,
187 int current_bus,
188 int pci_devfn,
189 int sub_bus,
190 int *iosave,
191 int *memsave)
192{
193 int cmdstat;
194
195 /* Configure bus number registers */
196 early_write_config_byte(hose,
197 current_bus,
198 pci_devfn,
199 PCI_SUBORDINATE_BUS,
200 sub_bus);
201
202 /*
203 * Round memory allocator to 1MB boundary.
204 * If no space used, allocate minimum.
205 */
206 pciauto_upper_memspc &= ~(0x100000 - 1);
207 if (*memsave == pciauto_upper_memspc)
208 pciauto_upper_memspc -= 0x00100000;
209
210 early_write_config_word(hose,
211 current_bus,
212 pci_devfn,
213 PCI_MEMORY_BASE,
214 pciauto_upper_memspc >> 16);
215
216 /* Allocate 1MB for pre-fretch */
217 early_write_config_word(hose,
218 current_bus,
219 pci_devfn,
220 PCI_PREF_MEMORY_LIMIT,
221 ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
222
223 pciauto_upper_memspc -= 0x100000;
224
225 early_write_config_word(hose,
226 current_bus,
227 pci_devfn,
228 PCI_PREF_MEMORY_BASE,
229 pciauto_upper_memspc >> 16);
230
231 /* Round I/O allocator to 4KB boundary */
232 pciauto_upper_iospc &= ~(0x1000 - 1);
233 if (*iosave == pciauto_upper_iospc)
234 pciauto_upper_iospc -= 0x1000;
235
236 early_write_config_byte(hose,
237 current_bus,
238 pci_devfn,
239 PCI_IO_BASE,
240 (pciauto_upper_iospc & 0x0000f000) >> 8);
241 early_write_config_word(hose,
242 current_bus,
243 pci_devfn,
244 PCI_IO_BASE_UPPER16,
245 pciauto_upper_iospc >> 16);
246
247 /* Enable memory and I/O accesses, enable bus master */
248 early_read_config_dword(hose,
249 current_bus,
250 pci_devfn,
251 PCI_COMMAND,
252 &cmdstat);
253 early_write_config_dword(hose,
254 current_bus,
255 pci_devfn,
256 PCI_COMMAND,
257 cmdstat |
258 PCI_COMMAND_IO |
259 PCI_COMMAND_MEMORY |
260 PCI_COMMAND_MASTER);
261}
262
263void __init pciauto_prescan_setup_cardbus_bridge(struct pci_controller *hose,
264 int current_bus,
265 int pci_devfn,
266 int sub_bus,
267 int *iosave,
268 int *memsave)
269{
270 /* Configure bus number registers */
271 early_write_config_byte(hose,
272 current_bus,
273 pci_devfn,
274 PCI_PRIMARY_BUS,
275 current_bus);
276 early_write_config_byte(hose,
277 current_bus,
278 pci_devfn,
279 PCI_SECONDARY_BUS,
280 sub_bus + 1);
281 early_write_config_byte(hose,
282 current_bus,
283 pci_devfn,
284 PCI_SUBORDINATE_BUS,
285 0xff);
286
287 /* Round memory allocator to 4KB boundary */
288 pciauto_upper_memspc &= ~(0x1000 - 1);
289 *memsave = pciauto_upper_memspc;
290
291 /* Round I/O allocator to 4 byte boundary */
292 pciauto_upper_iospc &= ~(0x4 - 1);
293 *iosave = pciauto_upper_iospc;
294
295 /* Set up memory and I/O filter limits, assume 32-bit I/O space */
296 early_write_config_dword(hose,
297 current_bus,
298 pci_devfn,
299 0x20,
300 pciauto_upper_memspc - 1);
301 early_write_config_dword(hose,
302 current_bus,
303 pci_devfn,
304 0x30,
305 pciauto_upper_iospc - 1);
306}
307
308void __init pciauto_postscan_setup_cardbus_bridge(struct pci_controller *hose,
309 int current_bus,
310 int pci_devfn,
311 int sub_bus,
312 int *iosave,
313 int *memsave)
314{
315 int cmdstat;
316
317 /*
318 * Configure subordinate bus number. The PCI subsystem
319 * bus scan will renumber buses (reserving three additional
320 * for this PCI<->CardBus bridge for the case where a CardBus
321 * adapter contains a P2P or CB2CB bridge.
322 */
323 early_write_config_byte(hose,
324 current_bus,
325 pci_devfn,
326 PCI_SUBORDINATE_BUS,
327 sub_bus);
328
329 /*
330 * Reserve an additional 4MB for mem space and 16KB for
331 * I/O space. This should cover any additional space
332 * requirement of unusual CardBus devices with
333 * additional bridges that can consume more address space.
334 *
335 * Although pcmcia-cs currently will reprogram bridge
336 * windows, the goal is to add an option to leave them
337 * alone and use the bridge window ranges as the regions
338 * that are searched for free resources upon hot-insertion
339 * of a device. This will allow a PCI<->CardBus bridge
340 * configured by this routine to happily live behind a
341 * P2P bridge in a system.
342 */
343 pciauto_upper_memspc -= 0x00400000;
344 pciauto_upper_iospc -= 0x00004000;
345
346 /* Round memory allocator to 4KB boundary */
347 pciauto_upper_memspc &= ~(0x1000 - 1);
348
349 early_write_config_dword(hose,
350 current_bus,
351 pci_devfn,
352 0x1c,
353 pciauto_upper_memspc);
354
355 /* Round I/O allocator to 4 byte boundary */
356 pciauto_upper_iospc &= ~(0x4 - 1);
357 early_write_config_dword(hose,
358 current_bus,
359 pci_devfn,
360 0x2c,
361 pciauto_upper_iospc);
362
363 /* Enable memory and I/O accesses, enable bus master */
364 early_read_config_dword(hose,
365 current_bus,
366 pci_devfn,
367 PCI_COMMAND,
368 &cmdstat);
369 early_write_config_dword(hose,
370 current_bus,
371 pci_devfn,
372 PCI_COMMAND,
373 cmdstat |
374 PCI_COMMAND_IO |
375 PCI_COMMAND_MEMORY |
376 PCI_COMMAND_MASTER);
377}
378
379int __init pciauto_bus_scan(struct pci_controller *hose, int current_bus)
380{
381 int sub_bus, pci_devfn, pci_class, cmdstat, found_multi = 0;
382 unsigned short vid;
383 unsigned char header_type;
384
385 /*
386 * Fetch our I/O and memory space upper boundaries used
387 * to allocated base addresses on this hose.
388 */
389 if (current_bus == hose->first_busno) {
390 pciauto_upper_iospc = hose->io_space.end + 1;
391 pciauto_upper_memspc = hose->mem_space.end + 1;
392 }
393
394 sub_bus = current_bus;
395
396 for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
397 /* Skip our host bridge */
398 if ( (current_bus == hose->first_busno) && (pci_devfn == 0) )
399 continue;
400
401 if (PCI_FUNC(pci_devfn) && !found_multi)
402 continue;
403
404 /* If config space read fails from this device, move on */
405 if (early_read_config_byte(hose,
406 current_bus,
407 pci_devfn,
408 PCI_HEADER_TYPE,
409 &header_type))
410 continue;
411
412 if (!PCI_FUNC(pci_devfn))
413 found_multi = header_type & 0x80;
414
415 early_read_config_word(hose,
416 current_bus,
417 pci_devfn,
418 PCI_VENDOR_ID,
419 &vid);
420
421 if (vid != 0xffff) {
422 early_read_config_dword(hose,
423 current_bus,
424 pci_devfn,
425 PCI_CLASS_REVISION, &pci_class);
426 if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) {
427 int iosave, memsave;
428
429 DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn));
430 /* Allocate PCI I/O and/or memory space */
431 pciauto_setup_bars(hose,
432 current_bus,
433 pci_devfn,
434 PCI_BASE_ADDRESS_1);
435
436 pciauto_prescan_setup_bridge(hose,
437 current_bus,
438 pci_devfn,
439 sub_bus,
440 &iosave,
441 &memsave);
442 sub_bus = pciauto_bus_scan(hose, sub_bus+1);
443 pciauto_postscan_setup_bridge(hose,
444 current_bus,
445 pci_devfn,
446 sub_bus,
447 &iosave,
448 &memsave);
449 } else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
450 int iosave, memsave;
451
452 DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
453 /* Place CardBus Socket/ExCA registers */
454 pciauto_setup_bars(hose,
455 current_bus,
456 pci_devfn,
457 PCI_BASE_ADDRESS_0);
458
459 pciauto_prescan_setup_cardbus_bridge(hose,
460 current_bus,
461 pci_devfn,
462 sub_bus,
463 &iosave,
464 &memsave);
465 sub_bus = pciauto_bus_scan(hose, sub_bus+1);
466 pciauto_postscan_setup_cardbus_bridge(hose,
467 current_bus,
468 pci_devfn,
469 sub_bus,
470 &iosave,
471 &memsave);
472 } else {
473 if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
474 unsigned char prg_iface;
475
476 early_read_config_byte(hose,
477 current_bus,
478 pci_devfn,
479 PCI_CLASS_PROG,
480 &prg_iface);
481 if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
482 DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n");
483 continue;
484 }
485 }
486 /* Allocate PCI I/O and/or memory space */
487 pciauto_setup_bars(hose,
488 current_bus,
489 pci_devfn,
490 PCI_BASE_ADDRESS_5);
491
492 /*
493 * Enable some standard settings
494 */
495 early_read_config_dword(hose,
496 current_bus,
497 pci_devfn,
498 PCI_COMMAND,
499 &cmdstat);
500 early_write_config_dword(hose,
501 current_bus,
502 pci_devfn,
503 PCI_COMMAND,
504 cmdstat |
505 PCI_COMMAND_IO |
506 PCI_COMMAND_MEMORY |
507 PCI_COMMAND_MASTER);
508 early_write_config_byte(hose,
509 current_bus,
510 pci_devfn,
511 PCI_LATENCY_TIMER,
512 0x80);
513 }
514 }
515 }
516 return sub_bus;
517}
diff --git a/arch/ppc/syslib/ppc403_pic.c b/arch/ppc/syslib/ppc403_pic.c
new file mode 100644
index 000000000000..06cb0af2a58d
--- /dev/null
+++ b/arch/ppc/syslib/ppc403_pic.c
@@ -0,0 +1,127 @@
1/*
2 *
3 * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
4 *
5 * Module name: ppc403_pic.c
6 *
7 * Description:
8 * Interrupt controller driver for PowerPC 403-based processors.
9 */
10
11/*
12 * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has
13 * 32 possible interrupts, a majority of which are not implemented on
14 * all cores. There are six configurable, external interrupt pins and
15 * there are eight internal interrupts for the on-chip serial port
16 * (SPU), DMA controller, and JTAG controller.
17 *
18 */
19
20#include <linux/init.h>
21#include <linux/sched.h>
22#include <linux/signal.h>
23#include <linux/stddef.h>
24
25#include <asm/processor.h>
26#include <asm/system.h>
27#include <asm/irq.h>
28#include <asm/ppc4xx_pic.h>
29
30/* Function Prototypes */
31
32static void ppc403_aic_enable(unsigned int irq);
33static void ppc403_aic_disable(unsigned int irq);
34static void ppc403_aic_disable_and_ack(unsigned int irq);
35
36static struct hw_interrupt_type ppc403_aic = {
37 "403GC AIC",
38 NULL,
39 NULL,
40 ppc403_aic_enable,
41 ppc403_aic_disable,
42 ppc403_aic_disable_and_ack,
43 0
44};
45
46int
47ppc403_pic_get_irq(struct pt_regs *regs)
48{
49 int irq;
50 unsigned long bits;
51
52 /*
53 * Only report the status of those interrupts that are actually
54 * enabled.
55 */
56
57 bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER);
58
59 /*
60 * Walk through the interrupts from highest priority to lowest, and
61 * report the first pending interrupt found.
62 * We want PPC, not C bit numbering, so just subtract the ffs()
63 * result from 32.
64 */
65 irq = 32 - ffs(bits);
66
67 if (irq == NR_AIC_IRQS)
68 irq = -1;
69
70 return (irq);
71}
72
73static void
74ppc403_aic_enable(unsigned int irq)
75{
76 int bit, word;
77
78 bit = irq & 0x1f;
79 word = irq >> 5;
80
81 ppc_cached_irq_mask[word] |= (1 << (31 - bit));
82 mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
83}
84
85static void
86ppc403_aic_disable(unsigned int irq)
87{
88 int bit, word;
89
90 bit = irq & 0x1f;
91 word = irq >> 5;
92
93 ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
94 mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
95}
96
97static void
98ppc403_aic_disable_and_ack(unsigned int irq)
99{
100 int bit, word;
101
102 bit = irq & 0x1f;
103 word = irq >> 5;
104
105 ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
106 mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
107 mtdcr(DCRN_EXISR, (1 << (31 - bit)));
108}
109
110void __init
111ppc4xx_pic_init(void)
112{
113 int i;
114
115 /*
116 * Disable all external interrupts until they are
117 * explicity requested.
118 */
119 ppc_cached_irq_mask[0] = 0;
120
121 mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]);
122
123 ppc_md.get_irq = ppc403_pic_get_irq;
124
125 for (i = 0; i < NR_IRQS; i++)
126 irq_desc[i].handler = &ppc403_aic;
127}
diff --git a/arch/ppc/syslib/ppc405_pci.c b/arch/ppc/syslib/ppc405_pci.c
new file mode 100644
index 000000000000..81c83bf98df4
--- /dev/null
+++ b/arch/ppc/syslib/ppc405_pci.c
@@ -0,0 +1,177 @@
1/*
2 * Authors: Frank Rowand <frank_rowand@mvista.com>,
3 * Debbie Chu <debbie_chu@mvista.com>, or source@mvista.com
4 * Further modifications by Armin Kuster <akuster@mvista.com>
5 *
6 * 2000 (c) MontaVista, Software, Inc. This file is licensed under
7 * the terms of the GNU General Public License version 2. This program
8 * is licensed "as is" without any warranty of any kind, whether express
9 * or implied.
10 *
11 * Based on arch/ppc/kernel/indirect.c, Copyright (C) 1998 Gabriel Paubert.
12 */
13
14#include <linux/pci.h>
15#include <asm/io.h>
16#include <asm/system.h>
17#include <asm/machdep.h>
18#include <linux/init.h>
19#include <linux/errno.h>
20#include <asm/ocp.h>
21#include <asm/ibm4xx.h>
22#include <asm/pci-bridge.h>
23#include <asm/ibm_ocp_pci.h>
24
25
26extern void bios_fixup(struct pci_controller *, struct pcil0_regs *);
27extern int ppc405_map_irq(struct pci_dev *dev, unsigned char idsel,
28 unsigned char pin);
29
30void
31ppc405_pcibios_fixup_resources(struct pci_dev *dev)
32{
33 int i;
34 unsigned long max_host_addr;
35 unsigned long min_host_addr;
36 struct resource *res;
37
38 /*
39 * openbios puts some graphics cards in the same range as the host
40 * controller uses to map to SDRAM. Fix it.
41 */
42
43 min_host_addr = 0;
44 max_host_addr = PPC405_PCI_MEM_BASE - 1;
45
46 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
47 res = dev->resource + i;
48 if (!res->start)
49 continue;
50 if ((res->flags & IORESOURCE_MEM) &&
51 (((res->start >= min_host_addr)
52 && (res->start <= max_host_addr))
53 || ((res->end >= min_host_addr)
54 && (res->end <= max_host_addr))
55 || ((res->start < min_host_addr)
56 && (res->end > max_host_addr))
57 )
58 ) {
59
60 /* force pcibios_assign_resources() to assign a new address */
61 res->end -= res->start;
62 res->start = 0;
63 }
64 }
65}
66
67static int
68ppc4xx_exclude_device(unsigned char bus, unsigned char devfn)
69{
70 /* We prevent us from seeing ourselves to avoid having
71 * the kernel try to remap our BAR #1 and fuck up bus
72 * master from external PCI devices
73 */
74 return (bus == 0 && devfn == 0);
75}
76
77void
78ppc4xx_find_bridges(void)
79{
80 struct pci_controller *hose_a;
81 struct pcil0_regs *pcip;
82 unsigned int tmp_addr;
83 unsigned int tmp_size;
84 unsigned int reg_index;
85 unsigned int new_pmm_max = 0;
86 unsigned int new_pmm_min = 0;
87
88 isa_io_base = 0;
89 isa_mem_base = 0;
90 pci_dram_offset = 0;
91
92#if (PSR_PCI_ARBIT_EN > 1)
93 /* Check if running in slave mode */
94 if ((mfdcr(DCRN_CHPSR) & PSR_PCI_ARBIT_EN) == 0) {
95 printk("Running as PCI slave, kernel PCI disabled !\n");
96 return;
97 }
98#endif
99 /* Setup PCI32 hose */
100 hose_a = pcibios_alloc_controller();
101 if (!hose_a)
102 return;
103 setup_indirect_pci(hose_a, PPC405_PCI_CONFIG_ADDR,
104 PPC405_PCI_CONFIG_DATA);
105
106 pcip = ioremap(PPC4xx_PCI_LCFG_PADDR, PAGE_SIZE);
107 if (pcip != NULL) {
108
109#if defined(CONFIG_BIOS_FIXUP)
110 bios_fixup(hose_a, pcip);
111#endif
112 new_pmm_min = 0xffffffff;
113 for (reg_index = 0; reg_index < 3; reg_index++) {
114 tmp_size = in_le32(&pcip->pmm[reg_index].ma); // mask & attrs
115 /* test the enable bit */
116 if ((tmp_size & 0x1) == 0)
117 continue;
118 tmp_addr = in_le32(&pcip->pmm[reg_index].pcila); // PCI addr
119 if (tmp_addr < PPC405_PCI_PHY_MEM_BASE) {
120 printk(KERN_DEBUG
121 "Disabling mapping to PCI mem addr 0x%8.8x\n",
122 tmp_addr);
123 out_le32(&pcip->pmm[reg_index].ma, tmp_size & ~1); // *_PMMOMA
124 continue;
125 }
126 tmp_addr = in_le32(&pcip->pmm[reg_index].la); // *_PMMOLA
127 if (tmp_addr < new_pmm_min)
128 new_pmm_min = tmp_addr;
129 tmp_addr = tmp_addr +
130 (0xffffffff - (tmp_size & 0xffffc000));
131 if (tmp_addr > PPC405_PCI_UPPER_MEM) {
132 new_pmm_max = tmp_addr; // PPC405_PCI_UPPER_MEM
133 } else {
134 new_pmm_max = PPC405_PCI_UPPER_MEM;
135 }
136
137 } // for
138
139 iounmap(pcip);
140 }
141
142 hose_a->first_busno = 0;
143 hose_a->last_busno = 0xff;
144 hose_a->pci_mem_offset = 0;
145
146 /* Setup bridge memory/IO ranges & resources
147 * TODO: Handle firmwares setting up a legacy ISA mem base
148 */
149 hose_a->io_space.start = PPC405_PCI_LOWER_IO;
150 hose_a->io_space.end = PPC405_PCI_UPPER_IO;
151 hose_a->mem_space.start = new_pmm_min;
152 hose_a->mem_space.end = new_pmm_max;
153 hose_a->io_base_phys = PPC405_PCI_PHY_IO_BASE;
154 hose_a->io_base_virt = ioremap(hose_a->io_base_phys, 0x10000);
155 hose_a->io_resource.start = 0;
156 hose_a->io_resource.end = PPC405_PCI_UPPER_IO - PPC405_PCI_LOWER_IO;
157 hose_a->io_resource.flags = IORESOURCE_IO;
158 hose_a->io_resource.name = "PCI I/O";
159 hose_a->mem_resources[0].start = new_pmm_min;
160 hose_a->mem_resources[0].end = new_pmm_max;
161 hose_a->mem_resources[0].flags = IORESOURCE_MEM;
162 hose_a->mem_resources[0].name = "PCI Memory";
163 isa_io_base = (int) hose_a->io_base_virt;
164 isa_mem_base = 0; /* ISA not implemented */
165 ISA_DMA_THRESHOLD = 0x00ffffff; /* ??? ISA not implemented */
166
167 /* Scan busses & initial setup by pci_auto */
168 hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
169 hose_a->last_busno = 0;
170
171 /* Setup ppc_md */
172 ppc_md.pcibios_fixup = NULL;
173 ppc_md.pci_exclude_device = ppc4xx_exclude_device;
174 ppc_md.pcibios_fixup_resources = ppc405_pcibios_fixup_resources;
175 ppc_md.pci_swizzle = common_swizzle;
176 ppc_md.pci_map_irq = ppc405_map_irq;
177}
diff --git a/arch/ppc/syslib/ppc4xx_dma.c b/arch/ppc/syslib/ppc4xx_dma.c
new file mode 100644
index 000000000000..5015ab99afd2
--- /dev/null
+++ b/arch/ppc/syslib/ppc4xx_dma.c
@@ -0,0 +1,708 @@
1/*
2 * arch/ppc/kernel/ppc4xx_dma.c
3 *
4 * IBM PPC4xx DMA engine core library
5 *
6 * Copyright 2000-2004 MontaVista Software Inc.
7 *
8 * Cleaned up and converted to new DCR access
9 * Matt Porter <mporter@kernel.crashing.org>
10 *
11 * Original code by Armin Kuster <akuster@mvista.com>
12 * and Pete Popov <ppopov@mvista.com>
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <linux/config.h>
25#include <linux/kernel.h>
26#include <linux/mm.h>
27#include <linux/miscdevice.h>
28#include <linux/init.h>
29#include <linux/module.h>
30
31#include <asm/system.h>
32#include <asm/io.h>
33#include <asm/ppc4xx_dma.h>
34
35ppc_dma_ch_t dma_channels[MAX_PPC4xx_DMA_CHANNELS];
36
37int
38ppc4xx_get_dma_status(void)
39{
40 return (mfdcr(DCRN_DMASR));
41}
42
43void
44ppc4xx_set_src_addr(int dmanr, phys_addr_t src_addr)
45{
46 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
47 printk("set_src_addr: bad channel: %d\n", dmanr);
48 return;
49 }
50
51#ifdef PPC4xx_DMA_64BIT
52 mtdcr(DCRN_DMASAH0 + dmanr*2, (u32)(src_addr >> 32));
53#else
54 mtdcr(DCRN_DMASA0 + dmanr*2, (u32)src_addr);
55#endif
56}
57
58void
59ppc4xx_set_dst_addr(int dmanr, phys_addr_t dst_addr)
60{
61 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
62 printk("set_dst_addr: bad channel: %d\n", dmanr);
63 return;
64 }
65
66#ifdef PPC4xx_DMA_64BIT
67 mtdcr(DCRN_DMADAH0 + dmanr*2, (u32)(dst_addr >> 32));
68#else
69 mtdcr(DCRN_DMADA0 + dmanr*2, (u32)dst_addr);
70#endif
71}
72
73void
74ppc4xx_enable_dma(unsigned int dmanr)
75{
76 unsigned int control;
77 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
78 unsigned int status_bits[] = { DMA_CS0 | DMA_TS0 | DMA_CH0_ERR,
79 DMA_CS1 | DMA_TS1 | DMA_CH1_ERR,
80 DMA_CS2 | DMA_TS2 | DMA_CH2_ERR,
81 DMA_CS3 | DMA_TS3 | DMA_CH3_ERR};
82
83 if (p_dma_ch->in_use) {
84 printk("enable_dma: channel %d in use\n", dmanr);
85 return;
86 }
87
88 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
89 printk("enable_dma: bad channel: %d\n", dmanr);
90 return;
91 }
92
93 if (p_dma_ch->mode == DMA_MODE_READ) {
94 /* peripheral to memory */
95 ppc4xx_set_src_addr(dmanr, 0);
96 ppc4xx_set_dst_addr(dmanr, p_dma_ch->addr);
97 } else if (p_dma_ch->mode == DMA_MODE_WRITE) {
98 /* memory to peripheral */
99 ppc4xx_set_src_addr(dmanr, p_dma_ch->addr);
100 ppc4xx_set_dst_addr(dmanr, 0);
101 }
102
103 /* for other xfer modes, the addresses are already set */
104 control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
105
106 control &= ~(DMA_TM_MASK | DMA_TD); /* clear all mode bits */
107 if (p_dma_ch->mode == DMA_MODE_MM) {
108 /* software initiated memory to memory */
109 control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;
110 }
111
112 mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
113
114 /*
115 * Clear the CS, TS, RI bits for the channel from DMASR. This
116 * has been observed to happen correctly only after the mode and
117 * ETD/DCE bits in DMACRx are set above. Must do this before
118 * enabling the channel.
119 */
120
121 mtdcr(DCRN_DMASR, status_bits[dmanr]);
122
123 /*
124 * For device-paced transfers, Terminal Count Enable apparently
125 * must be on, and this must be turned on after the mode, etc.
126 * bits are cleared above (at least on Redwood-6).
127 */
128
129 if ((p_dma_ch->mode == DMA_MODE_MM_DEVATDST) ||
130 (p_dma_ch->mode == DMA_MODE_MM_DEVATSRC))
131 control |= DMA_TCE_ENABLE;
132
133 /*
134 * Now enable the channel.
135 */
136
137 control |= (p_dma_ch->mode | DMA_CE_ENABLE);
138
139 mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
140
141 p_dma_ch->in_use = 1;
142}
143
144void
145ppc4xx_disable_dma(unsigned int dmanr)
146{
147 unsigned int control;
148 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
149
150 if (!p_dma_ch->in_use) {
151 printk("disable_dma: channel %d not in use\n", dmanr);
152 return;
153 }
154
155 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
156 printk("disable_dma: bad channel: %d\n", dmanr);
157 return;
158 }
159
160 control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
161 control &= ~DMA_CE_ENABLE;
162 mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
163
164 p_dma_ch->in_use = 0;
165}
166
167/*
168 * Sets the dma mode for single DMA transfers only.
169 * For scatter/gather transfers, the mode is passed to the
170 * alloc_dma_handle() function as one of the parameters.
171 *
172 * The mode is simply saved and used later. This allows
173 * the driver to call set_dma_mode() and set_dma_addr() in
174 * any order.
175 *
176 * Valid mode values are:
177 *
178 * DMA_MODE_READ peripheral to memory
179 * DMA_MODE_WRITE memory to peripheral
180 * DMA_MODE_MM memory to memory
181 * DMA_MODE_MM_DEVATSRC device-paced memory to memory, device at src
182 * DMA_MODE_MM_DEVATDST device-paced memory to memory, device at dst
183 */
184int
185ppc4xx_set_dma_mode(unsigned int dmanr, unsigned int mode)
186{
187 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
188
189 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
190 printk("set_dma_mode: bad channel 0x%x\n", dmanr);
191 return DMA_STATUS_BAD_CHANNEL;
192 }
193
194 p_dma_ch->mode = mode;
195
196 return DMA_STATUS_GOOD;
197}
198
199/*
200 * Sets the DMA Count register. Note that 'count' is in bytes.
201 * However, the DMA Count register counts the number of "transfers",
202 * where each transfer is equal to the bus width. Thus, count
203 * MUST be a multiple of the bus width.
204 */
205void
206ppc4xx_set_dma_count(unsigned int dmanr, unsigned int count)
207{
208 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
209
210#ifdef DEBUG_4xxDMA
211 {
212 int error = 0;
213 switch (p_dma_ch->pwidth) {
214 case PW_8:
215 break;
216 case PW_16:
217 if (count & 0x1)
218 error = 1;
219 break;
220 case PW_32:
221 if (count & 0x3)
222 error = 1;
223 break;
224 case PW_64:
225 if (count & 0x7)
226 error = 1;
227 break;
228 default:
229 printk("set_dma_count: invalid bus width: 0x%x\n",
230 p_dma_ch->pwidth);
231 return;
232 }
233 if (error)
234 printk
235 ("Warning: set_dma_count count 0x%x bus width %d\n",
236 count, p_dma_ch->pwidth);
237 }
238#endif
239
240 count = count >> p_dma_ch->shift;
241
242 mtdcr(DCRN_DMACT0 + (dmanr * 0x8), count);
243}
244
245/*
246 * Returns the number of bytes left to be transfered.
247 * After a DMA transfer, this should return zero.
248 * Reading this while a DMA transfer is still in progress will return
249 * unpredictable results.
250 */
251int
252ppc4xx_get_dma_residue(unsigned int dmanr)
253{
254 unsigned int count;
255 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
256
257 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
258 printk("ppc4xx_get_dma_residue: bad channel 0x%x\n", dmanr);
259 return DMA_STATUS_BAD_CHANNEL;
260 }
261
262 count = mfdcr(DCRN_DMACT0 + (dmanr * 0x8));
263
264 return (count << p_dma_ch->shift);
265}
266
267/*
268 * Sets the DMA address for a memory to peripheral or peripheral
269 * to memory transfer. The address is just saved in the channel
270 * structure for now and used later in enable_dma().
271 */
272void
273ppc4xx_set_dma_addr(unsigned int dmanr, phys_addr_t addr)
274{
275 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
276
277 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
278 printk("ppc4xx_set_dma_addr: bad channel: %d\n", dmanr);
279 return;
280 }
281
282#ifdef DEBUG_4xxDMA
283 {
284 int error = 0;
285 switch (p_dma_ch->pwidth) {
286 case PW_8:
287 break;
288 case PW_16:
289 if ((unsigned) addr & 0x1)
290 error = 1;
291 break;
292 case PW_32:
293 if ((unsigned) addr & 0x3)
294 error = 1;
295 break;
296 case PW_64:
297 if ((unsigned) addr & 0x7)
298 error = 1;
299 break;
300 default:
301 printk("ppc4xx_set_dma_addr: invalid bus width: 0x%x\n",
302 p_dma_ch->pwidth);
303 return;
304 }
305 if (error)
306 printk("Warning: ppc4xx_set_dma_addr addr 0x%x bus width %d\n",
307 addr, p_dma_ch->pwidth);
308 }
309#endif
310
311 /* save dma address and program it later after we know the xfer mode */
312 p_dma_ch->addr = addr;
313}
314
315/*
316 * Sets both DMA addresses for a memory to memory transfer.
317 * For memory to peripheral or peripheral to memory transfers
318 * the function set_dma_addr() should be used instead.
319 */
320void
321ppc4xx_set_dma_addr2(unsigned int dmanr, phys_addr_t src_dma_addr,
322 phys_addr_t dst_dma_addr)
323{
324 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
325 printk("ppc4xx_set_dma_addr2: bad channel: %d\n", dmanr);
326 return;
327 }
328
329#ifdef DEBUG_4xxDMA
330 {
331 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
332 int error = 0;
333 switch (p_dma_ch->pwidth) {
334 case PW_8:
335 break;
336 case PW_16:
337 if (((unsigned) src_dma_addr & 0x1) ||
338 ((unsigned) dst_dma_addr & 0x1)
339 )
340 error = 1;
341 break;
342 case PW_32:
343 if (((unsigned) src_dma_addr & 0x3) ||
344 ((unsigned) dst_dma_addr & 0x3)
345 )
346 error = 1;
347 break;
348 case PW_64:
349 if (((unsigned) src_dma_addr & 0x7) ||
350 ((unsigned) dst_dma_addr & 0x7)
351 )
352 error = 1;
353 break;
354 default:
355 printk("ppc4xx_set_dma_addr2: invalid bus width: 0x%x\n",
356 p_dma_ch->pwidth);
357 return;
358 }
359 if (error)
360 printk
361 ("Warning: ppc4xx_set_dma_addr2 src 0x%x dst 0x%x bus width %d\n",
362 src_dma_addr, dst_dma_addr, p_dma_ch->pwidth);
363 }
364#endif
365
366 ppc4xx_set_src_addr(dmanr, src_dma_addr);
367 ppc4xx_set_dst_addr(dmanr, dst_dma_addr);
368}
369
370/*
371 * Enables the channel interrupt.
372 *
373 * If performing a scatter/gatter transfer, this function
374 * MUST be called before calling alloc_dma_handle() and building
375 * the sgl list. Otherwise, interrupts will not be enabled, if
376 * they were previously disabled.
377 */
378int
379ppc4xx_enable_dma_interrupt(unsigned int dmanr)
380{
381 unsigned int control;
382 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
383
384 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
385 printk("ppc4xx_enable_dma_interrupt: bad channel: %d\n", dmanr);
386 return DMA_STATUS_BAD_CHANNEL;
387 }
388
389 p_dma_ch->int_enable = 1;
390
391 control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
392 control |= DMA_CIE_ENABLE; /* Channel Interrupt Enable */
393 mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
394
395 return DMA_STATUS_GOOD;
396}
397
398/*
399 * Disables the channel interrupt.
400 *
401 * If performing a scatter/gatter transfer, this function
402 * MUST be called before calling alloc_dma_handle() and building
403 * the sgl list. Otherwise, interrupts will not be disabled, if
404 * they were previously enabled.
405 */
406int
407ppc4xx_disable_dma_interrupt(unsigned int dmanr)
408{
409 unsigned int control;
410 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
411
412 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
413 printk("ppc4xx_disable_dma_interrupt: bad channel: %d\n", dmanr);
414 return DMA_STATUS_BAD_CHANNEL;
415 }
416
417 p_dma_ch->int_enable = 0;
418
419 control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
420 control &= ~DMA_CIE_ENABLE; /* Channel Interrupt Enable */
421 mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
422
423 return DMA_STATUS_GOOD;
424}
425
426/*
427 * Configures a DMA channel, including the peripheral bus width, if a
428 * peripheral is attached to the channel, the polarity of the DMAReq and
429 * DMAAck signals, etc. This information should really be setup by the boot
430 * code, since most likely the configuration won't change dynamically.
431 * If the kernel has to call this function, it's recommended that it's
432 * called from platform specific init code. The driver should not need to
433 * call this function.
434 */
435int
436ppc4xx_init_dma_channel(unsigned int dmanr, ppc_dma_ch_t * p_init)
437{
438 unsigned int polarity;
439 uint32_t control = 0;
440 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
441
442 DMA_MODE_READ = (unsigned long) DMA_TD; /* Peripheral to Memory */
443 DMA_MODE_WRITE = 0; /* Memory to Peripheral */
444
445 if (!p_init) {
446 printk("ppc4xx_init_dma_channel: NULL p_init\n");
447 return DMA_STATUS_NULL_POINTER;
448 }
449
450 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
451 printk("ppc4xx_init_dma_channel: bad channel %d\n", dmanr);
452 return DMA_STATUS_BAD_CHANNEL;
453 }
454
455#if DCRN_POL > 0
456 polarity = mfdcr(DCRN_POL);
457#else
458 polarity = 0;
459#endif
460
461 /* Setup the control register based on the values passed to
462 * us in p_init. Then, over-write the control register with this
463 * new value.
464 */
465 control |= SET_DMA_CONTROL;
466
467 /* clear all polarity signals and then "or" in new signal levels */
468 polarity &= ~GET_DMA_POLARITY(dmanr);
469 polarity |= p_init->polarity;
470#if DCRN_POL > 0
471 mtdcr(DCRN_POL, polarity);
472#endif
473 mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
474
475 /* save these values in our dma channel structure */
476 memcpy(p_dma_ch, p_init, sizeof (ppc_dma_ch_t));
477
478 /*
479 * The peripheral width values written in the control register are:
480 * PW_8 0
481 * PW_16 1
482 * PW_32 2
483 * PW_64 3
484 *
485 * Since the DMA count register takes the number of "transfers",
486 * we need to divide the count sent to us in certain
487 * functions by the appropriate number. It so happens that our
488 * right shift value is equal to the peripheral width value.
489 */
490 p_dma_ch->shift = p_init->pwidth;
491
492 /*
493 * Save the control word for easy access.
494 */
495 p_dma_ch->control = control;
496
497 mtdcr(DCRN_DMASR, 0xffffffff); /* clear status register */
498 return DMA_STATUS_GOOD;
499}
500
501/*
502 * This function returns the channel configuration.
503 */
504int
505ppc4xx_get_channel_config(unsigned int dmanr, ppc_dma_ch_t * p_dma_ch)
506{
507 unsigned int polarity;
508 unsigned int control;
509
510 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
511 printk("ppc4xx_get_channel_config: bad channel %d\n", dmanr);
512 return DMA_STATUS_BAD_CHANNEL;
513 }
514
515 memcpy(p_dma_ch, &dma_channels[dmanr], sizeof (ppc_dma_ch_t));
516
517#if DCRN_POL > 0
518 polarity = mfdcr(DCRN_POL);
519#else
520 polarity = 0;
521#endif
522
523 p_dma_ch->polarity = polarity & GET_DMA_POLARITY(dmanr);
524 control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
525
526 p_dma_ch->cp = GET_DMA_PRIORITY(control);
527 p_dma_ch->pwidth = GET_DMA_PW(control);
528 p_dma_ch->psc = GET_DMA_PSC(control);
529 p_dma_ch->pwc = GET_DMA_PWC(control);
530 p_dma_ch->phc = GET_DMA_PHC(control);
531 p_dma_ch->ce = GET_DMA_CE_ENABLE(control);
532 p_dma_ch->int_enable = GET_DMA_CIE_ENABLE(control);
533 p_dma_ch->shift = GET_DMA_PW(control);
534
535#ifdef CONFIG_PPC4xx_EDMA
536 p_dma_ch->pf = GET_DMA_PREFETCH(control);
537#else
538 p_dma_ch->ch_enable = GET_DMA_CH(control);
539 p_dma_ch->ece_enable = GET_DMA_ECE(control);
540 p_dma_ch->tcd_disable = GET_DMA_TCD(control);
541#endif
542 return DMA_STATUS_GOOD;
543}
544
545/*
546 * Sets the priority for the DMA channel dmanr.
547 * Since this is setup by the hardware init function, this function
548 * can be used to dynamically change the priority of a channel.
549 *
550 * Acceptable priorities:
551 *
552 * PRIORITY_LOW
553 * PRIORITY_MID_LOW
554 * PRIORITY_MID_HIGH
555 * PRIORITY_HIGH
556 *
557 */
558int
559ppc4xx_set_channel_priority(unsigned int dmanr, unsigned int priority)
560{
561 unsigned int control;
562
563 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
564 printk("ppc4xx_set_channel_priority: bad channel %d\n", dmanr);
565 return DMA_STATUS_BAD_CHANNEL;
566 }
567
568 if ((priority != PRIORITY_LOW) &&
569 (priority != PRIORITY_MID_LOW) &&
570 (priority != PRIORITY_MID_HIGH) && (priority != PRIORITY_HIGH)) {
571 printk("ppc4xx_set_channel_priority: bad priority: 0x%x\n", priority);
572 }
573
574 control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
575 control |= SET_DMA_PRIORITY(priority);
576 mtdcr(DCRN_DMACR0 + (dmanr * 0x8), control);
577
578 return DMA_STATUS_GOOD;
579}
580
581/*
582 * Returns the width of the peripheral attached to this channel. This assumes
583 * that someone who knows the hardware configuration, boot code or some other
584 * init code, already set the width.
585 *
586 * The return value is one of:
587 * PW_8
588 * PW_16
589 * PW_32
590 * PW_64
591 *
592 * The function returns 0 on error.
593 */
594unsigned int
595ppc4xx_get_peripheral_width(unsigned int dmanr)
596{
597 unsigned int control;
598
599 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
600 printk("ppc4xx_get_peripheral_width: bad channel %d\n", dmanr);
601 return DMA_STATUS_BAD_CHANNEL;
602 }
603
604 control = mfdcr(DCRN_DMACR0 + (dmanr * 0x8));
605
606 return (GET_DMA_PW(control));
607}
608
609/*
610 * Clears the channel status bits
611 */
612int
613ppc4xx_clr_dma_status(unsigned int dmanr)
614{
615 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
616 printk(KERN_ERR "ppc4xx_clr_dma_status: bad channel: %d\n", dmanr);
617 return DMA_STATUS_BAD_CHANNEL;
618 }
619 mtdcr(DCRN_DMASR, ((u32)DMA_CH0_ERR | (u32)DMA_CS0 | (u32)DMA_TS0) >> dmanr);
620 return DMA_STATUS_GOOD;
621}
622
623/*
624 * Enables the burst on the channel (BTEN bit in the control/count register)
625 * Note:
626 * For scatter/gather dma, this function MUST be called before the
627 * ppc4xx_alloc_dma_handle() func as the chan count register is copied into the
628 * sgl list and used as each sgl element is added.
629 */
630int
631ppc4xx_enable_burst(unsigned int dmanr)
632{
633 unsigned int ctc;
634 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
635 printk(KERN_ERR "ppc4xx_enable_burst: bad channel: %d\n", dmanr);
636 return DMA_STATUS_BAD_CHANNEL;
637 }
638 ctc = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) | DMA_CTC_BTEN;
639 mtdcr(DCRN_DMACT0 + (dmanr * 0x8), ctc);
640 return DMA_STATUS_GOOD;
641}
642/*
643 * Disables the burst on the channel (BTEN bit in the control/count register)
644 * Note:
645 * For scatter/gather dma, this function MUST be called before the
646 * ppc4xx_alloc_dma_handle() func as the chan count register is copied into the
647 * sgl list and used as each sgl element is added.
648 */
649int
650ppc4xx_disable_burst(unsigned int dmanr)
651{
652 unsigned int ctc;
653 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
654 printk(KERN_ERR "ppc4xx_disable_burst: bad channel: %d\n", dmanr);
655 return DMA_STATUS_BAD_CHANNEL;
656 }
657 ctc = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) &~ DMA_CTC_BTEN;
658 mtdcr(DCRN_DMACT0 + (dmanr * 0x8), ctc);
659 return DMA_STATUS_GOOD;
660}
661/*
662 * Sets the burst size (number of peripheral widths) for the channel
663 * (BSIZ bits in the control/count register))
664 * must be one of:
665 * DMA_CTC_BSIZ_2
666 * DMA_CTC_BSIZ_4
667 * DMA_CTC_BSIZ_8
668 * DMA_CTC_BSIZ_16
669 * Note:
670 * For scatter/gather dma, this function MUST be called before the
671 * ppc4xx_alloc_dma_handle() func as the chan count register is copied into the
672 * sgl list and used as each sgl element is added.
673 */
674int
675ppc4xx_set_burst_size(unsigned int dmanr, unsigned int bsize)
676{
677 unsigned int ctc;
678 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
679 printk(KERN_ERR "ppc4xx_set_burst_size: bad channel: %d\n", dmanr);
680 return DMA_STATUS_BAD_CHANNEL;
681 }
682 ctc = mfdcr(DCRN_DMACT0 + (dmanr * 0x8)) &~ DMA_CTC_BSIZ_MSK;
683 ctc |= (bsize & DMA_CTC_BSIZ_MSK);
684 mtdcr(DCRN_DMACT0 + (dmanr * 0x8), ctc);
685 return DMA_STATUS_GOOD;
686}
687
688EXPORT_SYMBOL(ppc4xx_init_dma_channel);
689EXPORT_SYMBOL(ppc4xx_get_channel_config);
690EXPORT_SYMBOL(ppc4xx_set_channel_priority);
691EXPORT_SYMBOL(ppc4xx_get_peripheral_width);
692EXPORT_SYMBOL(dma_channels);
693EXPORT_SYMBOL(ppc4xx_set_src_addr);
694EXPORT_SYMBOL(ppc4xx_set_dst_addr);
695EXPORT_SYMBOL(ppc4xx_set_dma_addr);
696EXPORT_SYMBOL(ppc4xx_set_dma_addr2);
697EXPORT_SYMBOL(ppc4xx_enable_dma);
698EXPORT_SYMBOL(ppc4xx_disable_dma);
699EXPORT_SYMBOL(ppc4xx_set_dma_mode);
700EXPORT_SYMBOL(ppc4xx_set_dma_count);
701EXPORT_SYMBOL(ppc4xx_get_dma_residue);
702EXPORT_SYMBOL(ppc4xx_enable_dma_interrupt);
703EXPORT_SYMBOL(ppc4xx_disable_dma_interrupt);
704EXPORT_SYMBOL(ppc4xx_get_dma_status);
705EXPORT_SYMBOL(ppc4xx_clr_dma_status);
706EXPORT_SYMBOL(ppc4xx_enable_burst);
707EXPORT_SYMBOL(ppc4xx_disable_burst);
708EXPORT_SYMBOL(ppc4xx_set_burst_size);
diff --git a/arch/ppc/syslib/ppc4xx_kgdb.c b/arch/ppc/syslib/ppc4xx_kgdb.c
new file mode 100644
index 000000000000..fe8668bf8137
--- /dev/null
+++ b/arch/ppc/syslib/ppc4xx_kgdb.c
@@ -0,0 +1,124 @@
1#include <linux/config.h>
2#include <linux/types.h>
3#include <asm/ibm4xx.h>
4#include <linux/kernel.h>
5
6
7
8#define LSR_DR 0x01 /* Data ready */
9#define LSR_OE 0x02 /* Overrun */
10#define LSR_PE 0x04 /* Parity error */
11#define LSR_FE 0x08 /* Framing error */
12#define LSR_BI 0x10 /* Break */
13#define LSR_THRE 0x20 /* Xmit holding register empty */
14#define LSR_TEMT 0x40 /* Xmitter empty */
15#define LSR_ERR 0x80 /* Error */
16
17#include <platforms/4xx/ibm_ocp.h>
18
19extern struct NS16550* COM_PORTS[];
20#ifndef NULL
21#define NULL 0x00
22#endif
23
24static volatile struct NS16550 *kgdb_debugport = NULL;
25
26volatile struct NS16550 *
27NS16550_init(int chan)
28{
29 volatile struct NS16550 *com_port;
30 int quot;
31#ifdef BASE_BAUD
32 quot = BASE_BAUD / 9600;
33#else
34 quot = 0x000c; /* 0xc = 9600 baud (on a pc) */
35#endif
36
37 com_port = (struct NS16550 *) COM_PORTS[chan];
38
39 com_port->lcr = 0x00;
40 com_port->ier = 0xFF;
41 com_port->ier = 0x00;
42 com_port->lcr = com_port->lcr | 0x80; /* Access baud rate */
43 com_port->dll = ( quot & 0x00ff ); /* 0xc = 9600 baud */
44 com_port->dlm = ( quot & 0xff00 ) >> 8;
45 com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */
46 com_port->mcr = 0x00; /* RTS/DTR */
47 com_port->fcr = 0x07; /* Clear & enable FIFOs */
48
49 return( com_port );
50}
51
52
53void
54NS16550_putc(volatile struct NS16550 *com_port, unsigned char c)
55{
56 while ((com_port->lsr & LSR_THRE) == 0)
57 ;
58 com_port->thr = c;
59 return;
60}
61
62unsigned char
63NS16550_getc(volatile struct NS16550 *com_port)
64{
65 while ((com_port->lsr & LSR_DR) == 0)
66 ;
67 return (com_port->rbr);
68}
69
70unsigned char
71NS16550_tstc(volatile struct NS16550 *com_port)
72{
73 return ((com_port->lsr & LSR_DR) != 0);
74}
75
76
77#if defined(CONFIG_KGDB_TTYS0)
78#define KGDB_PORT 0
79#elif defined(CONFIG_KGDB_TTYS1)
80#define KGDB_PORT 1
81#elif defined(CONFIG_KGDB_TTYS2)
82#define KGDB_PORT 2
83#elif defined(CONFIG_KGDB_TTYS3)
84#define KGDB_PORT 3
85#else
86#error "invalid kgdb_tty port"
87#endif
88
89void putDebugChar( unsigned char c )
90{
91 if ( kgdb_debugport == NULL )
92 kgdb_debugport = NS16550_init(KGDB_PORT);
93 NS16550_putc( kgdb_debugport, c );
94}
95
96int getDebugChar( void )
97{
98 if (kgdb_debugport == NULL)
99 kgdb_debugport = NS16550_init(KGDB_PORT);
100
101 return(NS16550_getc(kgdb_debugport));
102}
103
104void kgdb_interruptible(int enable)
105{
106 return;
107}
108
109void putDebugString(char* str)
110{
111 while (*str != '\0') {
112 putDebugChar(*str);
113 str++;
114 }
115 putDebugChar('\r');
116 return;
117}
118
119void
120kgdb_map_scc(void)
121{
122 printk("kgdb init \n");
123 kgdb_debugport = NS16550_init(KGDB_PORT);
124}
diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c
new file mode 100644
index 000000000000..08f06dd17e7b
--- /dev/null
+++ b/arch/ppc/syslib/ppc4xx_pic.c
@@ -0,0 +1,244 @@
1/*
2 * arch/ppc/syslib/ppc4xx_pic.c
3 *
4 * Interrupt controller driver for PowerPC 4xx-based processors.
5 *
6 * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
7 * Copyright (c) 2004, 2005 Zultys Technologies
8 *
9 * Based on original code by
10 * Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
11 * Armin Custer <akuster@mvista.com>
12 *
13 * This program is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2 of the License, or (at your
16 * option) any later version.
17*/
18#include <linux/config.h>
19#include <linux/init.h>
20#include <linux/sched.h>
21#include <linux/signal.h>
22#include <linux/stddef.h>
23
24#include <asm/processor.h>
25#include <asm/system.h>
26#include <asm/irq.h>
27#include <asm/ppc4xx_pic.h>
28
29/* See comment in include/arch-ppc/ppc4xx_pic.h
30 * for more info about these two variables
31 */
32extern struct ppc4xx_uic_settings ppc4xx_core_uic_cfg[NR_UICS]
33 __attribute__ ((weak));
34extern unsigned char ppc4xx_uic_ext_irq_cfg[] __attribute__ ((weak));
35
36#define IRQ_MASK_UIC0(irq) (1 << (31 - (irq)))
37#define IRQ_MASK_UICx(irq) (1 << (31 - ((irq) & 0x1f)))
38#define IRQ_MASK_UIC1(irq) IRQ_MASK_UICx(irq)
39#define IRQ_MASK_UIC2(irq) IRQ_MASK_UICx(irq)
40
41#define UIC_HANDLERS(n) \
42static void ppc4xx_uic##n##_enable(unsigned int irq) \
43{ \
44 ppc_cached_irq_mask[n] |= IRQ_MASK_UIC##n(irq); \
45 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
46} \
47 \
48static void ppc4xx_uic##n##_disable(unsigned int irq) \
49{ \
50 ppc_cached_irq_mask[n] &= ~IRQ_MASK_UIC##n(irq); \
51 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
52 ACK_UIC##n##_PARENT \
53} \
54 \
55static void ppc4xx_uic##n##_ack(unsigned int irq) \
56{ \
57 u32 mask = IRQ_MASK_UIC##n(irq); \
58 ppc_cached_irq_mask[n] &= ~mask; \
59 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
60 mtdcr(DCRN_UIC_SR(UIC##n), mask); \
61 ACK_UIC##n##_PARENT \
62} \
63 \
64static void ppc4xx_uic##n##_end(unsigned int irq) \
65{ \
66 unsigned int status = irq_desc[irq].status; \
67 u32 mask = IRQ_MASK_UIC##n(irq); \
68 if (status & IRQ_LEVEL) { \
69 mtdcr(DCRN_UIC_SR(UIC##n), mask); \
70 ACK_UIC##n##_PARENT \
71 } \
72 if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { \
73 ppc_cached_irq_mask[n] |= mask; \
74 mtdcr(DCRN_UIC_ER(UIC##n), ppc_cached_irq_mask[n]); \
75 } \
76}
77
78#define DECLARE_UIC(n) \
79{ \
80 .typename = "UIC"#n, \
81 .enable = ppc4xx_uic##n##_enable, \
82 .disable = ppc4xx_uic##n##_disable, \
83 .ack = ppc4xx_uic##n##_ack, \
84 .end = ppc4xx_uic##n##_end, \
85} \
86
87#if NR_UICS == 3
88#define ACK_UIC0_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC0NC);
89#define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC1NC);
90#define ACK_UIC2_PARENT mtdcr(DCRN_UIC_SR(UICB), UICB_UIC2NC);
91UIC_HANDLERS(0);
92UIC_HANDLERS(1);
93UIC_HANDLERS(2);
94
95static int ppc4xx_pic_get_irq(struct pt_regs *regs)
96{
97 u32 uicb = mfdcr(DCRN_UIC_MSR(UICB));
98 if (uicb & UICB_UIC0NC)
99 return 32 - ffs(mfdcr(DCRN_UIC_MSR(UIC0)));
100 else if (uicb & UICB_UIC1NC)
101 return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
102 else if (uicb & UICB_UIC2NC)
103 return 96 - ffs(mfdcr(DCRN_UIC_MSR(UIC2)));
104 else
105 return -1;
106}
107
108static void __init ppc4xx_pic_impl_init(void)
109{
110 /* Configure Base UIC */
111 mtdcr(DCRN_UIC_CR(UICB), 0);
112 mtdcr(DCRN_UIC_TR(UICB), 0);
113 mtdcr(DCRN_UIC_PR(UICB), 0xffffffff);
114 mtdcr(DCRN_UIC_SR(UICB), 0xffffffff);
115 mtdcr(DCRN_UIC_ER(UICB), UICB_UIC0NC | UICB_UIC1NC | UICB_UIC2NC);
116}
117
118#elif NR_UICS == 2
119#define ACK_UIC0_PARENT
120#define ACK_UIC1_PARENT mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
121UIC_HANDLERS(0);
122UIC_HANDLERS(1);
123
124static int ppc4xx_pic_get_irq(struct pt_regs *regs)
125{
126 u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
127 if (uic0 & UIC0_UIC1NC)
128 return 64 - ffs(mfdcr(DCRN_UIC_MSR(UIC1)));
129 else
130 return uic0 ? 32 - ffs(uic0) : -1;
131}
132
133static void __init ppc4xx_pic_impl_init(void)
134{
135 /* Enable cascade interrupt in UIC0 */
136 ppc_cached_irq_mask[0] |= UIC0_UIC1NC;
137 mtdcr(DCRN_UIC_SR(UIC0), UIC0_UIC1NC);
138 mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
139}
140
141#elif NR_UICS == 1
142#define ACK_UIC0_PARENT
143UIC_HANDLERS(0);
144
145static int ppc4xx_pic_get_irq(struct pt_regs *regs)
146{
147 u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
148 return uic0 ? 32 - ffs(uic0) : -1;
149}
150
151static inline void ppc4xx_pic_impl_init(void)
152{
153}
154#endif
155
156static struct ppc4xx_uic_impl {
157 struct hw_interrupt_type decl;
158 int base; /* Base DCR number */
159} __uic[] = {
160 { .decl = DECLARE_UIC(0), .base = UIC0 },
161#if NR_UICS > 1
162 { .decl = DECLARE_UIC(1), .base = UIC1 },
163#if NR_UICS > 2
164 { .decl = DECLARE_UIC(2), .base = UIC2 },
165#endif
166#endif
167};
168
169static inline int is_level_sensitive(int irq)
170{
171 u32 tr = mfdcr(DCRN_UIC_TR(__uic[irq >> 5].base));
172 return (tr & IRQ_MASK_UICx(irq)) == 0;
173}
174
175void __init ppc4xx_pic_init(void)
176{
177 int i;
178 unsigned char *eirqs = ppc4xx_uic_ext_irq_cfg;
179
180 for (i = 0; i < NR_UICS; ++i) {
181 int base = __uic[i].base;
182
183 /* Disable everything by default */
184 ppc_cached_irq_mask[i] = 0;
185 mtdcr(DCRN_UIC_ER(base), 0);
186
187 /* We don't use critical interrupts */
188 mtdcr(DCRN_UIC_CR(base), 0);
189
190 /* Configure polarity and triggering */
191 if (ppc4xx_core_uic_cfg) {
192 struct ppc4xx_uic_settings *p = ppc4xx_core_uic_cfg + i;
193 u32 mask = p->ext_irq_mask;
194 u32 pr = mfdcr(DCRN_UIC_PR(base)) & mask;
195 u32 tr = mfdcr(DCRN_UIC_TR(base)) & mask;
196
197 /* "Fixed" interrupts (on-chip devices) */
198 pr |= p->polarity & ~mask;
199 tr |= p->triggering & ~mask;
200
201 /* Merge external IRQs settings if board port
202 * provided them
203 */
204 if (eirqs && mask) {
205 pr &= ~mask;
206 tr &= ~mask;
207 while (mask) {
208 /* Extract current external IRQ mask */
209 u32 eirq_mask = 1 << __ilog2(mask);
210
211 if (!(*eirqs & IRQ_SENSE_LEVEL))
212 tr |= eirq_mask;
213
214 if (*eirqs & IRQ_POLARITY_POSITIVE)
215 pr |= eirq_mask;
216
217 mask &= ~eirq_mask;
218 ++eirqs;
219 }
220 }
221 mtdcr(DCRN_UIC_PR(base), pr);
222 mtdcr(DCRN_UIC_TR(base), tr);
223 }
224
225 /* ACK any pending interrupts to prevent false
226 * triggering after first enable
227 */
228 mtdcr(DCRN_UIC_SR(base), 0xffffffff);
229 }
230
231 /* Perform optional implementation specific setup
232 * (e.g. enable cascade interrupts for multi-UIC configurations)
233 */
234 ppc4xx_pic_impl_init();
235
236 /* Attach low-level handlers */
237 for (i = 0; i < (NR_UICS << 5); ++i) {
238 irq_desc[i].handler = &__uic[i >> 5].decl;
239 if (is_level_sensitive(i))
240 irq_desc[i].status |= IRQ_LEVEL;
241 }
242
243 ppc_md.get_irq = ppc4xx_pic_get_irq;
244}
diff --git a/arch/ppc/syslib/ppc4xx_pm.c b/arch/ppc/syslib/ppc4xx_pm.c
new file mode 100644
index 000000000000..60a479204885
--- /dev/null
+++ b/arch/ppc/syslib/ppc4xx_pm.c
@@ -0,0 +1,47 @@
1/*
2 * Author: Armin Kuster <akuster@mvista.com>
3 *
4 * 2002 (c) MontaVista, Software, Inc. This file is licensed under
5 * the terms of the GNU General Public License version 2. This program
6 * is licensed "as is" without any warranty of any kind, whether express
7 * or implied.
8 *
9 * This an attempt to get Power Management going for the IBM 4xx processor.
10 * This was derived from the ppc4xx._setup.c file
11 */
12
13#include <linux/config.h>
14#include <linux/init.h>
15
16#include <asm/ibm4xx.h>
17
18void __init
19ppc4xx_pm_init(void)
20{
21
22 unsigned int value = 0;
23
24 /* turn off unused hardware to save power */
25#ifdef CONFIG_405GP
26 value |= CPM_DCP; /* CodePack */
27#endif
28
29#if !defined(CONFIG_IBM_OCP_GPIO)
30 value |= CPM_GPIO0;
31#endif
32
33#if !defined(CONFIG_PPC405_I2C_ADAP)
34 value |= CPM_IIC0;
35#ifdef CONFIG_STB03xxx
36 value |= CPM_IIC1;
37#endif
38#endif
39
40
41#if !defined(CONFIG_405_DMA)
42 value |= CPM_DMA;
43#endif
44
45 mtdcr(DCRN_CPMFR, value);
46
47}
diff --git a/arch/ppc/syslib/ppc4xx_setup.c b/arch/ppc/syslib/ppc4xx_setup.c
new file mode 100644
index 000000000000..e170aebeb69b
--- /dev/null
+++ b/arch/ppc/syslib/ppc4xx_setup.c
@@ -0,0 +1,321 @@
1/*
2 *
3 * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
4 *
5 * Copyright 2000-2001 MontaVista Software Inc.
6 * Completed implementation.
7 * Author: MontaVista Software, Inc. <source@mvista.com>
8 * Frank Rowand <frank_rowand@mvista.com>
9 * Debbie Chu <debbie_chu@mvista.com>
10 * Further modifications by Armin Kuster
11 *
12 * Module name: ppc4xx_setup.c
13 *
14 */
15
16#include <linux/config.h>
17#include <linux/init.h>
18#include <linux/smp.h>
19#include <linux/threads.h>
20#include <linux/spinlock.h>
21#include <linux/irq.h>
22#include <linux/reboot.h>
23#include <linux/param.h>
24#include <linux/string.h>
25#include <linux/initrd.h>
26#include <linux/pci.h>
27#include <linux/rtc.h>
28#include <linux/console.h>
29#include <linux/ide.h>
30#include <linux/serial_reg.h>
31#include <linux/seq_file.h>
32
33#include <asm/system.h>
34#include <asm/processor.h>
35#include <asm/machdep.h>
36#include <asm/page.h>
37#include <asm/kgdb.h>
38#include <asm/ibm4xx.h>
39#include <asm/time.h>
40#include <asm/todc.h>
41#include <asm/ppc4xx_pic.h>
42#include <asm/pci-bridge.h>
43#include <asm/bootinfo.h>
44
45#include <syslib/gen550.h>
46
47/* Function Prototypes */
48extern void abort(void);
49extern void ppc4xx_find_bridges(void);
50
51extern void ppc4xx_wdt_heartbeat(void);
52extern int wdt_enable;
53extern unsigned long wdt_period;
54
55/* Global Variables */
56bd_t __res;
57
58void __init
59ppc4xx_setup_arch(void)
60{
61#if !defined(CONFIG_BDI_SWITCH)
62 /*
63 * The Abatron BDI JTAG debugger does not tolerate others
64 * mucking with the debug registers.
65 */
66 mtspr(SPRN_DBCR0, (DBCR0_IDM));
67 mtspr(SPRN_DBSR, 0xffffffff);
68#endif
69
70 /* Setup PCI host bridges */
71#ifdef CONFIG_PCI
72 ppc4xx_find_bridges();
73#endif
74}
75
76/*
77 * This routine pretty-prints the platform's internal CPU clock
78 * frequencies into the buffer for usage in /proc/cpuinfo.
79 */
80
81static int
82ppc4xx_show_percpuinfo(struct seq_file *m, int i)
83{
84 seq_printf(m, "clock\t\t: %ldMHz\n", (long)__res.bi_intfreq / 1000000);
85
86 return 0;
87}
88
89/*
90 * This routine pretty-prints the platform's internal bus clock
91 * frequencies into the buffer for usage in /proc/cpuinfo.
92 */
93static int
94ppc4xx_show_cpuinfo(struct seq_file *m)
95{
96 bd_t *bip = &__res;
97
98 seq_printf(m, "machine\t\t: %s\n", PPC4xx_MACHINE_NAME);
99 seq_printf(m, "plb bus clock\t: %ldMHz\n",
100 (long) bip->bi_busfreq / 1000000);
101#ifdef CONFIG_PCI
102 seq_printf(m, "pci bus clock\t: %dMHz\n",
103 bip->bi_pci_busfreq / 1000000);
104#endif
105
106 return 0;
107}
108
109/*
110 * Return the virtual address representing the top of physical RAM.
111 */
112static unsigned long __init
113ppc4xx_find_end_of_memory(void)
114{
115 return ((unsigned long) __res.bi_memsize);
116}
117
118void __init
119ppc4xx_map_io(void)
120{
121 io_block_mapping(PPC4xx_ONB_IO_VADDR,
122 PPC4xx_ONB_IO_PADDR, PPC4xx_ONB_IO_SIZE, _PAGE_IO);
123#ifdef CONFIG_PCI
124 io_block_mapping(PPC4xx_PCI_IO_VADDR,
125 PPC4xx_PCI_IO_PADDR, PPC4xx_PCI_IO_SIZE, _PAGE_IO);
126 io_block_mapping(PPC4xx_PCI_CFG_VADDR,
127 PPC4xx_PCI_CFG_PADDR, PPC4xx_PCI_CFG_SIZE, _PAGE_IO);
128 io_block_mapping(PPC4xx_PCI_LCFG_VADDR,
129 PPC4xx_PCI_LCFG_PADDR, PPC4xx_PCI_LCFG_SIZE, _PAGE_IO);
130#endif
131}
132
133void __init
134ppc4xx_init_IRQ(void)
135{
136 ppc4xx_pic_init();
137}
138
139static void
140ppc4xx_restart(char *cmd)
141{
142 printk("%s\n", cmd);
143 abort();
144}
145
146static void
147ppc4xx_power_off(void)
148{
149 printk("System Halted\n");
150 local_irq_disable();
151 while (1) ;
152}
153
154static void
155ppc4xx_halt(void)
156{
157 printk("System Halted\n");
158 local_irq_disable();
159 while (1) ;
160}
161
162/*
163 * This routine retrieves the internal processor frequency from the board
164 * information structure, sets up the kernel timer decrementer based on
165 * that value, enables the 4xx programmable interval timer (PIT) and sets
166 * it up for auto-reload.
167 */
168static void __init
169ppc4xx_calibrate_decr(void)
170{
171 unsigned int freq;
172 bd_t *bip = &__res;
173
174#if defined(CONFIG_WALNUT) || defined(CONFIG_ASH) || defined(CONFIG_SYCAMORE)
175 /* Walnut boot rom sets DCR CHCR1 (aka CPC0_CR1) bit CETE to 1 */
176 mtdcr(DCRN_CHCR1, mfdcr(DCRN_CHCR1) & ~CHR1_CETE);
177#endif
178 freq = bip->bi_tbfreq;
179 tb_ticks_per_jiffy = freq / HZ;
180 tb_to_us = mulhwu_scale_factor(freq, 1000000);
181
182 /* Set the time base to zero.
183 ** At 200 Mhz, time base will rollover in ~2925 years.
184 */
185
186 mtspr(SPRN_TBWL, 0);
187 mtspr(SPRN_TBWU, 0);
188
189 /* Clear any pending timer interrupts */
190
191 mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
192 mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
193
194 /* Set the PIT reload value and just let it run. */
195 mtspr(SPRN_PIT, tb_ticks_per_jiffy);
196}
197
198/*
199 * IDE stuff.
200 * should be generic for every IDE PCI chipset
201 */
202#if defined(CONFIG_PCI) && defined(CONFIG_IDE)
203static void
204ppc4xx_ide_init_hwif_ports(hw_regs_t * hw, unsigned long data_port,
205 unsigned long ctrl_port, int *irq)
206{
207 int i;
208
209 for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
210 hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
211
212 hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
213}
214#endif /* defined(CONFIG_PCI) && defined(CONFIG_IDE) */
215
216TODC_ALLOC();
217
218/*
219 * Input(s):
220 * r3 - Optional pointer to a board information structure.
221 * r4 - Optional pointer to the physical starting address of the init RAM
222 * disk.
223 * r5 - Optional pointer to the physical ending address of the init RAM
224 * disk.
225 * r6 - Optional pointer to the physical starting address of any kernel
226 * command-line parameters.
227 * r7 - Optional pointer to the physical ending address of any kernel
228 * command-line parameters.
229 */
230void __init
231ppc4xx_init(unsigned long r3, unsigned long r4, unsigned long r5,
232 unsigned long r6, unsigned long r7)
233{
234 parse_bootinfo(find_bootinfo());
235
236 /*
237 * If we were passed in a board information, copy it into the
238 * residual data area.
239 */
240 if (r3)
241 __res = *(bd_t *)(r3 + KERNELBASE);
242
243#if defined(CONFIG_BLK_DEV_INITRD)
244 /*
245 * If the init RAM disk has been configured in, and there's a valid
246 * starting address for it, set it up.
247 */
248 if (r4) {
249 initrd_start = r4 + KERNELBASE;
250 initrd_end = r5 + KERNELBASE;
251 }
252#endif /* CONFIG_BLK_DEV_INITRD */
253
254 /* Copy the kernel command line arguments to a safe place. */
255
256 if (r6) {
257 *(char *) (r7 + KERNELBASE) = 0;
258 strcpy(cmd_line, (char *) (r6 + KERNELBASE));
259 }
260#if defined(CONFIG_PPC405_WDT)
261/* Look for wdt= option on command line */
262 if (strstr(cmd_line, "wdt=")) {
263 int valid_wdt = 0;
264 char *p, *q;
265 for (q = cmd_line; (p = strstr(q, "wdt=")) != 0;) {
266 q = p + 4;
267 if (p > cmd_line && p[-1] != ' ')
268 continue;
269 wdt_period = simple_strtoul(q, &q, 0);
270 valid_wdt = 1;
271 ++q;
272 }
273 wdt_enable = valid_wdt;
274 }
275#endif
276
277 /* Initialize machine-dependent vectors */
278
279 ppc_md.setup_arch = ppc4xx_setup_arch;
280 ppc_md.show_percpuinfo = ppc4xx_show_percpuinfo;
281 ppc_md.show_cpuinfo = ppc4xx_show_cpuinfo;
282 ppc_md.init_IRQ = ppc4xx_init_IRQ;
283
284 ppc_md.restart = ppc4xx_restart;
285 ppc_md.power_off = ppc4xx_power_off;
286 ppc_md.halt = ppc4xx_halt;
287
288 ppc_md.calibrate_decr = ppc4xx_calibrate_decr;
289
290#ifdef CONFIG_PPC405_WDT
291 ppc_md.heartbeat = ppc4xx_wdt_heartbeat;
292#endif
293 ppc_md.heartbeat_count = 0;
294
295 ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory;
296 ppc_md.setup_io_mappings = ppc4xx_map_io;
297
298#ifdef CONFIG_SERIAL_TEXT_DEBUG
299 ppc_md.progress = gen550_progress;
300#endif
301
302#if defined(CONFIG_PCI) && defined(CONFIG_IDE)
303 ppc_ide_md.ide_init_hwif = ppc4xx_ide_init_hwif_ports;
304#endif /* defined(CONFIG_PCI) && defined(CONFIG_IDE) */
305}
306
307/* Called from MachineCheckException */
308void platform_machine_check(struct pt_regs *regs)
309{
310#if defined(DCRN_PLB0_BEAR)
311 printk("PLB0: BEAR= 0x%08x ACR= 0x%08x BESR= 0x%08x\n",
312 mfdcr(DCRN_PLB0_BEAR), mfdcr(DCRN_PLB0_ACR),
313 mfdcr(DCRN_PLB0_BESR));
314#endif
315#if defined(DCRN_POB0_BEAR)
316 printk("PLB0 to OPB: BEAR= 0x%08x BESR0= 0x%08x BESR1= 0x%08x\n",
317 mfdcr(DCRN_POB0_BEAR), mfdcr(DCRN_POB0_BESR0),
318 mfdcr(DCRN_POB0_BESR1));
319#endif
320
321}
diff --git a/arch/ppc/syslib/ppc4xx_sgdma.c b/arch/ppc/syslib/ppc4xx_sgdma.c
new file mode 100644
index 000000000000..9f76e8ee39ed
--- /dev/null
+++ b/arch/ppc/syslib/ppc4xx_sgdma.c
@@ -0,0 +1,467 @@
1/*
2 * arch/ppc/kernel/ppc4xx_sgdma.c
3 *
4 * IBM PPC4xx DMA engine scatter/gather library
5 *
6 * Copyright 2002-2003 MontaVista Software Inc.
7 *
8 * Cleaned up and converted to new DCR access
9 * Matt Porter <mporter@kernel.crashing.org>
10 *
11 * Original code by Armin Kuster <akuster@mvista.com>
12 * and Pete Popov <ppopov@mvista.com>
13 *
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24#include <linux/config.h>
25#include <linux/kernel.h>
26#include <linux/mm.h>
27#include <linux/init.h>
28#include <linux/module.h>
29#include <linux/pci.h>
30
31#include <asm/system.h>
32#include <asm/io.h>
33#include <asm/ppc4xx_dma.h>
34
35void
36ppc4xx_set_sg_addr(int dmanr, phys_addr_t sg_addr)
37{
38 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
39 printk("ppc4xx_set_sg_addr: bad channel: %d\n", dmanr);
40 return;
41 }
42
43#ifdef PPC4xx_DMA_64BIT
44 mtdcr(DCRN_ASGH0 + (dmanr * 0x8), (u32)(sg_addr >> 32));
45#endif
46 mtdcr(DCRN_ASG0 + (dmanr * 0x8), (u32)sg_addr);
47}
48
49/*
50 * Add a new sgl descriptor to the end of a scatter/gather list
51 * which was created by alloc_dma_handle().
52 *
53 * For a memory to memory transfer, both dma addresses must be
54 * valid. For a peripheral to memory transfer, one of the addresses
55 * must be set to NULL, depending on the direction of the transfer:
56 * memory to peripheral: set dst_addr to NULL,
57 * peripheral to memory: set src_addr to NULL.
58 */
59int
60ppc4xx_add_dma_sgl(sgl_handle_t handle, phys_addr_t src_addr, phys_addr_t dst_addr,
61 unsigned int count)
62{
63 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
64 ppc_dma_ch_t *p_dma_ch;
65
66 if (!handle) {
67 printk("ppc4xx_add_dma_sgl: null handle\n");
68 return DMA_STATUS_BAD_HANDLE;
69 }
70
71 if (psgl->dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
72 printk("ppc4xx_add_dma_sgl: bad channel: %d\n", psgl->dmanr);
73 return DMA_STATUS_BAD_CHANNEL;
74 }
75
76 p_dma_ch = &dma_channels[psgl->dmanr];
77
78#ifdef DEBUG_4xxDMA
79 {
80 int error = 0;
81 unsigned int aligned =
82 (unsigned) src_addr | (unsigned) dst_addr | count;
83 switch (p_dma_ch->pwidth) {
84 case PW_8:
85 break;
86 case PW_16:
87 if (aligned & 0x1)
88 error = 1;
89 break;
90 case PW_32:
91 if (aligned & 0x3)
92 error = 1;
93 break;
94 case PW_64:
95 if (aligned & 0x7)
96 error = 1;
97 break;
98 default:
99 printk("ppc4xx_add_dma_sgl: invalid bus width: 0x%x\n",
100 p_dma_ch->pwidth);
101 return DMA_STATUS_GENERAL_ERROR;
102 }
103 if (error)
104 printk
105 ("Alignment warning: ppc4xx_add_dma_sgl src 0x%x dst 0x%x count 0x%x bus width var %d\n",
106 src_addr, dst_addr, count, p_dma_ch->pwidth);
107
108 }
109#endif
110
111 if ((unsigned) (psgl->ptail + 1) >= ((unsigned) psgl + SGL_LIST_SIZE)) {
112 printk("sgl handle out of memory \n");
113 return DMA_STATUS_OUT_OF_MEMORY;
114 }
115
116 if (!psgl->ptail) {
117 psgl->phead = (ppc_sgl_t *)
118 ((unsigned) psgl + sizeof (sgl_list_info_t));
119 psgl->phead_dma = psgl->dma_addr + sizeof(sgl_list_info_t);
120 psgl->ptail = psgl->phead;
121 psgl->ptail_dma = psgl->phead_dma;
122 } else {
123 if(p_dma_ch->int_on_final_sg) {
124 /* mask out all dma interrupts, except error, on tail
125 before adding new tail. */
126 psgl->ptail->control_count &=
127 ~(SG_TCI_ENABLE | SG_ETI_ENABLE);
128 }
129 psgl->ptail->next = psgl->ptail_dma + sizeof(ppc_sgl_t);
130 psgl->ptail++;
131 psgl->ptail_dma += sizeof(ppc_sgl_t);
132 }
133
134 psgl->ptail->control = psgl->control;
135 psgl->ptail->src_addr = src_addr;
136 psgl->ptail->dst_addr = dst_addr;
137 psgl->ptail->control_count = (count >> p_dma_ch->shift) |
138 psgl->sgl_control;
139 psgl->ptail->next = (uint32_t) NULL;
140
141 return DMA_STATUS_GOOD;
142}
143
144/*
145 * Enable (start) the DMA described by the sgl handle.
146 */
147void
148ppc4xx_enable_dma_sgl(sgl_handle_t handle)
149{
150 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
151 ppc_dma_ch_t *p_dma_ch;
152 uint32_t sg_command;
153
154 if (!handle) {
155 printk("ppc4xx_enable_dma_sgl: null handle\n");
156 return;
157 } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
158 printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
159 psgl->dmanr);
160 return;
161 } else if (!psgl->phead) {
162 printk("ppc4xx_enable_dma_sgl: sg list empty\n");
163 return;
164 }
165
166 p_dma_ch = &dma_channels[psgl->dmanr];
167 psgl->ptail->control_count &= ~SG_LINK; /* make this the last dscrptr */
168 sg_command = mfdcr(DCRN_ASGC);
169
170 ppc4xx_set_sg_addr(psgl->dmanr, psgl->phead_dma);
171
172 sg_command |= SSG_ENABLE(psgl->dmanr);
173
174 mtdcr(DCRN_ASGC, sg_command); /* start transfer */
175}
176
177/*
178 * Halt an active scatter/gather DMA operation.
179 */
180void
181ppc4xx_disable_dma_sgl(sgl_handle_t handle)
182{
183 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
184 uint32_t sg_command;
185
186 if (!handle) {
187 printk("ppc4xx_enable_dma_sgl: null handle\n");
188 return;
189 } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
190 printk("ppc4xx_enable_dma_sgl: bad channel in handle %d\n",
191 psgl->dmanr);
192 return;
193 }
194
195 sg_command = mfdcr(DCRN_ASGC);
196 sg_command &= ~SSG_ENABLE(psgl->dmanr);
197 mtdcr(DCRN_ASGC, sg_command); /* stop transfer */
198}
199
200/*
201 * Returns number of bytes left to be transferred from the entire sgl list.
202 * *src_addr and *dst_addr get set to the source/destination address of
203 * the sgl descriptor where the DMA stopped.
204 *
205 * An sgl transfer must NOT be active when this function is called.
206 */
207int
208ppc4xx_get_dma_sgl_residue(sgl_handle_t handle, phys_addr_t * src_addr,
209 phys_addr_t * dst_addr)
210{
211 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
212 ppc_dma_ch_t *p_dma_ch;
213 ppc_sgl_t *pnext, *sgl_addr;
214 uint32_t count_left;
215
216 if (!handle) {
217 printk("ppc4xx_get_dma_sgl_residue: null handle\n");
218 return DMA_STATUS_BAD_HANDLE;
219 } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
220 printk("ppc4xx_get_dma_sgl_residue: bad channel in handle %d\n",
221 psgl->dmanr);
222 return DMA_STATUS_BAD_CHANNEL;
223 }
224
225 sgl_addr = (ppc_sgl_t *) __va(mfdcr(DCRN_ASG0 + (psgl->dmanr * 0x8)));
226 count_left = mfdcr(DCRN_DMACT0 + (psgl->dmanr * 0x8)) & SG_COUNT_MASK;
227
228 if (!sgl_addr) {
229 printk("ppc4xx_get_dma_sgl_residue: sgl addr register is null\n");
230 goto error;
231 }
232
233 pnext = psgl->phead;
234 while (pnext &&
235 ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE) &&
236 (pnext != sgl_addr))
237 ) {
238 pnext++;
239 }
240
241 if (pnext == sgl_addr) { /* found the sgl descriptor */
242
243 *src_addr = pnext->src_addr;
244 *dst_addr = pnext->dst_addr;
245
246 /*
247 * Now search the remaining descriptors and add their count.
248 * We already have the remaining count from this descriptor in
249 * count_left.
250 */
251 pnext++;
252
253 while ((pnext != psgl->ptail) &&
254 ((unsigned) pnext < ((unsigned) psgl + SGL_LIST_SIZE))
255 ) {
256 count_left += pnext->control_count & SG_COUNT_MASK;
257 }
258
259 if (pnext != psgl->ptail) { /* should never happen */
260 printk
261 ("ppc4xx_get_dma_sgl_residue error (1) psgl->ptail 0x%x handle 0x%x\n",
262 (unsigned int) psgl->ptail, (unsigned int) handle);
263 goto error;
264 }
265
266 /* success */
267 p_dma_ch = &dma_channels[psgl->dmanr];
268 return (count_left << p_dma_ch->shift); /* count in bytes */
269
270 } else {
271 /* this shouldn't happen */
272 printk
273 ("get_dma_sgl_residue, unable to match current address 0x%x, handle 0x%x\n",
274 (unsigned int) sgl_addr, (unsigned int) handle);
275
276 }
277
278 error:
279 *src_addr = (phys_addr_t) NULL;
280 *dst_addr = (phys_addr_t) NULL;
281 return 0;
282}
283
284/*
285 * Returns the address(es) of the buffer(s) contained in the head element of
286 * the scatter/gather list. The element is removed from the scatter/gather
287 * list and the next element becomes the head.
288 *
289 * This function should only be called when the DMA is not active.
290 */
291int
292ppc4xx_delete_dma_sgl_element(sgl_handle_t handle, phys_addr_t * src_dma_addr,
293 phys_addr_t * dst_dma_addr)
294{
295 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
296
297 if (!handle) {
298 printk("ppc4xx_delete_sgl_element: null handle\n");
299 return DMA_STATUS_BAD_HANDLE;
300 } else if (psgl->dmanr > (MAX_PPC4xx_DMA_CHANNELS - 1)) {
301 printk("ppc4xx_delete_sgl_element: bad channel in handle %d\n",
302 psgl->dmanr);
303 return DMA_STATUS_BAD_CHANNEL;
304 }
305
306 if (!psgl->phead) {
307 printk("ppc4xx_delete_sgl_element: sgl list empty\n");
308 *src_dma_addr = (phys_addr_t) NULL;
309 *dst_dma_addr = (phys_addr_t) NULL;
310 return DMA_STATUS_SGL_LIST_EMPTY;
311 }
312
313 *src_dma_addr = (phys_addr_t) psgl->phead->src_addr;
314 *dst_dma_addr = (phys_addr_t) psgl->phead->dst_addr;
315
316 if (psgl->phead == psgl->ptail) {
317 /* last descriptor on the list */
318 psgl->phead = NULL;
319 psgl->ptail = NULL;
320 } else {
321 psgl->phead++;
322 psgl->phead_dma += sizeof(ppc_sgl_t);
323 }
324
325 return DMA_STATUS_GOOD;
326}
327
328
329/*
330 * Create a scatter/gather list handle. This is simply a structure which
331 * describes a scatter/gather list.
332 *
333 * A handle is returned in "handle" which the driver should save in order to
334 * be able to access this list later. A chunk of memory will be allocated
335 * to be used by the API for internal management purposes, including managing
336 * the sg list and allocating memory for the sgl descriptors. One page should
337 * be more than enough for that purpose. Perhaps it's a bit wasteful to use
338 * a whole page for a single sg list, but most likely there will be only one
339 * sg list per channel.
340 *
341 * Interrupt notes:
342 * Each sgl descriptor has a copy of the DMA control word which the DMA engine
343 * loads in the control register. The control word has a "global" interrupt
344 * enable bit for that channel. Interrupts are further qualified by a few bits
345 * in the sgl descriptor count register. In order to setup an sgl, we have to
346 * know ahead of time whether or not interrupts will be enabled at the completion
347 * of the transfers. Thus, enable_dma_interrupt()/disable_dma_interrupt() MUST
348 * be called before calling alloc_dma_handle(). If the interrupt mode will never
349 * change after powerup, then enable_dma_interrupt()/disable_dma_interrupt()
350 * do not have to be called -- interrupts will be enabled or disabled based
351 * on how the channel was configured after powerup by the hw_init_dma_channel()
352 * function. Each sgl descriptor will be setup to interrupt if an error occurs;
353 * however, only the last descriptor will be setup to interrupt. Thus, an
354 * interrupt will occur (if interrupts are enabled) only after the complete
355 * sgl transfer is done.
356 */
357int
358ppc4xx_alloc_dma_handle(sgl_handle_t * phandle, unsigned int mode, unsigned int dmanr)
359{
360 sgl_list_info_t *psgl=NULL;
361 dma_addr_t dma_addr;
362 ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
363 uint32_t sg_command;
364 uint32_t ctc_settings;
365 void *ret;
366
367 if (dmanr >= MAX_PPC4xx_DMA_CHANNELS) {
368 printk("ppc4xx_alloc_dma_handle: invalid channel 0x%x\n", dmanr);
369 return DMA_STATUS_BAD_CHANNEL;
370 }
371
372 if (!phandle) {
373 printk("ppc4xx_alloc_dma_handle: null handle pointer\n");
374 return DMA_STATUS_NULL_POINTER;
375 }
376
377 /* Get a page of memory, which is zeroed out by consistent_alloc() */
378 ret = dma_alloc_coherent(NULL, DMA_PPC4xx_SIZE, &dma_addr, GFP_KERNEL);
379 if (ret != NULL) {
380 memset(ret, 0, DMA_PPC4xx_SIZE);
381 psgl = (sgl_list_info_t *) ret;
382 }
383
384 if (psgl == NULL) {
385 *phandle = (sgl_handle_t) NULL;
386 return DMA_STATUS_OUT_OF_MEMORY;
387 }
388
389 psgl->dma_addr = dma_addr;
390 psgl->dmanr = dmanr;
391
392 /*
393 * Modify and save the control word. These words will be
394 * written to each sgl descriptor. The DMA engine then
395 * loads this control word into the control register
396 * every time it reads a new descriptor.
397 */
398 psgl->control = p_dma_ch->control;
399 /* Clear all mode bits */
400 psgl->control &= ~(DMA_TM_MASK | DMA_TD);
401 /* Save control word and mode */
402 psgl->control |= (mode | DMA_CE_ENABLE);
403
404 /* In MM mode, we must set ETD/TCE */
405 if (mode == DMA_MODE_MM)
406 psgl->control |= DMA_ETD_OUTPUT | DMA_TCE_ENABLE;
407
408 if (p_dma_ch->int_enable) {
409 /* Enable channel interrupt */
410 psgl->control |= DMA_CIE_ENABLE;
411 } else {
412 psgl->control &= ~DMA_CIE_ENABLE;
413 }
414
415 sg_command = mfdcr(DCRN_ASGC);
416 sg_command |= SSG_MASK_ENABLE(dmanr);
417
418 /* Enable SGL control access */
419 mtdcr(DCRN_ASGC, sg_command);
420 psgl->sgl_control = SG_ERI_ENABLE | SG_LINK;
421
422 /* keep control count register settings */
423 ctc_settings = mfdcr(DCRN_DMACT0 + (dmanr * 0x8))
424 & (DMA_CTC_BSIZ_MSK | DMA_CTC_BTEN); /*burst mode settings*/
425 psgl->sgl_control |= ctc_settings;
426
427 if (p_dma_ch->int_enable) {
428 if (p_dma_ch->tce_enable)
429 psgl->sgl_control |= SG_TCI_ENABLE;
430 else
431 psgl->sgl_control |= SG_ETI_ENABLE;
432 }
433
434 *phandle = (sgl_handle_t) psgl;
435 return DMA_STATUS_GOOD;
436}
437
438/*
439 * Destroy a scatter/gather list handle that was created by alloc_dma_handle().
440 * The list must be empty (contain no elements).
441 */
442void
443ppc4xx_free_dma_handle(sgl_handle_t handle)
444{
445 sgl_list_info_t *psgl = (sgl_list_info_t *) handle;
446
447 if (!handle) {
448 printk("ppc4xx_free_dma_handle: got NULL\n");
449 return;
450 } else if (psgl->phead) {
451 printk("ppc4xx_free_dma_handle: list not empty\n");
452 return;
453 } else if (!psgl->dma_addr) { /* should never happen */
454 printk("ppc4xx_free_dma_handle: no dma address\n");
455 return;
456 }
457
458 dma_free_coherent(NULL, DMA_PPC4xx_SIZE, (void *) psgl, 0);
459}
460
461EXPORT_SYMBOL(ppc4xx_alloc_dma_handle);
462EXPORT_SYMBOL(ppc4xx_free_dma_handle);
463EXPORT_SYMBOL(ppc4xx_add_dma_sgl);
464EXPORT_SYMBOL(ppc4xx_delete_dma_sgl_element);
465EXPORT_SYMBOL(ppc4xx_enable_dma_sgl);
466EXPORT_SYMBOL(ppc4xx_disable_dma_sgl);
467EXPORT_SYMBOL(ppc4xx_get_dma_sgl_residue);
diff --git a/arch/ppc/syslib/ppc83xx_setup.c b/arch/ppc/syslib/ppc83xx_setup.c
new file mode 100644
index 000000000000..c28f9d679484
--- /dev/null
+++ b/arch/ppc/syslib/ppc83xx_setup.c
@@ -0,0 +1,138 @@
1/*
2 * arch/ppc/syslib/ppc83xx_setup.c
3 *
4 * MPC83XX common board code
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2005 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/config.h>
17#include <linux/types.h>
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/pci.h>
21#include <linux/serial.h>
22#include <linux/tty.h> /* for linux/serial_core.h */
23#include <linux/serial_core.h>
24#include <linux/serial_8250.h>
25
26#include <asm/prom.h>
27#include <asm/time.h>
28#include <asm/mpc83xx.h>
29#include <asm/mmu.h>
30#include <asm/ppc_sys.h>
31#include <asm/kgdb.h>
32
33#include <syslib/ppc83xx_setup.h>
34
35phys_addr_t immrbar;
36
37/* Return the amount of memory */
38unsigned long __init
39mpc83xx_find_end_of_memory(void)
40{
41 bd_t *binfo;
42
43 binfo = (bd_t *) __res;
44
45 return binfo->bi_memsize;
46}
47
48long __init
49mpc83xx_time_init(void)
50{
51#define SPCR_OFFS 0x00000110
52#define SPCR_TBEN 0x00400000
53
54 bd_t *binfo = (bd_t *)__res;
55 u32 *spcr = ioremap(binfo->bi_immr_base + SPCR_OFFS, 4);
56
57 *spcr |= SPCR_TBEN;
58
59 iounmap(spcr);
60
61 return 0;
62}
63
64/* The decrementer counts at the system (internal) clock freq divided by 4 */
65void __init
66mpc83xx_calibrate_decr(void)
67{
68 bd_t *binfo = (bd_t *) __res;
69 unsigned int freq, divisor;
70
71 freq = binfo->bi_busfreq;
72 divisor = 4;
73 tb_ticks_per_jiffy = freq / HZ / divisor;
74 tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
75}
76
77#ifdef CONFIG_SERIAL_8250
78void __init
79mpc83xx_early_serial_map(void)
80{
81#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
82 struct uart_port serial_req;
83#endif
84 struct plat_serial8250_port *pdata;
85 bd_t *binfo = (bd_t *) __res;
86 pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(MPC83xx_DUART);
87
88 /* Setup serial port access */
89 pdata[0].uartclk = binfo->bi_busfreq;
90 pdata[0].mapbase += binfo->bi_immr_base;
91 pdata[0].membase = ioremap(pdata[0].mapbase, 0x100);
92
93#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
94 memset(&serial_req, 0, sizeof (serial_req));
95 serial_req.iotype = SERIAL_IO_MEM;
96 serial_req.mapbase = pdata[0].mapbase;
97 serial_req.membase = pdata[0].membase;
98 serial_req.regshift = 0;
99
100 gen550_init(0, &serial_req);
101#endif
102
103 pdata[1].uartclk = binfo->bi_busfreq;
104 pdata[1].mapbase += binfo->bi_immr_base;
105 pdata[1].membase = ioremap(pdata[1].mapbase, 0x100);
106
107#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
108 /* Assume gen550_init() doesn't modify serial_req */
109 serial_req.mapbase = pdata[1].mapbase;
110 serial_req.membase = pdata[1].membase;
111
112 gen550_init(1, &serial_req);
113#endif
114}
115#endif
116
117void
118mpc83xx_restart(char *cmd)
119{
120 local_irq_disable();
121 for(;;);
122}
123
124void
125mpc83xx_power_off(void)
126{
127 local_irq_disable();
128 for(;;);
129}
130
131void
132mpc83xx_halt(void)
133{
134 local_irq_disable();
135 for(;;);
136}
137
138/* PCI SUPPORT DOES NOT EXIT, MODEL after ppc85xx_setup.c */
diff --git a/arch/ppc/syslib/ppc83xx_setup.h b/arch/ppc/syslib/ppc83xx_setup.h
new file mode 100644
index 000000000000..683f179b746c
--- /dev/null
+++ b/arch/ppc/syslib/ppc83xx_setup.h
@@ -0,0 +1,53 @@
1/*
2 * arch/ppc/syslib/ppc83xx_setup.h
3 *
4 * MPC83XX common board definitions
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2005 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
17#ifndef __PPC_SYSLIB_PPC83XX_SETUP_H
18#define __PPC_SYSLIB_PPC83XX_SETUP_H
19
20#include <linux/config.h>
21#include <linux/init.h>
22#include <asm/ppcboot.h>
23
24extern unsigned long mpc83xx_find_end_of_memory(void) __init;
25extern long mpc83xx_time_init(void) __init;
26extern void mpc83xx_calibrate_decr(void) __init;
27extern void mpc83xx_early_serial_map(void) __init;
28extern void mpc83xx_restart(char *cmd);
29extern void mpc83xx_power_off(void);
30extern void mpc83xx_halt(void);
31extern void mpc83xx_setup_hose(void) __init;
32
33/* PCI config */
34#if 0
35#define PCI1_CFG_ADDR_OFFSET (FIXME)
36#define PCI1_CFG_DATA_OFFSET (FIXME)
37
38#define PCI2_CFG_ADDR_OFFSET (FIXME)
39#define PCI2_CFG_DATA_OFFSET (FIXME)
40#endif
41
42/* Serial Config */
43#ifdef CONFIG_SERIAL_MANY_PORTS
44#define RS_TABLE_SIZE 64
45#else
46#define RS_TABLE_SIZE 2
47#endif
48
49#ifndef BASE_BAUD
50#define BASE_BAUD 115200
51#endif
52
53#endif /* __PPC_SYSLIB_PPC83XX_SETUP_H */
diff --git a/arch/ppc/syslib/ppc85xx_common.c b/arch/ppc/syslib/ppc85xx_common.c
new file mode 100644
index 000000000000..e83f2f8686d3
--- /dev/null
+++ b/arch/ppc/syslib/ppc85xx_common.c
@@ -0,0 +1,33 @@
1/*
2 * arch/ppc/syslib/ppc85xx_common.c
3 *
4 * MPC85xx support routines
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2004 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/config.h>
17#include <linux/types.h>
18#include <linux/module.h>
19#include <linux/init.h>
20
21#include <asm/mpc85xx.h>
22#include <asm/mmu.h>
23
24/* ************************************************************************ */
25/* Return the value of CCSRBAR for the current board */
26
27phys_addr_t
28get_ccsrbar(void)
29{
30 return BOARD_CCSRBAR;
31}
32
33EXPORT_SYMBOL(get_ccsrbar);
diff --git a/arch/ppc/syslib/ppc85xx_common.h b/arch/ppc/syslib/ppc85xx_common.h
new file mode 100644
index 000000000000..2c8f304441bf
--- /dev/null
+++ b/arch/ppc/syslib/ppc85xx_common.h
@@ -0,0 +1,25 @@
1/*
2 * arch/ppc/syslib/ppc85xx_common.h
3 *
4 * MPC85xx support routines
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2004 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#ifndef __PPC_SYSLIB_PPC85XX_COMMON_H
17#define __PPC_SYSLIB_PPC85XX_COMMON_H
18
19#include <linux/config.h>
20#include <linux/init.h>
21
22/* Provide access to ccsrbar for any modules, etc */
23phys_addr_t get_ccsrbar(void);
24
25#endif /* __PPC_SYSLIB_PPC85XX_COMMON_H */
diff --git a/arch/ppc/syslib/ppc85xx_setup.c b/arch/ppc/syslib/ppc85xx_setup.c
new file mode 100644
index 000000000000..81f1968c3269
--- /dev/null
+++ b/arch/ppc/syslib/ppc85xx_setup.c
@@ -0,0 +1,354 @@
1/*
2 * arch/ppc/syslib/ppc85xx_setup.c
3 *
4 * MPC85XX common board code
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2004 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/config.h>
17#include <linux/types.h>
18#include <linux/module.h>
19#include <linux/init.h>
20#include <linux/pci.h>
21#include <linux/serial.h>
22#include <linux/tty.h> /* for linux/serial_core.h */
23#include <linux/serial_core.h>
24#include <linux/serial_8250.h>
25
26#include <asm/prom.h>
27#include <asm/time.h>
28#include <asm/mpc85xx.h>
29#include <asm/immap_85xx.h>
30#include <asm/mmu.h>
31#include <asm/ppc_sys.h>
32#include <asm/kgdb.h>
33
34#include <syslib/ppc85xx_setup.h>
35
36/* Return the amount of memory */
37unsigned long __init
38mpc85xx_find_end_of_memory(void)
39{
40 bd_t *binfo;
41
42 binfo = (bd_t *) __res;
43
44 return binfo->bi_memsize;
45}
46
47/* The decrementer counts at the system (internal) clock freq divided by 8 */
48void __init
49mpc85xx_calibrate_decr(void)
50{
51 bd_t *binfo = (bd_t *) __res;
52 unsigned int freq, divisor;
53
54 /* get the core frequency */
55 freq = binfo->bi_busfreq;
56
57 /* The timebase is updated every 8 bus clocks, HID0[SEL_TBCLK] = 0 */
58 divisor = 8;
59 tb_ticks_per_jiffy = freq / divisor / HZ;
60 tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
61
62 /* Set the time base to zero */
63 mtspr(SPRN_TBWL, 0);
64 mtspr(SPRN_TBWU, 0);
65
66 /* Clear any pending timer interrupts */
67 mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS);
68
69 /* Enable decrementer interrupt */
70 mtspr(SPRN_TCR, TCR_DIE);
71}
72
73#ifdef CONFIG_SERIAL_8250
74void __init
75mpc85xx_early_serial_map(void)
76{
77#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
78 struct uart_port serial_req;
79#endif
80 struct plat_serial8250_port *pdata;
81 bd_t *binfo = (bd_t *) __res;
82 pdata = (struct plat_serial8250_port *) ppc_sys_get_pdata(MPC85xx_DUART);
83
84 /* Setup serial port access */
85 pdata[0].uartclk = binfo->bi_busfreq;
86 pdata[0].mapbase += binfo->bi_immr_base;
87 pdata[0].membase = ioremap(pdata[0].mapbase, MPC85xx_UART0_SIZE);
88
89#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
90 memset(&serial_req, 0, sizeof (serial_req));
91 serial_req.iotype = SERIAL_IO_MEM;
92 serial_req.mapbase = pdata[0].mapbase;
93 serial_req.membase = pdata[0].membase;
94 serial_req.regshift = 0;
95
96 gen550_init(0, &serial_req);
97#endif
98
99 pdata[1].uartclk = binfo->bi_busfreq;
100 pdata[1].mapbase += binfo->bi_immr_base;
101 pdata[1].membase = ioremap(pdata[1].mapbase, MPC85xx_UART0_SIZE);
102
103#if defined(CONFIG_SERIAL_TEXT_DEBUG) || defined(CONFIG_KGDB)
104 /* Assume gen550_init() doesn't modify serial_req */
105 serial_req.mapbase = pdata[1].mapbase;
106 serial_req.membase = pdata[1].membase;
107
108 gen550_init(1, &serial_req);
109#endif
110}
111#endif
112
113void
114mpc85xx_restart(char *cmd)
115{
116 local_irq_disable();
117 abort();
118}
119
120void
121mpc85xx_power_off(void)
122{
123 local_irq_disable();
124 for(;;);
125}
126
127void
128mpc85xx_halt(void)
129{
130 local_irq_disable();
131 for(;;);
132}
133
134#ifdef CONFIG_PCI
135static void __init
136mpc85xx_setup_pci1(struct pci_controller *hose)
137{
138 volatile struct ccsr_pci *pci;
139 volatile struct ccsr_guts *guts;
140 unsigned short temps;
141 bd_t *binfo = (bd_t *) __res;
142
143 pci = ioremap(binfo->bi_immr_base + MPC85xx_PCI1_OFFSET,
144 MPC85xx_PCI1_SIZE);
145
146 guts = ioremap(binfo->bi_immr_base + MPC85xx_GUTS_OFFSET,
147 MPC85xx_GUTS_SIZE);
148
149 early_read_config_word(hose, 0, 0, PCI_COMMAND, &temps);
150 temps |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
151 early_write_config_word(hose, 0, 0, PCI_COMMAND, temps);
152
153#define PORDEVSR_PCI (0x00800000) /* PCI Mode */
154 if (guts->pordevsr & PORDEVSR_PCI) {
155 early_write_config_byte(hose, 0, 0, PCI_LATENCY_TIMER, 0x80);
156 } else {
157 /* PCI-X init */
158 temps = PCI_X_CMD_MAX_SPLIT | PCI_X_CMD_MAX_READ
159 | PCI_X_CMD_ERO | PCI_X_CMD_DPERR_E;
160 early_write_config_word(hose, 0, 0, PCIX_COMMAND, temps);
161 }
162
163 /* Disable all windows (except powar0 since its ignored) */
164 pci->powar1 = 0;
165 pci->powar2 = 0;
166 pci->powar3 = 0;
167 pci->powar4 = 0;
168 pci->piwar1 = 0;
169 pci->piwar2 = 0;
170 pci->piwar3 = 0;
171
172 /* Setup Phys:PCI 1:1 outbound mem window @ MPC85XX_PCI1_LOWER_MEM */
173 pci->potar1 = (MPC85XX_PCI1_LOWER_MEM >> 12) & 0x000fffff;
174 pci->potear1 = 0x00000000;
175 pci->powbar1 = (MPC85XX_PCI1_LOWER_MEM >> 12) & 0x000fffff;
176 /* Enable, Mem R/W */
177 pci->powar1 = 0x80044000 |
178 (__ilog2(MPC85XX_PCI1_UPPER_MEM - MPC85XX_PCI1_LOWER_MEM + 1) - 1);
179
180 /* Setup outboud IO windows @ MPC85XX_PCI1_IO_BASE */
181 pci->potar2 = 0x00000000;
182 pci->potear2 = 0x00000000;
183 pci->powbar2 = (MPC85XX_PCI1_IO_BASE >> 12) & 0x000fffff;
184 /* Enable, IO R/W */
185 pci->powar2 = 0x80088000 | (__ilog2(MPC85XX_PCI1_IO_SIZE) - 1);
186
187 /* Setup 2G inbound Memory Window @ 0 */
188 pci->pitar1 = 0x00000000;
189 pci->piwbar1 = 0x00000000;
190 pci->piwar1 = 0xa0f5501e; /* Enable, Prefetch, Local
191 Mem, Snoop R/W, 2G */
192}
193
194
195extern int mpc85xx_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin);
196extern int mpc85xx_exclude_device(u_char bus, u_char devfn);
197
198#ifdef CONFIG_85xx_PCI2
199static void __init
200mpc85xx_setup_pci2(struct pci_controller *hose)
201{
202 volatile struct ccsr_pci *pci;
203 unsigned short temps;
204 bd_t *binfo = (bd_t *) __res;
205
206 pci = ioremap(binfo->bi_immr_base + MPC85xx_PCI2_OFFSET,
207 MPC85xx_PCI2_SIZE);
208
209 early_read_config_word(hose, hose->bus_offset, 0, PCI_COMMAND, &temps);
210 temps |= PCI_COMMAND_SERR | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
211 early_write_config_word(hose, hose->bus_offset, 0, PCI_COMMAND, temps);
212 early_write_config_byte(hose, hose->bus_offset, 0, PCI_LATENCY_TIMER, 0x80);
213
214 /* Disable all windows (except powar0 since its ignored) */
215 pci->powar1 = 0;
216 pci->powar2 = 0;
217 pci->powar3 = 0;
218 pci->powar4 = 0;
219 pci->piwar1 = 0;
220 pci->piwar2 = 0;
221 pci->piwar3 = 0;
222
223 /* Setup Phys:PCI 1:1 outbound mem window @ MPC85XX_PCI2_LOWER_MEM */
224 pci->potar1 = (MPC85XX_PCI2_LOWER_MEM >> 12) & 0x000fffff;
225 pci->potear1 = 0x00000000;
226 pci->powbar1 = (MPC85XX_PCI2_LOWER_MEM >> 12) & 0x000fffff;
227 /* Enable, Mem R/W */
228 pci->powar1 = 0x80044000 |
229 (__ilog2(MPC85XX_PCI1_UPPER_MEM - MPC85XX_PCI1_LOWER_MEM + 1) - 1);
230
231 /* Setup outboud IO windows @ MPC85XX_PCI2_IO_BASE */
232 pci->potar2 = 0x00000000;
233 pci->potear2 = 0x00000000;
234 pci->powbar2 = (MPC85XX_PCI2_IO_BASE >> 12) & 0x000fffff;
235 /* Enable, IO R/W */
236 pci->powar2 = 0x80088000 | (__ilog2(MPC85XX_PCI1_IO_SIZE) - 1);
237
238 /* Setup 2G inbound Memory Window @ 0 */
239 pci->pitar1 = 0x00000000;
240 pci->piwbar1 = 0x00000000;
241 pci->piwar1 = 0xa0f5501e; /* Enable, Prefetch, Local
242 Mem, Snoop R/W, 2G */
243}
244#endif /* CONFIG_85xx_PCI2 */
245
246int mpc85xx_pci1_last_busno = 0;
247
248void __init
249mpc85xx_setup_hose(void)
250{
251 struct pci_controller *hose_a;
252#ifdef CONFIG_85xx_PCI2
253 struct pci_controller *hose_b;
254#endif
255 bd_t *binfo = (bd_t *) __res;
256
257 hose_a = pcibios_alloc_controller();
258
259 if (!hose_a)
260 return;
261
262 ppc_md.pci_swizzle = common_swizzle;
263 ppc_md.pci_map_irq = mpc85xx_map_irq;
264
265 hose_a->first_busno = 0;
266 hose_a->bus_offset = 0;
267 hose_a->last_busno = 0xff;
268
269 setup_indirect_pci(hose_a, binfo->bi_immr_base + PCI1_CFG_ADDR_OFFSET,
270 binfo->bi_immr_base + PCI1_CFG_DATA_OFFSET);
271 hose_a->set_cfg_type = 1;
272
273 mpc85xx_setup_pci1(hose_a);
274
275 hose_a->pci_mem_offset = MPC85XX_PCI1_MEM_OFFSET;
276 hose_a->mem_space.start = MPC85XX_PCI1_LOWER_MEM;
277 hose_a->mem_space.end = MPC85XX_PCI1_UPPER_MEM;
278
279 hose_a->io_space.start = MPC85XX_PCI1_LOWER_IO;
280 hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO;
281 hose_a->io_base_phys = MPC85XX_PCI1_IO_BASE;
282#ifdef CONFIG_85xx_PCI2
283 isa_io_base =
284 (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE,
285 MPC85XX_PCI1_IO_SIZE +
286 MPC85XX_PCI2_IO_SIZE);
287#else
288 isa_io_base =
289 (unsigned long) ioremap(MPC85XX_PCI1_IO_BASE,
290 MPC85XX_PCI1_IO_SIZE);
291#endif
292 hose_a->io_base_virt = (void *) isa_io_base;
293
294 /* setup resources */
295 pci_init_resource(&hose_a->mem_resources[0],
296 MPC85XX_PCI1_LOWER_MEM,
297 MPC85XX_PCI1_UPPER_MEM,
298 IORESOURCE_MEM, "PCI1 host bridge");
299
300 pci_init_resource(&hose_a->io_resource,
301 MPC85XX_PCI1_LOWER_IO,
302 MPC85XX_PCI1_UPPER_IO,
303 IORESOURCE_IO, "PCI1 host bridge");
304
305 ppc_md.pci_exclude_device = mpc85xx_exclude_device;
306
307 hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
308
309#ifdef CONFIG_85xx_PCI2
310 hose_b = pcibios_alloc_controller();
311
312 if (!hose_b)
313 return;
314
315 hose_b->bus_offset = hose_a->last_busno + 1;
316 hose_b->first_busno = hose_a->last_busno + 1;
317 hose_b->last_busno = 0xff;
318
319 setup_indirect_pci(hose_b, binfo->bi_immr_base + PCI2_CFG_ADDR_OFFSET,
320 binfo->bi_immr_base + PCI2_CFG_DATA_OFFSET);
321 hose_b->set_cfg_type = 1;
322
323 mpc85xx_setup_pci2(hose_b);
324
325 hose_b->pci_mem_offset = MPC85XX_PCI2_MEM_OFFSET;
326 hose_b->mem_space.start = MPC85XX_PCI2_LOWER_MEM;
327 hose_b->mem_space.end = MPC85XX_PCI2_UPPER_MEM;
328
329 hose_b->io_space.start = MPC85XX_PCI2_LOWER_IO;
330 hose_b->io_space.end = MPC85XX_PCI2_UPPER_IO;
331 hose_b->io_base_phys = MPC85XX_PCI2_IO_BASE;
332 hose_b->io_base_virt = (void *) isa_io_base + MPC85XX_PCI1_IO_SIZE;
333
334 /* setup resources */
335 pci_init_resource(&hose_b->mem_resources[0],
336 MPC85XX_PCI2_LOWER_MEM,
337 MPC85XX_PCI2_UPPER_MEM,
338 IORESOURCE_MEM, "PCI2 host bridge");
339
340 pci_init_resource(&hose_b->io_resource,
341 MPC85XX_PCI2_LOWER_IO,
342 MPC85XX_PCI2_UPPER_IO,
343 IORESOURCE_IO, "PCI2 host bridge");
344
345 hose_b->last_busno = pciauto_bus_scan(hose_b, hose_b->first_busno);
346
347 /* let board code know what the last bus number was on PCI1 */
348 mpc85xx_pci1_last_busno = hose_a->last_busno;
349#endif
350 return;
351}
352#endif /* CONFIG_PCI */
353
354
diff --git a/arch/ppc/syslib/ppc85xx_setup.h b/arch/ppc/syslib/ppc85xx_setup.h
new file mode 100644
index 000000000000..6e6cfe162faf
--- /dev/null
+++ b/arch/ppc/syslib/ppc85xx_setup.h
@@ -0,0 +1,59 @@
1/*
2 * arch/ppc/syslib/ppc85xx_setup.h
3 *
4 * MPC85XX common board definitions
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2004 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 *
15 */
16
17#ifndef __PPC_SYSLIB_PPC85XX_SETUP_H
18#define __PPC_SYSLIB_PPC85XX_SETUP_H
19
20#include <linux/config.h>
21#include <linux/init.h>
22#include <asm/ppcboot.h>
23
24extern unsigned long mpc85xx_find_end_of_memory(void) __init;
25extern void mpc85xx_calibrate_decr(void) __init;
26extern void mpc85xx_early_serial_map(void) __init;
27extern void mpc85xx_restart(char *cmd);
28extern void mpc85xx_power_off(void);
29extern void mpc85xx_halt(void);
30extern void mpc85xx_setup_hose(void) __init;
31
32/* PCI config */
33#define PCI1_CFG_ADDR_OFFSET (0x8000)
34#define PCI1_CFG_DATA_OFFSET (0x8004)
35
36#define PCI2_CFG_ADDR_OFFSET (0x9000)
37#define PCI2_CFG_DATA_OFFSET (0x9004)
38
39/* Additional register for PCI-X configuration */
40#define PCIX_NEXT_CAP 0x60
41#define PCIX_CAP_ID 0x61
42#define PCIX_COMMAND 0x62
43#define PCIX_STATUS 0x64
44
45/* Serial Config */
46#ifdef CONFIG_SERIAL_MANY_PORTS
47#define RS_TABLE_SIZE 64
48#else
49#define RS_TABLE_SIZE 2
50#endif
51
52#ifndef BASE_BAUD
53#define BASE_BAUD 115200
54#endif
55
56/* Offset of CPM register space */
57#define CPM_MAP_ADDR (CCSRBAR + MPC85xx_CPM_OFFSET)
58
59#endif /* __PPC_SYSLIB_PPC85XX_SETUP_H */
diff --git a/arch/ppc/syslib/ppc8xx_pic.c b/arch/ppc/syslib/ppc8xx_pic.c
new file mode 100644
index 000000000000..d3b01c6c97de
--- /dev/null
+++ b/arch/ppc/syslib/ppc8xx_pic.c
@@ -0,0 +1,130 @@
1#include <linux/config.h>
2#include <linux/module.h>
3#include <linux/stddef.h>
4#include <linux/init.h>
5#include <linux/sched.h>
6#include <linux/signal.h>
7#include <linux/interrupt.h>
8#include <asm/irq.h>
9#include <asm/8xx_immap.h>
10#include <asm/mpc8xx.h>
11#include "ppc8xx_pic.h"
12
13extern int cpm_get_irq(struct pt_regs *regs);
14
15/* The 8xx internal interrupt controller. It is usually
16 * the only interrupt controller. Some boards, like the MBX and
17 * Sandpoint have the 8259 as a secondary controller. Depending
18 * upon the processor type, the internal controller can have as
19 * few as 16 interrups or as many as 64. We could use the
20 * "clear_bit()" and "set_bit()" functions like other platforms,
21 * but they are overkill for us.
22 */
23
24static void m8xx_mask_irq(unsigned int irq_nr)
25{
26 int bit, word;
27
28 bit = irq_nr & 0x1f;
29 word = irq_nr >> 5;
30
31 ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
32 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
33 ppc_cached_irq_mask[word];
34}
35
36static void m8xx_unmask_irq(unsigned int irq_nr)
37{
38 int bit, word;
39
40 bit = irq_nr & 0x1f;
41 word = irq_nr >> 5;
42
43 ppc_cached_irq_mask[word] |= (1 << (31-bit));
44 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
45 ppc_cached_irq_mask[word];
46}
47
48static void m8xx_end_irq(unsigned int irq_nr)
49{
50 if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
51 && irq_desc[irq_nr].action) {
52 int bit, word;
53
54 bit = irq_nr & 0x1f;
55 word = irq_nr >> 5;
56
57 ppc_cached_irq_mask[word] |= (1 << (31-bit));
58 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
59 ppc_cached_irq_mask[word];
60 }
61}
62
63
64static void m8xx_mask_and_ack(unsigned int irq_nr)
65{
66 int bit, word;
67
68 bit = irq_nr & 0x1f;
69 word = irq_nr >> 5;
70
71 ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
72 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
73 ppc_cached_irq_mask[word];
74 ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit);
75}
76
77struct hw_interrupt_type ppc8xx_pic = {
78 .typename = " 8xx SIU ",
79 .enable = m8xx_unmask_irq,
80 .disable = m8xx_mask_irq,
81 .ack = m8xx_mask_and_ack,
82 .end = m8xx_end_irq,
83};
84
85/*
86 * We either return a valid interrupt or -1 if there is nothing pending
87 */
88int
89m8xx_get_irq(struct pt_regs *regs)
90{
91 int irq;
92
93 /* For MPC8xx, read the SIVEC register and shift the bits down
94 * to get the irq number.
95 */
96 irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26;
97
98 /*
99 * When we read the sivec without an interrupt to process, we will
100 * get back SIU_LEVEL7. In this case, return -1
101 */
102 if (irq == CPM_INTERRUPT)
103 irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
104#if defined(CONFIG_PCI)
105 else if (irq == ISA_BRIDGE_INT) {
106 int isa_irq;
107
108 if ((isa_irq = i8259_poll(regs)) >= 0)
109 irq = I8259_IRQ_OFFSET + isa_irq;
110 }
111#endif /* CONFIG_PCI */
112 else if (irq == SIU_LEVEL7)
113 irq = -1;
114
115 return irq;
116}
117
118#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
119/* Only the MBX uses the external 8259. This allows us to catch standard
120 * drivers that may mess up the internal interrupt controllers, and also
121 * allow them to run without modification on the MBX.
122 */
123void mbx_i8259_action(int irq, void *dev_id, struct pt_regs *regs)
124{
125 /* This interrupt handler never actually gets called. It is
126 * installed only to unmask the 8259 cascade interrupt in the SIU
127 * and to make the 8259 cascade interrupt visible in /proc/interrupts.
128 */
129}
130#endif /* CONFIG_PCI */
diff --git a/arch/ppc/syslib/ppc8xx_pic.h b/arch/ppc/syslib/ppc8xx_pic.h
new file mode 100644
index 000000000000..784935eac365
--- /dev/null
+++ b/arch/ppc/syslib/ppc8xx_pic.h
@@ -0,0 +1,21 @@
1#ifndef _PPC_KERNEL_PPC8xx_H
2#define _PPC_KERNEL_PPC8xx_H
3
4#include <linux/config.h>
5#include <linux/irq.h>
6#include <linux/interrupt.h>
7
8extern struct hw_interrupt_type ppc8xx_pic;
9
10void m8xx_pic_init(void);
11void m8xx_do_IRQ(struct pt_regs *regs,
12 int cpu);
13int m8xx_get_irq(struct pt_regs *regs);
14
15#ifdef CONFIG_MBX
16#include <asm/i8259.h>
17#include <asm/io.h>
18void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs);
19#endif
20
21#endif /* _PPC_KERNEL_PPC8xx_H */
diff --git a/arch/ppc/syslib/ppc_sys.c b/arch/ppc/syslib/ppc_sys.c
new file mode 100644
index 000000000000..879202352560
--- /dev/null
+++ b/arch/ppc/syslib/ppc_sys.c
@@ -0,0 +1,103 @@
1/*
2 * arch/ppc/syslib/ppc_sys.c
3 *
4 * PPC System library functions
5 *
6 * Maintainer: Kumar Gala <kumar.gala@freescale.com>
7 *
8 * Copyright 2005 Freescale Semiconductor Inc.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <asm/ppc_sys.h>
17
18int (*ppc_sys_device_fixup) (struct platform_device * pdev);
19
20static int ppc_sys_inited;
21
22void __init identify_ppc_sys_by_id(u32 id)
23{
24 unsigned int i = 0;
25 while (1) {
26 if ((ppc_sys_specs[i].mask & id) == ppc_sys_specs[i].value)
27 break;
28 i++;
29 }
30
31 cur_ppc_sys_spec = &ppc_sys_specs[i];
32
33 return;
34}
35
36void __init identify_ppc_sys_by_name(char *name)
37{
38 /* TODO */
39 return;
40}
41
42/* Update all memory resources by paddr, call before platform_device_register */
43void __init
44ppc_sys_fixup_mem_resource(struct platform_device *pdev, phys_addr_t paddr)
45{
46 int i;
47 for (i = 0; i < pdev->num_resources; i++) {
48 struct resource *r = &pdev->resource[i];
49 if ((r->flags & IORESOURCE_MEM) == IORESOURCE_MEM) {
50 r->start += paddr;
51 r->end += paddr;
52 }
53 }
54}
55
56/* Get platform_data pointer out of platform device, call before platform_device_register */
57void *__init ppc_sys_get_pdata(enum ppc_sys_devices dev)
58{
59 return ppc_sys_platform_devices[dev].dev.platform_data;
60}
61
62void ppc_sys_device_remove(enum ppc_sys_devices dev)
63{
64 unsigned int i;
65
66 if (ppc_sys_inited) {
67 platform_device_unregister(&ppc_sys_platform_devices[dev]);
68 } else {
69 if (cur_ppc_sys_spec == NULL)
70 return;
71 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++)
72 if (cur_ppc_sys_spec->device_list[i] == dev)
73 cur_ppc_sys_spec->device_list[i] = -1;
74 }
75}
76
77static int __init ppc_sys_init(void)
78{
79 unsigned int i, dev_id, ret = 0;
80
81 BUG_ON(cur_ppc_sys_spec == NULL);
82
83 for (i = 0; i < cur_ppc_sys_spec->num_devices; i++) {
84 dev_id = cur_ppc_sys_spec->device_list[i];
85 if (dev_id != -1) {
86 if (ppc_sys_device_fixup != NULL)
87 ppc_sys_device_fixup(&ppc_sys_platform_devices
88 [dev_id]);
89 if (platform_device_register
90 (&ppc_sys_platform_devices[dev_id])) {
91 ret = 1;
92 printk(KERN_ERR
93 "unable to register device %d\n",
94 dev_id);
95 }
96 }
97 }
98
99 ppc_sys_inited = 1;
100 return ret;
101}
102
103subsys_initcall(ppc_sys_init);
diff --git a/arch/ppc/syslib/prep_nvram.c b/arch/ppc/syslib/prep_nvram.c
new file mode 100644
index 000000000000..2bcf8a16d1c9
--- /dev/null
+++ b/arch/ppc/syslib/prep_nvram.c
@@ -0,0 +1,141 @@
1/*
2 * arch/ppc/kernel/prep_nvram.c
3 *
4 * Copyright (C) 1998 Corey Minyard
5 *
6 * This reads the NvRAM on PReP compliant machines (generally from IBM or
7 * Motorola). Motorola kept the format of NvRAM in their ROM, PPCBUG, the
8 * same, long after they had stopped producing PReP compliant machines. So
9 * this code is useful in those cases as well.
10 *
11 */
12#include <linux/init.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/ioport.h>
16
17#include <asm/sections.h>
18#include <asm/segment.h>
19#include <asm/io.h>
20#include <asm/machdep.h>
21#include <asm/prep_nvram.h>
22
23static char nvramData[MAX_PREP_NVRAM];
24static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0];
25
26unsigned char __prep prep_nvram_read_val(int addr)
27{
28 outb(addr, PREP_NVRAM_AS0);
29 outb(addr>>8, PREP_NVRAM_AS1);
30 return inb(PREP_NVRAM_DATA);
31}
32
33void __prep prep_nvram_write_val(int addr,
34 unsigned char val)
35{
36 outb(addr, PREP_NVRAM_AS0);
37 outb(addr>>8, PREP_NVRAM_AS1);
38 outb(val, PREP_NVRAM_DATA);
39}
40
41void __init init_prep_nvram(void)
42{
43 unsigned char *nvp;
44 int i;
45 int nvramSize;
46
47 /*
48 * The following could fail if the NvRAM were corrupt but
49 * we expect the boot firmware to have checked its checksum
50 * before boot
51 */
52 nvp = (char *) &nvram->Header;
53 for (i=0; i<sizeof(HEADER); i++)
54 {
55 *nvp = ppc_md.nvram_read_val(i);
56 nvp++;
57 }
58
59 /*
60 * The PReP NvRAM may be any size so read in the header to
61 * determine how much we must read in order to get the complete
62 * GE area
63 */
64 nvramSize=(int)nvram->Header.GEAddress+nvram->Header.GELength;
65 if(nvramSize>MAX_PREP_NVRAM)
66 {
67 /*
68 * NvRAM is too large
69 */
70 nvram->Header.GELength=0;
71 return;
72 }
73
74 /*
75 * Read the remainder of the PReP NvRAM
76 */
77 nvp = (char *) &nvram->GEArea[0];
78 for (i=sizeof(HEADER); i<nvramSize; i++)
79 {
80 *nvp = ppc_md.nvram_read_val(i);
81 nvp++;
82 }
83}
84
85__prep
86char __prep *prep_nvram_get_var(const char *name)
87{
88 char *cp;
89 int namelen;
90
91 namelen = strlen(name);
92 cp = prep_nvram_first_var();
93 while (cp != NULL) {
94 if ((strncmp(name, cp, namelen) == 0)
95 && (cp[namelen] == '='))
96 {
97 return cp+namelen+1;
98 }
99 cp = prep_nvram_next_var(cp);
100 }
101
102 return NULL;
103}
104
105__prep
106char __prep *prep_nvram_first_var(void)
107{
108 if (nvram->Header.GELength == 0) {
109 return NULL;
110 } else {
111 return (((char *)nvram)
112 + ((unsigned int) nvram->Header.GEAddress));
113 }
114}
115
116__prep
117char __prep *prep_nvram_next_var(char *name)
118{
119 char *cp;
120
121
122 cp = name;
123 while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
124 && (*cp != '\0'))
125 {
126 cp++;
127 }
128
129 /* Skip over any null characters. */
130 while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
131 && (*cp == '\0'))
132 {
133 cp++;
134 }
135
136 if ((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) {
137 return cp;
138 } else {
139 return NULL;
140 }
141}
diff --git a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c
new file mode 100644
index 000000000000..2c64ed627475
--- /dev/null
+++ b/arch/ppc/syslib/prom.c
@@ -0,0 +1,1447 @@
1/*
2 * Procedures for interfacing to the Open Firmware PROM on
3 * Power Macintosh computers.
4 *
5 * In particular, we are interested in the device tree
6 * and in using some of its services (exit, write to stdout).
7 *
8 * Paul Mackerras August 1996.
9 * Copyright (C) 1996 Paul Mackerras.
10 */
11#include <stdarg.h>
12#include <linux/config.h>
13#include <linux/kernel.h>
14#include <linux/string.h>
15#include <linux/init.h>
16#include <linux/version.h>
17#include <linux/threads.h>
18#include <linux/spinlock.h>
19#include <linux/ioport.h>
20#include <linux/pci.h>
21#include <linux/slab.h>
22#include <linux/bitops.h>
23
24#include <asm/sections.h>
25#include <asm/prom.h>
26#include <asm/page.h>
27#include <asm/processor.h>
28#include <asm/irq.h>
29#include <asm/io.h>
30#include <asm/smp.h>
31#include <asm/bootx.h>
32#include <asm/system.h>
33#include <asm/mmu.h>
34#include <asm/pgtable.h>
35#include <asm/bootinfo.h>
36#include <asm/btext.h>
37#include <asm/pci-bridge.h>
38#include <asm/open_pic.h>
39
40
41struct pci_address {
42 unsigned a_hi;
43 unsigned a_mid;
44 unsigned a_lo;
45};
46
47struct pci_reg_property {
48 struct pci_address addr;
49 unsigned size_hi;
50 unsigned size_lo;
51};
52
53struct isa_reg_property {
54 unsigned space;
55 unsigned address;
56 unsigned size;
57};
58
59typedef unsigned long interpret_func(struct device_node *, unsigned long,
60 int, int);
61static interpret_func interpret_pci_props;
62static interpret_func interpret_dbdma_props;
63static interpret_func interpret_isa_props;
64static interpret_func interpret_macio_props;
65static interpret_func interpret_root_props;
66
67extern char *klimit;
68
69/* Set for a newworld or CHRP machine */
70int use_of_interrupt_tree;
71struct device_node *dflt_interrupt_controller;
72int num_interrupt_controllers;
73
74int pmac_newworld;
75
76extern unsigned int rtas_entry; /* physical pointer */
77
78extern struct device_node *allnodes;
79
80static unsigned long finish_node(struct device_node *, unsigned long,
81 interpret_func *, int, int);
82static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
83static struct device_node *find_phandle(phandle);
84
85extern void enter_rtas(void *);
86void phys_call_rtas(int, int, int, ...);
87
88extern char cmd_line[512]; /* XXX */
89extern boot_infos_t *boot_infos;
90unsigned long dev_tree_size;
91
92void __openfirmware
93phys_call_rtas(int service, int nargs, int nret, ...)
94{
95 va_list list;
96 union {
97 unsigned long words[16];
98 double align;
99 } u;
100 void (*rtas)(void *, unsigned long);
101 int i;
102
103 u.words[0] = service;
104 u.words[1] = nargs;
105 u.words[2] = nret;
106 va_start(list, nret);
107 for (i = 0; i < nargs; ++i)
108 u.words[i+3] = va_arg(list, unsigned long);
109 va_end(list);
110
111 rtas = (void (*)(void *, unsigned long)) rtas_entry;
112 rtas(&u, rtas_data);
113}
114
115/*
116 * finish_device_tree is called once things are running normally
117 * (i.e. with text and data mapped to the address they were linked at).
118 * It traverses the device tree and fills in the name, type,
119 * {n_}addrs and {n_}intrs fields of each node.
120 */
121void __init
122finish_device_tree(void)
123{
124 unsigned long mem = (unsigned long) klimit;
125 struct device_node *np;
126
127 /* All newworld pmac machines and CHRPs now use the interrupt tree */
128 for (np = allnodes; np != NULL; np = np->allnext) {
129 if (get_property(np, "interrupt-parent", NULL)) {
130 use_of_interrupt_tree = 1;
131 break;
132 }
133 }
134 if (_machine == _MACH_Pmac && use_of_interrupt_tree)
135 pmac_newworld = 1;
136
137#ifdef CONFIG_BOOTX_TEXT
138 if (boot_infos && pmac_newworld) {
139 prom_print("WARNING ! BootX/miBoot booting is not supported on this machine\n");
140 prom_print(" You should use an Open Firmware bootloader\n");
141 }
142#endif /* CONFIG_BOOTX_TEXT */
143
144 if (use_of_interrupt_tree) {
145 /*
146 * We want to find out here how many interrupt-controller
147 * nodes there are, and if we are booted from BootX,
148 * we need a pointer to the first (and hopefully only)
149 * such node. But we can't use find_devices here since
150 * np->name has not been set yet. -- paulus
151 */
152 int n = 0;
153 char *name, *ic;
154 int iclen;
155
156 for (np = allnodes; np != NULL; np = np->allnext) {
157 ic = get_property(np, "interrupt-controller", &iclen);
158 name = get_property(np, "name", NULL);
159 /* checking iclen makes sure we don't get a false
160 match on /chosen.interrupt_controller */
161 if ((name != NULL
162 && strcmp(name, "interrupt-controller") == 0)
163 || (ic != NULL && iclen == 0 && strcmp(name, "AppleKiwi"))) {
164 if (n == 0)
165 dflt_interrupt_controller = np;
166 ++n;
167 }
168 }
169 num_interrupt_controllers = n;
170 }
171
172 mem = finish_node(allnodes, mem, NULL, 1, 1);
173 dev_tree_size = mem - (unsigned long) allnodes;
174 klimit = (char *) mem;
175}
176
177static unsigned long __init
178finish_node(struct device_node *np, unsigned long mem_start,
179 interpret_func *ifunc, int naddrc, int nsizec)
180{
181 struct device_node *child;
182 int *ip;
183
184 np->name = get_property(np, "name", NULL);
185 np->type = get_property(np, "device_type", NULL);
186
187 if (!np->name)
188 np->name = "<NULL>";
189 if (!np->type)
190 np->type = "<NULL>";
191
192 /* get the device addresses and interrupts */
193 if (ifunc != NULL)
194 mem_start = ifunc(np, mem_start, naddrc, nsizec);
195
196 if (use_of_interrupt_tree)
197 mem_start = finish_node_interrupts(np, mem_start);
198
199 /* Look for #address-cells and #size-cells properties. */
200 ip = (int *) get_property(np, "#address-cells", NULL);
201 if (ip != NULL)
202 naddrc = *ip;
203 ip = (int *) get_property(np, "#size-cells", NULL);
204 if (ip != NULL)
205 nsizec = *ip;
206
207 if (np->parent == NULL)
208 ifunc = interpret_root_props;
209 else if (np->type == 0)
210 ifunc = NULL;
211 else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
212 ifunc = interpret_pci_props;
213 else if (!strcmp(np->type, "dbdma"))
214 ifunc = interpret_dbdma_props;
215 else if (!strcmp(np->type, "mac-io")
216 || ifunc == interpret_macio_props)
217 ifunc = interpret_macio_props;
218 else if (!strcmp(np->type, "isa"))
219 ifunc = interpret_isa_props;
220 else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
221 ifunc = interpret_root_props;
222 else if (!((ifunc == interpret_dbdma_props
223 || ifunc == interpret_macio_props)
224 && (!strcmp(np->type, "escc")
225 || !strcmp(np->type, "media-bay"))))
226 ifunc = NULL;
227
228 /* if we were booted from BootX, convert the full name */
229 if (boot_infos
230 && strncmp(np->full_name, "Devices:device-tree", 19) == 0) {
231 if (np->full_name[19] == 0) {
232 strcpy(np->full_name, "/");
233 } else if (np->full_name[19] == ':') {
234 char *p = np->full_name + 19;
235 np->full_name = p;
236 for (; *p; ++p)
237 if (*p == ':')
238 *p = '/';
239 }
240 }
241
242 for (child = np->child; child != NULL; child = child->sibling)
243 mem_start = finish_node(child, mem_start, ifunc,
244 naddrc, nsizec);
245
246 return mem_start;
247}
248
249/*
250 * Find the interrupt parent of a node.
251 */
252static struct device_node * __init
253intr_parent(struct device_node *p)
254{
255 phandle *parp;
256
257 parp = (phandle *) get_property(p, "interrupt-parent", NULL);
258 if (parp == NULL)
259 return p->parent;
260 p = find_phandle(*parp);
261 if (p != NULL)
262 return p;
263 /*
264 * On a powermac booted with BootX, we don't get to know the
265 * phandles for any nodes, so find_phandle will return NULL.
266 * Fortunately these machines only have one interrupt controller
267 * so there isn't in fact any ambiguity. -- paulus
268 */
269 if (num_interrupt_controllers == 1)
270 p = dflt_interrupt_controller;
271 return p;
272}
273
274/*
275 * Find out the size of each entry of the interrupts property
276 * for a node.
277 */
278static int __init
279prom_n_intr_cells(struct device_node *np)
280{
281 struct device_node *p;
282 unsigned int *icp;
283
284 for (p = np; (p = intr_parent(p)) != NULL; ) {
285 icp = (unsigned int *)
286 get_property(p, "#interrupt-cells", NULL);
287 if (icp != NULL)
288 return *icp;
289 if (get_property(p, "interrupt-controller", NULL) != NULL
290 || get_property(p, "interrupt-map", NULL) != NULL) {
291 printk("oops, node %s doesn't have #interrupt-cells\n",
292 p->full_name);
293 return 1;
294 }
295 }
296 printk("prom_n_intr_cells failed for %s\n", np->full_name);
297 return 1;
298}
299
300/*
301 * Map an interrupt from a device up to the platform interrupt
302 * descriptor.
303 */
304static int __init
305map_interrupt(unsigned int **irq, struct device_node **ictrler,
306 struct device_node *np, unsigned int *ints, int nintrc)
307{
308 struct device_node *p, *ipar;
309 unsigned int *imap, *imask, *ip;
310 int i, imaplen, match;
311 int newintrc = 1, newaddrc = 1;
312 unsigned int *reg;
313 int naddrc;
314
315 reg = (unsigned int *) get_property(np, "reg", NULL);
316 naddrc = prom_n_addr_cells(np);
317 p = intr_parent(np);
318 while (p != NULL) {
319 if (get_property(p, "interrupt-controller", NULL) != NULL)
320 /* this node is an interrupt controller, stop here */
321 break;
322 imap = (unsigned int *)
323 get_property(p, "interrupt-map", &imaplen);
324 if (imap == NULL) {
325 p = intr_parent(p);
326 continue;
327 }
328 imask = (unsigned int *)
329 get_property(p, "interrupt-map-mask", NULL);
330 if (imask == NULL) {
331 printk("oops, %s has interrupt-map but no mask\n",
332 p->full_name);
333 return 0;
334 }
335 imaplen /= sizeof(unsigned int);
336 match = 0;
337 ipar = NULL;
338 while (imaplen > 0 && !match) {
339 /* check the child-interrupt field */
340 match = 1;
341 for (i = 0; i < naddrc && match; ++i)
342 match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
343 for (; i < naddrc + nintrc && match; ++i)
344 match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
345 imap += naddrc + nintrc;
346 imaplen -= naddrc + nintrc;
347 /* grab the interrupt parent */
348 ipar = find_phandle((phandle) *imap++);
349 --imaplen;
350 if (ipar == NULL && num_interrupt_controllers == 1)
351 /* cope with BootX not giving us phandles */
352 ipar = dflt_interrupt_controller;
353 if (ipar == NULL) {
354 printk("oops, no int parent %x in map of %s\n",
355 imap[-1], p->full_name);
356 return 0;
357 }
358 /* find the parent's # addr and intr cells */
359 ip = (unsigned int *)
360 get_property(ipar, "#interrupt-cells", NULL);
361 if (ip == NULL) {
362 printk("oops, no #interrupt-cells on %s\n",
363 ipar->full_name);
364 return 0;
365 }
366 newintrc = *ip;
367 ip = (unsigned int *)
368 get_property(ipar, "#address-cells", NULL);
369 newaddrc = (ip == NULL)? 0: *ip;
370 imap += newaddrc + newintrc;
371 imaplen -= newaddrc + newintrc;
372 }
373 if (imaplen < 0) {
374 printk("oops, error decoding int-map on %s, len=%d\n",
375 p->full_name, imaplen);
376 return 0;
377 }
378 if (!match) {
379 printk("oops, no match in %s int-map for %s\n",
380 p->full_name, np->full_name);
381 return 0;
382 }
383 p = ipar;
384 naddrc = newaddrc;
385 nintrc = newintrc;
386 ints = imap - nintrc;
387 reg = ints - naddrc;
388 }
389 if (p == NULL)
390 printk("hmmm, int tree for %s doesn't have ctrler\n",
391 np->full_name);
392 *irq = ints;
393 *ictrler = p;
394 return nintrc;
395}
396
397/*
398 * New version of finish_node_interrupts.
399 */
400static unsigned long __init
401finish_node_interrupts(struct device_node *np, unsigned long mem_start)
402{
403 unsigned int *ints;
404 int intlen, intrcells;
405 int i, j, n, offset;
406 unsigned int *irq;
407 struct device_node *ic;
408
409 ints = (unsigned int *) get_property(np, "interrupts", &intlen);
410 if (ints == NULL)
411 return mem_start;
412 intrcells = prom_n_intr_cells(np);
413 intlen /= intrcells * sizeof(unsigned int);
414 np->n_intrs = intlen;
415 np->intrs = (struct interrupt_info *) mem_start;
416 mem_start += intlen * sizeof(struct interrupt_info);
417
418 for (i = 0; i < intlen; ++i) {
419 np->intrs[i].line = 0;
420 np->intrs[i].sense = 1;
421 n = map_interrupt(&irq, &ic, np, ints, intrcells);
422 if (n <= 0)
423 continue;
424 offset = 0;
425 /*
426 * On a CHRP we have an 8259 which is subordinate to
427 * the openpic in the interrupt tree, but we want the
428 * openpic's interrupt numbers offsetted, not the 8259's.
429 * So we apply the offset if the controller is at the
430 * root of the interrupt tree, i.e. has no interrupt-parent.
431 * This doesn't cope with the general case of multiple
432 * cascaded interrupt controllers, but then neither will
433 * irq.c at the moment either. -- paulus
434 * The G5 triggers that code, I add a machine test. On
435 * those machines, we want to offset interrupts from the
436 * second openpic by 128 -- BenH
437 */
438 if (_machine != _MACH_Pmac && num_interrupt_controllers > 1
439 && ic != NULL
440 && get_property(ic, "interrupt-parent", NULL) == NULL)
441 offset = 16;
442 else if (_machine == _MACH_Pmac && num_interrupt_controllers > 1
443 && ic != NULL && ic->parent != NULL) {
444 char *name = get_property(ic->parent, "name", NULL);
445 if (name && !strcmp(name, "u3"))
446 offset = 128;
447 }
448
449 np->intrs[i].line = irq[0] + offset;
450 if (n > 1)
451 np->intrs[i].sense = irq[1];
452 if (n > 2) {
453 printk("hmmm, got %d intr cells for %s:", n,
454 np->full_name);
455 for (j = 0; j < n; ++j)
456 printk(" %d", irq[j]);
457 printk("\n");
458 }
459 ints += intrcells;
460 }
461
462 return mem_start;
463}
464
465/*
466 * When BootX makes a copy of the device tree from the MacOS
467 * Name Registry, it is in the format we use but all of the pointers
468 * are offsets from the start of the tree.
469 * This procedure updates the pointers.
470 */
471void __init
472relocate_nodes(void)
473{
474 unsigned long base;
475 struct device_node *np;
476 struct property *pp;
477
478#define ADDBASE(x) (x = (typeof (x))((x)? ((unsigned long)(x) + base): 0))
479
480 base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset;
481 allnodes = (struct device_node *)(base + 4);
482 for (np = allnodes; np != 0; np = np->allnext) {
483 ADDBASE(np->full_name);
484 ADDBASE(np->properties);
485 ADDBASE(np->parent);
486 ADDBASE(np->child);
487 ADDBASE(np->sibling);
488 ADDBASE(np->allnext);
489 for (pp = np->properties; pp != 0; pp = pp->next) {
490 ADDBASE(pp->name);
491 ADDBASE(pp->value);
492 ADDBASE(pp->next);
493 }
494 }
495}
496
497int
498prom_n_addr_cells(struct device_node* np)
499{
500 int* ip;
501 do {
502 if (np->parent)
503 np = np->parent;
504 ip = (int *) get_property(np, "#address-cells", NULL);
505 if (ip != NULL)
506 return *ip;
507 } while (np->parent);
508 /* No #address-cells property for the root node, default to 1 */
509 return 1;
510}
511
512int
513prom_n_size_cells(struct device_node* np)
514{
515 int* ip;
516 do {
517 if (np->parent)
518 np = np->parent;
519 ip = (int *) get_property(np, "#size-cells", NULL);
520 if (ip != NULL)
521 return *ip;
522 } while (np->parent);
523 /* No #size-cells property for the root node, default to 1 */
524 return 1;
525}
526
527static unsigned long __init
528map_addr(struct device_node *np, unsigned long space, unsigned long addr)
529{
530 int na;
531 unsigned int *ranges;
532 int rlen = 0;
533 unsigned int type;
534
535 type = (space >> 24) & 3;
536 if (type == 0)
537 return addr;
538
539 while ((np = np->parent) != NULL) {
540 if (strcmp(np->type, "pci") != 0)
541 continue;
542 /* PCI bridge: map the address through the ranges property */
543 na = prom_n_addr_cells(np);
544 ranges = (unsigned int *) get_property(np, "ranges", &rlen);
545 while ((rlen -= (na + 5) * sizeof(unsigned int)) >= 0) {
546 if (((ranges[0] >> 24) & 3) == type
547 && ranges[2] <= addr
548 && addr - ranges[2] < ranges[na+4]) {
549 /* ok, this matches, translate it */
550 addr += ranges[na+2] - ranges[2];
551 break;
552 }
553 ranges += na + 5;
554 }
555 }
556 return addr;
557}
558
559static unsigned long __init
560interpret_pci_props(struct device_node *np, unsigned long mem_start,
561 int naddrc, int nsizec)
562{
563 struct address_range *adr;
564 struct pci_reg_property *pci_addrs;
565 int i, l, *ip;
566
567 pci_addrs = (struct pci_reg_property *)
568 get_property(np, "assigned-addresses", &l);
569 if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
570 i = 0;
571 adr = (struct address_range *) mem_start;
572 while ((l -= sizeof(struct pci_reg_property)) >= 0) {
573 adr[i].space = pci_addrs[i].addr.a_hi;
574 adr[i].address = map_addr(np, pci_addrs[i].addr.a_hi,
575 pci_addrs[i].addr.a_lo);
576 adr[i].size = pci_addrs[i].size_lo;
577 ++i;
578 }
579 np->addrs = adr;
580 np->n_addrs = i;
581 mem_start += i * sizeof(struct address_range);
582 }
583
584 if (use_of_interrupt_tree)
585 return mem_start;
586
587 ip = (int *) get_property(np, "AAPL,interrupts", &l);
588 if (ip == 0 && np->parent)
589 ip = (int *) get_property(np->parent, "AAPL,interrupts", &l);
590 if (ip == 0)
591 ip = (int *) get_property(np, "interrupts", &l);
592 if (ip != 0) {
593 np->intrs = (struct interrupt_info *) mem_start;
594 np->n_intrs = l / sizeof(int);
595 mem_start += np->n_intrs * sizeof(struct interrupt_info);
596 for (i = 0; i < np->n_intrs; ++i) {
597 np->intrs[i].line = *ip++;
598 np->intrs[i].sense = 1;
599 }
600 }
601
602 return mem_start;
603}
604
605static unsigned long __init
606interpret_dbdma_props(struct device_node *np, unsigned long mem_start,
607 int naddrc, int nsizec)
608{
609 struct reg_property *rp;
610 struct address_range *adr;
611 unsigned long base_address;
612 int i, l, *ip;
613 struct device_node *db;
614
615 base_address = 0;
616 for (db = np->parent; db != NULL; db = db->parent) {
617 if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
618 base_address = db->addrs[0].address;
619 break;
620 }
621 }
622
623 rp = (struct reg_property *) get_property(np, "reg", &l);
624 if (rp != 0 && l >= sizeof(struct reg_property)) {
625 i = 0;
626 adr = (struct address_range *) mem_start;
627 while ((l -= sizeof(struct reg_property)) >= 0) {
628 adr[i].space = 2;
629 adr[i].address = rp[i].address + base_address;
630 adr[i].size = rp[i].size;
631 ++i;
632 }
633 np->addrs = adr;
634 np->n_addrs = i;
635 mem_start += i * sizeof(struct address_range);
636 }
637
638 if (use_of_interrupt_tree)
639 return mem_start;
640
641 ip = (int *) get_property(np, "AAPL,interrupts", &l);
642 if (ip == 0)
643 ip = (int *) get_property(np, "interrupts", &l);
644 if (ip != 0) {
645 np->intrs = (struct interrupt_info *) mem_start;
646 np->n_intrs = l / sizeof(int);
647 mem_start += np->n_intrs * sizeof(struct interrupt_info);
648 for (i = 0; i < np->n_intrs; ++i) {
649 np->intrs[i].line = *ip++;
650 np->intrs[i].sense = 1;
651 }
652 }
653
654 return mem_start;
655}
656
657static unsigned long __init
658interpret_macio_props(struct device_node *np, unsigned long mem_start,
659 int naddrc, int nsizec)
660{
661 struct reg_property *rp;
662 struct address_range *adr;
663 unsigned long base_address;
664 int i, l, *ip;
665 struct device_node *db;
666
667 base_address = 0;
668 for (db = np->parent; db != NULL; db = db->parent) {
669 if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
670 base_address = db->addrs[0].address;
671 break;
672 }
673 }
674
675 rp = (struct reg_property *) get_property(np, "reg", &l);
676 if (rp != 0 && l >= sizeof(struct reg_property)) {
677 i = 0;
678 adr = (struct address_range *) mem_start;
679 while ((l -= sizeof(struct reg_property)) >= 0) {
680 adr[i].space = 2;
681 adr[i].address = rp[i].address + base_address;
682 adr[i].size = rp[i].size;
683 ++i;
684 }
685 np->addrs = adr;
686 np->n_addrs = i;
687 mem_start += i * sizeof(struct address_range);
688 }
689
690 if (use_of_interrupt_tree)
691 return mem_start;
692
693 ip = (int *) get_property(np, "interrupts", &l);
694 if (ip == 0)
695 ip = (int *) get_property(np, "AAPL,interrupts", &l);
696 if (ip != 0) {
697 np->intrs = (struct interrupt_info *) mem_start;
698 np->n_intrs = l / sizeof(int);
699 for (i = 0; i < np->n_intrs; ++i) {
700 np->intrs[i].line = *ip++;
701 np->intrs[i].sense = 1;
702 }
703 mem_start += np->n_intrs * sizeof(struct interrupt_info);
704 }
705
706 return mem_start;
707}
708
709static unsigned long __init
710interpret_isa_props(struct device_node *np, unsigned long mem_start,
711 int naddrc, int nsizec)
712{
713 struct isa_reg_property *rp;
714 struct address_range *adr;
715 int i, l, *ip;
716
717 rp = (struct isa_reg_property *) get_property(np, "reg", &l);
718 if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
719 i = 0;
720 adr = (struct address_range *) mem_start;
721 while ((l -= sizeof(struct reg_property)) >= 0) {
722 adr[i].space = rp[i].space;
723 adr[i].address = rp[i].address
724 + (adr[i].space? 0: _ISA_MEM_BASE);
725 adr[i].size = rp[i].size;
726 ++i;
727 }
728 np->addrs = adr;
729 np->n_addrs = i;
730 mem_start += i * sizeof(struct address_range);
731 }
732
733 if (use_of_interrupt_tree)
734 return mem_start;
735
736 ip = (int *) get_property(np, "interrupts", &l);
737 if (ip != 0) {
738 np->intrs = (struct interrupt_info *) mem_start;
739 np->n_intrs = l / (2 * sizeof(int));
740 mem_start += np->n_intrs * sizeof(struct interrupt_info);
741 for (i = 0; i < np->n_intrs; ++i) {
742 np->intrs[i].line = *ip++;
743 np->intrs[i].sense = *ip++;
744 }
745 }
746
747 return mem_start;
748}
749
750static unsigned long __init
751interpret_root_props(struct device_node *np, unsigned long mem_start,
752 int naddrc, int nsizec)
753{
754 struct address_range *adr;
755 int i, l, *ip;
756 unsigned int *rp;
757 int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
758
759 rp = (unsigned int *) get_property(np, "reg", &l);
760 if (rp != 0 && l >= rpsize) {
761 i = 0;
762 adr = (struct address_range *) mem_start;
763 while ((l -= rpsize) >= 0) {
764 adr[i].space = (naddrc >= 2? rp[naddrc-2]: 2);
765 adr[i].address = rp[naddrc - 1];
766 adr[i].size = rp[naddrc + nsizec - 1];
767 ++i;
768 rp += naddrc + nsizec;
769 }
770 np->addrs = adr;
771 np->n_addrs = i;
772 mem_start += i * sizeof(struct address_range);
773 }
774
775 if (use_of_interrupt_tree)
776 return mem_start;
777
778 ip = (int *) get_property(np, "AAPL,interrupts", &l);
779 if (ip == 0)
780 ip = (int *) get_property(np, "interrupts", &l);
781 if (ip != 0) {
782 np->intrs = (struct interrupt_info *) mem_start;
783 np->n_intrs = l / sizeof(int);
784 mem_start += np->n_intrs * sizeof(struct interrupt_info);
785 for (i = 0; i < np->n_intrs; ++i) {
786 np->intrs[i].line = *ip++;
787 np->intrs[i].sense = 1;
788 }
789 }
790
791 return mem_start;
792}
793
794/*
795 * Work out the sense (active-low level / active-high edge)
796 * of each interrupt from the device tree.
797 */
798void __init
799prom_get_irq_senses(unsigned char *senses, int off, int max)
800{
801 struct device_node *np;
802 int i, j;
803
804 /* default to level-triggered */
805 memset(senses, 1, max - off);
806 if (!use_of_interrupt_tree)
807 return;
808
809 for (np = allnodes; np != 0; np = np->allnext) {
810 for (j = 0; j < np->n_intrs; j++) {
811 i = np->intrs[j].line;
812 if (i >= off && i < max) {
813 if (np->intrs[j].sense == 1)
814 senses[i-off] = (IRQ_SENSE_LEVEL
815 | IRQ_POLARITY_NEGATIVE);
816 else
817 senses[i-off] = (IRQ_SENSE_EDGE
818 | IRQ_POLARITY_POSITIVE);
819 }
820 }
821 }
822}
823
824/*
825 * Construct and return a list of the device_nodes with a given name.
826 */
827struct device_node *
828find_devices(const char *name)
829{
830 struct device_node *head, **prevp, *np;
831
832 prevp = &head;
833 for (np = allnodes; np != 0; np = np->allnext) {
834 if (np->name != 0 && strcasecmp(np->name, name) == 0) {
835 *prevp = np;
836 prevp = &np->next;
837 }
838 }
839 *prevp = NULL;
840 return head;
841}
842
843/*
844 * Construct and return a list of the device_nodes with a given type.
845 */
846struct device_node *
847find_type_devices(const char *type)
848{
849 struct device_node *head, **prevp, *np;
850
851 prevp = &head;
852 for (np = allnodes; np != 0; np = np->allnext) {
853 if (np->type != 0 && strcasecmp(np->type, type) == 0) {
854 *prevp = np;
855 prevp = &np->next;
856 }
857 }
858 *prevp = NULL;
859 return head;
860}
861
862/*
863 * Returns all nodes linked together
864 */
865struct device_node * __openfirmware
866find_all_nodes(void)
867{
868 struct device_node *head, **prevp, *np;
869
870 prevp = &head;
871 for (np = allnodes; np != 0; np = np->allnext) {
872 *prevp = np;
873 prevp = &np->next;
874 }
875 *prevp = NULL;
876 return head;
877}
878
879/* Checks if the given "compat" string matches one of the strings in
880 * the device's "compatible" property
881 */
882int
883device_is_compatible(struct device_node *device, const char *compat)
884{
885 const char* cp;
886 int cplen, l;
887
888 cp = (char *) get_property(device, "compatible", &cplen);
889 if (cp == NULL)
890 return 0;
891 while (cplen > 0) {
892 if (strncasecmp(cp, compat, strlen(compat)) == 0)
893 return 1;
894 l = strlen(cp) + 1;
895 cp += l;
896 cplen -= l;
897 }
898
899 return 0;
900}
901
902
903/*
904 * Indicates whether the root node has a given value in its
905 * compatible property.
906 */
907int
908machine_is_compatible(const char *compat)
909{
910 struct device_node *root;
911
912 root = find_path_device("/");
913 if (root == 0)
914 return 0;
915 return device_is_compatible(root, compat);
916}
917
918/*
919 * Construct and return a list of the device_nodes with a given type
920 * and compatible property.
921 */
922struct device_node *
923find_compatible_devices(const char *type, const char *compat)
924{
925 struct device_node *head, **prevp, *np;
926
927 prevp = &head;
928 for (np = allnodes; np != 0; np = np->allnext) {
929 if (type != NULL
930 && !(np->type != 0 && strcasecmp(np->type, type) == 0))
931 continue;
932 if (device_is_compatible(np, compat)) {
933 *prevp = np;
934 prevp = &np->next;
935 }
936 }
937 *prevp = NULL;
938 return head;
939}
940
941/*
942 * Find the device_node with a given full_name.
943 */
944struct device_node *
945find_path_device(const char *path)
946{
947 struct device_node *np;
948
949 for (np = allnodes; np != 0; np = np->allnext)
950 if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
951 return np;
952 return NULL;
953}
954
955/*******
956 *
957 * New implementation of the OF "find" APIs, return a refcounted
958 * object, call of_node_put() when done. Currently, still lacks
959 * locking as old implementation, this is beeing done for ppc64.
960 *
961 * Note that property management will need some locking as well,
962 * this isn't dealt with yet
963 *
964 *******/
965
966/**
967 * of_find_node_by_name - Find a node by it's "name" property
968 * @from: The node to start searching from or NULL, the node
969 * you pass will not be searched, only the next one
970 * will; typically, you pass what the previous call
971 * returned. of_node_put() will be called on it
972 * @name: The name string to match against
973 *
974 * Returns a node pointer with refcount incremented, use
975 * of_node_put() on it when done.
976 */
977struct device_node *of_find_node_by_name(struct device_node *from,
978 const char *name)
979{
980 struct device_node *np = from ? from->allnext : allnodes;
981
982 for (; np != 0; np = np->allnext)
983 if (np->name != 0 && strcasecmp(np->name, name) == 0)
984 break;
985 if (from)
986 of_node_put(from);
987 return of_node_get(np);
988}
989
990/**
991 * of_find_node_by_type - Find a node by it's "device_type" property
992 * @from: The node to start searching from or NULL, the node
993 * you pass will not be searched, only the next one
994 * will; typically, you pass what the previous call
995 * returned. of_node_put() will be called on it
996 * @name: The type string to match against
997 *
998 * Returns a node pointer with refcount incremented, use
999 * of_node_put() on it when done.
1000 */
1001struct device_node *of_find_node_by_type(struct device_node *from,
1002 const char *type)
1003{
1004 struct device_node *np = from ? from->allnext : allnodes;
1005
1006 for (; np != 0; np = np->allnext)
1007 if (np->type != 0 && strcasecmp(np->type, type) == 0)
1008 break;
1009 if (from)
1010 of_node_put(from);
1011 return of_node_get(np);
1012}
1013
1014/**
1015 * of_find_compatible_node - Find a node based on type and one of the
1016 * tokens in it's "compatible" property
1017 * @from: The node to start searching from or NULL, the node
1018 * you pass will not be searched, only the next one
1019 * will; typically, you pass what the previous call
1020 * returned. of_node_put() will be called on it
1021 * @type: The type string to match "device_type" or NULL to ignore
1022 * @compatible: The string to match to one of the tokens in the device
1023 * "compatible" list.
1024 *
1025 * Returns a node pointer with refcount incremented, use
1026 * of_node_put() on it when done.
1027 */
1028struct device_node *of_find_compatible_node(struct device_node *from,
1029 const char *type, const char *compatible)
1030{
1031 struct device_node *np = from ? from->allnext : allnodes;
1032
1033 for (; np != 0; np = np->allnext) {
1034 if (type != NULL
1035 && !(np->type != 0 && strcasecmp(np->type, type) == 0))
1036 continue;
1037 if (device_is_compatible(np, compatible))
1038 break;
1039 }
1040 if (from)
1041 of_node_put(from);
1042 return of_node_get(np);
1043}
1044
1045/**
1046 * of_find_node_by_path - Find a node matching a full OF path
1047 * @path: The full path to match
1048 *
1049 * Returns a node pointer with refcount incremented, use
1050 * of_node_put() on it when done.
1051 */
1052struct device_node *of_find_node_by_path(const char *path)
1053{
1054 struct device_node *np = allnodes;
1055
1056 for (; np != 0; np = np->allnext)
1057 if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
1058 break;
1059 return of_node_get(np);
1060}
1061
1062/**
1063 * of_find_all_nodes - Get next node in global list
1064 * @prev: Previous node or NULL to start iteration
1065 * of_node_put() will be called on it
1066 *
1067 * Returns a node pointer with refcount incremented, use
1068 * of_node_put() on it when done.
1069 */
1070struct device_node *of_find_all_nodes(struct device_node *prev)
1071{
1072 return of_node_get(prev ? prev->allnext : allnodes);
1073}
1074
1075/**
1076 * of_get_parent - Get a node's parent if any
1077 * @node: Node to get parent
1078 *
1079 * Returns a node pointer with refcount incremented, use
1080 * of_node_put() on it when done.
1081 */
1082struct device_node *of_get_parent(const struct device_node *node)
1083{
1084 return node ? of_node_get(node->parent) : NULL;
1085}
1086
1087/**
1088 * of_get_next_child - Iterate a node childs
1089 * @node: parent node
1090 * @prev: previous child of the parent node, or NULL to get first
1091 *
1092 * Returns a node pointer with refcount incremented, use
1093 * of_node_put() on it when done.
1094 */
1095struct device_node *of_get_next_child(const struct device_node *node,
1096 struct device_node *prev)
1097{
1098 struct device_node *next = prev ? prev->sibling : node->child;
1099
1100 for (; next != 0; next = next->sibling)
1101 if (of_node_get(next))
1102 break;
1103 if (prev)
1104 of_node_put(prev);
1105 return next;
1106}
1107
1108/**
1109 * of_node_get - Increment refcount of a node
1110 * @node: Node to inc refcount, NULL is supported to
1111 * simplify writing of callers
1112 *
1113 * Returns the node itself or NULL if gone. Current implementation
1114 * does nothing as we don't yet do dynamic node allocation on ppc32
1115 */
1116struct device_node *of_node_get(struct device_node *node)
1117{
1118 return node;
1119}
1120
1121/**
1122 * of_node_put - Decrement refcount of a node
1123 * @node: Node to dec refcount, NULL is supported to
1124 * simplify writing of callers
1125 *
1126 * Current implementation does nothing as we don't yet do dynamic node
1127 * allocation on ppc32
1128 */
1129void of_node_put(struct device_node *node)
1130{
1131}
1132
1133/*
1134 * Find the device_node with a given phandle.
1135 */
1136static struct device_node * __init
1137find_phandle(phandle ph)
1138{
1139 struct device_node *np;
1140
1141 for (np = allnodes; np != 0; np = np->allnext)
1142 if (np->node == ph)
1143 return np;
1144 return NULL;
1145}
1146
1147/*
1148 * Find a property with a given name for a given node
1149 * and return the value.
1150 */
1151unsigned char *
1152get_property(struct device_node *np, const char *name, int *lenp)
1153{
1154 struct property *pp;
1155
1156 for (pp = np->properties; pp != 0; pp = pp->next)
1157 if (pp->name != NULL && strcmp(pp->name, name) == 0) {
1158 if (lenp != 0)
1159 *lenp = pp->length;
1160 return pp->value;
1161 }
1162 return NULL;
1163}
1164
1165/*
1166 * Add a property to a node
1167 */
1168void __openfirmware
1169prom_add_property(struct device_node* np, struct property* prop)
1170{
1171 struct property **next = &np->properties;
1172
1173 prop->next = NULL;
1174 while (*next)
1175 next = &(*next)->next;
1176 *next = prop;
1177}
1178
1179/* I quickly hacked that one, check against spec ! */
1180static inline unsigned long __openfirmware
1181bus_space_to_resource_flags(unsigned int bus_space)
1182{
1183 u8 space = (bus_space >> 24) & 0xf;
1184 if (space == 0)
1185 space = 0x02;
1186 if (space == 0x02)
1187 return IORESOURCE_MEM;
1188 else if (space == 0x01)
1189 return IORESOURCE_IO;
1190 else {
1191 printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
1192 bus_space);
1193 return 0;
1194 }
1195}
1196
1197static struct resource* __openfirmware
1198find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range)
1199{
1200 unsigned long mask;
1201 int i;
1202
1203 /* Check this one */
1204 mask = bus_space_to_resource_flags(range->space);
1205 for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
1206 if ((pdev->resource[i].flags & mask) == mask &&
1207 pdev->resource[i].start <= range->address &&
1208 pdev->resource[i].end > range->address) {
1209 if ((range->address + range->size - 1) > pdev->resource[i].end) {
1210 /* Add better message */
1211 printk(KERN_WARNING "PCI/OF resource overlap !\n");
1212 return NULL;
1213 }
1214 break;
1215 }
1216 }
1217 if (i == DEVICE_COUNT_RESOURCE)
1218 return NULL;
1219 return &pdev->resource[i];
1220}
1221
1222/*
1223 * Request an OF device resource. Currently handles child of PCI devices,
1224 * or other nodes attached to the root node. Ultimately, put some
1225 * link to resources in the OF node.
1226 */
1227struct resource* __openfirmware
1228request_OF_resource(struct device_node* node, int index, const char* name_postfix)
1229{
1230 struct pci_dev* pcidev;
1231 u8 pci_bus, pci_devfn;
1232 unsigned long iomask;
1233 struct device_node* nd;
1234 struct resource* parent;
1235 struct resource *res = NULL;
1236 int nlen, plen;
1237
1238 if (index >= node->n_addrs)
1239 goto fail;
1240
1241 /* Sanity check on bus space */
1242 iomask = bus_space_to_resource_flags(node->addrs[index].space);
1243 if (iomask & IORESOURCE_MEM)
1244 parent = &iomem_resource;
1245 else if (iomask & IORESOURCE_IO)
1246 parent = &ioport_resource;
1247 else
1248 goto fail;
1249
1250 /* Find a PCI parent if any */
1251 nd = node;
1252 pcidev = NULL;
1253 while(nd) {
1254 if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
1255 pcidev = pci_find_slot(pci_bus, pci_devfn);
1256 if (pcidev) break;
1257 nd = nd->parent;
1258 }
1259 if (pcidev)
1260 parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
1261 if (!parent) {
1262 printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
1263 node->name);
1264 goto fail;
1265 }
1266
1267 res = __request_region(parent, node->addrs[index].address, node->addrs[index].size, NULL);
1268 if (!res)
1269 goto fail;
1270 nlen = strlen(node->name);
1271 plen = name_postfix ? strlen(name_postfix) : 0;
1272 res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
1273 if (res->name) {
1274 strcpy((char *)res->name, node->name);
1275 if (plen)
1276 strcpy((char *)res->name+nlen, name_postfix);
1277 }
1278 return res;
1279fail:
1280 return NULL;
1281}
1282
1283int __openfirmware
1284release_OF_resource(struct device_node* node, int index)
1285{
1286 struct pci_dev* pcidev;
1287 u8 pci_bus, pci_devfn;
1288 unsigned long iomask, start, end;
1289 struct device_node* nd;
1290 struct resource* parent;
1291 struct resource *res = NULL;
1292
1293 if (index >= node->n_addrs)
1294 return -EINVAL;
1295
1296 /* Sanity check on bus space */
1297 iomask = bus_space_to_resource_flags(node->addrs[index].space);
1298 if (iomask & IORESOURCE_MEM)
1299 parent = &iomem_resource;
1300 else if (iomask & IORESOURCE_IO)
1301 parent = &ioport_resource;
1302 else
1303 return -EINVAL;
1304
1305 /* Find a PCI parent if any */
1306 nd = node;
1307 pcidev = NULL;
1308 while(nd) {
1309 if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
1310 pcidev = pci_find_slot(pci_bus, pci_devfn);
1311 if (pcidev) break;
1312 nd = nd->parent;
1313 }
1314 if (pcidev)
1315 parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
1316 if (!parent) {
1317 printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
1318 node->name);
1319 return -ENODEV;
1320 }
1321
1322 /* Find us in the parent and its childs */
1323 res = parent->child;
1324 start = node->addrs[index].address;
1325 end = start + node->addrs[index].size - 1;
1326 while (res) {
1327 if (res->start == start && res->end == end &&
1328 (res->flags & IORESOURCE_BUSY))
1329 break;
1330 if (res->start <= start && res->end >= end)
1331 res = res->child;
1332 else
1333 res = res->sibling;
1334 }
1335 if (!res)
1336 return -ENODEV;
1337
1338 if (res->name) {
1339 kfree(res->name);
1340 res->name = NULL;
1341 }
1342 release_resource(res);
1343 kfree(res);
1344
1345 return 0;
1346}
1347
1348#if 0
1349void __openfirmware
1350print_properties(struct device_node *np)
1351{
1352 struct property *pp;
1353 char *cp;
1354 int i, n;
1355
1356 for (pp = np->properties; pp != 0; pp = pp->next) {
1357 printk(KERN_INFO "%s", pp->name);
1358 for (i = strlen(pp->name); i < 16; ++i)
1359 printk(" ");
1360 cp = (char *) pp->value;
1361 for (i = pp->length; i > 0; --i, ++cp)
1362 if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
1363 || (i == 1 && *cp != 0))
1364 break;
1365 if (i == 0 && pp->length > 1) {
1366 /* looks like a string */
1367 printk(" %s\n", (char *) pp->value);
1368 } else {
1369 /* dump it in hex */
1370 n = pp->length;
1371 if (n > 64)
1372 n = 64;
1373 if (pp->length % 4 == 0) {
1374 unsigned int *p = (unsigned int *) pp->value;
1375
1376 n /= 4;
1377 for (i = 0; i < n; ++i) {
1378 if (i != 0 && (i % 4) == 0)
1379 printk("\n ");
1380 printk(" %08x", *p++);
1381 }
1382 } else {
1383 unsigned char *bp = pp->value;
1384
1385 for (i = 0; i < n; ++i) {
1386 if (i != 0 && (i % 16) == 0)
1387 printk("\n ");
1388 printk(" %02x", *bp++);
1389 }
1390 }
1391 printk("\n");
1392 if (pp->length > 64)
1393 printk(" ... (length = %d)\n",
1394 pp->length);
1395 }
1396 }
1397}
1398#endif
1399
1400static DEFINE_SPINLOCK(rtas_lock);
1401
1402/* this can be called after setup -- Cort */
1403int __openfirmware
1404call_rtas(const char *service, int nargs, int nret,
1405 unsigned long *outputs, ...)
1406{
1407 va_list list;
1408 int i;
1409 unsigned long s;
1410 struct device_node *rtas;
1411 int *tokp;
1412 union {
1413 unsigned long words[16];
1414 double align;
1415 } u;
1416
1417 rtas = find_devices("rtas");
1418 if (rtas == NULL)
1419 return -1;
1420 tokp = (int *) get_property(rtas, service, NULL);
1421 if (tokp == NULL) {
1422 printk(KERN_ERR "No RTAS service called %s\n", service);
1423 return -1;
1424 }
1425 u.words[0] = *tokp;
1426 u.words[1] = nargs;
1427 u.words[2] = nret;
1428 va_start(list, outputs);
1429 for (i = 0; i < nargs; ++i)
1430 u.words[i+3] = va_arg(list, unsigned long);
1431 va_end(list);
1432
1433 /*
1434 * RTAS doesn't use floating point.
1435 * Or at least, according to the CHRP spec we enter RTAS
1436 * with FP disabled, and it doesn't change the FP registers.
1437 * -- paulus.
1438 */
1439 spin_lock_irqsave(&rtas_lock, s);
1440 enter_rtas((void *)__pa(&u));
1441 spin_unlock_irqrestore(&rtas_lock, s);
1442
1443 if (nret > 1 && outputs != NULL)
1444 for (i = 0; i < nret-1; ++i)
1445 outputs[i] = u.words[i+nargs+4];
1446 return u.words[nargs+3];
1447}
diff --git a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c
new file mode 100644
index 000000000000..2cee87137f2e
--- /dev/null
+++ b/arch/ppc/syslib/prom_init.c
@@ -0,0 +1,1002 @@
1/*
2 * Note that prom_init() and anything called from prom_init()
3 * may be running at an address that is different from the address
4 * that it was linked at. References to static data items are
5 * handled by compiling this file with -mrelocatable-lib.
6 */
7
8#include <linux/config.h>
9#include <linux/kernel.h>
10#include <linux/string.h>
11#include <linux/init.h>
12#include <linux/version.h>
13#include <linux/threads.h>
14#include <linux/spinlock.h>
15#include <linux/ioport.h>
16#include <linux/pci.h>
17#include <linux/slab.h>
18#include <linux/bitops.h>
19
20#include <asm/sections.h>
21#include <asm/prom.h>
22#include <asm/page.h>
23#include <asm/irq.h>
24#include <asm/io.h>
25#include <asm/smp.h>
26#include <asm/bootx.h>
27#include <asm/system.h>
28#include <asm/mmu.h>
29#include <asm/pgtable.h>
30#include <asm/bootinfo.h>
31#include <asm/btext.h>
32#include <asm/pci-bridge.h>
33#include <asm/open_pic.h>
34#include <asm/cacheflush.h>
35
36#ifdef CONFIG_LOGO_LINUX_CLUT224
37#include <linux/linux_logo.h>
38extern const struct linux_logo logo_linux_clut224;
39#endif
40
41/*
42 * Properties whose value is longer than this get excluded from our
43 * copy of the device tree. This way we don't waste space storing
44 * things like "driver,AAPL,MacOS,PowerPC" properties. But this value
45 * does need to be big enough to ensure that we don't lose things
46 * like the interrupt-map property on a PCI-PCI bridge.
47 */
48#define MAX_PROPERTY_LENGTH 4096
49
50#ifndef FB_MAX /* avoid pulling in all of the fb stuff */
51#define FB_MAX 8
52#endif
53
54#define ALIGNUL(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
55
56typedef u32 prom_arg_t;
57
58struct prom_args {
59 const char *service;
60 int nargs;
61 int nret;
62 prom_arg_t args[10];
63};
64
65struct pci_address {
66 unsigned a_hi;
67 unsigned a_mid;
68 unsigned a_lo;
69};
70
71struct pci_reg_property {
72 struct pci_address addr;
73 unsigned size_hi;
74 unsigned size_lo;
75};
76
77struct pci_range {
78 struct pci_address addr;
79 unsigned phys;
80 unsigned size_hi;
81 unsigned size_lo;
82};
83
84struct isa_reg_property {
85 unsigned space;
86 unsigned address;
87 unsigned size;
88};
89
90struct pci_intr_map {
91 struct pci_address addr;
92 unsigned dunno;
93 phandle int_ctrler;
94 unsigned intr;
95};
96
97static void prom_exit(void);
98static int call_prom(const char *service, int nargs, int nret, ...);
99static int call_prom_ret(const char *service, int nargs, int nret,
100 prom_arg_t *rets, ...);
101static void prom_print_hex(unsigned int v);
102static int prom_set_color(ihandle ih, int i, int r, int g, int b);
103static int prom_next_node(phandle *nodep);
104static unsigned long check_display(unsigned long mem);
105static void setup_disp_fake_bi(ihandle dp);
106static unsigned long copy_device_tree(unsigned long mem_start,
107 unsigned long mem_end);
108static unsigned long inspect_node(phandle node, struct device_node *dad,
109 unsigned long mem_start, unsigned long mem_end,
110 struct device_node ***allnextpp);
111static void prom_hold_cpus(unsigned long mem);
112static void prom_instantiate_rtas(void);
113static void * early_get_property(unsigned long base, unsigned long node,
114 char *prop);
115
116prom_entry prom __initdata;
117ihandle prom_chosen __initdata;
118ihandle prom_stdout __initdata;
119
120static char *prom_display_paths[FB_MAX] __initdata;
121static phandle prom_display_nodes[FB_MAX] __initdata;
122static unsigned int prom_num_displays __initdata;
123static ihandle prom_disp_node __initdata;
124char *of_stdout_device __initdata;
125
126unsigned int rtas_data; /* physical pointer */
127unsigned int rtas_entry; /* physical pointer */
128unsigned int rtas_size;
129unsigned int old_rtas;
130
131boot_infos_t *boot_infos;
132char *bootpath;
133char *bootdevice;
134struct device_node *allnodes;
135
136extern char *klimit;
137
138static void __init
139prom_exit(void)
140{
141 struct prom_args args;
142
143 args.service = "exit";
144 args.nargs = 0;
145 args.nret = 0;
146 prom(&args);
147 for (;;) /* should never get here */
148 ;
149}
150
151static int __init
152call_prom(const char *service, int nargs, int nret, ...)
153{
154 va_list list;
155 int i;
156 struct prom_args prom_args;
157
158 prom_args.service = service;
159 prom_args.nargs = nargs;
160 prom_args.nret = nret;
161 va_start(list, nret);
162 for (i = 0; i < nargs; ++i)
163 prom_args.args[i] = va_arg(list, prom_arg_t);
164 va_end(list);
165 for (i = 0; i < nret; ++i)
166 prom_args.args[i + nargs] = 0;
167 prom(&prom_args);
168 return prom_args.args[nargs];
169}
170
171static int __init
172call_prom_ret(const char *service, int nargs, int nret, prom_arg_t *rets, ...)
173{
174 va_list list;
175 int i;
176 struct prom_args prom_args;
177
178 prom_args.service = service;
179 prom_args.nargs = nargs;
180 prom_args.nret = nret;
181 va_start(list, rets);
182 for (i = 0; i < nargs; ++i)
183 prom_args.args[i] = va_arg(list, int);
184 va_end(list);
185 for (i = 0; i < nret; ++i)
186 prom_args.args[i + nargs] = 0;
187 prom(&prom_args);
188 for (i = 1; i < nret; ++i)
189 rets[i-1] = prom_args.args[nargs + i];
190 return prom_args.args[nargs];
191}
192
193void __init
194prom_print(const char *msg)
195{
196 const char *p, *q;
197
198 if (prom_stdout == 0)
199 return;
200
201 for (p = msg; *p != 0; p = q) {
202 for (q = p; *q != 0 && *q != '\n'; ++q)
203 ;
204 if (q > p)
205 call_prom("write", 3, 1, prom_stdout, p, q - p);
206 if (*q != 0) {
207 ++q;
208 call_prom("write", 3, 1, prom_stdout, "\r\n", 2);
209 }
210 }
211}
212
213static void __init
214prom_print_hex(unsigned int v)
215{
216 char buf[16];
217 int i, c;
218
219 for (i = 0; i < 8; ++i) {
220 c = (v >> ((7-i)*4)) & 0xf;
221 c += (c >= 10)? ('a' - 10): '0';
222 buf[i] = c;
223 }
224 buf[i] = ' ';
225 buf[i+1] = 0;
226 prom_print(buf);
227}
228
229static int __init
230prom_set_color(ihandle ih, int i, int r, int g, int b)
231{
232 return call_prom("call-method", 6, 1, "color!", ih, i, b, g, r);
233}
234
235static int __init
236prom_next_node(phandle *nodep)
237{
238 phandle node;
239
240 if ((node = *nodep) != 0
241 && (*nodep = call_prom("child", 1, 1, node)) != 0)
242 return 1;
243 if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
244 return 1;
245 for (;;) {
246 if ((node = call_prom("parent", 1, 1, node)) == 0)
247 return 0;
248 if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
249 return 1;
250 }
251}
252
253#ifdef CONFIG_POWER4
254/*
255 * Set up a hash table with a set of entries in it to map the
256 * first 64MB of RAM. This is used on 64-bit machines since
257 * some of them don't have BATs.
258 */
259
260static inline void make_pte(unsigned long htab, unsigned int hsize,
261 unsigned int va, unsigned int pa, int mode)
262{
263 unsigned int *pteg;
264 unsigned int hash, i, vsid;
265
266 vsid = ((va >> 28) * 0x111) << 12;
267 hash = ((va ^ vsid) >> 5) & 0x7fff80;
268 pteg = (unsigned int *)(htab + (hash & (hsize - 1)));
269 for (i = 0; i < 8; ++i, pteg += 4) {
270 if ((pteg[1] & 1) == 0) {
271 pteg[1] = vsid | ((va >> 16) & 0xf80) | 1;
272 pteg[3] = pa | mode;
273 break;
274 }
275 }
276}
277
278extern unsigned long _SDR1;
279extern PTE *Hash;
280extern unsigned long Hash_size;
281
282static void __init
283prom_alloc_htab(void)
284{
285 unsigned int hsize;
286 unsigned long htab;
287 unsigned int addr;
288
289 /*
290 * Because of OF bugs we can't use the "claim" client
291 * interface to allocate memory for the hash table.
292 * This code is only used on 64-bit PPCs, and the only
293 * 64-bit PPCs at the moment are RS/6000s, and their
294 * OF is based at 0xc00000 (the 12M point), so we just
295 * arbitrarily use the 0x800000 - 0xc00000 region for the
296 * hash table.
297 * -- paulus.
298 */
299 hsize = 4 << 20; /* POWER4 has no BATs */
300 htab = (8 << 20);
301 call_prom("claim", 3, 1, htab, hsize, 0);
302 Hash = (void *)(htab + KERNELBASE);
303 Hash_size = hsize;
304 _SDR1 = htab + __ilog2(hsize) - 18;
305
306 /*
307 * Put in PTEs for the first 64MB of RAM
308 */
309 memset((void *)htab, 0, hsize);
310 for (addr = 0; addr < 0x4000000; addr += 0x1000)
311 make_pte(htab, hsize, addr + KERNELBASE, addr,
312 _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX);
313#if 0 /* DEBUG stuff mapping the SCC */
314 make_pte(htab, hsize, 0x80013000, 0x80013000,
315 _PAGE_ACCESSED | _PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX);
316#endif
317}
318#endif /* CONFIG_POWER4 */
319
320
321/*
322 * If we have a display that we don't know how to drive,
323 * we will want to try to execute OF's open method for it
324 * later. However, OF will probably fall over if we do that
325 * we've taken over the MMU.
326 * So we check whether we will need to open the display,
327 * and if so, open it now.
328 */
329static unsigned long __init
330check_display(unsigned long mem)
331{
332 phandle node;
333 ihandle ih;
334 int i, j;
335 char type[16], *path;
336 static unsigned char default_colors[] = {
337 0x00, 0x00, 0x00,
338 0x00, 0x00, 0xaa,
339 0x00, 0xaa, 0x00,
340 0x00, 0xaa, 0xaa,
341 0xaa, 0x00, 0x00,
342 0xaa, 0x00, 0xaa,
343 0xaa, 0xaa, 0x00,
344 0xaa, 0xaa, 0xaa,
345 0x55, 0x55, 0x55,
346 0x55, 0x55, 0xff,
347 0x55, 0xff, 0x55,
348 0x55, 0xff, 0xff,
349 0xff, 0x55, 0x55,
350 0xff, 0x55, 0xff,
351 0xff, 0xff, 0x55,
352 0xff, 0xff, 0xff
353 };
354 const unsigned char *clut;
355
356 prom_disp_node = 0;
357
358 for (node = 0; prom_next_node(&node); ) {
359 type[0] = 0;
360 call_prom("getprop", 4, 1, node, "device_type",
361 type, sizeof(type));
362 if (strcmp(type, "display") != 0)
363 continue;
364 /* It seems OF doesn't null-terminate the path :-( */
365 path = (char *) mem;
366 memset(path, 0, 256);
367 if (call_prom("package-to-path", 3, 1, node, path, 255) < 0)
368 continue;
369
370 /*
371 * If this display is the device that OF is using for stdout,
372 * move it to the front of the list.
373 */
374 mem += strlen(path) + 1;
375 i = prom_num_displays++;
376 if (of_stdout_device != 0 && i > 0
377 && strcmp(of_stdout_device, path) == 0) {
378 for (; i > 0; --i) {
379 prom_display_paths[i]
380 = prom_display_paths[i-1];
381 prom_display_nodes[i]
382 = prom_display_nodes[i-1];
383 }
384 }
385 prom_display_paths[i] = path;
386 prom_display_nodes[i] = node;
387 if (i == 0)
388 prom_disp_node = node;
389 if (prom_num_displays >= FB_MAX)
390 break;
391 }
392
393 for (j=0; j<prom_num_displays; j++) {
394 path = prom_display_paths[j];
395 node = prom_display_nodes[j];
396 prom_print("opening display ");
397 prom_print(path);
398 ih = call_prom("open", 1, 1, path);
399 if (ih == 0 || ih == (ihandle) -1) {
400 prom_print("... failed\n");
401 for (i=j+1; i<prom_num_displays; i++) {
402 prom_display_paths[i-1] = prom_display_paths[i];
403 prom_display_nodes[i-1] = prom_display_nodes[i];
404 }
405 if (--prom_num_displays > 0) {
406 prom_disp_node = prom_display_nodes[j];
407 j--;
408 } else
409 prom_disp_node = 0;
410 continue;
411 } else {
412 prom_print("... ok\n");
413 call_prom("setprop", 4, 1, node, "linux,opened", 0, 0);
414
415 /*
416 * Setup a usable color table when the appropriate
417 * method is available.
418 * Should update this to use set-colors.
419 */
420 clut = default_colors;
421 for (i = 0; i < 32; i++, clut += 3)
422 if (prom_set_color(ih, i, clut[0], clut[1],
423 clut[2]) != 0)
424 break;
425
426#ifdef CONFIG_LOGO_LINUX_CLUT224
427 clut = PTRRELOC(logo_linux_clut224.clut);
428 for (i = 0; i < logo_linux_clut224.clutsize;
429 i++, clut += 3)
430 if (prom_set_color(ih, i + 32, clut[0],
431 clut[1], clut[2]) != 0)
432 break;
433#endif /* CONFIG_LOGO_LINUX_CLUT224 */
434 }
435 }
436
437 if (prom_stdout) {
438 phandle p;
439 p = call_prom("instance-to-package", 1, 1, prom_stdout);
440 if (p && p != -1) {
441 type[0] = 0;
442 call_prom("getprop", 4, 1, p, "device_type",
443 type, sizeof(type));
444 if (strcmp(type, "display") == 0)
445 call_prom("setprop", 4, 1, p, "linux,boot-display",
446 0, 0);
447 }
448 }
449
450 return ALIGNUL(mem);
451}
452
453/* This function will enable the early boot text when doing OF booting. This
454 * way, xmon output should work too
455 */
456static void __init
457setup_disp_fake_bi(ihandle dp)
458{
459#ifdef CONFIG_BOOTX_TEXT
460 int width = 640, height = 480, depth = 8, pitch;
461 unsigned address;
462 struct pci_reg_property addrs[8];
463 int i, naddrs;
464 char name[32];
465 char *getprop = "getprop";
466
467 prom_print("Initializing fake screen: ");
468
469 memset(name, 0, sizeof(name));
470 call_prom(getprop, 4, 1, dp, "name", name, sizeof(name));
471 name[sizeof(name)-1] = 0;
472 prom_print(name);
473 prom_print("\n");
474 call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width));
475 call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height));
476 call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth));
477 pitch = width * ((depth + 7) / 8);
478 call_prom(getprop, 4, 1, dp, "linebytes",
479 &pitch, sizeof(pitch));
480 if (pitch == 1)
481 pitch = 0x1000; /* for strange IBM display */
482 address = 0;
483 call_prom(getprop, 4, 1, dp, "address",
484 &address, sizeof(address));
485 if (address == 0) {
486 /* look for an assigned address with a size of >= 1MB */
487 naddrs = call_prom(getprop, 4, 1, dp, "assigned-addresses",
488 addrs, sizeof(addrs));
489 naddrs /= sizeof(struct pci_reg_property);
490 for (i = 0; i < naddrs; ++i) {
491 if (addrs[i].size_lo >= (1 << 20)) {
492 address = addrs[i].addr.a_lo;
493 /* use the BE aperture if possible */
494 if (addrs[i].size_lo >= (16 << 20))
495 address += (8 << 20);
496 break;
497 }
498 }
499 if (address == 0) {
500 prom_print("Failed to get address\n");
501 return;
502 }
503 }
504 /* kludge for valkyrie */
505 if (strcmp(name, "valkyrie") == 0)
506 address += 0x1000;
507
508#ifdef CONFIG_POWER4
509#if CONFIG_TASK_SIZE > 0x80000000
510#error CONFIG_TASK_SIZE cannot be above 0x80000000 with BOOTX_TEXT on G5
511#endif
512 {
513 extern boot_infos_t disp_bi;
514 unsigned long va, pa, i, offset;
515 va = 0x90000000;
516 pa = address & 0xfffff000ul;
517 offset = address & 0x00000fff;
518
519 for (i=0; i<0x4000; i++) {
520 make_pte((unsigned long)Hash - KERNELBASE, Hash_size, va, pa,
521 _PAGE_ACCESSED | _PAGE_NO_CACHE |
522 _PAGE_GUARDED | PP_RWXX);
523 va += 0x1000;
524 pa += 0x1000;
525 }
526 btext_setup_display(width, height, depth, pitch, 0x90000000 | offset);
527 disp_bi.dispDeviceBase = (u8 *)address;
528 }
529#else /* CONFIG_POWER4 */
530 btext_setup_display(width, height, depth, pitch, address);
531 btext_prepare_BAT();
532#endif /* CONFIG_POWER4 */
533#endif /* CONFIG_BOOTX_TEXT */
534}
535
536/*
537 * Make a copy of the device tree from the PROM.
538 */
539static unsigned long __init
540copy_device_tree(unsigned long mem_start, unsigned long mem_end)
541{
542 phandle root;
543 unsigned long new_start;
544 struct device_node **allnextp;
545
546 root = call_prom("peer", 1, 1, (phandle)0);
547 if (root == (phandle)0) {
548 prom_print("couldn't get device tree root\n");
549 prom_exit();
550 }
551 allnextp = &allnodes;
552 mem_start = ALIGNUL(mem_start);
553 new_start = inspect_node(root, NULL, mem_start, mem_end, &allnextp);
554 *allnextp = NULL;
555 return new_start;
556}
557
558static unsigned long __init
559inspect_node(phandle node, struct device_node *dad,
560 unsigned long mem_start, unsigned long mem_end,
561 struct device_node ***allnextpp)
562{
563 int l;
564 phandle child;
565 struct device_node *np;
566 struct property *pp, **prev_propp;
567 char *prev_name, *namep;
568 unsigned char *valp;
569
570 np = (struct device_node *) mem_start;
571 mem_start += sizeof(struct device_node);
572 memset(np, 0, sizeof(*np));
573 np->node = node;
574 **allnextpp = PTRUNRELOC(np);
575 *allnextpp = &np->allnext;
576 if (dad != 0) {
577 np->parent = PTRUNRELOC(dad);
578 /* we temporarily use the `next' field as `last_child'. */
579 if (dad->next == 0)
580 dad->child = PTRUNRELOC(np);
581 else
582 dad->next->sibling = PTRUNRELOC(np);
583 dad->next = np;
584 }
585
586 /* get and store all properties */
587 prev_propp = &np->properties;
588 prev_name = "";
589 for (;;) {
590 pp = (struct property *) mem_start;
591 namep = (char *) (pp + 1);
592 pp->name = PTRUNRELOC(namep);
593 if (call_prom("nextprop", 3, 1, node, prev_name, namep) <= 0)
594 break;
595 mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1);
596 prev_name = namep;
597 valp = (unsigned char *) mem_start;
598 pp->value = PTRUNRELOC(valp);
599 pp->length = call_prom("getprop", 4, 1, node, namep,
600 valp, mem_end - mem_start);
601 if (pp->length < 0)
602 continue;
603#ifdef MAX_PROPERTY_LENGTH
604 if (pp->length > MAX_PROPERTY_LENGTH)
605 continue; /* ignore this property */
606#endif
607 mem_start = ALIGNUL(mem_start + pp->length);
608 *prev_propp = PTRUNRELOC(pp);
609 prev_propp = &pp->next;
610 }
611 if (np->node != 0) {
612 /* Add a "linux,phandle" property" */
613 pp = (struct property *) mem_start;
614 *prev_propp = PTRUNRELOC(pp);
615 prev_propp = &pp->next;
616 namep = (char *) (pp + 1);
617 pp->name = PTRUNRELOC(namep);
618 strcpy(namep, "linux,phandle");
619 mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1);
620 pp->value = (unsigned char *) PTRUNRELOC(&np->node);
621 pp->length = sizeof(np->node);
622 }
623 *prev_propp = NULL;
624
625 /* get the node's full name */
626 l = call_prom("package-to-path", 3, 1, node,
627 mem_start, mem_end - mem_start);
628 if (l >= 0) {
629 np->full_name = PTRUNRELOC((char *) mem_start);
630 *(char *)(mem_start + l) = 0;
631 mem_start = ALIGNUL(mem_start + l + 1);
632 }
633
634 /* do all our children */
635 child = call_prom("child", 1, 1, node);
636 while (child != 0) {
637 mem_start = inspect_node(child, np, mem_start, mem_end,
638 allnextpp);
639 child = call_prom("peer", 1, 1, child);
640 }
641
642 return mem_start;
643}
644
645unsigned long smp_chrp_cpu_nr __initdata = 0;
646
647/*
648 * With CHRP SMP we need to use the OF to start the other
649 * processors so we can't wait until smp_boot_cpus (the OF is
650 * trashed by then) so we have to put the processors into
651 * a holding pattern controlled by the kernel (not OF) before
652 * we destroy the OF.
653 *
654 * This uses a chunk of high memory, puts some holding pattern
655 * code there and sends the other processors off to there until
656 * smp_boot_cpus tells them to do something. We do that by using
657 * physical address 0x0. The holding pattern checks that address
658 * until its cpu # is there, when it is that cpu jumps to
659 * __secondary_start(). smp_boot_cpus() takes care of setting those
660 * values.
661 *
662 * We also use physical address 0x4 here to tell when a cpu
663 * is in its holding pattern code.
664 *
665 * -- Cort
666 *
667 * Note that we have to do this if we have more than one CPU,
668 * even if this is a UP kernel. Otherwise when we trash OF
669 * the other CPUs will start executing some random instructions
670 * and crash the system. -- paulus
671 */
672static void __init
673prom_hold_cpus(unsigned long mem)
674{
675 extern void __secondary_hold(void);
676 unsigned long i;
677 int cpu;
678 phandle node;
679 char type[16], *path;
680 unsigned int reg;
681
682 /*
683 * XXX: hack to make sure we're chrp, assume that if we're
684 * chrp we have a device_type property -- Cort
685 */
686 node = call_prom("finddevice", 1, 1, "/");
687 if (call_prom("getprop", 4, 1, node,
688 "device_type", type, sizeof(type)) <= 0)
689 return;
690
691 /* copy the holding pattern code to someplace safe (0) */
692 /* the holding pattern is now within the first 0x100
693 bytes of the kernel image -- paulus */
694 memcpy((void *)0, _stext, 0x100);
695 flush_icache_range(0, 0x100);
696
697 /* look for cpus */
698 *(unsigned long *)(0x0) = 0;
699 asm volatile("dcbf 0,%0": : "r" (0) : "memory");
700 for (node = 0; prom_next_node(&node); ) {
701 type[0] = 0;
702 call_prom("getprop", 4, 1, node, "device_type",
703 type, sizeof(type));
704 if (strcmp(type, "cpu") != 0)
705 continue;
706 path = (char *) mem;
707 memset(path, 0, 256);
708 if (call_prom("package-to-path", 3, 1, node, path, 255) < 0)
709 continue;
710 reg = -1;
711 call_prom("getprop", 4, 1, node, "reg", &reg, sizeof(reg));
712 cpu = smp_chrp_cpu_nr++;
713#ifdef CONFIG_SMP
714 smp_hw_index[cpu] = reg;
715#endif /* CONFIG_SMP */
716 /* XXX: hack - don't start cpu 0, this cpu -- Cort */
717 if (cpu == 0)
718 continue;
719 prom_print("starting cpu ");
720 prom_print(path);
721 *(ulong *)(0x4) = 0;
722 call_prom("start-cpu", 3, 0, node,
723 (char *)__secondary_hold - _stext, cpu);
724 prom_print("...");
725 for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ )
726 ;
727 if (*(ulong *)(0x4) == cpu)
728 prom_print("ok\n");
729 else {
730 prom_print("failed: ");
731 prom_print_hex(*(ulong *)0x4);
732 prom_print("\n");
733 }
734 }
735}
736
737static void __init
738prom_instantiate_rtas(void)
739{
740 ihandle prom_rtas;
741 prom_arg_t result;
742
743 prom_rtas = call_prom("finddevice", 1, 1, "/rtas");
744 if (prom_rtas == -1)
745 return;
746
747 rtas_size = 0;
748 call_prom("getprop", 4, 1, prom_rtas,
749 "rtas-size", &rtas_size, sizeof(rtas_size));
750 prom_print("instantiating rtas");
751 if (rtas_size == 0) {
752 rtas_data = 0;
753 } else {
754 /*
755 * Ask OF for some space for RTAS.
756 * Actually OF has bugs so we just arbitrarily
757 * use memory at the 6MB point.
758 */
759 rtas_data = 6 << 20;
760 prom_print(" at ");
761 prom_print_hex(rtas_data);
762 }
763
764 prom_rtas = call_prom("open", 1, 1, "/rtas");
765 prom_print("...");
766 rtas_entry = 0;
767 if (call_prom_ret("call-method", 3, 2, &result,
768 "instantiate-rtas", prom_rtas, rtas_data) == 0)
769 rtas_entry = result;
770 if ((rtas_entry == -1) || (rtas_entry == 0))
771 prom_print(" failed\n");
772 else
773 prom_print(" done\n");
774}
775
776/*
777 * We enter here early on, when the Open Firmware prom is still
778 * handling exceptions and the MMU hash table for us.
779 */
780unsigned long __init
781prom_init(int r3, int r4, prom_entry pp)
782{
783 unsigned long mem;
784 ihandle prom_mmu;
785 unsigned long offset = reloc_offset();
786 int i, l;
787 char *p, *d;
788 unsigned long phys;
789 prom_arg_t result[3];
790 char model[32];
791 phandle node;
792 int rc;
793
794 /* Default */
795 phys = (unsigned long) &_stext;
796
797 /* First get a handle for the stdout device */
798 prom = pp;
799 prom_chosen = call_prom("finddevice", 1, 1, "/chosen");
800 if (prom_chosen == -1)
801 prom_exit();
802 if (call_prom("getprop", 4, 1, prom_chosen, "stdout",
803 &prom_stdout, sizeof(prom_stdout)) <= 0)
804 prom_exit();
805
806 /* Get the full OF pathname of the stdout device */
807 mem = (unsigned long) klimit + offset;
808 p = (char *) mem;
809 memset(p, 0, 256);
810 call_prom("instance-to-path", 3, 1, prom_stdout, p, 255);
811 of_stdout_device = p;
812 mem += strlen(p) + 1;
813
814 /* Get the boot device and translate it to a full OF pathname. */
815 p = (char *) mem;
816 l = call_prom("getprop", 4, 1, prom_chosen, "bootpath", p, 1<<20);
817 if (l > 0) {
818 p[l] = 0; /* should already be null-terminated */
819 bootpath = PTRUNRELOC(p);
820 mem += l + 1;
821 d = (char *) mem;
822 *d = 0;
823 call_prom("canon", 3, 1, p, d, 1<<20);
824 bootdevice = PTRUNRELOC(d);
825 mem = ALIGNUL(mem + strlen(d) + 1);
826 }
827
828 prom_instantiate_rtas();
829
830#ifdef CONFIG_POWER4
831 /*
832 * Find out how much memory we have and allocate a
833 * suitably-sized hash table.
834 */
835 prom_alloc_htab();
836#endif
837 mem = check_display(mem);
838
839 prom_print("copying OF device tree...");
840 mem = copy_device_tree(mem, mem + (1<<20));
841 prom_print("done\n");
842
843 prom_hold_cpus(mem);
844
845 klimit = (char *) (mem - offset);
846
847 node = call_prom("finddevice", 1, 1, "/");
848 rc = call_prom("getprop", 4, 1, node, "model", model, sizeof(model));
849 if (rc > 0 && !strncmp (model, "Pegasos", 7)
850 && strncmp (model, "Pegasos2", 8)) {
851 /* Pegasos 1 has a broken translate method in the OF,
852 * and furthermore the BATs are mapped 1:1 so the phys
853 * address calculated above is correct, so let's use
854 * it directly.
855 */
856 } else if (offset == 0) {
857 /* If we are already running at 0xc0000000, we assume we were
858 * loaded by an OF bootloader which did set a BAT for us.
859 * This breaks OF translate so we force phys to be 0.
860 */
861 prom_print("(already at 0xc0000000) phys=0\n");
862 phys = 0;
863 } else if (call_prom("getprop", 4, 1, prom_chosen, "mmu",
864 &prom_mmu, sizeof(prom_mmu)) <= 0) {
865 prom_print(" no MMU found\n");
866 } else if (call_prom_ret("call-method", 4, 4, result, "translate",
867 prom_mmu, &_stext, 1) != 0) {
868 prom_print(" (translate failed)\n");
869 } else {
870 /* We assume the phys. address size is 3 cells */
871 phys = result[2];
872 }
873
874 if (prom_disp_node != 0)
875 setup_disp_fake_bi(prom_disp_node);
876
877 /* Use quiesce call to get OF to shut down any devices it's using */
878 prom_print("Calling quiesce ...\n");
879 call_prom("quiesce", 0, 0);
880
881 /* Relocate various pointers which will be used once the
882 kernel is running at the address it was linked at. */
883 for (i = 0; i < prom_num_displays; ++i)
884 prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]);
885
886#ifdef CONFIG_SERIAL_CORE_CONSOLE
887 /* Relocate the of stdout for console autodetection */
888 of_stdout_device = PTRUNRELOC(of_stdout_device);
889#endif
890
891 prom_print("returning 0x");
892 prom_print_hex(phys);
893 prom_print("from prom_init\n");
894 prom_stdout = 0;
895
896 return phys;
897}
898
899/*
900 * early_get_property is used to access the device tree image prepared
901 * by BootX very early on, before the pointers in it have been relocated.
902 */
903static void * __init
904early_get_property(unsigned long base, unsigned long node, char *prop)
905{
906 struct device_node *np = (struct device_node *)(base + node);
907 struct property *pp;
908
909 for (pp = np->properties; pp != 0; pp = pp->next) {
910 pp = (struct property *) (base + (unsigned long)pp);
911 if (strcmp((char *)((unsigned long)pp->name + base),
912 prop) == 0) {
913 return (void *)((unsigned long)pp->value + base);
914 }
915 }
916 return NULL;
917}
918
919/* Is boot-info compatible ? */
920#define BOOT_INFO_IS_COMPATIBLE(bi) ((bi)->compatible_version <= BOOT_INFO_VERSION)
921#define BOOT_INFO_IS_V2_COMPATIBLE(bi) ((bi)->version >= 2)
922#define BOOT_INFO_IS_V4_COMPATIBLE(bi) ((bi)->version >= 4)
923
924void __init
925bootx_init(unsigned long r4, unsigned long phys)
926{
927 boot_infos_t *bi = (boot_infos_t *) r4;
928 unsigned long space;
929 unsigned long ptr, x;
930 char *model;
931
932 boot_infos = PTRUNRELOC(bi);
933 if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
934 bi->logicalDisplayBase = NULL;
935
936#ifdef CONFIG_BOOTX_TEXT
937 btext_init(bi);
938
939 /*
940 * Test if boot-info is compatible. Done only in config
941 * CONFIG_BOOTX_TEXT since there is nothing much we can do
942 * with an incompatible version, except display a message
943 * and eventually hang the processor...
944 *
945 * I'll try to keep enough of boot-info compatible in the
946 * future to always allow display of this message;
947 */
948 if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
949 btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!\n\n\n");
950 btext_flushscreen();
951 }
952#endif /* CONFIG_BOOTX_TEXT */
953
954 /* New BootX enters kernel with MMU off, i/os are not allowed
955 here. This hack will have been done by the boostrap anyway.
956 */
957 if (bi->version < 4) {
958 /*
959 * XXX If this is an iMac, turn off the USB controller.
960 */
961 model = (char *) early_get_property
962 (r4 + bi->deviceTreeOffset, 4, "model");
963 if (model
964 && (strcmp(model, "iMac,1") == 0
965 || strcmp(model, "PowerMac1,1") == 0)) {
966 out_le32((unsigned *)0x80880008, 1); /* XXX */
967 }
968 }
969
970 /* Move klimit to enclose device tree, args, ramdisk, etc... */
971 if (bi->version < 5) {
972 space = bi->deviceTreeOffset + bi->deviceTreeSize;
973 if (bi->ramDisk)
974 space = bi->ramDisk + bi->ramDiskSize;
975 } else
976 space = bi->totalParamsSize;
977 klimit = PTRUNRELOC((char *) bi + space);
978
979 /* New BootX will have flushed all TLBs and enters kernel with
980 MMU switched OFF, so this should not be useful anymore.
981 */
982 if (bi->version < 4) {
983 /*
984 * Touch each page to make sure the PTEs for them
985 * are in the hash table - the aim is to try to avoid
986 * getting DSI exceptions while copying the kernel image.
987 */
988 for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
989 ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
990 x = *(volatile unsigned long *)ptr;
991 }
992
993#ifdef CONFIG_BOOTX_TEXT
994 /*
995 * Note that after we call btext_prepare_BAT, we can't do
996 * prom_draw*, flushscreen or clearscreen until we turn the MMU
997 * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase
998 * to a virtual address.
999 */
1000 btext_prepare_BAT();
1001#endif
1002}
diff --git a/arch/ppc/syslib/qspan_pci.c b/arch/ppc/syslib/qspan_pci.c
new file mode 100644
index 000000000000..57f4ed5e5ae1
--- /dev/null
+++ b/arch/ppc/syslib/qspan_pci.c
@@ -0,0 +1,381 @@
1/*
2 * QSpan pci routines.
3 * Most 8xx boards use the QSpan PCI bridge. The config address register
4 * is located 0x500 from the base of the bridge control/status registers.
5 * The data register is located at 0x504.
6 * This is a two step operation. First, the address register is written,
7 * then the data register is read/written as required.
8 * I don't know what to do about interrupts (yet).
9 *
10 * The RPX Classic implementation shares a chip select for normal
11 * PCI access and QSpan control register addresses. The selection is
12 * further selected by a bit setting in a board control register.
13 * Although it should happen, we disable interrupts during this operation
14 * to make sure some driver doesn't accidentally access the PCI while
15 * we have switched the chip select.
16 */
17
18#include <linux/config.h>
19#include <linux/kernel.h>
20#include <linux/pci.h>
21#include <linux/delay.h>
22#include <linux/string.h>
23#include <linux/init.h>
24
25#include <asm/io.h>
26#include <asm/mpc8xx.h>
27#include <asm/system.h>
28#include <asm/machdep.h>
29#include <asm/pci-bridge.h>
30
31
32/*
33 * This blows......
34 * When reading the configuration space, if something does not respond
35 * the bus times out and we get a machine check interrupt. So, the
36 * good ol' exception tables come to mind to trap it and return some
37 * value.
38 *
39 * On an error we just return a -1, since that is what the caller wants
40 * returned if nothing is present. I copied this from __get_user_asm,
41 * with the only difference of returning -1 instead of EFAULT.
42 * There is an associated hack in the machine check trap code.
43 *
44 * The QSPAN is also a big endian device, that is it makes the PCI
45 * look big endian to us. This presents a problem for the Linux PCI
46 * functions, which assume little endian. For example, we see the
47 * first 32-bit word like this:
48 * ------------------------
49 * | Device ID | Vendor ID |
50 * ------------------------
51 * If we read/write as a double word, that's OK. But in our world,
52 * when read as a word, device ID is at location 0, not location 2 as
53 * the little endian PCI would believe. We have to switch bits in
54 * the PCI addresses given to us to get the data to/from the correct
55 * byte lanes.
56 *
57 * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5.
58 * It always forces the MS bit to zero. Therefore, dev_fn values
59 * greater than 128 are returned as "no device found" errors.
60 *
61 * The QSPAN can only perform long word (32-bit) configuration cycles.
62 * The "offset" must have the two LS bits set to zero. Read operations
63 * require we read the entire word and then sort out what should be
64 * returned. Write operations other than long word require that we
65 * read the long word, update the proper word or byte, then write the
66 * entire long word back.
67 *
68 * PCI Bridge hack. We assume (correctly) that bus 0 is the primary
69 * PCI bus from the QSPAN. If we are called with a bus number other
70 * than zero, we create a Type 1 configuration access that a downstream
71 * PCI bridge will interpret.
72 */
73
74#define __get_qspan_pci_config(x, addr, op) \
75 __asm__ __volatile__( \
76 "1: "op" %0,0(%1)\n" \
77 " eieio\n" \
78 "2:\n" \
79 ".section .fixup,\"ax\"\n" \
80 "3: li %0,-1\n" \
81 " b 2b\n" \
82 ".section __ex_table,\"a\"\n" \
83 " .align 2\n" \
84 " .long 1b,3b\n" \
85 ".text" \
86 : "=r"(x) : "r"(addr) : " %0")
87
88#define QS_CONFIG_ADDR ((volatile uint *)(PCI_CSR_ADDR + 0x500))
89#define QS_CONFIG_DATA ((volatile uint *)(PCI_CSR_ADDR + 0x504))
90
91#define mk_config_addr(bus, dev, offset) \
92 (((bus)<<16) | ((dev)<<8) | (offset & 0xfc))
93
94#define mk_config_type1(bus, dev, offset) \
95 mk_config_addr(bus, dev, offset) | 1;
96
97static spinlock_t pcibios_lock = SPIN_LOCK_UNLOCKED;
98
99int qspan_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
100 unsigned char offset, unsigned char *val)
101{
102 uint temp;
103 u_char *cp;
104#ifdef CONFIG_RPXCLASSIC
105 unsigned long flags;
106#endif
107
108 if ((bus > 7) || (dev_fn > 127)) {
109 *val = 0xff;
110 return PCIBIOS_DEVICE_NOT_FOUND;
111 }
112
113#ifdef CONFIG_RPXCLASSIC
114 /* disable interrupts */
115 spin_lock_irqsave(&pcibios_lock, flags);
116 *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
117 eieio();
118#endif
119
120 if (bus == 0)
121 *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
122 else
123 *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
124 __get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz");
125
126#ifdef CONFIG_RPXCLASSIC
127 *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
128 eieio();
129 spin_unlock_irqrestore(&pcibios_lock, flags);
130#endif
131
132 offset ^= 0x03;
133 cp = ((u_char *)&temp) + (offset & 0x03);
134 *val = *cp;
135 return PCIBIOS_SUCCESSFUL;
136}
137
138int qspan_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
139 unsigned char offset, unsigned short *val)
140{
141 uint temp;
142 ushort *sp;
143#ifdef CONFIG_RPXCLASSIC
144 unsigned long flags;
145#endif
146
147 if ((bus > 7) || (dev_fn > 127)) {
148 *val = 0xffff;
149 return PCIBIOS_DEVICE_NOT_FOUND;
150 }
151
152#ifdef CONFIG_RPXCLASSIC
153 /* disable interrupts */
154 spin_lock_irqsave(&pcibios_lock, flags);
155 *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
156 eieio();
157#endif
158
159 if (bus == 0)
160 *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
161 else
162 *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
163 __get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz");
164 offset ^= 0x02;
165
166#ifdef CONFIG_RPXCLASSIC
167 *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
168 eieio();
169 spin_unlock_irqrestore(&pcibios_lock, flags);
170#endif
171
172 sp = ((ushort *)&temp) + ((offset >> 1) & 1);
173 *val = *sp;
174 return PCIBIOS_SUCCESSFUL;
175}
176
177int qspan_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
178 unsigned char offset, unsigned int *val)
179{
180#ifdef CONFIG_RPXCLASSIC
181 unsigned long flags;
182#endif
183
184 if ((bus > 7) || (dev_fn > 127)) {
185 *val = 0xffffffff;
186 return PCIBIOS_DEVICE_NOT_FOUND;
187 }
188
189#ifdef CONFIG_RPXCLASSIC
190 /* disable interrupts */
191 spin_lock_irqsave(&pcibios_lock, flags);
192 *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
193 eieio();
194#endif
195
196 if (bus == 0)
197 *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
198 else
199 *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
200 __get_qspan_pci_config(*val, QS_CONFIG_DATA, "lwz");
201
202#ifdef CONFIG_RPXCLASSIC
203 *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
204 eieio();
205 spin_unlock_irqrestore(&pcibios_lock, flags);
206#endif
207
208 return PCIBIOS_SUCCESSFUL;
209}
210
211int qspan_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
212 unsigned char offset, unsigned char val)
213{
214 uint temp;
215 u_char *cp;
216#ifdef CONFIG_RPXCLASSIC
217 unsigned long flags;
218#endif
219
220 if ((bus > 7) || (dev_fn > 127))
221 return PCIBIOS_DEVICE_NOT_FOUND;
222
223 qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
224
225 offset ^= 0x03;
226 cp = ((u_char *)&temp) + (offset & 0x03);
227 *cp = val;
228
229#ifdef CONFIG_RPXCLASSIC
230 /* disable interrupts */
231 spin_lock_irqsave(&pcibios_lock, flags);
232 *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
233 eieio();
234#endif
235
236 if (bus == 0)
237 *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
238 else
239 *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
240 *QS_CONFIG_DATA = temp;
241
242#ifdef CONFIG_RPXCLASSIC
243 *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
244 eieio();
245 spin_unlock_irqrestore(&pcibios_lock, flags);
246#endif
247
248 return PCIBIOS_SUCCESSFUL;
249}
250
251int qspan_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
252 unsigned char offset, unsigned short val)
253{
254 uint temp;
255 ushort *sp;
256#ifdef CONFIG_RPXCLASSIC
257 unsigned long flags;
258#endif
259
260 if ((bus > 7) || (dev_fn > 127))
261 return PCIBIOS_DEVICE_NOT_FOUND;
262
263 qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
264
265 offset ^= 0x02;
266 sp = ((ushort *)&temp) + ((offset >> 1) & 1);
267 *sp = val;
268
269#ifdef CONFIG_RPXCLASSIC
270 /* disable interrupts */
271 spin_lock_irqsave(&pcibios_lock, flags);
272 *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
273 eieio();
274#endif
275
276 if (bus == 0)
277 *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
278 else
279 *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
280 *QS_CONFIG_DATA = temp;
281
282#ifdef CONFIG_RPXCLASSIC
283 *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
284 eieio();
285 spin_unlock_irqrestore(&pcibios_lock, flags);
286#endif
287
288 return PCIBIOS_SUCCESSFUL;
289}
290
291int qspan_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
292 unsigned char offset, unsigned int val)
293{
294#ifdef CONFIG_RPXCLASSIC
295 unsigned long flags;
296#endif
297
298 if ((bus > 7) || (dev_fn > 127))
299 return PCIBIOS_DEVICE_NOT_FOUND;
300
301#ifdef CONFIG_RPXCLASSIC
302 /* disable interrupts */
303 spin_lock_irqsave(&pcibios_lock, flags);
304 *((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
305 eieio();
306#endif
307
308 if (bus == 0)
309 *QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
310 else
311 *QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
312 *(unsigned int *)QS_CONFIG_DATA = val;
313
314#ifdef CONFIG_RPXCLASSIC
315 *((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
316 eieio();
317 spin_unlock_irqrestore(&pcibios_lock, flags);
318#endif
319
320 return PCIBIOS_SUCCESSFUL;
321}
322
323int qspan_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
324 unsigned short index, unsigned char *bus_ptr,
325 unsigned char *dev_fn_ptr)
326{
327 int num, devfn;
328 unsigned int x, vendev;
329
330 if (vendor == 0xffff)
331 return PCIBIOS_BAD_VENDOR_ID;
332 vendev = (dev_id << 16) + vendor;
333 num = 0;
334 for (devfn = 0; devfn < 32; devfn++) {
335 qspan_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
336 if (x == vendev) {
337 if (index == num) {
338 *bus_ptr = 0;
339 *dev_fn_ptr = devfn<<3;
340 return PCIBIOS_SUCCESSFUL;
341 }
342 ++num;
343 }
344 }
345 return PCIBIOS_DEVICE_NOT_FOUND;
346}
347
348int qspan_pcibios_find_class(unsigned int class_code, unsigned short index,
349 unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
350{
351 int devnr, x, num;
352
353 num = 0;
354 for (devnr = 0; devnr < 32; devnr++) {
355 qspan_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
356 if ((x>>8) == class_code) {
357 if (index == num) {
358 *bus_ptr = 0;
359 *dev_fn_ptr = devnr<<3;
360 return PCIBIOS_SUCCESSFUL;
361 }
362 ++num;
363 }
364 }
365 return PCIBIOS_DEVICE_NOT_FOUND;
366}
367
368void __init
369m8xx_pcibios_fixup(void))
370{
371 /* Lots to do here, all board and configuration specific. */
372}
373
374void __init
375m8xx_setup_pci_ptrs(void))
376{
377 set_config_access_method(qspan);
378
379 ppc_md.pcibios_fixup = m8xx_pcibios_fixup;
380}
381
diff --git a/arch/ppc/syslib/todc_time.c b/arch/ppc/syslib/todc_time.c
new file mode 100644
index 000000000000..1323c641c19d
--- /dev/null
+++ b/arch/ppc/syslib/todc_time.c
@@ -0,0 +1,513 @@
1/*
2 * arch/ppc/syslib/todc_time.c
3 *
4 * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818
5 * Real Time Clocks/Timekeepers.
6 *
7 * Author: Mark A. Greer
8 * mgreer@mvista.com
9 *
10 * 2001-2004 (c) MontaVista, Software, Inc. This file is licensed under
11 * the terms of the GNU General Public License version 2. This program
12 * is licensed "as is" without any warranty of any kind, whether express
13 * or implied.
14 */
15#include <linux/errno.h>
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/time.h>
19#include <linux/timex.h>
20#include <linux/bcd.h>
21#include <linux/mc146818rtc.h>
22
23#include <asm/machdep.h>
24#include <asm/io.h>
25#include <asm/time.h>
26#include <asm/todc.h>
27
28/*
29 * Depending on the hardware on your board and your board design, the
30 * RTC/NVRAM may be accessed either directly (like normal memory) or via
31 * address/data registers. If your board uses the direct method, set
32 * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and
33 * 'nvram_as1' NULL. If your board uses address/data regs to access nvram,
34 * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the
35 * address of the upper byte (leave NULL if using mc146818), and set
36 * 'nvram_data' to the address of the 8-bit data register.
37 *
38 * In order to break the assumption that the RTC and NVRAM are accessed by
39 * the same mechanism, you need to explicitly set 'ppc_md.rtc_read_val' and
40 * 'ppc_md.rtc_write_val', otherwise the values of 'ppc_md.rtc_read_val'
41 * and 'ppc_md.rtc_write_val' will be used.
42 *
43 * Note: Even though the documentation for the various RTC chips say that it
44 * take up to a second before it starts updating once the 'R' bit is
45 * cleared, they always seem to update even though we bang on it many
46 * times a second. This is true, except for the Dallas Semi 1746/1747
47 * (possibly others). Those chips seem to have a real problem whenever
48 * we set the 'R' bit before reading them, they basically stop counting.
49 * --MAG
50 */
51
52/*
53 * 'todc_info' should be initialized in your *_setup.c file to
54 * point to a fully initialized 'todc_info_t' structure.
55 * This structure holds all the register offsets for your particular
56 * TODC/RTC chip.
57 * TODC_ALLOC()/TODC_INIT() will allocate and initialize this table for you.
58 */
59
60#ifdef RTC_FREQ_SELECT
61#undef RTC_FREQ_SELECT
62#define RTC_FREQ_SELECT control_b /* Register A */
63#endif
64
65#ifdef RTC_CONTROL
66#undef RTC_CONTROL
67#define RTC_CONTROL control_a /* Register B */
68#endif
69
70#ifdef RTC_INTR_FLAGS
71#undef RTC_INTR_FLAGS
72#define RTC_INTR_FLAGS watchdog /* Register C */
73#endif
74
75#ifdef RTC_VALID
76#undef RTC_VALID
77#define RTC_VALID interrupts /* Register D */
78#endif
79
80/* Access routines when RTC accessed directly (like normal memory) */
81u_char
82todc_direct_read_val(int addr)
83{
84 return readb((void __iomem *)(todc_info->nvram_data + addr));
85}
86
87void
88todc_direct_write_val(int addr, unsigned char val)
89{
90 writeb(val, (void __iomem *)(todc_info->nvram_data + addr));
91 return;
92}
93
94/* Access routines for accessing m48txx type chips via addr/data regs */
95u_char
96todc_m48txx_read_val(int addr)
97{
98 outb(addr, todc_info->nvram_as0);
99 outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
100 return inb(todc_info->nvram_data);
101}
102
103void
104todc_m48txx_write_val(int addr, unsigned char val)
105{
106 outb(addr, todc_info->nvram_as0);
107 outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
108 outb(val, todc_info->nvram_data);
109 return;
110}
111
112/* Access routines for accessing mc146818 type chips via addr/data regs */
113u_char
114todc_mc146818_read_val(int addr)
115{
116 outb_p(addr, todc_info->nvram_as0);
117 return inb_p(todc_info->nvram_data);
118}
119
120void
121todc_mc146818_write_val(int addr, unsigned char val)
122{
123 outb_p(addr, todc_info->nvram_as0);
124 outb_p(val, todc_info->nvram_data);
125}
126
127
128/*
129 * Routines to make RTC chips with NVRAM buried behind an addr/data pair
130 * have the NVRAM and clock regs appear at the same level.
131 * The NVRAM will appear to start at addr 0 and the clock regs will appear
132 * to start immediately after the NVRAM (actually, start at offset
133 * todc_info->nvram_size).
134 */
135static inline u_char
136todc_read_val(int addr)
137{
138 u_char val;
139
140 if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
141 if (addr < todc_info->nvram_size) { /* NVRAM */
142 ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr);
143 val = ppc_md.rtc_read_val(todc_info->nvram_data_reg);
144 }
145 else { /* Clock Reg */
146 addr -= todc_info->nvram_size;
147 val = ppc_md.rtc_read_val(addr);
148 }
149 }
150 else {
151 val = ppc_md.rtc_read_val(addr);
152 }
153
154 return val;
155}
156
157static inline void
158todc_write_val(int addr, u_char val)
159{
160 if (todc_info->sw_flags & TODC_FLAG_2_LEVEL_NVRAM) {
161 if (addr < todc_info->nvram_size) { /* NVRAM */
162 ppc_md.rtc_write_val(todc_info->nvram_addr_reg, addr);
163 ppc_md.rtc_write_val(todc_info->nvram_data_reg, val);
164 }
165 else { /* Clock Reg */
166 addr -= todc_info->nvram_size;
167 ppc_md.rtc_write_val(addr, val);
168 }
169 }
170 else {
171 ppc_md.rtc_write_val(addr, val);
172 }
173}
174
175/*
176 * TODC routines
177 *
178 * There is some ugly stuff in that there are assumptions for the mc146818.
179 *
180 * Assumptions:
181 * - todc_info->control_a has the offset as mc146818 Register B reg
182 * - todc_info->control_b has the offset as mc146818 Register A reg
183 * - m48txx control reg's write enable or 'W' bit is same as
184 * mc146818 Register B 'SET' bit (i.e., 0x80)
185 *
186 * These assumptions were made to make the code simpler.
187 */
188long __init
189todc_time_init(void)
190{
191 u_char cntl_b;
192
193 if (!ppc_md.rtc_read_val)
194 ppc_md.rtc_read_val = ppc_md.nvram_read_val;
195 if (!ppc_md.rtc_write_val)
196 ppc_md.rtc_write_val = ppc_md.nvram_write_val;
197
198 cntl_b = todc_read_val(todc_info->control_b);
199
200 if (todc_info->rtc_type == TODC_TYPE_MC146818) {
201 if ((cntl_b & 0x70) != 0x20) {
202 printk(KERN_INFO "TODC %s %s\n",
203 "real-time-clock was stopped.",
204 "Now starting...");
205 cntl_b &= ~0x70;
206 cntl_b |= 0x20;
207 }
208
209 todc_write_val(todc_info->control_b, cntl_b);
210 } else if (todc_info->rtc_type == TODC_TYPE_DS17285) {
211 u_char mode;
212
213 mode = todc_read_val(TODC_TYPE_DS17285_CNTL_A);
214 /* Make sure countdown clear is not set */
215 mode &= ~0x40;
216 /* Enable oscillator, extended register set */
217 mode |= 0x30;
218 todc_write_val(TODC_TYPE_DS17285_CNTL_A, mode);
219
220 } else if (todc_info->rtc_type == TODC_TYPE_DS1501) {
221 u_char month;
222
223 todc_info->enable_read = TODC_DS1501_CNTL_B_TE;
224 todc_info->enable_write = TODC_DS1501_CNTL_B_TE;
225
226 month = todc_read_val(todc_info->month);
227
228 if ((month & 0x80) == 0x80) {
229 printk(KERN_INFO "TODC %s %s\n",
230 "real-time-clock was stopped.",
231 "Now starting...");
232 month &= ~0x80;
233 todc_write_val(todc_info->month, month);
234 }
235
236 cntl_b &= ~TODC_DS1501_CNTL_B_TE;
237 todc_write_val(todc_info->control_b, cntl_b);
238 } else { /* must be a m48txx type */
239 u_char cntl_a;
240
241 todc_info->enable_read = TODC_MK48TXX_CNTL_A_R;
242 todc_info->enable_write = TODC_MK48TXX_CNTL_A_W;
243
244 cntl_a = todc_read_val(todc_info->control_a);
245
246 /* Check & clear STOP bit in control B register */
247 if (cntl_b & TODC_MK48TXX_DAY_CB) {
248 printk(KERN_INFO "TODC %s %s\n",
249 "real-time-clock was stopped.",
250 "Now starting...");
251
252 cntl_a |= todc_info->enable_write;
253 cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */
254
255 todc_write_val(todc_info->control_a, cntl_a);
256 todc_write_val(todc_info->control_b, cntl_b);
257 }
258
259 /* Make sure READ & WRITE bits are cleared. */
260 cntl_a &= ~(todc_info->enable_write |
261 todc_info->enable_read);
262 todc_write_val(todc_info->control_a, cntl_a);
263 }
264
265 return 0;
266}
267
268/*
269 * There is some ugly stuff in that there are assumptions that for a mc146818,
270 * the todc_info->control_a has the offset of the mc146818 Register B reg and
271 * that the register'ss 'SET' bit is the same as the m48txx's write enable
272 * bit in the control register of the m48txx (i.e., 0x80).
273 *
274 * It was done to make the code look simpler.
275 */
276ulong
277todc_get_rtc_time(void)
278{
279 uint year = 0, mon = 0, day = 0, hour = 0, min = 0, sec = 0;
280 uint limit, i;
281 u_char save_control, uip = 0;
282
283 spin_lock(&rtc_lock);
284 save_control = todc_read_val(todc_info->control_a);
285
286 if (todc_info->rtc_type != TODC_TYPE_MC146818) {
287 limit = 1;
288
289 switch (todc_info->rtc_type) {
290 case TODC_TYPE_DS1553:
291 case TODC_TYPE_DS1557:
292 case TODC_TYPE_DS1743:
293 case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */
294 case TODC_TYPE_DS1747:
295 case TODC_TYPE_DS17285:
296 break;
297 default:
298 todc_write_val(todc_info->control_a,
299 (save_control | todc_info->enable_read));
300 }
301 }
302 else {
303 limit = 100000000;
304 }
305
306 for (i=0; i<limit; i++) {
307 if (todc_info->rtc_type == TODC_TYPE_MC146818) {
308 uip = todc_read_val(todc_info->RTC_FREQ_SELECT);
309 }
310
311 sec = todc_read_val(todc_info->seconds) & 0x7f;
312 min = todc_read_val(todc_info->minutes) & 0x7f;
313 hour = todc_read_val(todc_info->hours) & 0x3f;
314 day = todc_read_val(todc_info->day_of_month) & 0x3f;
315 mon = todc_read_val(todc_info->month) & 0x1f;
316 year = todc_read_val(todc_info->year) & 0xff;
317
318 if (todc_info->rtc_type == TODC_TYPE_MC146818) {
319 uip |= todc_read_val(todc_info->RTC_FREQ_SELECT);
320 if ((uip & RTC_UIP) == 0) break;
321 }
322 }
323
324 if (todc_info->rtc_type != TODC_TYPE_MC146818) {
325 switch (todc_info->rtc_type) {
326 case TODC_TYPE_DS1553:
327 case TODC_TYPE_DS1557:
328 case TODC_TYPE_DS1743:
329 case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */
330 case TODC_TYPE_DS1747:
331 case TODC_TYPE_DS17285:
332 break;
333 default:
334 save_control &= ~(todc_info->enable_read);
335 todc_write_val(todc_info->control_a,
336 save_control);
337 }
338 }
339 spin_unlock(&rtc_lock);
340
341 if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
342 ((save_control & RTC_DM_BINARY) == 0) ||
343 RTC_ALWAYS_BCD) {
344
345 BCD_TO_BIN(sec);
346 BCD_TO_BIN(min);
347 BCD_TO_BIN(hour);
348 BCD_TO_BIN(day);
349 BCD_TO_BIN(mon);
350 BCD_TO_BIN(year);
351 }
352
353 year = year + 1900;
354 if (year < 1970) {
355 year += 100;
356 }
357
358 return mktime(year, mon, day, hour, min, sec);
359}
360
361int
362todc_set_rtc_time(unsigned long nowtime)
363{
364 struct rtc_time tm;
365 u_char save_control, save_freq_select = 0;
366
367 spin_lock(&rtc_lock);
368 to_tm(nowtime, &tm);
369
370 save_control = todc_read_val(todc_info->control_a);
371
372 /* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */
373 todc_write_val(todc_info->control_a,
374 (save_control | todc_info->enable_write));
375 save_control &= ~(todc_info->enable_write); /* in case it was set */
376
377 if (todc_info->rtc_type == TODC_TYPE_MC146818) {
378 save_freq_select = todc_read_val(todc_info->RTC_FREQ_SELECT);
379 todc_write_val(todc_info->RTC_FREQ_SELECT,
380 save_freq_select | RTC_DIV_RESET2);
381 }
382
383
384 tm.tm_year = (tm.tm_year - 1900) % 100;
385
386 if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
387 ((save_control & RTC_DM_BINARY) == 0) ||
388 RTC_ALWAYS_BCD) {
389
390 BIN_TO_BCD(tm.tm_sec);
391 BIN_TO_BCD(tm.tm_min);
392 BIN_TO_BCD(tm.tm_hour);
393 BIN_TO_BCD(tm.tm_mon);
394 BIN_TO_BCD(tm.tm_mday);
395 BIN_TO_BCD(tm.tm_year);
396 }
397
398 todc_write_val(todc_info->seconds, tm.tm_sec);
399 todc_write_val(todc_info->minutes, tm.tm_min);
400 todc_write_val(todc_info->hours, tm.tm_hour);
401 todc_write_val(todc_info->month, tm.tm_mon);
402 todc_write_val(todc_info->day_of_month, tm.tm_mday);
403 todc_write_val(todc_info->year, tm.tm_year);
404
405 todc_write_val(todc_info->control_a, save_control);
406
407 if (todc_info->rtc_type == TODC_TYPE_MC146818) {
408 todc_write_val(todc_info->RTC_FREQ_SELECT, save_freq_select);
409 }
410 spin_unlock(&rtc_lock);
411
412 return 0;
413}
414
415/*
416 * Manipulates read bit to reliably read seconds at a high rate.
417 */
418static unsigned char __init todc_read_timereg(int addr)
419{
420 unsigned char save_control = 0, val;
421
422 switch (todc_info->rtc_type) {
423 case TODC_TYPE_DS1553:
424 case TODC_TYPE_DS1557:
425 case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */
426 case TODC_TYPE_DS1747:
427 case TODC_TYPE_DS17285:
428 case TODC_TYPE_MC146818:
429 break;
430 default:
431 save_control = todc_read_val(todc_info->control_a);
432 todc_write_val(todc_info->control_a,
433 (save_control | todc_info->enable_read));
434 }
435 val = todc_read_val(addr);
436
437 switch (todc_info->rtc_type) {
438 case TODC_TYPE_DS1553:
439 case TODC_TYPE_DS1557:
440 case TODC_TYPE_DS1746: /* XXXX BAD HACK -> FIX */
441 case TODC_TYPE_DS1747:
442 case TODC_TYPE_DS17285:
443 case TODC_TYPE_MC146818:
444 break;
445 default:
446 save_control &= ~(todc_info->enable_read);
447 todc_write_val(todc_info->control_a, save_control);
448 }
449
450 return val;
451}
452
453/*
454 * This was taken from prep_setup.c
455 * Use the NVRAM RTC to time a second to calibrate the decrementer.
456 */
457void __init
458todc_calibrate_decr(void)
459{
460 ulong freq;
461 ulong tbl, tbu;
462 long i, loop_count;
463 u_char sec;
464
465 todc_time_init();
466
467 /*
468 * Actually this is bad for precision, we should have a loop in
469 * which we only read the seconds counter. todc_read_val writes
470 * the address bytes on every call and this takes a lot of time.
471 * Perhaps an nvram_wait_change method returning a time
472 * stamp with a loop count as parameter would be the solution.
473 */
474 /*
475 * Need to make sure the tbl doesn't roll over so if tbu increments
476 * during this test, we need to do it again.
477 */
478 loop_count = 0;
479
480 sec = todc_read_timereg(todc_info->seconds) & 0x7f;
481
482 do {
483 tbu = get_tbu();
484
485 for (i = 0 ; i < 10000000 ; i++) {/* may take up to 1 second */
486 tbl = get_tbl();
487
488 if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
489 break;
490 }
491 }
492
493 sec = todc_read_timereg(todc_info->seconds) & 0x7f;
494
495 for (i = 0 ; i < 10000000 ; i++) { /* Should take 1 second */
496 freq = get_tbl();
497
498 if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
499 break;
500 }
501 }
502
503 freq -= tbl;
504 } while ((get_tbu() != tbu) && (++loop_count < 2));
505
506 printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",
507 freq/1000000, freq%1000000);
508
509 tb_ticks_per_jiffy = freq / HZ;
510 tb_to_us = mulhwu_scale_factor(freq, 1000000);
511
512 return;
513}
diff --git a/arch/ppc/syslib/xilinx_pic.c b/arch/ppc/syslib/xilinx_pic.c
new file mode 100644
index 000000000000..e0bd66f0847a
--- /dev/null
+++ b/arch/ppc/syslib/xilinx_pic.c
@@ -0,0 +1,157 @@
1/*
2 * arch/ppc/syslib/xilinx_pic.c
3 *
4 * Interrupt controller driver for Xilinx Virtex-II Pro.
5 *
6 * Author: MontaVista Software, Inc.
7 * source@mvista.com
8 *
9 * 2002-2004 (c) MontaVista Software, Inc. This file is licensed under
10 * the terms of the GNU General Public License version 2. This program
11 * is licensed "as is" without any warranty of any kind, whether express
12 * or implied.
13 */
14
15#include <linux/init.h>
16#include <linux/irq.h>
17#include <asm/io.h>
18#include <asm/xparameters.h>
19#include <asm/ibm4xx.h>
20
21/* No one else should require these constants, so define them locally here. */
22#define ISR 0 /* Interrupt Status Register */
23#define IPR 1 /* Interrupt Pending Register */
24#define IER 2 /* Interrupt Enable Register */
25#define IAR 3 /* Interrupt Acknowledge Register */
26#define SIE 4 /* Set Interrupt Enable bits */
27#define CIE 5 /* Clear Interrupt Enable bits */
28#define IVR 6 /* Interrupt Vector Register */
29#define MER 7 /* Master Enable Register */
30
31#if XPAR_XINTC_USE_DCR == 0
32static volatile u32 *intc;
33#define intc_out_be32(addr, mask) out_be32((addr), (mask))
34#define intc_in_be32(addr) in_be32((addr))
35#else
36#define intc XPAR_INTC_0_BASEADDR
37#define intc_out_be32(addr, mask) mtdcr((addr), (mask))
38#define intc_in_be32(addr) mfdcr((addr))
39#endif
40
41static void
42xilinx_intc_enable(unsigned int irq)
43{
44 unsigned long mask = (0x00000001 << (irq & 31));
45 pr_debug("enable: %d\n", irq);
46 intc_out_be32(intc + SIE, mask);
47}
48
49static void
50xilinx_intc_disable(unsigned int irq)
51{
52 unsigned long mask = (0x00000001 << (irq & 31));
53 pr_debug("disable: %d\n", irq);
54 intc_out_be32(intc + CIE, mask);
55}
56
57static void
58xilinx_intc_disable_and_ack(unsigned int irq)
59{
60 unsigned long mask = (0x00000001 << (irq & 31));
61 pr_debug("disable_and_ack: %d\n", irq);
62 intc_out_be32(intc + CIE, mask);
63 if (!(irq_desc[irq].status & IRQ_LEVEL))
64 intc_out_be32(intc + IAR, mask); /* ack edge triggered intr */
65}
66
67static void
68xilinx_intc_end(unsigned int irq)
69{
70 unsigned long mask = (0x00000001 << (irq & 31));
71
72 pr_debug("end: %d\n", irq);
73 if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
74 intc_out_be32(intc + SIE, mask);
75 /* ack level sensitive intr */
76 if (irq_desc[irq].status & IRQ_LEVEL)
77 intc_out_be32(intc + IAR, mask);
78 }
79}
80
81static struct hw_interrupt_type xilinx_intc = {
82 "Xilinx Interrupt Controller",
83 NULL,
84 NULL,
85 xilinx_intc_enable,
86 xilinx_intc_disable,
87 xilinx_intc_disable_and_ack,
88 xilinx_intc_end,
89 0
90};
91
92int
93xilinx_pic_get_irq(struct pt_regs *regs)
94{
95 int irq;
96
97 /*
98 * NOTE: This function is the one that needs to be improved in
99 * order to handle multiple interrupt controllers. It currently
100 * is hardcoded to check for interrupts only on the first INTC.
101 */
102
103 irq = intc_in_be32(intc + IVR);
104 if (irq != -1)
105 irq = irq;
106
107 pr_debug("get_irq: %d\n", irq);
108
109 return (irq);
110}
111
112void __init
113ppc4xx_pic_init(void)
114{
115 int i;
116
117 /*
118 * NOTE: The assumption here is that NR_IRQS is 32 or less
119 * (NR_IRQS is 32 for PowerPC 405 cores by default).
120 */
121#if (NR_IRQS > 32)
122#error NR_IRQS > 32 not supported
123#endif
124
125#if XPAR_XINTC_USE_DCR == 0
126 intc = ioremap(XPAR_INTC_0_BASEADDR, 32);
127
128 printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX mapped to 0x%08lX\n",
129 (unsigned long) XPAR_INTC_0_BASEADDR, (unsigned long) intc);
130#else
131 printk(KERN_INFO "Xilinx INTC #0 at 0x%08lX (DCR)\n",
132 (unsigned long) XPAR_INTC_0_BASEADDR);
133#endif
134
135 /*
136 * Disable all external interrupts until they are
137 * explicity requested.
138 */
139 intc_out_be32(intc + IER, 0);
140
141 /* Acknowledge any pending interrupts just in case. */
142 intc_out_be32(intc + IAR, ~(u32) 0);
143
144 /* Turn on the Master Enable. */
145 intc_out_be32(intc + MER, 0x3UL);
146
147 ppc_md.get_irq = xilinx_pic_get_irq;
148
149 for (i = 0; i < NR_IRQS; ++i) {
150 irq_desc[i].handler = &xilinx_intc;
151
152 if (XPAR_INTC_0_KIND_OF_INTR & (0x00000001 << i))
153 irq_desc[i].status &= ~IRQ_LEVEL;
154 else
155 irq_desc[i].status |= IRQ_LEVEL;
156 }
157}