aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/52xx/Makefile1
-rw-r--r--arch/powerpc/platforms/52xx/lite5200.c6
-rw-r--r--arch/powerpc/platforms/52xx/mpc52xx_pci.c412
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx.c2
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx_ads.c2
-rw-r--r--arch/powerpc/platforms/82xx/pq2ads.h5
-rw-r--r--arch/powerpc/platforms/83xx/misc.c29
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c3
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_itx.c2
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_sys.c2
-rw-r--r--arch/powerpc/platforms/83xx/mpc8360e_pb.c3
-rw-r--r--arch/powerpc/platforms/86xx/Kconfig1
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_smp.c1
-rw-r--r--arch/powerpc/platforms/8xx/Kconfig300
-rw-r--r--arch/powerpc/platforms/8xx/Makefile6
-rw-r--r--arch/powerpc/platforms/8xx/m8xx_setup.c303
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads.h95
-rw-r--r--arch/powerpc/platforms/8xx/mpc86xads_setup.c301
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads.h95
-rw-r--r--arch/powerpc/platforms/8xx/mpc885ads_setup.c387
-rw-r--r--arch/powerpc/platforms/Makefile3
-rw-r--r--arch/powerpc/platforms/cell/Makefile7
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c3
-rw-r--r--arch/powerpc/platforms/cell/spu_manage.c420
-rw-r--r--arch/powerpc/platforms/cell/spu_priv1_mmio.c422
-rw-r--r--arch/powerpc/platforms/celleb/Makefile9
-rw-r--r--arch/powerpc/platforms/celleb/beat.c163
-rw-r--r--arch/powerpc/platforms/celleb/beat.h40
-rw-r--r--arch/powerpc/platforms/celleb/beat_syscall.h160
-rw-r--r--arch/powerpc/platforms/celleb/beat_wrapper.h220
-rw-r--r--arch/powerpc/platforms/celleb/htab.c311
-rw-r--r--arch/powerpc/platforms/celleb/hvCall.S287
-rw-r--r--arch/powerpc/platforms/celleb/interrupt.c274
-rw-r--r--arch/powerpc/platforms/celleb/interrupt.h33
-rw-r--r--arch/powerpc/platforms/celleb/iommu.c104
-rw-r--r--arch/powerpc/platforms/celleb/pci.c481
-rw-r--r--arch/powerpc/platforms/celleb/pci.h35
-rw-r--r--arch/powerpc/platforms/celleb/scc.h145
-rw-r--r--arch/powerpc/platforms/celleb/scc_epci.c409
-rw-r--r--arch/powerpc/platforms/celleb/scc_sio.c101
-rw-r--r--arch/powerpc/platforms/celleb/scc_uhc.c94
-rw-r--r--arch/powerpc/platforms/celleb/setup.c191
-rw-r--r--arch/powerpc/platforms/celleb/smp.c124
-rw-r--r--arch/powerpc/platforms/celleb/spu_priv1.c208
-rw-r--r--arch/powerpc/platforms/celleb/udbg_beat.c97
-rw-r--r--arch/powerpc/platforms/embedded6xx/Kconfig9
-rw-r--r--arch/powerpc/platforms/maple/pci.c23
-rw-r--r--arch/powerpc/platforms/maple/setup.c3
-rw-r--r--arch/powerpc/platforms/pasemi/Kconfig10
-rw-r--r--arch/powerpc/platforms/pasemi/Makefile3
-rw-r--r--arch/powerpc/platforms/pasemi/idle.c88
-rw-r--r--arch/powerpc/platforms/pasemi/iommu.c281
-rw-r--r--arch/powerpc/platforms/pasemi/pasemi.h12
-rw-r--r--arch/powerpc/platforms/pasemi/pci.c13
-rw-r--r--arch/powerpc/platforms/pasemi/powersave.S80
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c105
-rw-r--r--arch/powerpc/platforms/powermac/smp.c1
-rw-r--r--arch/powerpc/platforms/ps3/Makefile1
-rw-r--r--arch/powerpc/platforms/ps3/htab.c1
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c442
-rw-r--r--arch/powerpc/platforms/ps3/mm.c1
-rw-r--r--arch/powerpc/platforms/ps3/os-area.c22
-rw-r--r--arch/powerpc/platforms/ps3/platform.h151
-rw-r--r--arch/powerpc/platforms/ps3/repository.c220
-rw-r--r--arch/powerpc/platforms/ps3/setup.c19
-rw-r--r--arch/powerpc/platforms/ps3/smp.c3
-rw-r--r--arch/powerpc/platforms/ps3/spu.c20
-rw-r--r--arch/powerpc/platforms/ps3/system-bus.c382
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c19
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c3
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c1
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c55
-rw-r--r--arch/powerpc/platforms/pseries/pci.c2
73 files changed, 7299 insertions, 968 deletions
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile
index a46184a0c750..795b713ec9ee 100644
--- a/arch/powerpc/platforms/52xx/Makefile
+++ b/arch/powerpc/platforms/52xx/Makefile
@@ -3,6 +3,7 @@
3# 3#
4ifeq ($(CONFIG_PPC_MERGE),y) 4ifeq ($(CONFIG_PPC_MERGE),y)
5obj-y += mpc52xx_pic.o mpc52xx_common.o 5obj-y += mpc52xx_pic.o mpc52xx_common.o
6obj-$(CONFIG_PCI) += mpc52xx_pci.o
6endif 7endif
7 8
8obj-$(CONFIG_PPC_EFIKA) += efika-setup.o efika-pci.o 9obj-$(CONFIG_PPC_EFIKA) += efika-setup.o efika-pci.o
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c
index 0f21bab33f6c..cdb16bfa6ca6 100644
--- a/arch/powerpc/platforms/52xx/lite5200.c
+++ b/arch/powerpc/platforms/52xx/lite5200.c
@@ -107,6 +107,12 @@ static void __init lite52xx_setup_arch(void)
107 mpc52xx_setup_cpu(); /* Generic */ 107 mpc52xx_setup_cpu(); /* Generic */
108 lite52xx_setup_cpu(); /* Platorm specific */ 108 lite52xx_setup_cpu(); /* Platorm specific */
109 109
110#ifdef CONFIG_PCI
111 np = of_find_node_by_type(np, "pci");
112 if (np)
113 mpc52xx_add_bridge(np);
114#endif
115
110#ifdef CONFIG_BLK_DEV_INITRD 116#ifdef CONFIG_BLK_DEV_INITRD
111 if (initrd_start) 117 if (initrd_start)
112 ROOT_DEV = Root_RAM0; 118 ROOT_DEV = Root_RAM0;
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
new file mode 100644
index 000000000000..faf161bdbc1c
--- /dev/null
+++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c
@@ -0,0 +1,412 @@
1/*
2 * PCI code for the Freescale MPC52xx embedded CPU.
3 *
4 * Copyright (C) 2006 Secret Lab Technologies Ltd.
5 * Grant Likely <grant.likely@secretlab.ca>
6 * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com>
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12
13#undef DEBUG
14
15#include <asm/pci.h>
16#include <asm/mpc52xx.h>
17#include <asm/delay.h>
18#include <asm/machdep.h>
19#include <linux/kernel.h>
20
21
22/* ======================================================================== */
23/* PCI windows config */
24/* ======================================================================== */
25
26#define MPC52xx_PCI_TARGET_IO 0xf0000000
27#define MPC52xx_PCI_TARGET_MEM 0x00000000
28
29
30/* ======================================================================== */
31/* Structures mapping & Defines for PCI Unit */
32/* ======================================================================== */
33
34#define MPC52xx_PCI_GSCR_BM 0x40000000
35#define MPC52xx_PCI_GSCR_PE 0x20000000
36#define MPC52xx_PCI_GSCR_SE 0x10000000
37#define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000
38#define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24
39#define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000
40#define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16
41#define MPC52xx_PCI_GSCR_BME 0x00004000
42#define MPC52xx_PCI_GSCR_PEE 0x00002000
43#define MPC52xx_PCI_GSCR_SEE 0x00001000
44#define MPC52xx_PCI_GSCR_PR 0x00000001
45
46
47#define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \
48 ( ( (proc_ad) & 0xff000000 ) | \
49 ( (((size) - 1) >> 8) & 0x00ff0000 ) | \
50 ( ((pci_ad) >> 16) & 0x0000ff00 ) )
51
52#define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \
53 ((win1) << 16) | \
54 ((win2) << 8))
55
56#define MPC52xx_PCI_IWCR_DISABLE 0x0
57#define MPC52xx_PCI_IWCR_ENABLE 0x1
58#define MPC52xx_PCI_IWCR_READ 0x0
59#define MPC52xx_PCI_IWCR_READ_LINE 0x2
60#define MPC52xx_PCI_IWCR_READ_MULTI 0x4
61#define MPC52xx_PCI_IWCR_MEM 0x0
62#define MPC52xx_PCI_IWCR_IO 0x8
63
64#define MPC52xx_PCI_TCR_P 0x01000000
65#define MPC52xx_PCI_TCR_LD 0x00010000
66
67#define MPC52xx_PCI_TBATR_DISABLE 0x0
68#define MPC52xx_PCI_TBATR_ENABLE 0x1
69
70struct mpc52xx_pci {
71 u32 idr; /* PCI + 0x00 */
72 u32 scr; /* PCI + 0x04 */
73 u32 ccrir; /* PCI + 0x08 */
74 u32 cr1; /* PCI + 0x0C */
75 u32 bar0; /* PCI + 0x10 */
76 u32 bar1; /* PCI + 0x14 */
77 u8 reserved1[16]; /* PCI + 0x18 */
78 u32 ccpr; /* PCI + 0x28 */
79 u32 sid; /* PCI + 0x2C */
80 u32 erbar; /* PCI + 0x30 */
81 u32 cpr; /* PCI + 0x34 */
82 u8 reserved2[4]; /* PCI + 0x38 */
83 u32 cr2; /* PCI + 0x3C */
84 u8 reserved3[32]; /* PCI + 0x40 */
85 u32 gscr; /* PCI + 0x60 */
86 u32 tbatr0; /* PCI + 0x64 */
87 u32 tbatr1; /* PCI + 0x68 */
88 u32 tcr; /* PCI + 0x6C */
89 u32 iw0btar; /* PCI + 0x70 */
90 u32 iw1btar; /* PCI + 0x74 */
91 u32 iw2btar; /* PCI + 0x78 */
92 u8 reserved4[4]; /* PCI + 0x7C */
93 u32 iwcr; /* PCI + 0x80 */
94 u32 icr; /* PCI + 0x84 */
95 u32 isr; /* PCI + 0x88 */
96 u32 arb; /* PCI + 0x8C */
97 u8 reserved5[104]; /* PCI + 0x90 */
98 u32 car; /* PCI + 0xF8 */
99 u8 reserved6[4]; /* PCI + 0xFC */
100};
101
102
103/* ======================================================================== */
104/* PCI configuration acess */
105/* ======================================================================== */
106
107static int
108mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
109 int offset, int len, u32 *val)
110{
111 struct pci_controller *hose = bus->sysdata;
112 u32 value;
113
114 if (ppc_md.pci_exclude_device)
115 if (ppc_md.pci_exclude_device(bus->number, devfn))
116 return PCIBIOS_DEVICE_NOT_FOUND;
117
118 out_be32(hose->cfg_addr,
119 (1 << 31) |
120 ((bus->number - hose->bus_offset) << 16) |
121 (devfn << 8) |
122 (offset & 0xfc));
123 mb();
124
125#if defined(CONFIG_PPC_MPC5200_BUGFIX)
126 if (bus->number != hose->bus_offset) {
127 /* workaround for the bug 435 of the MPC5200 (L25R);
128 * Don't do 32 bits config access during type-1 cycles */
129 switch (len) {
130 case 1:
131 value = in_8(((u8 __iomem *)hose->cfg_data) +
132 (offset & 3));
133 break;
134 case 2:
135 value = in_le16(((u16 __iomem *)hose->cfg_data) +
136 ((offset>>1) & 1));
137 break;
138
139 default:
140 value = in_le16((u16 __iomem *)hose->cfg_data) |
141 (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16);
142 break;
143 }
144 }
145 else
146#endif
147 {
148 value = in_le32(hose->cfg_data);
149
150 if (len != 4) {
151 value >>= ((offset & 0x3) << 3);
152 value &= 0xffffffff >> (32 - (len << 3));
153 }
154 }
155
156 *val = value;
157
158 out_be32(hose->cfg_addr, 0);
159 mb();
160
161 return PCIBIOS_SUCCESSFUL;
162}
163
164static int
165mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn,
166 int offset, int len, u32 val)
167{
168 struct pci_controller *hose = bus->sysdata;
169 u32 value, mask;
170
171 if (ppc_md.pci_exclude_device)
172 if (ppc_md.pci_exclude_device(bus->number, devfn))
173 return PCIBIOS_DEVICE_NOT_FOUND;
174
175 out_be32(hose->cfg_addr,
176 (1 << 31) |
177 ((bus->number - hose->bus_offset) << 16) |
178 (devfn << 8) |
179 (offset & 0xfc));
180 mb();
181
182#if defined(CONFIG_PPC_MPC5200_BUGFIX)
183 if (bus->number != hose->bus_offset) {
184 /* workaround for the bug 435 of the MPC5200 (L25R);
185 * Don't do 32 bits config access during type-1 cycles */
186 switch (len) {
187 case 1:
188 out_8(((u8 __iomem *)hose->cfg_data) +
189 (offset & 3), val);
190 break;
191 case 2:
192 out_le16(((u16 __iomem *)hose->cfg_data) +
193 ((offset>>1) & 1), val);
194 break;
195
196 default:
197 out_le16((u16 __iomem *)hose->cfg_data,
198 (u16)val);
199 out_le16(((u16 __iomem *)hose->cfg_data) + 1,
200 (u16)(val>>16));
201 break;
202 }
203 }
204 else
205#endif
206 {
207 if (len != 4) {
208 value = in_le32(hose->cfg_data);
209
210 offset = (offset & 0x3) << 3;
211 mask = (0xffffffff >> (32 - (len << 3)));
212 mask <<= offset;
213
214 value &= ~mask;
215 val = value | ((val << offset) & mask);
216 }
217
218 out_le32(hose->cfg_data, val);
219 }
220 mb();
221
222 out_be32(hose->cfg_addr, 0);
223 mb();
224
225 return PCIBIOS_SUCCESSFUL;
226}
227
228static struct pci_ops mpc52xx_pci_ops = {
229 .read = mpc52xx_pci_read_config,
230 .write = mpc52xx_pci_write_config
231};
232
233
234/* ======================================================================== */
235/* PCI setup */
236/* ======================================================================== */
237
238static void __init
239mpc52xx_pci_setup(struct pci_controller *hose,
240 struct mpc52xx_pci __iomem *pci_regs)
241{
242 struct resource *res;
243 u32 tmp;
244 int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0;
245
246 pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs);
247
248 /* pci_process_bridge_OF_ranges() found all our addresses for us;
249 * now store them in the right places */
250 hose->cfg_addr = &pci_regs->car;
251 hose->cfg_data = hose->io_base_virt;
252
253 /* Control regs */
254 tmp = in_be32(&pci_regs->scr);
255 tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
256 out_be32(&pci_regs->scr, tmp);
257
258 /* Memory windows */
259 res = &hose->mem_resources[0];
260 if (res->flags) {
261 pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n",
262 res->start, res->end, res->flags);
263 out_be32(&pci_regs->iw0btar,
264 MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
265 res->end - res->start + 1));
266 iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
267 if (res->flags & IORESOURCE_PREFETCH)
268 iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI;
269 else
270 iwcr0 |= MPC52xx_PCI_IWCR_READ;
271 }
272
273 res = &hose->mem_resources[1];
274 if (res->flags) {
275 pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n",
276 res->start, res->end, res->flags);
277 out_be32(&pci_regs->iw1btar,
278 MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start,
279 res->end - res->start + 1));
280 iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM;
281 if (res->flags & IORESOURCE_PREFETCH)
282 iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI;
283 else
284 iwcr1 |= MPC52xx_PCI_IWCR_READ;
285 }
286
287 /* IO resources */
288 res = &hose->io_resource;
289 if (!res) {
290 printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__);
291 return;
292 }
293 pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} "
294 ".io_base_phys=0x%p\n",
295 res->start, res->end, res->flags, (void*)hose->io_base_phys);
296 out_be32(&pci_regs->iw2btar,
297 MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys,
298 res->start,
299 res->end - res->start + 1));
300 iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO;
301
302 /* Set all the IWCR fields at once; they're in the same reg */
303 out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2));
304
305 out_be32(&pci_regs->tbatr0,
306 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO );
307 out_be32(&pci_regs->tbatr1,
308 MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM );
309
310 out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD);
311
312 tmp = in_be32(&pci_regs->gscr);
313#if 0
314 /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */
315 /* Not necessary and can be a bad thing if for example the bootloader
316 is displaying a splash screen or ... Just left here for
317 documentation purpose if anyone need it */
318 out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR);
319 udelay(50);
320#endif
321
322 /* Make sure the PCI bridge is out of reset */
323 out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR);
324}
325
326static void
327mpc52xx_pci_fixup_resources(struct pci_dev *dev)
328{
329 int i;
330
331 pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n",
332 dev->vendor, dev->device);
333
334 /* We don't rely on boot loader for PCI and resets all
335 devices */
336 for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
337 struct resource *res = &dev->resource[i];
338 if (res->end > res->start) { /* Only valid resources */
339 res->end -= res->start;
340 res->start = 0;
341 res->flags |= IORESOURCE_UNSET;
342 }
343 }
344
345 /* The PCI Host bridge of MPC52xx has a prefetch memory resource
346 fixed to 1Gb. Doesn't fit in the resource system so we remove it */
347 if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) &&
348 ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200
349 || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) {
350 struct resource *res = &dev->resource[1];
351 res->start = res->end = res->flags = 0;
352 }
353}
354
355int __init
356mpc52xx_add_bridge(struct device_node *node)
357{
358 int len;
359 struct mpc52xx_pci __iomem *pci_regs;
360 struct pci_controller *hose;
361 const int *bus_range;
362 struct resource rsrc;
363
364 pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name);
365
366 pci_assign_all_buses = 1;
367
368 if (of_address_to_resource(node, 0, &rsrc) != 0) {
369 printk(KERN_ERR "Can't get %s resources\n", node->full_name);
370 return -EINVAL;
371 }
372
373 bus_range = get_property(node, "bus-range", &len);
374 if (bus_range == NULL || len < 2 * sizeof(int)) {
375 printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n",
376 node->full_name);
377 bus_range = NULL;
378 }
379
380 /* There are some PCI quirks on the 52xx, register the hook to
381 * fix them. */
382 ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources;
383
384 /* Alloc and initialize the pci controller. Values in the device
385 * tree are needed to configure the 52xx PCI controller. Rather
386 * than parse the tree here, let pci_process_bridge_OF_ranges()
387 * do it for us and extract the values after the fact */
388 hose = pcibios_alloc_controller();
389 if (!hose)
390 return -ENOMEM;
391
392 hose->arch_data = node;
393 hose->set_cfg_type = 1;
394
395 hose->first_busno = bus_range ? bus_range[0] : 0;
396 hose->last_busno = bus_range ? bus_range[1] : 0xff;
397
398 hose->bus_offset = 0;
399 hose->ops = &mpc52xx_pci_ops;
400
401 pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1);
402 if (!pci_regs)
403 return -ENOMEM;
404
405 pci_process_bridge_OF_ranges(hose, node, 1);
406
407 /* Finish setting up PCI using values obtained by
408 * pci_proces_bridge_OF_ranges */
409 mpc52xx_pci_setup(hose, pci_regs);
410
411 return 0;
412}
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c
index 0f5b30dc60da..74e7892cdfcf 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx.c
@@ -50,7 +50,7 @@
50#include <sysdev/fsl_soc.h> 50#include <sysdev/fsl_soc.h>
51#include <sysdev/cpm2_pic.h> 51#include <sysdev/cpm2_pic.h>
52 52
53#include "pq2ads_pd.h" 53#include "pq2ads.h"
54 54
55static int __init get_freq(char *name, unsigned long *val) 55static int __init get_freq(char *name, unsigned long *val)
56{ 56{
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
index ea880f1f0dcd..7334c1a15b90 100644
--- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -51,7 +51,7 @@
51#include <sysdev/fsl_soc.h> 51#include <sysdev/fsl_soc.h>
52#include <../sysdev/cpm2_pic.h> 52#include <../sysdev/cpm2_pic.h>
53 53
54#include "pq2ads_pd.h" 54#include "pq2ads.h"
55 55
56#ifdef CONFIG_PCI 56#ifdef CONFIG_PCI
57static uint pci_clk_frq; 57static uint pci_clk_frq;
diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h
index fb2f92bcd770..5b5cca6c8c88 100644
--- a/arch/powerpc/platforms/82xx/pq2ads.h
+++ b/arch/powerpc/platforms/82xx/pq2ads.h
@@ -22,6 +22,7 @@
22#ifndef __MACH_ADS8260_DEFS 22#ifndef __MACH_ADS8260_DEFS
23#define __MACH_ADS8260_DEFS 23#define __MACH_ADS8260_DEFS
24 24
25#include <linux/seq_file.h>
25#include <asm/ppcboot.h> 26#include <asm/ppcboot.h>
26 27
27/* For our show_cpuinfo hooks. */ 28/* For our show_cpuinfo hooks. */
@@ -46,12 +47,12 @@
46#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */ 47#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */
47#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */ 48#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */
48#define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/ 49#define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/
49#define BCSR3_FETH2_RS ((uint)0x80000000) /* 0 == reset */ 50#define BCSR3_FETH2_RST ((uint)0x80000000) /* 0 == reset */
50 51
51/* cpm serial driver works with constants below */ 52/* cpm serial driver works with constants below */
52 53
53#define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET) 54#define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET)
54#define SIU_INT_SMC2i ((uint)0x05+CPM_IRQ_OFFSET) 55#define SIU_INT_SMC2 ((uint)0x05+CPM_IRQ_OFFSET)
55#define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET) 56#define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET)
56#define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET) 57#define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET)
57#define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) 58#define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET)
diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c
index f0c6df61faa9..f01806c940e1 100644
--- a/arch/powerpc/platforms/83xx/misc.c
+++ b/arch/powerpc/platforms/83xx/misc.c
@@ -18,23 +18,36 @@
18 18
19#include "mpc83xx.h" 19#include "mpc83xx.h"
20 20
21static __be32 __iomem *restart_reg_base;
22
23static int __init mpc83xx_restart_init(void)
24{
25 /* map reset restart_reg_baseister space */
26 restart_reg_base = ioremap(get_immrbase() + 0x900, 0xff);
27
28 return 0;
29}
30
31arch_initcall(mpc83xx_restart_init);
32
21void mpc83xx_restart(char *cmd) 33void mpc83xx_restart(char *cmd)
22{ 34{
23#define RST_OFFSET 0x00000900 35#define RST_OFFSET 0x00000900
24#define RST_PROT_REG 0x00000018 36#define RST_PROT_REG 0x00000018
25#define RST_CTRL_REG 0x0000001c 37#define RST_CTRL_REG 0x0000001c
26 __be32 __iomem *reg;
27
28 /* map reset register space */
29 reg = ioremap(get_immrbase() + 0x900, 0xff);
30 38
31 local_irq_disable(); 39 local_irq_disable();
32 40
33 /* enable software reset "RSTE" */ 41 if (restart_reg_base) {
34 out_be32(reg + (RST_PROT_REG >> 2), 0x52535445); 42 /* enable software reset "RSTE" */
43 out_be32(restart_reg_base + (RST_PROT_REG >> 2), 0x52535445);
44
45 /* set software hard reset */
46 out_be32(restart_reg_base + (RST_CTRL_REG >> 2), 0x2);
47 } else {
48 printk (KERN_EMERG "Error: Restart registers not mapped, spinning!\n");
49 }
35 50
36 /* set software hard reset */
37 out_be32(reg + (RST_CTRL_REG >> 2), 0x2);
38 for (;;) ; 51 for (;;) ;
39} 52}
40 53
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index 4d471190be8d..3ecb55f8a6e2 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -25,6 +25,7 @@
25#include <linux/initrd.h> 25#include <linux/initrd.h>
26 26
27#include <asm/of_device.h> 27#include <asm/of_device.h>
28#include <asm/of_platform.h>
28#include <asm/system.h> 29#include <asm/system.h>
29#include <asm/atomic.h> 30#include <asm/atomic.h>
30#include <asm/time.h> 31#include <asm/time.h>
@@ -153,7 +154,7 @@ static int __init mpc832x_declare_of_platform_devices(void)
153} 154}
154device_initcall(mpc832x_declare_of_platform_devices); 155device_initcall(mpc832x_declare_of_platform_devices);
155 156
156void __init mpc832x_sys_init_IRQ(void) 157static void __init mpc832x_sys_init_IRQ(void)
157{ 158{
158 159
159 struct device_node *np; 160 struct device_node *np;
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
index 314c42ac6048..2446dea9407e 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
@@ -81,7 +81,7 @@ static void __init mpc834x_itx_setup_arch(void)
81#endif 81#endif
82} 82}
83 83
84void __init mpc834x_itx_init_IRQ(void) 84static void __init mpc834x_itx_init_IRQ(void)
85{ 85{
86 struct device_node *np; 86 struct device_node *np;
87 87
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_sys.c
index 80b735a414d9..f30393f0b832 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_sys.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_sys.c
@@ -79,7 +79,7 @@ static void __init mpc834x_sys_setup_arch(void)
79#endif 79#endif
80} 80}
81 81
82void __init mpc834x_sys_init_IRQ(void) 82static void __init mpc834x_sys_init_IRQ(void)
83{ 83{
84 struct device_node *np; 84 struct device_node *np;
85 85
diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
index 53b92a904e8e..ccce2f9f283d 100644
--- a/arch/powerpc/platforms/83xx/mpc8360e_pb.c
+++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
@@ -31,6 +31,7 @@
31#include <linux/initrd.h> 31#include <linux/initrd.h>
32 32
33#include <asm/of_device.h> 33#include <asm/of_device.h>
34#include <asm/of_platform.h>
34#include <asm/system.h> 35#include <asm/system.h>
35#include <asm/atomic.h> 36#include <asm/atomic.h>
36#include <asm/time.h> 37#include <asm/time.h>
@@ -158,7 +159,7 @@ static int __init mpc8360_declare_of_platform_devices(void)
158} 159}
159device_initcall(mpc8360_declare_of_platform_devices); 160device_initcall(mpc8360_declare_of_platform_devices);
160 161
161void __init mpc8360_sys_init_IRQ(void) 162static void __init mpc8360_sys_init_IRQ(void)
162{ 163{
163 164
164 struct device_node *np; 165 struct device_node *np;
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index d1ecc0f9ab58..0c70944d0e37 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -8,6 +8,7 @@ choice
8config MPC8641_HPCN 8config MPC8641_HPCN
9 bool "Freescale MPC8641 HPCN" 9 bool "Freescale MPC8641 HPCN"
10 select PPC_I8259 10 select PPC_I8259
11 select DEFAULT_UIMAGE
11 help 12 help
12 This option enables support for the MPC8641 HPCN board. 13 This option enables support for the MPC8641 HPCN board.
13 14
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
index bb7fb41933ad..7ef0c6854799 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c
@@ -65,7 +65,6 @@ smp_86xx_kick_cpu(int nr)
65 pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); 65 pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr);
66 66
67 local_irq_save(flags); 67 local_irq_save(flags);
68 local_irq_disable();
69 68
70 /* Save reset vector */ 69 /* Save reset vector */
71 save_vector = *vector; 70 save_vector = *vector;
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig
index c8c0ba3cf8e8..beea6834bb7e 100644
--- a/arch/powerpc/platforms/8xx/Kconfig
+++ b/arch/powerpc/platforms/8xx/Kconfig
@@ -1,105 +1,16 @@
1menu "Platform support"
2 depends on PPC_8xx
3
1config FADS 4config FADS
2 bool 5 bool
3 6
7config CPM1
8 bool
9
4choice 10choice
5 prompt "8xx Machine Type" 11 prompt "8xx Machine Type"
6 depends on 8xx 12 depends on 8xx
7 default RPXLITE 13 default MPC885ADS
8
9config RPXLITE
10 bool "RPX-Lite"
11 ---help---
12 Single-board computers based around the PowerPC MPC8xx chips and
13 intended for embedded applications. The following types are
14 supported:
15
16 RPX-Lite:
17 Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823.
18
19 RPX-Classic:
20 Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on
21 the MPC 860
22
23 BSE-IP:
24 Bright Star Engineering ip-Engine.
25
26 TQM823L:
27 TQM850L:
28 TQM855L:
29 TQM860L:
30 MPC8xx based family of mini modules, half credit card size,
31 up to 64 MB of RAM, 8 MB Flash, (Fast) Ethernet, 2 x serial ports,
32 2 x CAN bus interface, ...
33 Manufacturer: TQ Components, www.tq-group.de
34 Date of Release: October (?) 1999
35 End of Life: not yet :-)
36 URL:
37 - module: <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>
38 - starter kit: <http://www.denx.de/PDF/STK8xxLHWM201.pdf>
39 - images: <http://www.denx.de/embedded-ppc-en.html>
40
41 FPS850L:
42 FingerPrint Sensor System (based on TQM850L)
43 Manufacturer: IKENDI AG, <http://www.ikendi.com/>
44 Date of Release: November 1999
45 End of life: end 2000 ?
46 URL: see TQM850L
47
48 IVMS8:
49 MPC860 based board used in the "Integrated Voice Mail System",
50 Small Version (8 voice channels)
51 Manufacturer: Speech Design, <http://www.speech-design.de/>
52 Date of Release: December 2000 (?)
53 End of life: -
54 URL: <http://www.speech-design.de/>
55
56 IVML24:
57 MPC860 based board used in the "Integrated Voice Mail System",
58 Large Version (24 voice channels)
59 Manufacturer: Speech Design, <http://www.speech-design.de/>
60 Date of Release: March 2001 (?)
61 End of life: -
62 URL: <http://www.speech-design.de/>
63
64 HERMES:
65 Hermes-Pro ISDN/LAN router with integrated 8 x hub
66 Manufacturer: Multidata Gesellschaft fur Datentechnik und Informatik
67 <http://www.multidata.de/>
68 Date of Release: 2000 (?)
69 End of life: -
70 URL: <http://www.multidata.de/english/products/hpro.htm>
71
72 IP860:
73 VMEBus IP (Industry Pack) carrier board with MPC860
74 Manufacturer: MicroSys GmbH, <http://www.microsys.de/>
75 Date of Release: ?
76 End of life: -
77 URL: <http://www.microsys.de/html/ip860.html>
78
79 PCU_E:
80 PCU = Peripheral Controller Unit, Extended
81 Manufacturer: Siemens AG, ICN (Information and Communication Networks)
82 <http://www.siemens.de/page/1,3771,224315-1-999_2_226207-0,00.html>
83 Date of Release: April 2001
84 End of life: August 2001
85 URL: n. a.
86
87config RPXCLASSIC
88 bool "RPX-Classic"
89 help
90 The RPX-Classic is a single-board computer based on the Motorola
91 MPC860. It features 16MB of DRAM and a variable amount of flash,
92 I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two
93 LEDs. Variants with Ethernet ports exist. Say Y here to support it
94 directly.
95
96config BSEIP
97 bool "BSE-IP"
98 help
99 Say Y here to support the Bright Star Engineering ipEngine SBC.
100 This is a credit-card-sized device featuring a MPC823 processor,
101 26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video
102 controller, and two RS232 ports.
103 14
104config MPC8XXFADS 15config MPC8XXFADS
105 bool "FADS" 16 bool "FADS"
@@ -107,110 +18,58 @@ config MPC8XXFADS
107 18
108config MPC86XADS 19config MPC86XADS
109 bool "MPC86XADS" 20 bool "MPC86XADS"
21 select CPM1
110 help 22 help
111 MPC86x Application Development System by Freescale Semiconductor. 23 MPC86x Application Development System by Freescale Semiconductor.
112 The MPC86xADS is meant to serve as a platform for s/w and h/w 24 The MPC86xADS is meant to serve as a platform for s/w and h/w
113 development around the MPC86X processor families. 25 development around the MPC86X processor families.
114 select FADS
115 26
116config MPC885ADS 27config MPC885ADS
117 bool "MPC885ADS" 28 bool "MPC885ADS"
29 select CPM1
118 help 30 help
119 Freescale Semiconductor MPC885 Application Development System (ADS). 31 Freescale Semiconductor MPC885 Application Development System (ADS).
120 Also known as DUET. 32 Also known as DUET.
121 The MPC885ADS is meant to serve as a platform for s/w and h/w 33 The MPC885ADS is meant to serve as a platform for s/w and h/w
122 development around the MPC885 processor family. 34 development around the MPC885 processor family.
123 35
124config TQM823L 36endchoice
125 bool "TQM823L"
126 help
127 Say Y here to support the TQM823L, one of an MPC8xx-based family of
128 mini SBCs (half credit-card size) from TQ Components first released
129 in late 1999. Technical references are at
130 <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
131 <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
132 <http://www.denx.de/embedded-ppc-en.html>.
133
134config TQM850L
135 bool "TQM850L"
136 help
137 Say Y here to support the TQM850L, one of an MPC8xx-based family of
138 mini SBCs (half credit-card size) from TQ Components first released
139 in late 1999. Technical references are at
140 <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
141 <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
142 <http://www.denx.de/embedded-ppc-en.html>.
143
144config TQM855L
145 bool "TQM855L"
146 help
147 Say Y here to support the TQM855L, one of an MPC8xx-based family of
148 mini SBCs (half credit-card size) from TQ Components first released
149 in late 1999. Technical references are at
150 <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
151 <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
152 <http://www.denx.de/embedded-ppc-en.html>.
153
154config TQM860L
155 bool "TQM860L"
156 help
157 Say Y here to support the TQM860L, one of an MPC8xx-based family of
158 mini SBCs (half credit-card size) from TQ Components first released
159 in late 1999. Technical references are at
160 <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and
161 <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at
162 <http://www.denx.de/embedded-ppc-en.html>.
163
164config FPS850L
165 bool "FPS850L"
166
167config IVMS8
168 bool "IVMS8"
169 help
170 Say Y here to support the Integrated Voice-Mail Small 8-channel SBC
171 from Speech Design, released March 2001. The manufacturer's website
172 is at <http://www.speech-design.de/>.
173
174config IVML24
175 bool "IVML24"
176 help
177 Say Y here to support the Integrated Voice-Mail Large 24-channel SBC
178 from Speech Design, released March 2001. The manufacturer's website
179 is at <http://www.speech-design.de/>.
180
181config HERMES_PRO
182 bool "HERMES"
183
184config IP860
185 bool "IP860"
186
187config LWMON
188 bool "LWMON"
189
190config PCU_E
191 bool "PCU_E"
192
193config CCM
194 bool "CCM"
195
196config LANTEC
197 bool "LANTEC"
198 37
199config MBX 38menu "Freescale Ethernet driver platform-specific options"
200 bool "MBX" 39 depends on (FS_ENET && MPC885ADS)
201 help 40
202 MBX is a line of Motorola single-board computer based around the 41 config MPC8xx_SECOND_ETH
203 MPC821 and MPC860 processors, and intended for embedded-controller 42 bool "Second Ethernet channel"
204 applications. Say Y here to support these boards directly. 43 depends on MPC885ADS
44 default y
45 help
46 This enables support for second Ethernet on MPC885ADS and MPC86xADS boards.
47 The latter will use SCC1, for 885ADS you can select it below.
48
49 choice
50 prompt "Second Ethernet channel"
51 depends on MPC8xx_SECOND_ETH
52 default MPC8xx_SECOND_ETH_FEC2
53
54 config MPC8xx_SECOND_ETH_FEC2
55 bool "FEC2"
56 depends on MPC885ADS
57 help
58 Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2
59 (often 2-nd UART) will not work if this is enabled.
60
61 config MPC8xx_SECOND_ETH_SCC3
62 bool "SCC3"
63 depends on MPC885ADS
64 help
65 Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1
66 (often 1-nd UART) will not work if this is enabled.
67
68 endchoice
205 69
206config WINCEPT 70endmenu
207 bool "WinCept"
208 help
209 The Wincept 100/110 is a Motorola single-board computer based on the
210 MPC821 PowerPC, introduced in 1998 and designed to be used in
211 thin-client machines. Say Y to support it directly.
212 71
213endchoice 72endmenu
214 73
215# 74#
216# MPC8xx Communication options 75# MPC8xx Communication options
@@ -219,79 +78,6 @@ endchoice
219menu "MPC8xx CPM Options" 78menu "MPC8xx CPM Options"
220 depends on 8xx 79 depends on 8xx
221 80
222config SCC_ENET
223 bool "CPM SCC Ethernet"
224 depends on NET_ETHERNET
225 help
226 Enable Ethernet support via the Motorola MPC8xx serial
227 communications controller.
228
229choice
230 prompt "SCC used for Ethernet"
231 depends on SCC_ENET
232 default SCC1_ENET
233
234config SCC1_ENET
235 bool "SCC1"
236 help
237 Use MPC8xx serial communications controller 1 to drive Ethernet
238 (default).
239
240config SCC2_ENET
241 bool "SCC2"
242 help
243 Use MPC8xx serial communications controller 2 to drive Ethernet.
244
245config SCC3_ENET
246 bool "SCC3"
247 help
248 Use MPC8xx serial communications controller 3 to drive Ethernet.
249
250endchoice
251
252config FEC_ENET
253 bool "860T FEC Ethernet"
254 depends on NET_ETHERNET
255 help
256 Enable Ethernet support via the Fast Ethernet Controller (FCC) on
257 the Motorola MPC8260.
258
259config USE_MDIO
260 bool "Use MDIO for PHY configuration"
261 depends on FEC_ENET
262 help
263 On some boards the hardware configuration of the ethernet PHY can be
264 used without any software interaction over the MDIO interface, so
265 all MII code can be omitted. Say N here if unsure or if you don't
266 need link status reports.
267
268config FEC_AM79C874
269 bool "Support AMD79C874 PHY"
270 depends on USE_MDIO
271
272config FEC_LXT970
273 bool "Support LXT970 PHY"
274 depends on USE_MDIO
275
276config FEC_LXT971
277 bool "Support LXT971 PHY"
278 depends on USE_MDIO
279
280config FEC_QS6612
281 bool "Support QS6612 PHY"
282 depends on USE_MDIO
283
284config ENET_BIG_BUFFERS
285 bool "Use Big CPM Ethernet Buffers"
286 depends on SCC_ENET || FEC_ENET
287 help
288 Allocate large buffers for MPC8xx Ethernet. Increases throughput
289 and decreases the likelihood of dropped packets, but costs memory.
290
291config HTDMSOUND
292 bool "Embedded Planet HIOX Audio"
293 depends on SOUND=y
294
295# This doesn't really belong here, but it is convenient to ask 81# This doesn't really belong here, but it is convenient to ask
296# 8xx specific questions. 82# 8xx specific questions.
297comment "Generic MPC8xx Options" 83comment "Generic MPC8xx Options"
diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile
new file mode 100644
index 000000000000..5e2dae3afd2f
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/Makefile
@@ -0,0 +1,6 @@
1#
2# Makefile for the PowerPC 8xx linux kernel.
3#
4obj-$(CONFIG_PPC_8xx) += m8xx_setup.o
5obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o
6obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c
new file mode 100644
index 000000000000..9ed7125f0150
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/m8xx_setup.c
@@ -0,0 +1,303 @@
1/*
2 * Copyright (C) 1995 Linus Torvalds
3 * Adapted from 'alpha' version by Gary Thomas
4 * Modified by Cort Dougan (cort@cs.nmt.edu)
5 * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
6 * Further modified for generic 8xx by Dan.
7 */
8
9/*
10 * bootup setup stuff..
11 */
12
13#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/kernel.h>
16#include <linux/mm.h>
17#include <linux/stddef.h>
18#include <linux/unistd.h>
19#include <linux/ptrace.h>
20#include <linux/slab.h>
21#include <linux/user.h>
22#include <linux/a.out.h>
23#include <linux/tty.h>
24#include <linux/major.h>
25#include <linux/interrupt.h>
26#include <linux/reboot.h>
27#include <linux/init.h>
28#include <linux/initrd.h>
29#include <linux/ioport.h>
30#include <linux/bootmem.h>
31#include <linux/seq_file.h>
32#include <linux/root_dev.h>
33#include <linux/time.h>
34#include <linux/rtc.h>
35
36#include <asm/mmu.h>
37#include <asm/reg.h>
38#include <asm/residual.h>
39#include <asm/io.h>
40#include <asm/pgtable.h>
41#include <asm/mpc8xx.h>
42#include <asm/8xx_immap.h>
43#include <asm/machdep.h>
44#include <asm/bootinfo.h>
45#include <asm/time.h>
46#include <asm/prom.h>
47#include <asm/fs_pd.h>
48#include <mm/mmu_decl.h>
49
50#include "sysdev/mpc8xx_pic.h"
51
52void m8xx_calibrate_decr(void);
53extern void m8xx_wdt_handler_install(bd_t *bp);
54extern int cpm_pic_init(void);
55extern int cpm_get_irq(void);
56
57/* A place holder for time base interrupts, if they are ever enabled. */
58irqreturn_t timebase_interrupt(int irq, void * dev)
59{
60 printk ("timebase_interrupt()\n");
61
62 return IRQ_HANDLED;
63}
64
65static struct irqaction tbint_irqaction = {
66 .handler = timebase_interrupt,
67 .mask = CPU_MASK_NONE,
68 .name = "tbint",
69};
70
71/* per-board overridable init_internal_rtc() function. */
72void __init __attribute__ ((weak))
73init_internal_rtc(void)
74{
75 sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit);
76
77 /* Disable the RTC one second and alarm interrupts. */
78 clrbits16(&sys_tmr->sit_rtcsc, (RTCSC_SIE | RTCSC_ALE));
79
80 /* Enable the RTC */
81 setbits16(&sys_tmr->sit_rtcsc, (RTCSC_RTF | RTCSC_RTE));
82 immr_unmap(sys_tmr);
83}
84
85static int __init get_freq(char *name, unsigned long *val)
86{
87 struct device_node *cpu;
88 unsigned int *fp;
89 int found = 0;
90
91 /* The cpu node should have timebase and clock frequency properties */
92 cpu = of_find_node_by_type(NULL, "cpu");
93
94 if (cpu) {
95 fp = (unsigned int *)get_property(cpu, name, NULL);
96 if (fp) {
97 found = 1;
98 *val = *fp++;
99 }
100
101 of_node_put(cpu);
102 }
103
104 return found;
105}
106
107/* The decrementer counts at the system (internal) clock frequency divided by
108 * sixteen, or external oscillator divided by four. We force the processor
109 * to use system clock divided by sixteen.
110 */
111void __init mpc8xx_calibrate_decr(void)
112{
113 struct device_node *cpu;
114 cark8xx_t *clk_r1;
115 car8xx_t *clk_r2;
116 sitk8xx_t *sys_tmr1;
117 sit8xx_t *sys_tmr2;
118 int irq, virq;
119
120 clk_r1 = (cark8xx_t *) immr_map(im_clkrstk);
121
122 /* Unlock the SCCR. */
123 out_be32(&clk_r1->cark_sccrk, ~KAPWR_KEY);
124 out_be32(&clk_r1->cark_sccrk, KAPWR_KEY);
125 immr_unmap(clk_r1);
126
127 /* Force all 8xx processors to use divide by 16 processor clock. */
128 clk_r2 = (car8xx_t *) immr_map(im_clkrst);
129 setbits32(&clk_r2->car_sccr, 0x02000000);
130 immr_unmap(clk_r2);
131
132 /* Processor frequency is MHz.
133 */
134 ppc_tb_freq = 50000000;
135 if (!get_freq("bus-frequency", &ppc_tb_freq)) {
136 printk(KERN_ERR "WARNING: Estimating decrementer frequency "
137 "(not found)\n");
138 }
139 ppc_tb_freq /= 16;
140 ppc_proc_freq = 50000000;
141 if (!get_freq("clock-frequency", &ppc_proc_freq))
142 printk(KERN_ERR "WARNING: Estimating processor frequency"
143 "(not found)\n");
144
145 printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq);
146
147 /* Perform some more timer/timebase initialization. This used
148 * to be done elsewhere, but other changes caused it to get
149 * called more than once....that is a bad thing.
150 *
151 * First, unlock all of the registers we are going to modify.
152 * To protect them from corruption during power down, registers
153 * that are maintained by keep alive power are "locked". To
154 * modify these registers we have to write the key value to
155 * the key location associated with the register.
156 * Some boards power up with these unlocked, while others
157 * are locked. Writing anything (including the unlock code?)
158 * to the unlocked registers will lock them again. So, here
159 * we guarantee the registers are locked, then we unlock them
160 * for our use.
161 */
162 sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk);
163 out_be32(&sys_tmr1->sitk_tbscrk, ~KAPWR_KEY);
164 out_be32(&sys_tmr1->sitk_rtcsck, ~KAPWR_KEY);
165 out_be32(&sys_tmr1->sitk_tbk, ~KAPWR_KEY);
166 out_be32(&sys_tmr1->sitk_tbscrk, KAPWR_KEY);
167 out_be32(&sys_tmr1->sitk_rtcsck, KAPWR_KEY);
168 out_be32(&sys_tmr1->sitk_tbk, KAPWR_KEY);
169 immr_unmap(sys_tmr1);
170
171 init_internal_rtc();
172
173 /* Enabling the decrementer also enables the timebase interrupts
174 * (or from the other point of view, to get decrementer interrupts
175 * we have to enable the timebase). The decrementer interrupt
176 * is wired into the vector table, nothing to do here for that.
177 */
178 cpu = of_find_node_by_type(NULL, "cpu");
179 virq= irq_of_parse_and_map(cpu, 0);
180 irq = irq_map[virq].hwirq;
181
182 sys_tmr2 = (sit8xx_t *) immr_map(im_sit);
183 out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) |
184 (TBSCR_TBF | TBSCR_TBE));
185 immr_unmap(sys_tmr2);
186
187 if (setup_irq(virq, &tbint_irqaction))
188 panic("Could not allocate timer IRQ!");
189
190#ifdef CONFIG_8xx_WDT
191 /* Install watchdog timer handler early because it might be
192 * already enabled by the bootloader
193 */
194 m8xx_wdt_handler_install(binfo);
195#endif
196}
197
198/* The RTC on the MPC8xx is an internal register.
199 * We want to protect this during power down, so we need to unlock,
200 * modify, and re-lock.
201 */
202
203int mpc8xx_set_rtc_time(struct rtc_time *tm)
204{
205 sitk8xx_t *sys_tmr1;
206 sit8xx_t *sys_tmr2;
207 int time;
208
209 sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk);
210 sys_tmr2 = (sit8xx_t *) immr_map(im_sit);
211 time = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
212 tm->tm_hour, tm->tm_min, tm->tm_sec);
213
214 out_be32(&sys_tmr1->sitk_rtck, KAPWR_KEY);
215 out_be32(&sys_tmr2->sit_rtc, time);
216 out_be32(&sys_tmr1->sitk_rtck, ~KAPWR_KEY);
217
218 immr_unmap(sys_tmr2);
219 immr_unmap(sys_tmr1);
220 return 0;
221}
222
223void mpc8xx_get_rtc_time(struct rtc_time *tm)
224{
225 unsigned long data;
226 sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit);
227
228 /* Get time from the RTC. */
229 data = in_be32(&sys_tmr->sit_rtc);
230 to_tm(data, tm);
231 tm->tm_year -= 1900;
232 tm->tm_mon -= 1;
233 immr_unmap(sys_tmr);
234 return;
235}
236
237void mpc8xx_restart(char *cmd)
238{
239 __volatile__ unsigned char dummy;
240 car8xx_t * clk_r = (car8xx_t *) immr_map(im_clkrst);
241
242
243 local_irq_disable();
244
245 setbits32(&clk_r->car_plprcr, 0x00000080);
246 /* Clear the ME bit in MSR to cause checkstop on machine check
247 */
248 mtmsr(mfmsr() & ~0x1000);
249
250 dummy = in_8(&clk_r->res[0]);
251 printk("Restart failed\n");
252 while(1);
253}
254
255void mpc8xx_show_cpuinfo(struct seq_file *m)
256{
257 struct device_node *root;
258 uint memsize = total_memory;
259 const char *model = "";
260
261 seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
262
263 root = of_find_node_by_path("/");
264 if (root)
265 model = get_property(root, "model", NULL);
266 seq_printf(m, "Machine\t\t: %s\n", model);
267 of_node_put(root);
268
269 seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
270}
271
272static void cpm_cascade(unsigned int irq, struct irq_desc *desc)
273{
274 int cascade_irq;
275
276 if ((cascade_irq = cpm_get_irq()) >= 0) {
277 struct irq_desc *cdesc = irq_desc + cascade_irq;
278
279 generic_handle_irq(cascade_irq);
280 cdesc->chip->eoi(cascade_irq);
281 }
282 desc->chip->eoi(irq);
283}
284
285/* Initialize the internal interrupt controller. The number of
286 * interrupts supported can vary with the processor type, and the
287 * 82xx family can have up to 64.
288 * External interrupts can be either edge or level triggered, and
289 * need to be initialized by the appropriate driver.
290 */
291void __init m8xx_pic_init(void)
292{
293 int irq;
294
295 if (mpc8xx_pic_init()) {
296 printk(KERN_ERR "Failed interrupt 8xx controller initialization\n");
297 return;
298 }
299
300 irq = cpm_pic_init();
301 if (irq != NO_IRQ)
302 set_irq_chained_handler(irq, cpm_cascade);
303}
diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h
new file mode 100644
index 000000000000..b5d19dd0619c
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc86xads.h
@@ -0,0 +1,95 @@
1/*
2 * A collection of structures, addresses, and values associated with
3 * the Freescale MPC86xADS board.
4 * Copied from the FADS stuff.
5 *
6 * Author: MontaVista Software, Inc.
7 * source@mvista.com
8 *
9 * 2005 (c) MontaVista Software, Inc. This file is licensed under the
10 * terms of the GNU General Public License version 2. This program is licensed
11 * "as is" without any warranty of any kind, whether express or implied.
12 */
13
14#ifdef __KERNEL__
15#ifndef __ASM_MPC86XADS_H__
16#define __ASM_MPC86XADS_H__
17
18#include <asm/ppcboot.h>
19#include <sysdev/fsl_soc.h>
20
21/* U-Boot maps BCSR to 0xff080000 */
22#define BCSR_ADDR ((uint)0xff080000)
23#define BCSR_SIZE ((uint)32)
24#define BCSR0 ((uint)(BCSR_ADDR + 0x00))
25#define BCSR1 ((uint)(BCSR_ADDR + 0x04))
26#define BCSR2 ((uint)(BCSR_ADDR + 0x08))
27#define BCSR3 ((uint)(BCSR_ADDR + 0x0c))
28#define BCSR4 ((uint)(BCSR_ADDR + 0x10))
29
30#define CFG_PHYDEV_ADDR ((uint)0xff0a0000)
31#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300))
32
33#define IMAP_ADDR (get_immrbase())
34#define IMAP_SIZE ((uint)(64 * 1024))
35
36#define MPC8xx_CPM_OFFSET (0x9c0)
37#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET)
38#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver
39
40#define PCMCIA_MEM_ADDR (uint)0xff020000)
41#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
42
43/* Bits of interest in the BCSRs.
44 */
45#define BCSR1_ETHEN ((uint)0x20000000)
46#define BCSR1_IRDAEN ((uint)0x10000000)
47#define BCSR1_RS232EN_1 ((uint)0x01000000)
48#define BCSR1_PCCEN ((uint)0x00800000)
49#define BCSR1_PCCVCC0 ((uint)0x00400000)
50#define BCSR1_PCCVPP0 ((uint)0x00200000)
51#define BCSR1_PCCVPP1 ((uint)0x00100000)
52#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
53#define BCSR1_RS232EN_2 ((uint)0x00040000)
54#define BCSR1_PCCVCC1 ((uint)0x00010000)
55#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
56
57#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/
58#define BCSR4_USB_LO_SPD ((uint)0x04000000)
59#define BCSR4_USB_VCC ((uint)0x02000000)
60#define BCSR4_USB_FULL_SPD ((uint)0x00040000)
61#define BCSR4_USB_EN ((uint)0x00020000)
62
63#define BCSR5_MII2_EN 0x40
64#define BCSR5_MII2_RST 0x20
65#define BCSR5_T1_RST 0x10
66#define BCSR5_ATM155_RST 0x08
67#define BCSR5_ATM25_RST 0x04
68#define BCSR5_MII1_EN 0x02
69#define BCSR5_MII1_RST 0x01
70
71/* Interrupt level assignments */
72#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */
73#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */
74#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */
75
76/* We don't use the 8259 */
77#define NR_8259_INTS 0
78
79/* CPM Ethernet through SCC1 */
80#define PA_ENET_RXD ((ushort)0x0001)
81#define PA_ENET_TXD ((ushort)0x0002)
82#define PA_ENET_TCLK ((ushort)0x0100)
83#define PA_ENET_RCLK ((ushort)0x0200)
84#define PB_ENET_TENA ((uint)0x00001000)
85#define PC_ENET_CLSN ((ushort)0x0010)
86#define PC_ENET_RENA ((ushort)0x0020)
87
88/* Control bits in the SICR to route TCLK (CLK1) and RCLK (CLK2) to
89 * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
90 */
91#define SICR_ENET_MASK ((uint)0x000000ff)
92#define SICR_ENET_CLKRT ((uint)0x0000002c)
93
94#endif /* __ASM_MPC86XADS_H__ */
95#endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
new file mode 100644
index 000000000000..ef52ce701b0e
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c
@@ -0,0 +1,301 @@
1/*arch/ppc/platforms/mpc86xads-setup.c
2 *
3 * Platform setup for the Freescale mpc86xads board
4 *
5 * Vitaly Bordug <vbordug@ru.mvista.com>
6 *
7 * Copyright 2005 MontaVista Software Inc.
8 *
9 * This file is licensed under the terms of the GNU General Public License
10 * version 2. This program is licensed "as is" without any warranty of any
11 * kind, whether express or implied.
12 */
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/param.h>
17#include <linux/string.h>
18#include <linux/ioport.h>
19#include <linux/device.h>
20#include <linux/delay.h>
21#include <linux/root_dev.h>
22
23#include <linux/fs_enet_pd.h>
24#include <linux/fs_uart_pd.h>
25#include <linux/mii.h>
26
27#include <asm/delay.h>
28#include <asm/io.h>
29#include <asm/machdep.h>
30#include <asm/page.h>
31#include <asm/processor.h>
32#include <asm/system.h>
33#include <asm/time.h>
34#include <asm/ppcboot.h>
35#include <asm/mpc8xx.h>
36#include <asm/8xx_immap.h>
37#include <asm/commproc.h>
38#include <asm/fs_pd.h>
39#include <asm/prom.h>
40
41extern void cpm_reset(void);
42extern void mpc8xx_show_cpuinfo(struct seq_file*);
43extern void mpc8xx_restart(char *cmd);
44extern void mpc8xx_calibrate_decr(void);
45extern int mpc8xx_set_rtc_time(struct rtc_time *tm);
46extern void mpc8xx_get_rtc_time(struct rtc_time *tm);
47extern void m8xx_pic_init(void);
48extern unsigned int mpc8xx_get_irq(void);
49
50static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
51static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
52static void init_scc1_ioports(struct fs_platform_info* ptr);
53
54void __init mpc86xads_board_setup(void)
55{
56 cpm8xx_t *cp;
57 unsigned int *bcsr_io;
58 u8 tmpval8;
59
60 bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
61 cp = (cpm8xx_t *)immr_map(im_cpm);
62
63 if (bcsr_io == NULL) {
64 printk(KERN_CRIT "Could not remap BCSR\n");
65 return;
66 }
67#ifdef CONFIG_SERIAL_CPM_SMC1
68 clrbits32(bcsr_io, BCSR1_RS232EN_1);
69 clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */
70 tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX);
71 out_8(&(cp->cp_smc[0].smc_smcm), tmpval8);
72 clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN);
73#else
74 setbits32(bcsr_io,BCSR1_RS232EN_1);
75 out_be16(&cp->cp_smc[0].smc_smcmr, 0);
76 out_8(&cp->cp_smc[0].smc_smce, 0);
77#endif
78
79#ifdef CONFIG_SERIAL_CPM_SMC2
80 clrbits32(bcsr_io,BCSR1_RS232EN_2);
81 clrbits32(&cp->cp_simode, 0xe0000000 >> 1);
82 setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */
83 tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX);
84 out_8(&(cp->cp_smc[1].smc_smcm), tmpval8);
85 clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN);
86
87 init_smc2_uart_ioports(0);
88#else
89 setbits32(bcsr_io,BCSR1_RS232EN_2);
90 out_be16(&cp->cp_smc[1].smc_smcmr, 0);
91 out_8(&cp->cp_smc[1].smc_smce, 0);
92#endif
93 immr_unmap(cp);
94 iounmap(bcsr_io);
95}
96
97
98static void init_fec1_ioports(struct fs_platform_info* ptr)
99{
100 iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
101
102 /* configure FEC1 pins */
103
104 setbits16(&io_port->iop_pdpar, 0x1fff);
105 setbits16(&io_port->iop_pddir, 0x1fff);
106
107 immr_unmap(io_port);
108}
109
110void init_fec_ioports(struct fs_platform_info *fpi)
111{
112 int fec_no = fs_get_fec_index(fpi->fs_no);
113
114 switch (fec_no) {
115 case 0:
116 init_fec1_ioports(fpi);
117 break;
118 default:
119 printk(KERN_ERR "init_fec_ioports: invalid FEC number\n");
120 return;
121 }
122}
123
124static void init_scc1_ioports(struct fs_platform_info* fpi)
125{
126 unsigned *bcsr_io;
127 iop8xx_t *io_port;
128 cpm8xx_t *cp;
129
130 bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
131 io_port = (iop8xx_t *)immr_map(im_ioport);
132 cp = (cpm8xx_t *)immr_map(im_cpm);
133
134 if (bcsr_io == NULL) {
135 printk(KERN_CRIT "Could not remap BCSR\n");
136 return;
137 }
138
139 /* Configure port A pins for Txd and Rxd.
140 */
141 setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD);
142 clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD);
143 clrbits16(&io_port->iop_paodr, PA_ENET_TXD);
144
145 /* Configure port C pins to enable CLSN and RENA.
146 */
147 clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
148 clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
149 setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
150
151 /* Configure port A for TCLK and RCLK.
152 */
153 setbits16(&io_port->iop_papar, PA_ENET_TCLK | PA_ENET_RCLK);
154 clrbits16(&io_port->iop_padir, PA_ENET_TCLK | PA_ENET_RCLK);
155 clrbits32(&cp->cp_pbpar, PB_ENET_TENA);
156 clrbits32(&cp->cp_pbdir, PB_ENET_TENA);
157
158 /* Configure Serial Interface clock routing.
159 * First, clear all SCC bits to zero, then set the ones we want.
160 */
161 clrbits32(&cp->cp_sicr, SICR_ENET_MASK);
162 setbits32(&cp->cp_sicr, SICR_ENET_CLKRT);
163
164 /* In the original SCC enet driver the following code is placed at
165 the end of the initialization */
166 setbits32(&cp->cp_pbpar, PB_ENET_TENA);
167 setbits32(&cp->cp_pbdir, PB_ENET_TENA);
168
169 clrbits32(bcsr_io+1, BCSR1_ETHEN);
170 iounmap(bcsr_io);
171 immr_unmap(cp);
172 immr_unmap(io_port);
173}
174
175void init_scc_ioports(struct fs_platform_info *fpi)
176{
177 int scc_no = fs_get_scc_index(fpi->fs_no);
178
179 switch (scc_no) {
180 case 0:
181 init_scc1_ioports(fpi);
182 break;
183 default:
184 printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
185 return;
186 }
187}
188
189
190
191static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr)
192{
193 unsigned *bcsr_io;
194 cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
195
196 setbits32(&cp->cp_pbpar, 0x000000c0);
197 clrbits32(&cp->cp_pbdir, 0x000000c0);
198 clrbits16(&cp->cp_pbodr, 0x00c0);
199 immr_unmap(cp);
200
201 bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
202
203 if (bcsr_io == NULL) {
204 printk(KERN_CRIT "Could not remap BCSR1\n");
205 return;
206 }
207 clrbits32(bcsr_io,BCSR1_RS232EN_1);
208 iounmap(bcsr_io);
209}
210
211static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi)
212{
213 unsigned *bcsr_io;
214 cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
215
216 setbits32(&cp->cp_pbpar, 0x00000c00);
217 clrbits32(&cp->cp_pbdir, 0x00000c00);
218 clrbits16(&cp->cp_pbodr, 0x0c00);
219 immr_unmap(cp);
220
221 bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
222
223 if (bcsr_io == NULL) {
224 printk(KERN_CRIT "Could not remap BCSR1\n");
225 return;
226 }
227 clrbits32(bcsr_io,BCSR1_RS232EN_2);
228 iounmap(bcsr_io);
229}
230
231void init_smc_ioports(struct fs_uart_platform_info *data)
232{
233 int smc_no = fs_uart_id_fsid2smc(data->fs_no);
234
235 switch (smc_no) {
236 case 0:
237 init_smc1_uart_ioports(data);
238 data->brg = data->clk_rx;
239 break;
240 case 1:
241 init_smc2_uart_ioports(data);
242 data->brg = data->clk_rx;
243 break;
244 default:
245 printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
246 return;
247 }
248}
249
250int platform_device_skip(char *model, int id)
251{
252 return 0;
253}
254
255static void __init mpc86xads_setup_arch(void)
256{
257 struct device_node *cpu;
258
259 cpu = of_find_node_by_type(NULL, "cpu");
260 if (cpu != 0) {
261 const unsigned int *fp;
262
263 fp = get_property(cpu, "clock-frequency", NULL);
264 if (fp != 0)
265 loops_per_jiffy = *fp / HZ;
266 else
267 loops_per_jiffy = 50000000 / HZ;
268 of_node_put(cpu);
269 }
270
271 cpm_reset();
272
273 mpc86xads_board_setup();
274
275 ROOT_DEV = Root_NFS;
276}
277
278static int __init mpc86xads_probe(void)
279{
280 char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
281 "model", NULL);
282 if (model == NULL)
283 return 0;
284 if (strcmp(model, "MPC866ADS"))
285 return 0;
286
287 return 1;
288}
289
290define_machine(mpc86x_ads) {
291 .name = "MPC86x ADS",
292 .probe = mpc86xads_probe,
293 .setup_arch = mpc86xads_setup_arch,
294 .init_IRQ = m8xx_pic_init,
295 .show_cpuinfo = mpc8xx_show_cpuinfo,
296 .get_irq = mpc8xx_get_irq,
297 .restart = mpc8xx_restart,
298 .calibrate_decr = mpc8xx_calibrate_decr,
299 .set_rtc_time = mpc8xx_set_rtc_time,
300 .get_rtc_time = mpc8xx_get_rtc_time,
301};
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h
new file mode 100644
index 000000000000..30cbebfe84c5
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc885ads.h
@@ -0,0 +1,95 @@
1/*
2 * A collection of structures, addresses, and values associated with
3 * the Freescale MPC885ADS board.
4 * Copied from the FADS stuff.
5 *
6 * Author: MontaVista Software, Inc.
7 * source@mvista.com
8 *
9 * 2005 (c) MontaVista Software, Inc. This file is licensed under the
10 * terms of the GNU General Public License version 2. This program is licensed
11 * "as is" without any warranty of any kind, whether express or implied.
12 */
13
14#ifdef __KERNEL__
15#ifndef __ASM_MPC885ADS_H__
16#define __ASM_MPC885ADS_H__
17
18#include <asm/ppcboot.h>
19#include <sysdev/fsl_soc.h>
20
21/* U-Boot maps BCSR to 0xff080000 */
22#define BCSR_ADDR ((uint)0xff080000)
23#define BCSR_SIZE ((uint)32)
24#define BCSR0 ((uint)(BCSR_ADDR + 0x00))
25#define BCSR1 ((uint)(BCSR_ADDR + 0x04))
26#define BCSR2 ((uint)(BCSR_ADDR + 0x08))
27#define BCSR3 ((uint)(BCSR_ADDR + 0x0c))
28#define BCSR4 ((uint)(BCSR_ADDR + 0x10))
29
30#define CFG_PHYDEV_ADDR ((uint)0xff0a0000)
31#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300))
32
33#define IMAP_ADDR (get_immrbase())
34#define IMAP_SIZE ((uint)(64 * 1024))
35
36#define MPC8xx_CPM_OFFSET (0x9c0)
37#define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET)
38#define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver
39
40#define PCMCIA_MEM_ADDR (uint)0xff020000)
41#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
42
43/* Bits of interest in the BCSRs.
44 */
45#define BCSR1_ETHEN ((uint)0x20000000)
46#define BCSR1_IRDAEN ((uint)0x10000000)
47#define BCSR1_RS232EN_1 ((uint)0x01000000)
48#define BCSR1_PCCEN ((uint)0x00800000)
49#define BCSR1_PCCVCC0 ((uint)0x00400000)
50#define BCSR1_PCCVPP0 ((uint)0x00200000)
51#define BCSR1_PCCVPP1 ((uint)0x00100000)
52#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
53#define BCSR1_RS232EN_2 ((uint)0x00040000)
54#define BCSR1_PCCVCC1 ((uint)0x00010000)
55#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
56
57#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/
58#define BCSR4_USB_LO_SPD ((uint)0x04000000)
59#define BCSR4_USB_VCC ((uint)0x02000000)
60#define BCSR4_USB_FULL_SPD ((uint)0x00040000)
61#define BCSR4_USB_EN ((uint)0x00020000)
62
63#define BCSR5_MII2_EN 0x40
64#define BCSR5_MII2_RST 0x20
65#define BCSR5_T1_RST 0x10
66#define BCSR5_ATM155_RST 0x08
67#define BCSR5_ATM25_RST 0x04
68#define BCSR5_MII1_EN 0x02
69#define BCSR5_MII1_RST 0x01
70
71/* Interrupt level assignments */
72#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */
73#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */
74#define SIU_INT_FEC2 SIU_LEVEL3 /* FEC2 interrupt */
75#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */
76
77/* We don't use the 8259 */
78#define NR_8259_INTS 0
79
80/* CPM Ethernet through SCC3 */
81#define PA_ENET_RXD ((ushort)0x0040)
82#define PA_ENET_TXD ((ushort)0x0080)
83#define PE_ENET_TCLK ((uint)0x00004000)
84#define PE_ENET_RCLK ((uint)0x00008000)
85#define PE_ENET_TENA ((uint)0x00000010)
86#define PC_ENET_CLSN ((ushort)0x0400)
87#define PC_ENET_RENA ((ushort)0x0800)
88
89/* Control bits in the SICR to route TCLK (CLK5) and RCLK (CLK6) to
90 * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero */
91#define SICR_ENET_MASK ((uint)0x00ff0000)
92#define SICR_ENET_CLKRT ((uint)0x002c0000)
93
94#endif /* __ASM_MPC885ADS_H__ */
95#endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
new file mode 100644
index 000000000000..c5fefdf66c0a
--- /dev/null
+++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c
@@ -0,0 +1,387 @@
1/*arch/ppc/platforms/mpc885ads-setup.c
2 *
3 * Platform setup for the Freescale mpc885ads board
4 *
5 * Vitaly Bordug <vbordug@ru.mvista.com>
6 *
7 * Copyright 2005 MontaVista Software Inc.
8 *
9 * This file is licensed under the terms of the GNU General Public License
10 * version 2. This program is licensed "as is" without any warranty of any
11 * kind, whether express or implied.
12 */
13
14#include <linux/init.h>
15#include <linux/module.h>
16#include <linux/param.h>
17#include <linux/string.h>
18#include <linux/ioport.h>
19#include <linux/device.h>
20#include <linux/delay.h>
21#include <linux/root_dev.h>
22
23#include <linux/fs_enet_pd.h>
24#include <linux/fs_uart_pd.h>
25#include <linux/mii.h>
26
27#include <asm/delay.h>
28#include <asm/io.h>
29#include <asm/machdep.h>
30#include <asm/page.h>
31#include <asm/processor.h>
32#include <asm/system.h>
33#include <asm/time.h>
34#include <asm/ppcboot.h>
35#include <asm/mpc8xx.h>
36#include <asm/8xx_immap.h>
37#include <asm/commproc.h>
38#include <asm/fs_pd.h>
39#include <asm/prom.h>
40
41extern void cpm_reset(void);
42extern void mpc8xx_show_cpuinfo(struct seq_file*);
43extern void mpc8xx_restart(char *cmd);
44extern void mpc8xx_calibrate_decr(void);
45extern int mpc8xx_set_rtc_time(struct rtc_time *tm);
46extern void mpc8xx_get_rtc_time(struct rtc_time *tm);
47extern void m8xx_pic_init(void);
48extern unsigned int mpc8xx_get_irq(void);
49
50static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi);
51static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi);
52static void init_scc3_ioports(struct fs_platform_info* ptr);
53
54void __init mpc885ads_board_setup(void)
55{
56 cpm8xx_t *cp;
57 unsigned int *bcsr_io;
58 u8 tmpval8;
59
60#ifdef CONFIG_FS_ENET
61 iop8xx_t *io_port;
62#endif
63
64 bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
65 cp = (cpm8xx_t *)immr_map(im_cpm);
66
67 if (bcsr_io == NULL) {
68 printk(KERN_CRIT "Could not remap BCSR\n");
69 return;
70 }
71#ifdef CONFIG_SERIAL_CPM_SMC1
72 clrbits32(bcsr_io, BCSR1_RS232EN_1);
73 clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */
74 tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX);
75 out_8(&(cp->cp_smc[0].smc_smcm), tmpval8);
76 clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); /* brg1 */
77#else
78 setbits32(bcsr_io,BCSR1_RS232EN_1);
79 out_be16(&cp->cp_smc[0].smc_smcmr, 0);
80 out_8(&cp->cp_smc[0].smc_smce, 0);
81#endif
82
83#ifdef CONFIG_SERIAL_CPM_SMC2
84 clrbits32(bcsr_io,BCSR1_RS232EN_2);
85 clrbits32(&cp->cp_simode, 0xe0000000 >> 1);
86 setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */
87 tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX);
88 out_8(&(cp->cp_smc[1].smc_smcm), tmpval8);
89 clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN);
90
91 init_smc2_uart_ioports(0);
92#else
93 setbits32(bcsr_io,BCSR1_RS232EN_2);
94 out_be16(&cp->cp_smc[1].smc_smcmr, 0);
95 out_8(&cp->cp_smc[1].smc_smce, 0);
96#endif
97 immr_unmap(cp);
98 iounmap(bcsr_io);
99
100#ifdef CONFIG_FS_ENET
101 /* use MDC for MII (common) */
102 io_port = (iop8xx_t*)immr_map(im_ioport);
103 setbits16(&io_port->iop_pdpar, 0x0080);
104 clrbits16(&io_port->iop_pddir, 0x0080);
105
106 bcsr_io = ioremap(BCSR5, sizeof(unsigned long));
107 clrbits32(bcsr_io,BCSR5_MII1_EN);
108 clrbits32(bcsr_io,BCSR5_MII1_RST);
109#ifndef CONFIG_FC_ENET_HAS_SCC
110 clrbits32(bcsr_io,BCSR5_MII2_EN);
111 clrbits32(bcsr_io,BCSR5_MII2_RST);
112
113#endif
114 iounmap(bcsr_io);
115 immr_unmap(io_port);
116
117#endif
118}
119
120
121static void init_fec1_ioports(struct fs_platform_info* ptr)
122{
123 cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
124 iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
125
126 /* configure FEC1 pins */
127 setbits16(&io_port->iop_papar, 0xf830);
128 setbits16(&io_port->iop_padir, 0x0830);
129 clrbits16(&io_port->iop_padir, 0xf000);
130
131 setbits32(&cp->cp_pbpar, 0x00001001);
132 clrbits32(&cp->cp_pbdir, 0x00001001);
133
134 setbits16(&io_port->iop_pcpar, 0x000c);
135 clrbits16(&io_port->iop_pcdir, 0x000c);
136
137 setbits32(&cp->cp_pepar, 0x00000003);
138 setbits32(&cp->cp_pedir, 0x00000003);
139 clrbits32(&cp->cp_peso, 0x00000003);
140 clrbits32(&cp->cp_cptr, 0x00000100);
141
142 immr_unmap(io_port);
143 immr_unmap(cp);
144}
145
146
147static void init_fec2_ioports(struct fs_platform_info* ptr)
148{
149 cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm);
150 iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport);
151
152 /* configure FEC2 pins */
153 setbits32(&cp->cp_pepar, 0x0003fffc);
154 setbits32(&cp->cp_pedir, 0x0003fffc);
155 clrbits32(&cp->cp_peso, 0x000087fc);
156 setbits32(&cp->cp_peso, 0x00037800);
157 clrbits32(&cp->cp_cptr, 0x00000080);
158
159 immr_unmap(io_port);
160 immr_unmap(cp);
161}
162
163void init_fec_ioports(struct fs_platform_info *fpi)
164{
165 int fec_no = fs_get_fec_index(fpi->fs_no);
166
167 switch (fec_no) {
168 case 0:
169 init_fec1_ioports(fpi);
170 break;
171 case 1:
172 init_fec2_ioports(fpi);
173 break;
174 default:
175 printk(KERN_ERR "init_fec_ioports: invalid FEC number\n");
176 return;
177 }
178}
179
180static void init_scc3_ioports(struct fs_platform_info* fpi)
181{
182 unsigned *bcsr_io;
183 iop8xx_t *io_port;
184 cpm8xx_t *cp;
185
186 bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE);
187 io_port = (iop8xx_t *)immr_map(im_ioport);
188 cp = (cpm8xx_t *)immr_map(im_cpm);
189
190 if (bcsr_io == NULL) {
191 printk(KERN_CRIT "Could not remap BCSR\n");
192 return;
193 }
194
195 /* Enable the PHY.
196 */
197 clrbits32(bcsr_io+4, BCSR4_ETH10_RST);
198 udelay(1000);
199 setbits32(bcsr_io+4, BCSR4_ETH10_RST);
200 /* Configure port A pins for Txd and Rxd.
201 */
202 setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD);
203 clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD);
204
205 /* Configure port C pins to enable CLSN and RENA.
206 */
207 clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA);
208 clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA);
209 setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA);
210
211 /* Configure port E for TCLK and RCLK.
212 */
213 setbits32(&cp->cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK);
214 clrbits32(&cp->cp_pepar, PE_ENET_TENA);
215 clrbits32(&cp->cp_pedir,
216 PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA);
217 clrbits32(&cp->cp_peso, PE_ENET_TCLK | PE_ENET_RCLK);
218 setbits32(&cp->cp_peso, PE_ENET_TENA);
219
220 /* Configure Serial Interface clock routing.
221 * First, clear all SCC bits to zero, then set the ones we want.
222 */
223 clrbits32(&cp->cp_sicr, SICR_ENET_MASK);
224 setbits32(&cp->cp_sicr, SICR_ENET_CLKRT);
225
226 /* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used.
227 */
228 clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN);
229 /* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode
230 * by H/W setting after reset. SCC ethernet controller support only half duplex.
231 * This discrepancy of modes causes a lot of carrier lost errors.
232 */
233
234 /* In the original SCC enet driver the following code is placed at
235 the end of the initialization */
236 setbits32(&cp->cp_pepar, PE_ENET_TENA);
237 clrbits32(&cp->cp_pedir, PE_ENET_TENA);
238 setbits32(&cp->cp_peso, PE_ENET_TENA);
239
240 setbits32(bcsr_io+4, BCSR1_ETHEN);
241 iounmap(bcsr_io);
242 immr_unmap(io_port);
243 immr_unmap(cp);
244}
245
246void init_scc_ioports(struct fs_platform_info *fpi)
247{
248 int scc_no = fs_get_scc_index(fpi->fs_no);
249
250 switch (scc_no) {
251 case 2:
252 init_scc3_ioports(fpi);
253 break;
254 default:
255 printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
256 return;
257 }
258}
259
260
261
262static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr)
263{
264 unsigned *bcsr_io;
265 cpm8xx_t *cp;
266
267 cp = (cpm8xx_t *)immr_map(im_cpm);
268 setbits32(&cp->cp_pepar, 0x000000c0);
269 clrbits32(&cp->cp_pedir, 0x000000c0);
270 clrbits32(&cp->cp_peso, 0x00000040);
271 setbits32(&cp->cp_peso, 0x00000080);
272 immr_unmap(cp);
273
274 bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
275
276 if (bcsr_io == NULL) {
277 printk(KERN_CRIT "Could not remap BCSR1\n");
278 return;
279 }
280 clrbits32(bcsr_io,BCSR1_RS232EN_1);
281 iounmap(bcsr_io);
282}
283
284static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi)
285{
286 unsigned *bcsr_io;
287 cpm8xx_t *cp;
288
289 cp = (cpm8xx_t *)immr_map(im_cpm);
290 setbits32(&cp->cp_pepar, 0x00000c00);
291 clrbits32(&cp->cp_pedir, 0x00000c00);
292 clrbits32(&cp->cp_peso, 0x00000400);
293 setbits32(&cp->cp_peso, 0x00000800);
294 immr_unmap(cp);
295
296 bcsr_io = ioremap(BCSR1, sizeof(unsigned long));
297
298 if (bcsr_io == NULL) {
299 printk(KERN_CRIT "Could not remap BCSR1\n");
300 return;
301 }
302 clrbits32(bcsr_io,BCSR1_RS232EN_2);
303 iounmap(bcsr_io);
304}
305
306void init_smc_ioports(struct fs_uart_platform_info *data)
307{
308 int smc_no = fs_uart_id_fsid2smc(data->fs_no);
309
310 switch (smc_no) {
311 case 0:
312 init_smc1_uart_ioports(data);
313 data->brg = data->clk_rx;
314 break;
315 case 1:
316 init_smc2_uart_ioports(data);
317 data->brg = data->clk_rx;
318 break;
319 default:
320 printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
321 return;
322 }
323}
324
325int platform_device_skip(char *model, int id)
326{
327#ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3
328 const char *dev = "FEC";
329 int n = 2;
330#else
331 const char *dev = "SCC";
332 int n = 3;
333#endif
334
335 if (!strcmp(model, dev) && n == id)
336 return 1;
337
338 return 0;
339}
340
341static void __init mpc885ads_setup_arch(void)
342{
343 struct device_node *cpu;
344
345 cpu = of_find_node_by_type(NULL, "cpu");
346 if (cpu != 0) {
347 const unsigned int *fp;
348
349 fp = get_property(cpu, "clock-frequency", NULL);
350 if (fp != 0)
351 loops_per_jiffy = *fp / HZ;
352 else
353 loops_per_jiffy = 50000000 / HZ;
354 of_node_put(cpu);
355 }
356
357 cpm_reset();
358
359 mpc885ads_board_setup();
360
361 ROOT_DEV = Root_NFS;
362}
363
364static int __init mpc885ads_probe(void)
365{
366 char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
367 "model", NULL);
368 if (model == NULL)
369 return 0;
370 if (strcmp(model, "MPC885ADS"))
371 return 0;
372
373 return 1;
374}
375
376define_machine(mpc885_ads) {
377 .name = "MPC885 ADS",
378 .probe = mpc885ads_probe,
379 .setup_arch = mpc885ads_setup_arch,
380 .init_IRQ = m8xx_pic_init,
381 .show_cpuinfo = mpc8xx_show_cpuinfo,
382 .get_irq = mpc8xx_get_irq,
383 .restart = mpc8xx_restart,
384 .calibrate_decr = mpc8xx_calibrate_decr,
385 .set_rtc_time = mpc8xx_set_rtc_time,
386 .get_rtc_time = mpc8xx_get_rtc_time,
387};
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile
index 507d1b98f270..65e612315b9b 100644
--- a/arch/powerpc/platforms/Makefile
+++ b/arch/powerpc/platforms/Makefile
@@ -8,6 +8,8 @@ endif
8obj-$(CONFIG_PPC_MPC52xx) += 52xx/ 8obj-$(CONFIG_PPC_MPC52xx) += 52xx/
9obj-$(CONFIG_PPC_CHRP) += chrp/ 9obj-$(CONFIG_PPC_CHRP) += chrp/
10obj-$(CONFIG_4xx) += 4xx/ 10obj-$(CONFIG_4xx) += 4xx/
11obj-$(CONFIG_PPC_8xx) += 8xx/
12obj-$(CONFIG_PPC_82xx) += 82xx/
11obj-$(CONFIG_PPC_83xx) += 83xx/ 13obj-$(CONFIG_PPC_83xx) += 83xx/
12obj-$(CONFIG_PPC_85xx) += 85xx/ 14obj-$(CONFIG_PPC_85xx) += 85xx/
13obj-$(CONFIG_PPC_86xx) += 86xx/ 15obj-$(CONFIG_PPC_86xx) += 86xx/
@@ -17,4 +19,5 @@ obj-$(CONFIG_PPC_MAPLE) += maple/
17obj-$(CONFIG_PPC_PASEMI) += pasemi/ 19obj-$(CONFIG_PPC_PASEMI) += pasemi/
18obj-$(CONFIG_PPC_CELL) += cell/ 20obj-$(CONFIG_PPC_CELL) += cell/
19obj-$(CONFIG_PPC_PS3) += ps3/ 21obj-$(CONFIG_PPC_PS3) += ps3/
22obj-$(CONFIG_PPC_CELLEB) += celleb/
20obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ 23obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index f90e8337796c..869af89df6ff 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -14,7 +14,12 @@ endif
14spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o 14spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
15spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o 15spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o
16 16
17spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o
18spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o
19
17obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ 20obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \
18 spu_coredump.o \ 21 spu_coredump.o \
19 $(spufs-modular-m) \ 22 $(spufs-modular-m) \
20 $(spu-priv1-y) spufs/ 23 $(spu-priv1-y) \
24 $(spu-manage-y) \
25 spufs/
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index bd7bffc3ddd0..c43999a10deb 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -170,9 +170,11 @@ int
170spu_irq_class_0_bottom(struct spu *spu) 170spu_irq_class_0_bottom(struct spu *spu)
171{ 171{
172 unsigned long stat, mask; 172 unsigned long stat, mask;
173 unsigned long flags;
173 174
174 spu->class_0_pending = 0; 175 spu->class_0_pending = 0;
175 176
177 spin_lock_irqsave(&spu->register_lock, flags);
176 mask = spu_int_mask_get(spu, 0); 178 mask = spu_int_mask_get(spu, 0);
177 stat = spu_int_stat_get(spu, 0); 179 stat = spu_int_stat_get(spu, 0);
178 180
@@ -188,6 +190,7 @@ spu_irq_class_0_bottom(struct spu *spu)
188 __spu_trap_error(spu); 190 __spu_trap_error(spu);
189 191
190 spu_int_stat_clear(spu, 0, stat); 192 spu_int_stat_clear(spu, 0, stat);
193 spin_unlock_irqrestore(&spu->register_lock, flags);
191 194
192 return (stat & 0x7) ? -EIO : 0; 195 return (stat & 0x7) ? -EIO : 0;
193} 196}
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c
new file mode 100644
index 000000000000..d8b39fe39cdd
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_manage.c
@@ -0,0 +1,420 @@
1/*
2 * spu management operations for of based platforms
3 *
4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
5 * Copyright 2006 Sony Corp.
6 * (C) Copyright 2007 TOSHIBA CORPORATION
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#include <linux/interrupt.h>
23#include <linux/list.h>
24#include <linux/module.h>
25#include <linux/ptrace.h>
26#include <linux/slab.h>
27#include <linux/wait.h>
28#include <linux/mm.h>
29#include <linux/io.h>
30#include <linux/mutex.h>
31#include <linux/device.h>
32
33#include <asm/spu.h>
34#include <asm/spu_priv1.h>
35#include <asm/firmware.h>
36#include <asm/prom.h>
37
38#include "interrupt.h"
39
40struct device_node *spu_devnode(struct spu *spu)
41{
42 return spu->devnode;
43}
44
45EXPORT_SYMBOL_GPL(spu_devnode);
46
47static u64 __init find_spu_unit_number(struct device_node *spe)
48{
49 const unsigned int *prop;
50 int proplen;
51 prop = get_property(spe, "unit-id", &proplen);
52 if (proplen == 4)
53 return (u64)*prop;
54
55 prop = get_property(spe, "reg", &proplen);
56 if (proplen == 4)
57 return (u64)*prop;
58
59 return 0;
60}
61
62static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
63 const char *prop)
64{
65 const struct address_prop {
66 unsigned long address;
67 unsigned int len;
68 } __attribute__((packed)) *p;
69 int proplen;
70
71 unsigned long start_pfn, nr_pages;
72 struct pglist_data *pgdata;
73 struct zone *zone;
74 int ret;
75
76 p = get_property(spe, prop, &proplen);
77 WARN_ON(proplen != sizeof (*p));
78
79 start_pfn = p->address >> PAGE_SHIFT;
80 nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
81
82 pgdata = NODE_DATA(spu->node);
83 zone = pgdata->node_zones;
84
85 ret = __add_pages(zone, start_pfn, nr_pages);
86
87 return ret;
88}
89
90static void __iomem * __init map_spe_prop(struct spu *spu,
91 struct device_node *n, const char *name)
92{
93 const struct address_prop {
94 unsigned long address;
95 unsigned int len;
96 } __attribute__((packed)) *prop;
97
98 const void *p;
99 int proplen;
100 void __iomem *ret = NULL;
101 int err = 0;
102
103 p = get_property(n, name, &proplen);
104 if (proplen != sizeof (struct address_prop))
105 return NULL;
106
107 prop = p;
108
109 err = cell_spuprop_present(spu, n, name);
110 if (err && (err != -EEXIST))
111 goto out;
112
113 ret = ioremap(prop->address, prop->len);
114
115 out:
116 return ret;
117}
118
119static void spu_unmap(struct spu *spu)
120{
121 if (!firmware_has_feature(FW_FEATURE_LPAR))
122 iounmap(spu->priv1);
123 iounmap(spu->priv2);
124 iounmap(spu->problem);
125 iounmap((__force u8 __iomem *)spu->local_store);
126}
127
128static int __init spu_map_interrupts_old(struct spu *spu,
129 struct device_node *np)
130{
131 unsigned int isrc;
132 const u32 *tmp;
133 int nid;
134
135 /* Get the interrupt source unit from the device-tree */
136 tmp = get_property(np, "isrc", NULL);
137 if (!tmp)
138 return -ENODEV;
139 isrc = tmp[0];
140
141 tmp = get_property(np->parent->parent, "node-id", NULL);
142 if (!tmp) {
143 printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__);
144 nid = spu->node;
145 } else
146 nid = tmp[0];
147
148 /* Add the node number */
149 isrc |= nid << IIC_IRQ_NODE_SHIFT;
150
151 /* Now map interrupts of all 3 classes */
152 spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
153 spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
154 spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
155
156 /* Right now, we only fail if class 2 failed */
157 return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
158}
159
160static int __init spu_map_device_old(struct spu *spu)
161{
162 struct device_node *node = spu->devnode;
163 const char *prop;
164 int ret;
165
166 ret = -ENODEV;
167 spu->name = get_property(node, "name", NULL);
168 if (!spu->name)
169 goto out;
170
171 prop = get_property(node, "local-store", NULL);
172 if (!prop)
173 goto out;
174 spu->local_store_phys = *(unsigned long *)prop;
175
176 /* we use local store as ram, not io memory */
177 spu->local_store = (void __force *)
178 map_spe_prop(spu, node, "local-store");
179 if (!spu->local_store)
180 goto out;
181
182 prop = get_property(node, "problem", NULL);
183 if (!prop)
184 goto out_unmap;
185 spu->problem_phys = *(unsigned long *)prop;
186
187 spu->problem = map_spe_prop(spu, node, "problem");
188 if (!spu->problem)
189 goto out_unmap;
190
191 spu->priv2 = map_spe_prop(spu, node, "priv2");
192 if (!spu->priv2)
193 goto out_unmap;
194
195 if (!firmware_has_feature(FW_FEATURE_LPAR)) {
196 spu->priv1 = map_spe_prop(spu, node, "priv1");
197 if (!spu->priv1)
198 goto out_unmap;
199 }
200
201 ret = 0;
202 goto out;
203
204out_unmap:
205 spu_unmap(spu);
206out:
207 return ret;
208}
209
210static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
211{
212 struct of_irq oirq;
213 int ret;
214 int i;
215
216 for (i=0; i < 3; i++) {
217 ret = of_irq_map_one(np, i, &oirq);
218 if (ret) {
219 pr_debug("spu_new: failed to get irq %d\n", i);
220 goto err;
221 }
222 ret = -EINVAL;
223 pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0],
224 oirq.controller->full_name);
225 spu->irqs[i] = irq_create_of_mapping(oirq.controller,
226 oirq.specifier, oirq.size);
227 if (spu->irqs[i] == NO_IRQ) {
228 pr_debug("spu_new: failed to map it !\n");
229 goto err;
230 }
231 }
232 return 0;
233
234err:
235 pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier,
236 spu->name);
237 for (; i >= 0; i--) {
238 if (spu->irqs[i] != NO_IRQ)
239 irq_dispose_mapping(spu->irqs[i]);
240 }
241 return ret;
242}
243
244static int spu_map_resource(struct spu *spu, int nr,
245 void __iomem** virt, unsigned long *phys)
246{
247 struct device_node *np = spu->devnode;
248 unsigned long start_pfn, nr_pages;
249 struct pglist_data *pgdata;
250 struct zone *zone;
251 struct resource resource = { };
252 unsigned long len;
253 int ret;
254
255 ret = of_address_to_resource(np, nr, &resource);
256 if (ret)
257 goto out;
258
259 if (phys)
260 *phys = resource.start;
261 len = resource.end - resource.start + 1;
262 *virt = ioremap(resource.start, len);
263 if (!*virt)
264 ret = -EINVAL;
265
266 start_pfn = resource.start >> PAGE_SHIFT;
267 nr_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
268
269 pgdata = NODE_DATA(spu->node);
270 zone = pgdata->node_zones;
271
272 ret = __add_pages(zone, start_pfn, nr_pages);
273
274out:
275 return ret;
276}
277
278static int __init spu_map_device(struct spu *spu)
279{
280 struct device_node *np = spu->devnode;
281 int ret = -ENODEV;
282
283 spu->name = get_property(np, "name", NULL);
284 if (!spu->name)
285 goto out;
286
287 ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store,
288 &spu->local_store_phys);
289 if (ret) {
290 pr_debug("spu_new: failed to map %s resource 0\n",
291 np->full_name);
292 goto out;
293 }
294 ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem,
295 &spu->problem_phys);
296 if (ret) {
297 pr_debug("spu_new: failed to map %s resource 1\n",
298 np->full_name);
299 goto out_unmap;
300 }
301 ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL);
302 if (ret) {
303 pr_debug("spu_new: failed to map %s resource 2\n",
304 np->full_name);
305 goto out_unmap;
306 }
307 if (!firmware_has_feature(FW_FEATURE_LPAR))
308 ret = spu_map_resource(spu, 3,
309 (void __iomem**)&spu->priv1, NULL);
310 if (ret) {
311 pr_debug("spu_new: failed to map %s resource 3\n",
312 np->full_name);
313 goto out_unmap;
314 }
315 pr_debug("spu_new: %s maps:\n", np->full_name);
316 pr_debug(" local store : 0x%016lx -> 0x%p\n",
317 spu->local_store_phys, spu->local_store);
318 pr_debug(" problem state : 0x%016lx -> 0x%p\n",
319 spu->problem_phys, spu->problem);
320 pr_debug(" priv2 : 0x%p\n", spu->priv2);
321 pr_debug(" priv1 : 0x%p\n", spu->priv1);
322
323 return 0;
324
325out_unmap:
326 spu_unmap(spu);
327out:
328 pr_debug("failed to map spe %s: %d\n", spu->name, ret);
329 return ret;
330}
331
332static int __init of_enumerate_spus(int (*fn)(void *data))
333{
334 int ret;
335 struct device_node *node;
336
337 ret = -ENODEV;
338 for (node = of_find_node_by_type(NULL, "spe");
339 node; node = of_find_node_by_type(node, "spe")) {
340 ret = fn(node);
341 if (ret) {
342 printk(KERN_WARNING "%s: Error initializing %s\n",
343 __FUNCTION__, node->name);
344 break;
345 }
346 }
347 return ret;
348}
349
350static int __init of_create_spu(struct spu *spu, void *data)
351{
352 int ret;
353 struct device_node *spe = (struct device_node *)data;
354 static int legacy_map = 0, legacy_irq = 0;
355
356 spu->devnode = of_node_get(spe);
357 spu->spe_id = find_spu_unit_number(spe);
358
359 spu->node = of_node_to_nid(spe);
360 if (spu->node >= MAX_NUMNODES) {
361 printk(KERN_WARNING "SPE %s on node %d ignored,"
362 " node number too big\n", spe->full_name, spu->node);
363 printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
364 ret = -ENODEV;
365 goto out;
366 }
367
368 ret = spu_map_device(spu);
369 if (ret) {
370 if (!legacy_map) {
371 legacy_map = 1;
372 printk(KERN_WARNING "%s: Legacy device tree found, "
373 "trying to map old style\n", __FUNCTION__);
374 }
375 ret = spu_map_device_old(spu);
376 if (ret) {
377 printk(KERN_ERR "Unable to map %s\n",
378 spu->name);
379 goto out;
380 }
381 }
382
383 ret = spu_map_interrupts(spu, spe);
384 if (ret) {
385 if (!legacy_irq) {
386 legacy_irq = 1;
387 printk(KERN_WARNING "%s: Legacy device tree found, "
388 "trying old style irq\n", __FUNCTION__);
389 }
390 ret = spu_map_interrupts_old(spu, spe);
391 if (ret) {
392 printk(KERN_ERR "%s: could not map interrupts",
393 spu->name);
394 goto out_unmap;
395 }
396 }
397
398 pr_debug("Using SPE %s %p %p %p %p %d\n", spu->name,
399 spu->local_store, spu->problem, spu->priv1,
400 spu->priv2, spu->number);
401 goto out;
402
403out_unmap:
404 spu_unmap(spu);
405out:
406 return ret;
407}
408
409static int of_destroy_spu(struct spu *spu)
410{
411 spu_unmap(spu);
412 of_node_put(spu->devnode);
413 return 0;
414}
415
416const struct spu_management_ops spu_management_of_ops = {
417 .enumerate_spus = of_enumerate_spus,
418 .create_spu = of_create_spu,
419 .destroy_spu = of_destroy_spu,
420};
diff --git a/arch/powerpc/platforms/cell/spu_priv1_mmio.c b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
index 910a926b61a2..67fa7247b80a 100644
--- a/arch/powerpc/platforms/cell/spu_priv1_mmio.c
+++ b/arch/powerpc/platforms/cell/spu_priv1_mmio.c
@@ -37,490 +37,112 @@
37#include "interrupt.h" 37#include "interrupt.h"
38#include "spu_priv1_mmio.h" 38#include "spu_priv1_mmio.h"
39 39
40static DEFINE_MUTEX(add_spumem_mutex);
41
42struct spu_pdata {
43 struct device_node *devnode;
44 struct spu_priv1 __iomem *priv1;
45};
46
47static struct spu_pdata *spu_get_pdata(struct spu *spu)
48{
49 BUG_ON(!spu->pdata);
50 return spu->pdata;
51}
52
53struct device_node *spu_devnode(struct spu *spu)
54{
55 return spu_get_pdata(spu)->devnode;
56}
57
58EXPORT_SYMBOL_GPL(spu_devnode);
59
60static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe,
61 const char *prop)
62{
63 const struct address_prop {
64 unsigned long address;
65 unsigned int len;
66 } __attribute__((packed)) *p;
67 int proplen;
68
69 unsigned long start_pfn, nr_pages;
70 struct pglist_data *pgdata;
71 struct zone *zone;
72 int ret;
73
74 p = get_property(spe, prop, &proplen);
75 WARN_ON(proplen != sizeof (*p));
76
77 start_pfn = p->address >> PAGE_SHIFT;
78 nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT;
79
80 pgdata = NODE_DATA(spu->node);
81 zone = pgdata->node_zones;
82
83 /* XXX rethink locking here */
84 mutex_lock(&add_spumem_mutex);
85 ret = __add_pages(zone, start_pfn, nr_pages);
86 mutex_unlock(&add_spumem_mutex);
87
88 return ret;
89}
90
91static void __iomem * __init map_spe_prop(struct spu *spu,
92 struct device_node *n, const char *name)
93{
94 const struct address_prop {
95 unsigned long address;
96 unsigned int len;
97 } __attribute__((packed)) *prop;
98
99 const void *p;
100 int proplen;
101 void __iomem *ret = NULL;
102 int err = 0;
103
104 p = get_property(n, name, &proplen);
105 if (proplen != sizeof (struct address_prop))
106 return NULL;
107
108 prop = p;
109
110 err = cell_spuprop_present(spu, n, name);
111 if (err && (err != -EEXIST))
112 goto out;
113
114 ret = ioremap(prop->address, prop->len);
115
116 out:
117 return ret;
118}
119
120static void spu_unmap(struct spu *spu)
121{
122 iounmap(spu->priv2);
123 iounmap(spu_get_pdata(spu)->priv1);
124 iounmap(spu->problem);
125 iounmap((__force u8 __iomem *)spu->local_store);
126}
127
128static int __init spu_map_interrupts_old(struct spu *spu,
129 struct device_node *np)
130{
131 unsigned int isrc;
132 const u32 *tmp;
133 int nid;
134
135 /* Get the interrupt source unit from the device-tree */
136 tmp = get_property(np, "isrc", NULL);
137 if (!tmp)
138 return -ENODEV;
139 isrc = tmp[0];
140
141 tmp = get_property(np->parent->parent, "node-id", NULL);
142 if (!tmp) {
143 printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__);
144 nid = spu->node;
145 } else
146 nid = tmp[0];
147
148 /* Add the node number */
149 isrc |= nid << IIC_IRQ_NODE_SHIFT;
150
151 /* Now map interrupts of all 3 classes */
152 spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
153 spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
154 spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
155
156 /* Right now, we only fail if class 2 failed */
157 return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
158}
159
160static int __init spu_map_device_old(struct spu *spu, struct device_node *node)
161{
162 const char *prop;
163 int ret;
164
165 ret = -ENODEV;
166 spu->name = get_property(node, "name", NULL);
167 if (!spu->name)
168 goto out;
169
170 prop = get_property(node, "local-store", NULL);
171 if (!prop)
172 goto out;
173 spu->local_store_phys = *(unsigned long *)prop;
174
175 /* we use local store as ram, not io memory */
176 spu->local_store = (void __force *)
177 map_spe_prop(spu, node, "local-store");
178 if (!spu->local_store)
179 goto out;
180
181 prop = get_property(node, "problem", NULL);
182 if (!prop)
183 goto out_unmap;
184 spu->problem_phys = *(unsigned long *)prop;
185
186 spu->problem= map_spe_prop(spu, node, "problem");
187 if (!spu->problem)
188 goto out_unmap;
189
190 spu_get_pdata(spu)->priv1= map_spe_prop(spu, node, "priv1");
191
192 spu->priv2= map_spe_prop(spu, node, "priv2");
193 if (!spu->priv2)
194 goto out_unmap;
195 ret = 0;
196 goto out;
197
198out_unmap:
199 spu_unmap(spu);
200out:
201 return ret;
202}
203
204static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
205{
206 struct of_irq oirq;
207 int ret;
208 int i;
209
210 for (i=0; i < 3; i++) {
211 ret = of_irq_map_one(np, i, &oirq);
212 if (ret) {
213 pr_debug("spu_new: failed to get irq %d\n", i);
214 goto err;
215 }
216 ret = -EINVAL;
217 pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0],
218 oirq.controller->full_name);
219 spu->irqs[i] = irq_create_of_mapping(oirq.controller,
220 oirq.specifier, oirq.size);
221 if (spu->irqs[i] == NO_IRQ) {
222 pr_debug("spu_new: failed to map it !\n");
223 goto err;
224 }
225 }
226 return 0;
227
228err:
229 pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier,
230 spu->name);
231 for (; i >= 0; i--) {
232 if (spu->irqs[i] != NO_IRQ)
233 irq_dispose_mapping(spu->irqs[i]);
234 }
235 return ret;
236}
237
238static int spu_map_resource(struct spu *spu, int nr,
239 void __iomem** virt, unsigned long *phys)
240{
241 struct device_node *np = spu_get_pdata(spu)->devnode;
242 unsigned long start_pfn, nr_pages;
243 struct pglist_data *pgdata;
244 struct zone *zone;
245 struct resource resource = { };
246 unsigned long len;
247 int ret;
248
249 ret = of_address_to_resource(np, nr, &resource);
250 if (ret)
251 goto out;
252
253 if (phys)
254 *phys = resource.start;
255 len = resource.end - resource.start + 1;
256 *virt = ioremap(resource.start, len);
257 if (!*virt)
258 ret = -EINVAL;
259
260 start_pfn = resource.start >> PAGE_SHIFT;
261 nr_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT;
262
263 pgdata = NODE_DATA(spu->node);
264 zone = pgdata->node_zones;
265
266 /* XXX rethink locking here */
267 mutex_lock(&add_spumem_mutex);
268 ret = __add_pages(zone, start_pfn, nr_pages);
269 mutex_unlock(&add_spumem_mutex);
270
271out:
272 return ret;
273}
274
275static int __init spu_map_device(struct spu *spu)
276{
277 struct device_node *np = spu_get_pdata(spu)->devnode;
278 int ret = -ENODEV;
279
280 spu->name = get_property(np, "name", NULL);
281 if (!spu->name)
282 goto out;
283
284 ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store,
285 &spu->local_store_phys);
286 if (ret) {
287 pr_debug("spu_new: failed to map %s resource 0\n",
288 np->full_name);
289 goto out;
290 }
291 ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem,
292 &spu->problem_phys);
293 if (ret) {
294 pr_debug("spu_new: failed to map %s resource 1\n",
295 np->full_name);
296 goto out_unmap;
297 }
298 ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL);
299 if (ret) {
300 pr_debug("spu_new: failed to map %s resource 2\n",
301 np->full_name);
302 goto out_unmap;
303 }
304 if (!firmware_has_feature(FW_FEATURE_LPAR))
305 ret = spu_map_resource(spu, 3,
306 (void __iomem**)&spu_get_pdata(spu)->priv1, NULL);
307 if (ret) {
308 pr_debug("spu_new: failed to map %s resource 3\n",
309 np->full_name);
310 goto out_unmap;
311 }
312 pr_debug("spu_new: %s maps:\n", np->full_name);
313 pr_debug(" local store : 0x%016lx -> 0x%p\n",
314 spu->local_store_phys, spu->local_store);
315 pr_debug(" problem state : 0x%016lx -> 0x%p\n",
316 spu->problem_phys, spu->problem);
317 pr_debug(" priv2 : 0x%p\n", spu->priv2);
318 pr_debug(" priv1 : 0x%p\n",
319 spu_get_pdata(spu)->priv1);
320
321 return 0;
322
323out_unmap:
324 spu_unmap(spu);
325out:
326 pr_debug("failed to map spe %s: %d\n", spu->name, ret);
327 return ret;
328}
329
330static int __init of_enumerate_spus(int (*fn)(void *data))
331{
332 int ret;
333 struct device_node *node;
334
335 ret = -ENODEV;
336 for (node = of_find_node_by_type(NULL, "spe");
337 node; node = of_find_node_by_type(node, "spe")) {
338 ret = fn(node);
339 if (ret) {
340 printk(KERN_WARNING "%s: Error initializing %s\n",
341 __FUNCTION__, node->name);
342 break;
343 }
344 }
345 return ret;
346}
347
348static int __init of_create_spu(struct spu *spu, void *data)
349{
350 int ret;
351 struct device_node *spe = (struct device_node *)data;
352
353 spu->pdata = kzalloc(sizeof(struct spu_pdata),
354 GFP_KERNEL);
355 if (!spu->pdata) {
356 ret = -ENOMEM;
357 goto out;
358 }
359 spu_get_pdata(spu)->devnode = of_node_get(spe);
360
361 spu->node = of_node_to_nid(spe);
362 if (spu->node >= MAX_NUMNODES) {
363 printk(KERN_WARNING "SPE %s on node %d ignored,"
364 " node number too big\n", spe->full_name, spu->node);
365 printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
366 ret = -ENODEV;
367 goto out_free;
368 }
369
370 ret = spu_map_device(spu);
371 /* try old method */
372 if (ret)
373 ret = spu_map_device_old(spu, spe);
374 if (ret)
375 goto out_free;
376
377 ret = spu_map_interrupts(spu, spe);
378 if (ret)
379 ret = spu_map_interrupts_old(spu, spe);
380 if (ret)
381 goto out_unmap;
382
383 pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n", spu->name,
384 spu->local_store, spu->problem, spu_get_pdata(spu)->priv1,
385 spu->priv2, spu->number);
386 goto out;
387
388out_unmap:
389 spu_unmap(spu);
390out_free:
391 kfree(spu->pdata);
392 spu->pdata = NULL;
393out:
394 return ret;
395}
396
397static int of_destroy_spu(struct spu *spu)
398{
399 spu_unmap(spu);
400 of_node_put(spu_get_pdata(spu)->devnode);
401 kfree(spu->pdata);
402 spu->pdata = NULL;
403 return 0;
404}
405
406const struct spu_management_ops spu_management_of_ops = {
407 .enumerate_spus = of_enumerate_spus,
408 .create_spu = of_create_spu,
409 .destroy_spu = of_destroy_spu,
410};
411
412static void int_mask_and(struct spu *spu, int class, u64 mask) 40static void int_mask_and(struct spu *spu, int class, u64 mask)
413{ 41{
414 u64 old_mask; 42 u64 old_mask;
415 43
416 old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]); 44 old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
417 out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], 45 out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask);
418 old_mask & mask);
419} 46}
420 47
421static void int_mask_or(struct spu *spu, int class, u64 mask) 48static void int_mask_or(struct spu *spu, int class, u64 mask)
422{ 49{
423 u64 old_mask; 50 u64 old_mask;
424 51
425 old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]); 52 old_mask = in_be64(&spu->priv1->int_mask_RW[class]);
426 out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], 53 out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask);
427 old_mask | mask);
428} 54}
429 55
430static void int_mask_set(struct spu *spu, int class, u64 mask) 56static void int_mask_set(struct spu *spu, int class, u64 mask)
431{ 57{
432 out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], mask); 58 out_be64(&spu->priv1->int_mask_RW[class], mask);
433} 59}
434 60
435static u64 int_mask_get(struct spu *spu, int class) 61static u64 int_mask_get(struct spu *spu, int class)
436{ 62{
437 return in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]); 63 return in_be64(&spu->priv1->int_mask_RW[class]);
438} 64}
439 65
440static void int_stat_clear(struct spu *spu, int class, u64 stat) 66static void int_stat_clear(struct spu *spu, int class, u64 stat)
441{ 67{
442 out_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class], stat); 68 out_be64(&spu->priv1->int_stat_RW[class], stat);
443} 69}
444 70
445static u64 int_stat_get(struct spu *spu, int class) 71static u64 int_stat_get(struct spu *spu, int class)
446{ 72{
447 return in_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class]); 73 return in_be64(&spu->priv1->int_stat_RW[class]);
448} 74}
449 75
450static void cpu_affinity_set(struct spu *spu, int cpu) 76static void cpu_affinity_set(struct spu *spu, int cpu)
451{ 77{
452 u64 target = iic_get_target_id(cpu); 78 u64 target = iic_get_target_id(cpu);
453 u64 route = target << 48 | target << 32 | target << 16; 79 u64 route = target << 48 | target << 32 | target << 16;
454 out_be64(&spu_get_pdata(spu)->priv1->int_route_RW, route); 80 out_be64(&spu->priv1->int_route_RW, route);
455} 81}
456 82
457static u64 mfc_dar_get(struct spu *spu) 83static u64 mfc_dar_get(struct spu *spu)
458{ 84{
459 return in_be64(&spu_get_pdata(spu)->priv1->mfc_dar_RW); 85 return in_be64(&spu->priv1->mfc_dar_RW);
460} 86}
461 87
462static u64 mfc_dsisr_get(struct spu *spu) 88static u64 mfc_dsisr_get(struct spu *spu)
463{ 89{
464 return in_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW); 90 return in_be64(&spu->priv1->mfc_dsisr_RW);
465} 91}
466 92
467static void mfc_dsisr_set(struct spu *spu, u64 dsisr) 93static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
468{ 94{
469 out_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW, dsisr); 95 out_be64(&spu->priv1->mfc_dsisr_RW, dsisr);
470} 96}
471 97
472static void mfc_sdr_setup(struct spu *spu) 98static void mfc_sdr_setup(struct spu *spu)
473{ 99{
474 out_be64(&spu_get_pdata(spu)->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); 100 out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
475} 101}
476 102
477static void mfc_sr1_set(struct spu *spu, u64 sr1) 103static void mfc_sr1_set(struct spu *spu, u64 sr1)
478{ 104{
479 out_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW, sr1); 105 out_be64(&spu->priv1->mfc_sr1_RW, sr1);
480} 106}
481 107
482static u64 mfc_sr1_get(struct spu *spu) 108static u64 mfc_sr1_get(struct spu *spu)
483{ 109{
484 return in_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW); 110 return in_be64(&spu->priv1->mfc_sr1_RW);
485} 111}
486 112
487static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id) 113static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
488{ 114{
489 out_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW, tclass_id); 115 out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id);
490} 116}
491 117
492static u64 mfc_tclass_id_get(struct spu *spu) 118static u64 mfc_tclass_id_get(struct spu *spu)
493{ 119{
494 return in_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW); 120 return in_be64(&spu->priv1->mfc_tclass_id_RW);
495} 121}
496 122
497static void tlb_invalidate(struct spu *spu) 123static void tlb_invalidate(struct spu *spu)
498{ 124{
499 out_be64(&spu_get_pdata(spu)->priv1->tlb_invalidate_entry_W, 0ul); 125 out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul);
500} 126}
501 127
502static void resource_allocation_groupID_set(struct spu *spu, u64 id) 128static void resource_allocation_groupID_set(struct spu *spu, u64 id)
503{ 129{
504 out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW, 130 out_be64(&spu->priv1->resource_allocation_groupID_RW, id);
505 id);
506} 131}
507 132
508static u64 resource_allocation_groupID_get(struct spu *spu) 133static u64 resource_allocation_groupID_get(struct spu *spu)
509{ 134{
510 return in_be64( 135 return in_be64(&spu->priv1->resource_allocation_groupID_RW);
511 &spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW);
512} 136}
513 137
514static void resource_allocation_enable_set(struct spu *spu, u64 enable) 138static void resource_allocation_enable_set(struct spu *spu, u64 enable)
515{ 139{
516 out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_enable_RW, 140 out_be64(&spu->priv1->resource_allocation_enable_RW, enable);
517 enable);
518} 141}
519 142
520static u64 resource_allocation_enable_get(struct spu *spu) 143static u64 resource_allocation_enable_get(struct spu *spu)
521{ 144{
522 return in_be64( 145 return in_be64(&spu->priv1->resource_allocation_enable_RW);
523 &spu_get_pdata(spu)->priv1->resource_allocation_enable_RW);
524} 146}
525 147
526const struct spu_priv1_ops spu_priv1_mmio_ops = 148const struct spu_priv1_ops spu_priv1_mmio_ops =
diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile
new file mode 100644
index 000000000000..3baf658ac543
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/Makefile
@@ -0,0 +1,9 @@
1obj-y += interrupt.o iommu.o setup.o \
2 htab.o beat.o pci.o \
3 scc_epci.o hvCall.o
4
5obj-$(CONFIG_SMP) += smp.o
6obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o
7obj-$(CONFIG_USB) += scc_uhc.o
8obj-$(CONFIG_HAS_TXX9_SERIAL) += scc_sio.o
9obj-$(CONFIG_SPU_BASE) += spu_priv1.o
diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/celleb/beat.c
new file mode 100644
index 000000000000..99341ce8a697
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat.c
@@ -0,0 +1,163 @@
1/*
2 * Simple routines for Celleb/Beat
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <linux/module.h>
22#include <linux/init.h>
23#include <linux/err.h>
24#include <linux/rtc.h>
25
26#include <asm/hvconsole.h>
27#include <asm/time.h>
28
29#include "beat_wrapper.h"
30#include "beat.h"
31
32void beat_restart(char *cmd)
33{
34 beat_shutdown_logical_partition(1);
35}
36
37void beat_power_off(void)
38{
39 beat_shutdown_logical_partition(0);
40}
41
42u64 beat_halt_code = 0x1000000000000000UL;
43
44void beat_halt(void)
45{
46 beat_shutdown_logical_partition(beat_halt_code);
47}
48
49int beat_set_rtc_time(struct rtc_time *rtc_time)
50{
51 u64 tim;
52 tim = mktime(rtc_time->tm_year+1900,
53 rtc_time->tm_mon+1, rtc_time->tm_mday,
54 rtc_time->tm_hour, rtc_time->tm_min, rtc_time->tm_sec);
55 if (beat_rtc_write(tim))
56 return -1;
57 return 0;
58}
59
60void beat_get_rtc_time(struct rtc_time *rtc_time)
61{
62 u64 tim;
63
64 if (beat_rtc_read(&tim))
65 tim = 0;
66 to_tm(tim, rtc_time);
67 rtc_time->tm_year -= 1900;
68 rtc_time->tm_mon -= 1;
69}
70
71#define BEAT_NVRAM_SIZE 4096
72
73ssize_t beat_nvram_read(char *buf, size_t count, loff_t *index)
74{
75 unsigned int i;
76 unsigned long len;
77 char *p = buf;
78
79 if (*index >= BEAT_NVRAM_SIZE)
80 return -ENODEV;
81 i = *index;
82 if (i + count > BEAT_NVRAM_SIZE)
83 count = BEAT_NVRAM_SIZE - i;
84
85 for (; count != 0; count -= len) {
86 len = count;
87 if (len > BEAT_NVRW_CNT)
88 len = BEAT_NVRW_CNT;
89 if (beat_eeprom_read(i, len, p)) {
90 return -EIO;
91 }
92
93 p += len;
94 i += len;
95 }
96 *index = i;
97 return p - buf;
98}
99
100ssize_t beat_nvram_write(char *buf, size_t count, loff_t *index)
101{
102 unsigned int i;
103 unsigned long len;
104 char *p = buf;
105
106 if (*index >= BEAT_NVRAM_SIZE)
107 return -ENODEV;
108 i = *index;
109 if (i + count > BEAT_NVRAM_SIZE)
110 count = BEAT_NVRAM_SIZE - i;
111
112 for (; count != 0; count -= len) {
113 len = count;
114 if (len > BEAT_NVRW_CNT)
115 len = BEAT_NVRW_CNT;
116 if (beat_eeprom_write(i, len, p)) {
117 return -EIO;
118 }
119
120 p += len;
121 i += len;
122 }
123 *index = i;
124 return p - buf;
125}
126
127ssize_t beat_nvram_get_size(void)
128{
129 return BEAT_NVRAM_SIZE;
130}
131
132int beat_set_xdabr(unsigned long dabr)
133{
134 if (beat_set_dabr(dabr, DABRX_KERNEL | DABRX_USER))
135 return -1;
136 return 0;
137}
138
139int64_t beat_get_term_char(u64 vterm, u64 *len, u64 *t1, u64 *t2)
140{
141 u64 db[2];
142 s64 ret;
143
144 ret = beat_get_characters_from_console(vterm, len, (u8*)db);
145 if (ret == 0) {
146 *t1 = db[0];
147 *t2 = db[1];
148 }
149 return ret;
150}
151
152int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2)
153{
154 u64 db[2];
155
156 db[0] = t1;
157 db[1] = t2;
158 return beat_put_characters_to_console(vterm, len, (u8*)db);
159}
160
161EXPORT_SYMBOL(beat_get_term_char);
162EXPORT_SYMBOL(beat_put_term_char);
163EXPORT_SYMBOL(beat_halt_code);
diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/celleb/beat.h
new file mode 100644
index 000000000000..2b16bf3bee89
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat.h
@@ -0,0 +1,40 @@
1/*
2 * Guest OS Interfaces.
3 *
4 * (C) Copyright 2006 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#ifndef _CELLEB_BEAT_H
22#define _CELLEB_BEAT_H
23
24#define DABRX_KERNEL (1UL<<1)
25#define DABRX_USER (1UL<<0)
26
27int64_t beat_get_term_char(uint64_t,uint64_t*,uint64_t*,uint64_t*);
28int64_t beat_put_term_char(uint64_t,uint64_t,uint64_t,uint64_t);
29int64_t beat_repository_encode(int, const char *, uint64_t[4]);
30void beat_restart(char *);
31void beat_power_off(void);
32void beat_halt(void);
33int beat_set_rtc_time(struct rtc_time *);
34void beat_get_rtc_time(struct rtc_time *);
35ssize_t beat_nvram_get_size(void);
36ssize_t beat_nvram_read(char *, size_t, loff_t *);
37ssize_t beat_nvram_write(char *, size_t, loff_t *);
38int beat_set_xdabr(unsigned long);
39
40#endif /* _CELLEB_BEAT_H */
diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/celleb/beat_syscall.h
new file mode 100644
index 000000000000..14e16974773f
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat_syscall.h
@@ -0,0 +1,160 @@
1/*
2 * Beat hypervisor call numbers
3 *
4 * (C) Copyright 2004-2007 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#ifndef BEAT_BEAT_syscall_H
22#define BEAT_BEAT_syscall_H
23
24#ifdef __ASSEMBLY__
25#define __BEAT_ADD_VENDOR_ID(__x, __v) ((__v)<<60|(__x))
26#else
27#define __BEAT_ADD_VENDOR_ID(__x, __v) ((u64)(__v)<<60|(__x))
28#endif
29#define HV_allocate_memory __BEAT_ADD_VENDOR_ID(0, 0)
30#define HV_construct_virtual_address_space __BEAT_ADD_VENDOR_ID(2, 0)
31#define HV_destruct_virtual_address_space __BEAT_ADD_VENDOR_ID(10, 0)
32#define HV_get_virtual_address_space_id_of_ppe __BEAT_ADD_VENDOR_ID(4, 0)
33#define HV_query_logical_partition_address_region_info \
34 __BEAT_ADD_VENDOR_ID(6, 0)
35#define HV_release_memory __BEAT_ADD_VENDOR_ID(13, 0)
36#define HV_select_virtual_address_space __BEAT_ADD_VENDOR_ID(7, 0)
37#define HV_load_range_registers __BEAT_ADD_VENDOR_ID(68, 0)
38#define HV_set_ppe_l2cache_rmt_entry __BEAT_ADD_VENDOR_ID(70, 0)
39#define HV_set_ppe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(71, 0)
40#define HV_set_spe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(72, 0)
41#define HV_get_io_address_translation_fault_info __BEAT_ADD_VENDOR_ID(14, 0)
42#define HV_get_iopte __BEAT_ADD_VENDOR_ID(16, 0)
43#define HV_preload_iopt_cache __BEAT_ADD_VENDOR_ID(17, 0)
44#define HV_put_iopte __BEAT_ADD_VENDOR_ID(15, 0)
45#define HV_connect_event_ports __BEAT_ADD_VENDOR_ID(21, 0)
46#define HV_construct_event_receive_port __BEAT_ADD_VENDOR_ID(18, 0)
47#define HV_destruct_event_receive_port __BEAT_ADD_VENDOR_ID(19, 0)
48#define HV_destruct_event_send_port __BEAT_ADD_VENDOR_ID(22, 0)
49#define HV_get_state_of_event_send_port __BEAT_ADD_VENDOR_ID(25, 0)
50#define HV_request_to_connect_event_ports __BEAT_ADD_VENDOR_ID(20, 0)
51#define HV_send_event_externally __BEAT_ADD_VENDOR_ID(23, 0)
52#define HV_send_event_locally __BEAT_ADD_VENDOR_ID(24, 0)
53#define HV_construct_and_connect_irq_plug __BEAT_ADD_VENDOR_ID(28, 0)
54#define HV_destruct_irq_plug __BEAT_ADD_VENDOR_ID(29, 0)
55#define HV_detect_pending_interrupts __BEAT_ADD_VENDOR_ID(26, 0)
56#define HV_end_of_interrupt __BEAT_ADD_VENDOR_ID(27, 0)
57#define HV_assign_control_signal_notification_port __BEAT_ADD_VENDOR_ID(45, 0)
58#define HV_end_of_control_signal_processing __BEAT_ADD_VENDOR_ID(48, 0)
59#define HV_get_control_signal __BEAT_ADD_VENDOR_ID(46, 0)
60#define HV_set_irq_mask_for_spe __BEAT_ADD_VENDOR_ID(61, 0)
61#define HV_shutdown_logical_partition __BEAT_ADD_VENDOR_ID(44, 0)
62#define HV_connect_message_ports __BEAT_ADD_VENDOR_ID(35, 0)
63#define HV_destruct_message_port __BEAT_ADD_VENDOR_ID(36, 0)
64#define HV_receive_message __BEAT_ADD_VENDOR_ID(37, 0)
65#define HV_get_message_port_info __BEAT_ADD_VENDOR_ID(34, 0)
66#define HV_request_to_connect_message_ports __BEAT_ADD_VENDOR_ID(33, 0)
67#define HV_send_message __BEAT_ADD_VENDOR_ID(32, 0)
68#define HV_get_logical_ppe_id __BEAT_ADD_VENDOR_ID(69, 0)
69#define HV_pause __BEAT_ADD_VENDOR_ID(9, 0)
70#define HV_destruct_shared_memory_handle __BEAT_ADD_VENDOR_ID(51, 0)
71#define HV_get_shared_memory_info __BEAT_ADD_VENDOR_ID(52, 0)
72#define HV_permit_sharing_memory __BEAT_ADD_VENDOR_ID(50, 0)
73#define HV_request_to_attach_shared_memory __BEAT_ADD_VENDOR_ID(49, 0)
74#define HV_enable_logical_spe_execution __BEAT_ADD_VENDOR_ID(55, 0)
75#define HV_construct_logical_spe __BEAT_ADD_VENDOR_ID(53, 0)
76#define HV_disable_logical_spe_execution __BEAT_ADD_VENDOR_ID(56, 0)
77#define HV_destruct_logical_spe __BEAT_ADD_VENDOR_ID(54, 0)
78#define HV_sense_spe_execution_status __BEAT_ADD_VENDOR_ID(58, 0)
79#define HV_insert_htab_entry __BEAT_ADD_VENDOR_ID(101, 0)
80#define HV_read_htab_entries __BEAT_ADD_VENDOR_ID(95, 0)
81#define HV_write_htab_entry __BEAT_ADD_VENDOR_ID(94, 0)
82#define HV_assign_io_address_translation_fault_port \
83 __BEAT_ADD_VENDOR_ID(100, 0)
84#define HV_set_interrupt_mask __BEAT_ADD_VENDOR_ID(73, 0)
85#define HV_get_logical_partition_id __BEAT_ADD_VENDOR_ID(74, 0)
86#define HV_create_repository_node2 __BEAT_ADD_VENDOR_ID(90, 0)
87#define HV_create_repository_node __BEAT_ADD_VENDOR_ID(90, 0) /* alias */
88#define HV_get_repository_node_value2 __BEAT_ADD_VENDOR_ID(91, 0)
89#define HV_get_repository_node_value __BEAT_ADD_VENDOR_ID(91, 0) /* alias */
90#define HV_modify_repository_node_value2 __BEAT_ADD_VENDOR_ID(92, 0)
91#define HV_modify_repository_node_value __BEAT_ADD_VENDOR_ID(92, 0) /* alias */
92#define HV_remove_repository_node2 __BEAT_ADD_VENDOR_ID(93, 0)
93#define HV_remove_repository_node __BEAT_ADD_VENDOR_ID(93, 0) /* alias */
94#define HV_cancel_shared_memory __BEAT_ADD_VENDOR_ID(104, 0)
95#define HV_clear_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(206, 0)
96#define HV_construct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(80, 0)
97#define HV_destruct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(81, 0)
98#define HV_disconnect_ipspc_service __BEAT_ADD_VENDOR_ID(88, 0)
99#define HV_execute_ipspc_command __BEAT_ADD_VENDOR_ID(86, 0)
100#define HV_get_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(205, 0)
101#define HV_get_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(208, 0)
102#define HV_permit_use_of_ipspc_service __BEAT_ADD_VENDOR_ID(85, 0)
103#define HV_reinitialize_logical_spe __BEAT_ADD_VENDOR_ID(82, 0)
104#define HV_request_ipspc_service __BEAT_ADD_VENDOR_ID(84, 0)
105#define HV_stop_ipspc_command __BEAT_ADD_VENDOR_ID(87, 0)
106#define HV_set_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(204, 0)
107#define HV_get_status_of_ipspc_service __BEAT_ADD_VENDOR_ID(203, 0)
108#define HV_put_characters_to_console __BEAT_ADD_VENDOR_ID(0x101, 1)
109#define HV_get_characters_from_console __BEAT_ADD_VENDOR_ID(0x102, 1)
110#define HV_get_base_clock __BEAT_ADD_VENDOR_ID(0x111, 1)
111#define HV_set_base_clock __BEAT_ADD_VENDOR_ID(0x112, 1)
112#define HV_get_frame_cycle __BEAT_ADD_VENDOR_ID(0x114, 1)
113#define HV_disable_console __BEAT_ADD_VENDOR_ID(0x115, 1)
114#define HV_disable_all_console __BEAT_ADD_VENDOR_ID(0x116, 1)
115#define HV_oneshot_timer __BEAT_ADD_VENDOR_ID(0x117, 1)
116#define HV_set_dabr __BEAT_ADD_VENDOR_ID(0x118, 1)
117#define HV_get_dabr __BEAT_ADD_VENDOR_ID(0x119, 1)
118#define HV_start_hv_stats __BEAT_ADD_VENDOR_ID(0x21c, 1)
119#define HV_stop_hv_stats __BEAT_ADD_VENDOR_ID(0x21d, 1)
120#define HV_get_hv_stats __BEAT_ADD_VENDOR_ID(0x21e, 1)
121#define HV_get_hv_error_stats __BEAT_ADD_VENDOR_ID(0x221, 1)
122#define HV_get_stats __BEAT_ADD_VENDOR_ID(0x224, 1)
123#define HV_get_heap_stats __BEAT_ADD_VENDOR_ID(0x225, 1)
124#define HV_get_memory_stats __BEAT_ADD_VENDOR_ID(0x227, 1)
125#define HV_get_memory_detail __BEAT_ADD_VENDOR_ID(0x228, 1)
126#define HV_set_priority_of_irq_outlet __BEAT_ADD_VENDOR_ID(0x122, 1)
127#define HV_get_physical_spe_by_reservation_id __BEAT_ADD_VENDOR_ID(0x128, 1)
128#define HV_get_spe_context __BEAT_ADD_VENDOR_ID(0x129, 1)
129#define HV_set_spe_context __BEAT_ADD_VENDOR_ID(0x12a, 1)
130#define HV_downcount_of_interrupt __BEAT_ADD_VENDOR_ID(0x12e, 1)
131#define HV_peek_spe_context __BEAT_ADD_VENDOR_ID(0x12f, 1)
132#define HV_read_bpa_register __BEAT_ADD_VENDOR_ID(0x131, 1)
133#define HV_write_bpa_register __BEAT_ADD_VENDOR_ID(0x132, 1)
134#define HV_map_context_table_of_spe __BEAT_ADD_VENDOR_ID(0x137, 1)
135#define HV_get_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x138, 1)
136#define HV_set_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x139, 1)
137#define HV_init_pm __BEAT_ADD_VENDOR_ID(0x150, 1)
138#define HV_set_pm_signal __BEAT_ADD_VENDOR_ID(0x151, 1)
139#define HV_get_pm_signal __BEAT_ADD_VENDOR_ID(0x152, 1)
140#define HV_set_pm_config __BEAT_ADD_VENDOR_ID(0x153, 1)
141#define HV_get_pm_config __BEAT_ADD_VENDOR_ID(0x154, 1)
142#define HV_get_inner_trace_data __BEAT_ADD_VENDOR_ID(0x155, 1)
143#define HV_set_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x156, 1)
144#define HV_get_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x157, 1)
145#define HV_set_pm_interrupt __BEAT_ADD_VENDOR_ID(0x158, 1)
146#define HV_get_pm_interrupt __BEAT_ADD_VENDOR_ID(0x159, 1)
147#define HV_kick_pm __BEAT_ADD_VENDOR_ID(0x160, 1)
148#define HV_construct_pm_context __BEAT_ADD_VENDOR_ID(0x164, 1)
149#define HV_destruct_pm_context __BEAT_ADD_VENDOR_ID(0x165, 1)
150#define HV_be_slow __BEAT_ADD_VENDOR_ID(0x170, 1)
151#define HV_assign_ipspc_server_connection_status_notification_port \
152 __BEAT_ADD_VENDOR_ID(0x173, 1)
153#define HV_get_raid_of_physical_spe __BEAT_ADD_VENDOR_ID(0x174, 1)
154#define HV_set_physical_spe_to_rag __BEAT_ADD_VENDOR_ID(0x175, 1)
155#define HV_release_physical_spe_from_rag __BEAT_ADD_VENDOR_ID(0x176, 1)
156#define HV_rtc_read __BEAT_ADD_VENDOR_ID(0x190, 1)
157#define HV_rtc_write __BEAT_ADD_VENDOR_ID(0x191, 1)
158#define HV_eeprom_read __BEAT_ADD_VENDOR_ID(0x192, 1)
159#define HV_eeprom_write __BEAT_ADD_VENDOR_ID(0x193, 1)
160#endif
diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/celleb/beat_wrapper.h
new file mode 100644
index 000000000000..76ea0a6a9011
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/beat_wrapper.h
@@ -0,0 +1,220 @@
1/*
2 * Beat hypervisor call I/F
3 *
4 * (C) Copyright 2007 TOSHIBA CORPORATION
5 *
6 * This code is based on arch/powerpc/platforms/pseries/plpar_wrapper.h.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22#ifndef BEAT_HCALL
23#include "beat_syscall.h"
24
25/* defined in hvCall.S */
26extern s64 beat_hcall_norets(u64 opcode, ...);
27extern s64 beat_hcall_norets8(u64 opcode, u64 arg1, u64 arg2, u64 arg3,
28 u64 arg4, u64 arg5, u64 arg6, u64 arg7, u64 arg8);
29extern s64 beat_hcall1(u64 opcode, u64 retbuf[1], ...);
30extern s64 beat_hcall2(u64 opcode, u64 retbuf[2], ...);
31extern s64 beat_hcall3(u64 opcode, u64 retbuf[3], ...);
32extern s64 beat_hcall4(u64 opcode, u64 retbuf[4], ...);
33extern s64 beat_hcall5(u64 opcode, u64 retbuf[5], ...);
34extern s64 beat_hcall6(u64 opcode, u64 retbuf[6], ...);
35
36static inline s64 beat_downcount_of_interrupt(u64 plug_id)
37{
38 return beat_hcall_norets(HV_downcount_of_interrupt, plug_id);
39}
40
41static inline s64 beat_set_interrupt_mask(u64 index,
42 u64 val0, u64 val1, u64 val2, u64 val3)
43{
44 return beat_hcall_norets(HV_set_interrupt_mask, index,
45 val0, val1, val2, val3);
46}
47
48static inline s64 beat_destruct_irq_plug(u64 plug_id)
49{
50 return beat_hcall_norets(HV_destruct_irq_plug, plug_id);
51}
52
53static inline s64 beat_construct_and_connect_irq_plug(u64 plug_id,
54 u64 outlet_id)
55{
56 return beat_hcall_norets(HV_construct_and_connect_irq_plug, plug_id,
57 outlet_id);
58}
59
60static inline s64 beat_detect_pending_interrupts(u64 index, u64 *retbuf)
61{
62 return beat_hcall4(HV_detect_pending_interrupts, retbuf, index);
63}
64
65static inline s64 beat_pause(u64 style)
66{
67 return beat_hcall_norets(HV_pause, style);
68}
69
70static inline s64 beat_read_htab_entries(u64 htab_id, u64 index, u64 *retbuf)
71{
72 return beat_hcall5(HV_read_htab_entries, retbuf, htab_id, index);
73}
74
75static inline s64 beat_insert_htab_entry(u64 htab_id, u64 group,
76 u64 bitmask, u64 hpte_v, u64 hpte_r, u64 *slot)
77{
78 u64 dummy[3];
79 s64 ret;
80
81 ret = beat_hcall3(HV_insert_htab_entry, dummy, htab_id, group,
82 bitmask, hpte_v, hpte_r);
83 *slot = dummy[0];
84 return ret;
85}
86
87static inline s64 beat_write_htab_entry(u64 htab_id, u64 slot,
88 u64 hpte_v, u64 hpte_r, u64 mask_v, u64 mask_r,
89 u64 *ret_v, u64 *ret_r)
90{
91 u64 dummy[2];
92 s64 ret;
93
94 ret = beat_hcall2(HV_write_htab_entry, dummy, htab_id, slot,
95 hpte_v, hpte_r, mask_v, mask_r);
96 *ret_v = dummy[0];
97 *ret_r = dummy[1];
98 return ret;
99}
100
101static inline void beat_shutdown_logical_partition(u64 code)
102{
103 (void)beat_hcall_norets(HV_shutdown_logical_partition, code);
104}
105
106static inline s64 beat_rtc_write(u64 time_from_epoch)
107{
108 return beat_hcall_norets(HV_rtc_write, time_from_epoch);
109}
110
111static inline s64 beat_rtc_read(u64 *time_from_epoch)
112{
113 u64 dummy[1];
114 s64 ret;
115
116 ret = beat_hcall1(HV_rtc_read, dummy);
117 *time_from_epoch = dummy[0];
118 return ret;
119}
120
121#define BEAT_NVRW_CNT (sizeof(u64) * 6)
122
123static inline s64 beat_eeprom_write(u64 index, u64 length, u8 *buffer)
124{
125 u64 b[6];
126
127 if (length > BEAT_NVRW_CNT)
128 return -1;
129 memcpy(b, buffer, sizeof(b));
130 return beat_hcall_norets8(HV_eeprom_write, index, length,
131 b[0], b[1], b[2], b[3], b[4], b[5]);
132}
133
134static inline s64 beat_eeprom_read(u64 index, u64 length, u8 *buffer)
135{
136 u64 b[6];
137 s64 ret;
138
139 if (length > BEAT_NVRW_CNT)
140 return -1;
141 ret = beat_hcall6(HV_eeprom_read, b, index, length);
142 memcpy(buffer, b, length);
143 return ret;
144}
145
146static inline s64 beat_set_dabr(u64 value, u64 style)
147{
148 return beat_hcall_norets(HV_set_dabr, value, style);
149}
150
151static inline s64 beat_get_characters_from_console(u64 termno, u64 *len,
152 u8 *buffer)
153{
154 u64 dummy[3];
155 s64 ret;
156
157 ret = beat_hcall3(HV_get_characters_from_console, dummy, termno, len);
158 *len = dummy[0];
159 memcpy(buffer, dummy + 1, *len);
160 return ret;
161}
162
163static inline s64 beat_put_characters_to_console(u64 termno, u64 len,
164 u8 *buffer)
165{
166 u64 b[2];
167
168 memcpy(b, buffer, len);
169 return beat_hcall_norets(HV_put_characters_to_console, termno, len, b[0], b[1]);
170}
171
172static inline s64 beat_get_spe_privileged_state_1_registers(
173 u64 id, u64 offsetof, u64 *value)
174{
175 u64 dummy[1];
176 s64 ret;
177
178 ret = beat_hcall1(HV_get_spe_privileged_state_1_registers, dummy, id,
179 offsetof);
180 *value = dummy[0];
181 return ret;
182}
183
184static inline s64 beat_set_irq_mask_for_spe(u64 id, u64 class, u64 mask)
185{
186 return beat_hcall_norets(HV_set_irq_mask_for_spe, id, class, mask);
187}
188
189static inline s64 beat_clear_interrupt_status_of_spe(u64 id, u64 class,
190 u64 mask)
191{
192 return beat_hcall_norets(HV_clear_interrupt_status_of_spe,
193 id, class, mask);
194}
195
196static inline s64 beat_set_spe_privileged_state_1_registers(
197 u64 id, u64 offsetof, u64 value)
198{
199 return beat_hcall_norets(HV_set_spe_privileged_state_1_registers,
200 id, offsetof, value);
201}
202
203static inline s64 beat_get_interrupt_status_of_spe(u64 id, u64 class, u64 *val)
204{
205 u64 dummy[1];
206 s64 ret;
207
208 ret = beat_hcall1(HV_get_interrupt_status_of_spe, dummy, id, class);
209 *val = dummy[0];
210 return ret;
211}
212
213static inline s64 beat_put_iopte(u64 ioas_id, u64 io_addr, u64 real_addr,
214 u64 ioid, u64 flags)
215{
216 return beat_hcall_norets(HV_put_iopte, ioas_id, io_addr, real_addr,
217 ioid, flags);
218}
219
220#endif
diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/celleb/htab.c
new file mode 100644
index 000000000000..ffa7c2c2030d
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/htab.c
@@ -0,0 +1,311 @@
1/*
2 * "Cell Reference Set" HTAB support.
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This code is based on arch/powerpc/platforms/pseries/lpar.c:
7 * Copyright (C) 2001 Todd Inglett, IBM Corporation
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#undef DEBUG_LOW
25
26#include <linux/kernel.h>
27#include <linux/spinlock.h>
28
29#include <asm/mmu.h>
30#include <asm/page.h>
31#include <asm/pgtable.h>
32#include <asm/machdep.h>
33#include <asm/udbg.h>
34
35#include "beat_wrapper.h"
36
37#ifdef DEBUG_LOW
38#define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0)
39#else
40#define DBG_LOW(fmt...) do { } while(0)
41#endif
42
43static DEFINE_SPINLOCK(beat_htab_lock);
44
45static inline unsigned int beat_read_mask(unsigned hpte_group)
46{
47 unsigned long hpte_v[5];
48 unsigned long rmask = 0;
49
50 beat_read_htab_entries(0, hpte_group + 0, hpte_v);
51 if (!(hpte_v[0] & HPTE_V_BOLTED))
52 rmask |= 0x8000;
53 if (!(hpte_v[1] & HPTE_V_BOLTED))
54 rmask |= 0x4000;
55 if (!(hpte_v[2] & HPTE_V_BOLTED))
56 rmask |= 0x2000;
57 if (!(hpte_v[3] & HPTE_V_BOLTED))
58 rmask |= 0x1000;
59 beat_read_htab_entries(0, hpte_group + 4, hpte_v);
60 if (!(hpte_v[0] & HPTE_V_BOLTED))
61 rmask |= 0x0800;
62 if (!(hpte_v[1] & HPTE_V_BOLTED))
63 rmask |= 0x0400;
64 if (!(hpte_v[2] & HPTE_V_BOLTED))
65 rmask |= 0x0200;
66 if (!(hpte_v[3] & HPTE_V_BOLTED))
67 rmask |= 0x0100;
68 hpte_group = ~hpte_group & (htab_hash_mask * HPTES_PER_GROUP);
69 beat_read_htab_entries(0, hpte_group + 0, hpte_v);
70 if (!(hpte_v[0] & HPTE_V_BOLTED))
71 rmask |= 0x80;
72 if (!(hpte_v[1] & HPTE_V_BOLTED))
73 rmask |= 0x40;
74 if (!(hpte_v[2] & HPTE_V_BOLTED))
75 rmask |= 0x20;
76 if (!(hpte_v[3] & HPTE_V_BOLTED))
77 rmask |= 0x10;
78 beat_read_htab_entries(0, hpte_group + 4, hpte_v);
79 if (!(hpte_v[0] & HPTE_V_BOLTED))
80 rmask |= 0x08;
81 if (!(hpte_v[1] & HPTE_V_BOLTED))
82 rmask |= 0x04;
83 if (!(hpte_v[2] & HPTE_V_BOLTED))
84 rmask |= 0x02;
85 if (!(hpte_v[3] & HPTE_V_BOLTED))
86 rmask |= 0x01;
87 return rmask;
88}
89
90static long beat_lpar_hpte_insert(unsigned long hpte_group,
91 unsigned long va, unsigned long pa,
92 unsigned long rflags, unsigned long vflags,
93 int psize)
94{
95 unsigned long lpar_rc;
96 unsigned long slot;
97 unsigned long hpte_v, hpte_r;
98 unsigned long flags;
99
100 /* same as iseries */
101 if (vflags & HPTE_V_SECONDARY)
102 return -1;
103
104 if (!(vflags & HPTE_V_BOLTED))
105 DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, "
106 "rflags=%lx, vflags=%lx, psize=%d)\n",
107 hpte_group, va, pa, rflags, vflags, psize);
108
109 hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID;
110 hpte_r = hpte_encode_r(pa, psize) | rflags;
111
112 if (!(vflags & HPTE_V_BOLTED))
113 DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
114
115 if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE))
116 hpte_r &= ~_PAGE_COHERENT;
117
118 spin_lock_irqsave(&beat_htab_lock, flags);
119 if ((lpar_rc = beat_read_mask(hpte_group)) == 0) {
120 if (!(vflags & HPTE_V_BOLTED))
121 DBG_LOW(" full\n");
122 spin_unlock_irqrestore(&beat_htab_lock, flags);
123 return -1;
124 }
125
126 lpar_rc = beat_insert_htab_entry(0, hpte_group, lpar_rc << 48,
127 hpte_v, hpte_r, &slot);
128 spin_unlock_irqrestore(&beat_htab_lock, flags);
129
130 /*
131 * Since we try and ioremap PHBs we don't own, the pte insert
132 * will fail. However we must catch the failure in hash_page
133 * or we will loop forever, so return -2 in this case.
134 */
135 if (unlikely(lpar_rc != 0)) {
136 if (!(vflags & HPTE_V_BOLTED))
137 DBG_LOW(" lpar err %lx\n", lpar_rc);
138 return -2;
139 }
140 if (!(vflags & HPTE_V_BOLTED))
141 DBG_LOW(" -> slot: %lx\n", slot);
142
143 /* We have to pass down the secondary bucket bit here as well */
144 return (slot ^ hpte_group) & 15;
145}
146
147static long beat_lpar_hpte_remove(unsigned long hpte_group)
148{
149 DBG_LOW("hpte_remove(group=%lx)\n", hpte_group);
150 return -1;
151}
152
153static unsigned long beat_lpar_hpte_getword0(unsigned long slot)
154{
155 unsigned long dword0, dword[5];
156 unsigned long lpar_rc;
157
158 lpar_rc = beat_read_htab_entries(0, slot & ~3UL, dword);
159
160 dword0 = dword[slot&3];
161
162 BUG_ON(lpar_rc != 0);
163
164 return dword0;
165}
166
167static void beat_lpar_hptab_clear(void)
168{
169 unsigned long size_bytes = 1UL << ppc64_pft_size;
170 unsigned long hpte_count = size_bytes >> 4;
171 int i;
172 unsigned long dummy0, dummy1;
173
174 /* TODO: Use bulk call */
175 for (i = 0; i < hpte_count; i++)
176 beat_write_htab_entry(0, i, 0, 0, -1UL, -1UL, &dummy0, &dummy1);
177}
178
179/*
180 * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and
181 * the low 3 bits of flags happen to line up. So no transform is needed.
182 * We can probably optimize here and assume the high bits of newpp are
183 * already zero. For now I am paranoid.
184 */
185static long beat_lpar_hpte_updatepp(unsigned long slot,
186 unsigned long newpp,
187 unsigned long va,
188 int psize, int local)
189{
190 unsigned long lpar_rc;
191 unsigned long dummy0, dummy1, want_v;
192 unsigned long flags;
193
194 want_v = hpte_encode_v(va, psize);
195
196 DBG_LOW(" update: "
197 "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ",
198 want_v & HPTE_V_AVPN, slot, psize, newpp);
199
200 spin_lock_irqsave(&beat_htab_lock, flags);
201 dummy0 = beat_lpar_hpte_getword0(slot);
202 if ((dummy0 & ~0x7FUL) != (want_v & ~0x7FUL)) {
203 DBG_LOW("not found !\n");
204 spin_unlock_irqrestore(&beat_htab_lock, flags);
205 return -1;
206 }
207
208 lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, &dummy0,
209 &dummy1);
210 spin_unlock_irqrestore(&beat_htab_lock, flags);
211 if (lpar_rc != 0 || dummy0 == 0) {
212 DBG_LOW("not found !\n");
213 return -1;
214 }
215
216 DBG_LOW("ok %lx %lx\n", dummy0, dummy1);
217
218 BUG_ON(lpar_rc != 0);
219
220 return 0;
221}
222
223static long beat_lpar_hpte_find(unsigned long va, int psize)
224{
225 unsigned long hash;
226 unsigned long i, j;
227 long slot;
228 unsigned long want_v, hpte_v;
229
230 hash = hpt_hash(va, mmu_psize_defs[psize].shift);
231 want_v = hpte_encode_v(va, psize);
232
233 for (j = 0; j < 2; j++) {
234 slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
235 for (i = 0; i < HPTES_PER_GROUP; i++) {
236 hpte_v = beat_lpar_hpte_getword0(slot);
237
238 if (HPTE_V_COMPARE(hpte_v, want_v)
239 && (hpte_v & HPTE_V_VALID)
240 && (!!(hpte_v & HPTE_V_SECONDARY) == j)) {
241 /* HPTE matches */
242 if (j)
243 slot = -slot;
244 return slot;
245 }
246 ++slot;
247 }
248 hash = ~hash;
249 }
250
251 return -1;
252}
253
254static void beat_lpar_hpte_updateboltedpp(unsigned long newpp,
255 unsigned long ea,
256 int psize)
257{
258 unsigned long lpar_rc, slot, vsid, va, dummy0, dummy1;
259 unsigned long flags;
260
261 vsid = get_kernel_vsid(ea);
262 va = (vsid << 28) | (ea & 0x0fffffff);
263
264 spin_lock_irqsave(&beat_htab_lock, flags);
265 slot = beat_lpar_hpte_find(va, psize);
266 BUG_ON(slot == -1);
267
268 lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7,
269 &dummy0, &dummy1);
270 spin_unlock_irqrestore(&beat_htab_lock, flags);
271
272 BUG_ON(lpar_rc != 0);
273}
274
275static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
276 int psize, int local)
277{
278 unsigned long want_v;
279 unsigned long lpar_rc;
280 unsigned long dummy1, dummy2;
281 unsigned long flags;
282
283 DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n",
284 slot, va, psize, local);
285 want_v = hpte_encode_v(va, psize);
286
287 spin_lock_irqsave(&beat_htab_lock, flags);
288 dummy1 = beat_lpar_hpte_getword0(slot);
289
290 if ((dummy1 & ~0x7FUL) != (want_v & ~0x7FUL)) {
291 DBG_LOW("not found !\n");
292 spin_unlock_irqrestore(&beat_htab_lock, flags);
293 return;
294 }
295
296 lpar_rc = beat_write_htab_entry(0, slot, 0, 0, HPTE_V_VALID, 0,
297 &dummy1, &dummy2);
298 spin_unlock_irqrestore(&beat_htab_lock, flags);
299
300 BUG_ON(lpar_rc != 0);
301}
302
303void __init hpte_init_beat(void)
304{
305 ppc_md.hpte_invalidate = beat_lpar_hpte_invalidate;
306 ppc_md.hpte_updatepp = beat_lpar_hpte_updatepp;
307 ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp;
308 ppc_md.hpte_insert = beat_lpar_hpte_insert;
309 ppc_md.hpte_remove = beat_lpar_hpte_remove;
310 ppc_md.hpte_clear_all = beat_lpar_hptab_clear;
311}
diff --git a/arch/powerpc/platforms/celleb/hvCall.S b/arch/powerpc/platforms/celleb/hvCall.S
new file mode 100644
index 000000000000..74c817448948
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/hvCall.S
@@ -0,0 +1,287 @@
1/*
2 * Beat hypervisor call I/F
3 *
4 * (C) Copyright 2007 TOSHIBA CORPORATION
5 *
6 * This code is based on arch/powerpc/platforms/pseries/hvCall.S.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include <asm/ppc_asm.h>
24
25#define STK_PARM(i) (48 + ((i)-3)*8)
26
27/* Not implemented on Beat, now */
28#define HCALL_INST_PRECALL
29#define HCALL_INST_POSTCALL
30
31 .text
32
33#define HVSC .long 0x44000022
34
35/* Note: takes only 7 input parameters at maximum */
36_GLOBAL(beat_hcall_norets)
37 HMT_MEDIUM
38
39 mfcr r0
40 stw r0,8(r1)
41
42 HCALL_INST_PRECALL
43
44 mr r11,r3
45 mr r3,r4
46 mr r4,r5
47 mr r5,r6
48 mr r6,r7
49 mr r7,r8
50 mr r8,r9
51
52 HVSC /* invoke the hypervisor */
53
54 HCALL_INST_POSTCALL
55
56 lwz r0,8(r1)
57 mtcrf 0xff,r0
58
59 blr /* return r3 = status */
60
61/* Note: takes 8 input parameters at maximum */
62_GLOBAL(beat_hcall_norets8)
63 HMT_MEDIUM
64
65 mfcr r0
66 stw r0,8(r1)
67
68 HCALL_INST_PRECALL
69
70 mr r11,r3
71 mr r3,r4
72 mr r4,r5
73 mr r5,r6
74 mr r6,r7
75 mr r7,r8
76 mr r8,r9
77 ld r10,STK_PARM(r10)(r1)
78
79 HVSC /* invoke the hypervisor */
80
81 HCALL_INST_POSTCALL
82
83 lwz r0,8(r1)
84 mtcrf 0xff,r0
85
86 blr /* return r3 = status */
87
88/* Note: takes only 6 input parameters, 1 output parameters at maximum */
89_GLOBAL(beat_hcall1)
90 HMT_MEDIUM
91
92 mfcr r0
93 stw r0,8(r1)
94
95 HCALL_INST_PRECALL
96
97 std r4,STK_PARM(r4)(r1) /* save ret buffer */
98
99 mr r11,r3
100 mr r3,r5
101 mr r4,r6
102 mr r5,r7
103 mr r6,r8
104 mr r7,r9
105 mr r8,r10
106
107 HVSC /* invoke the hypervisor */
108
109 HCALL_INST_POSTCALL
110
111 ld r12,STK_PARM(r4)(r1)
112 std r4, 0(r12)
113
114 lwz r0,8(r1)
115 mtcrf 0xff,r0
116
117 blr /* return r3 = status */
118
119/* Note: takes only 6 input parameters, 2 output parameters at maximum */
120_GLOBAL(beat_hcall2)
121 HMT_MEDIUM
122
123 mfcr r0
124 stw r0,8(r1)
125
126 HCALL_INST_PRECALL
127
128 std r4,STK_PARM(r4)(r1) /* save ret buffer */
129
130 mr r11,r3
131 mr r3,r5
132 mr r4,r6
133 mr r5,r7
134 mr r6,r8
135 mr r7,r9
136 mr r8,r10
137
138 HVSC /* invoke the hypervisor */
139
140 HCALL_INST_POSTCALL
141
142 ld r12,STK_PARM(r4)(r1)
143 std r4, 0(r12)
144 std r5, 8(r12)
145
146 lwz r0,8(r1)
147 mtcrf 0xff,r0
148
149 blr /* return r3 = status */
150
151/* Note: takes only 6 input parameters, 3 output parameters at maximum */
152_GLOBAL(beat_hcall3)
153 HMT_MEDIUM
154
155 mfcr r0
156 stw r0,8(r1)
157
158 HCALL_INST_PRECALL
159
160 std r4,STK_PARM(r4)(r1) /* save ret buffer */
161
162 mr r11,r3
163 mr r3,r5
164 mr r4,r6
165 mr r5,r7
166 mr r6,r8
167 mr r7,r9
168 mr r8,r10
169
170 HVSC /* invoke the hypervisor */
171
172 HCALL_INST_POSTCALL
173
174 ld r12,STK_PARM(r4)(r1)
175 std r4, 0(r12)
176 std r5, 8(r12)
177 std r6, 16(r12)
178
179 lwz r0,8(r1)
180 mtcrf 0xff,r0
181
182 blr /* return r3 = status */
183
184/* Note: takes only 6 input parameters, 4 output parameters at maximum */
185_GLOBAL(beat_hcall4)
186 HMT_MEDIUM
187
188 mfcr r0
189 stw r0,8(r1)
190
191 HCALL_INST_PRECALL
192
193 std r4,STK_PARM(r4)(r1) /* save ret buffer */
194
195 mr r11,r3
196 mr r3,r5
197 mr r4,r6
198 mr r5,r7
199 mr r6,r8
200 mr r7,r9
201 mr r8,r10
202
203 HVSC /* invoke the hypervisor */
204
205 HCALL_INST_POSTCALL
206
207 ld r12,STK_PARM(r4)(r1)
208 std r4, 0(r12)
209 std r5, 8(r12)
210 std r6, 16(r12)
211 std r7, 24(r12)
212
213 lwz r0,8(r1)
214 mtcrf 0xff,r0
215
216 blr /* return r3 = status */
217
218/* Note: takes only 6 input parameters, 5 output parameters at maximum */
219_GLOBAL(beat_hcall5)
220 HMT_MEDIUM
221
222 mfcr r0
223 stw r0,8(r1)
224
225 HCALL_INST_PRECALL
226
227 std r4,STK_PARM(r4)(r1) /* save ret buffer */
228
229 mr r11,r3
230 mr r3,r5
231 mr r4,r6
232 mr r5,r7
233 mr r6,r8
234 mr r7,r9
235 mr r8,r10
236
237 HVSC /* invoke the hypervisor */
238
239 HCALL_INST_POSTCALL
240
241 ld r12,STK_PARM(r4)(r1)
242 std r4, 0(r12)
243 std r5, 8(r12)
244 std r6, 16(r12)
245 std r7, 24(r12)
246 std r8, 32(r12)
247
248 lwz r0,8(r1)
249 mtcrf 0xff,r0
250
251 blr /* return r3 = status */
252
253/* Note: takes only 6 input parameters, 6 output parameters at maximum */
254_GLOBAL(beat_hcall6)
255 HMT_MEDIUM
256
257 mfcr r0
258 stw r0,8(r1)
259
260 HCALL_INST_PRECALL
261
262 std r4,STK_PARM(r4)(r1) /* save ret buffer */
263
264 mr r11,r3
265 mr r3,r5
266 mr r4,r6
267 mr r5,r7
268 mr r6,r8
269 mr r7,r9
270 mr r8,r10
271
272 HVSC /* invoke the hypervisor */
273
274 HCALL_INST_POSTCALL
275
276 ld r12,STK_PARM(r4)(r1)
277 std r4, 0(r12)
278 std r5, 8(r12)
279 std r6, 16(r12)
280 std r7, 24(r12)
281 std r8, 32(r12)
282 std r9, 40(r12)
283
284 lwz r0,8(r1)
285 mtcrf 0xff,r0
286
287 blr /* return r3 = status */
diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/celleb/interrupt.c
new file mode 100644
index 000000000000..98e6665681d3
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/interrupt.c
@@ -0,0 +1,274 @@
1/*
2 * Celleb/Beat Interrupt controller
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <linux/init.h>
22#include <linux/interrupt.h>
23#include <linux/irq.h>
24#include <linux/percpu.h>
25#include <linux/types.h>
26
27#include <asm/machdep.h>
28
29#include "interrupt.h"
30#include "beat_wrapper.h"
31
32#define MAX_IRQS NR_IRQS
33static DEFINE_SPINLOCK(beatic_irq_mask_lock);
34static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64];
35static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64];
36
37static struct irq_host *beatic_host = NULL;
38
39/*
40 * In this implementation, "virq" == "IRQ plug number",
41 * "(irq_hw_number_t)hwirq" == "IRQ outlet number".
42 */
43
44/* assumption: locked */
45static inline void beatic_update_irq_mask(unsigned int irq_plug)
46{
47 int off;
48 unsigned long masks[4];
49
50 off = (irq_plug / 256) * 4;
51 masks[0] = beatic_irq_mask_enable[off + 0]
52 & beatic_irq_mask_ack[off + 0];
53 masks[1] = beatic_irq_mask_enable[off + 1]
54 & beatic_irq_mask_ack[off + 1];
55 masks[2] = beatic_irq_mask_enable[off + 2]
56 & beatic_irq_mask_ack[off + 2];
57 masks[3] = beatic_irq_mask_enable[off + 3]
58 & beatic_irq_mask_ack[off + 3];
59 if (beat_set_interrupt_mask(irq_plug&~255UL,
60 masks[0], masks[1], masks[2], masks[3]) != 0)
61 panic("Failed to set mask IRQ!");
62}
63
64static void beatic_mask_irq(unsigned int irq_plug)
65{
66 unsigned long flags;
67
68 spin_lock_irqsave(&beatic_irq_mask_lock, flags);
69 beatic_irq_mask_enable[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
70 beatic_update_irq_mask(irq_plug);
71 spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
72}
73
74static void beatic_unmask_irq(unsigned int irq_plug)
75{
76 unsigned long flags;
77
78 spin_lock_irqsave(&beatic_irq_mask_lock, flags);
79 beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
80 beatic_update_irq_mask(irq_plug);
81 spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
82}
83
84static void beatic_ack_irq(unsigned int irq_plug)
85{
86 unsigned long flags;
87
88 spin_lock_irqsave(&beatic_irq_mask_lock, flags);
89 beatic_irq_mask_ack[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64)));
90 beatic_update_irq_mask(irq_plug);
91 spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
92}
93
94static void beatic_end_irq(unsigned int irq_plug)
95{
96 s64 err;
97 unsigned long flags;
98
99 if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) {
100 if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */
101 panic("Failed to downcount IRQ! Error = %16lx", err);
102
103 printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug);
104 }
105 spin_lock_irqsave(&beatic_irq_mask_lock, flags);
106 beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64));
107 beatic_update_irq_mask(irq_plug);
108 spin_unlock_irqrestore(&beatic_irq_mask_lock, flags);
109}
110
111static struct irq_chip beatic_pic = {
112 .typename = " CELL-BEAT ",
113 .unmask = beatic_unmask_irq,
114 .mask = beatic_mask_irq,
115 .eoi = beatic_end_irq,
116};
117
118/*
119 * Dispose binding hardware IRQ number (hw) and Virtuql IRQ number (virq),
120 * update flags.
121 *
122 * Note that the number (virq) is already assigned at upper layer.
123 */
124static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq)
125{
126 beat_destruct_irq_plug(virq);
127}
128
129/*
130 * Create or update binding hardware IRQ number (hw) and Virtuql
131 * IRQ number (virq). This is called only once for a given mapping.
132 *
133 * Note that the number (virq) is already assigned at upper layer.
134 */
135static int beatic_pic_host_map(struct irq_host *h, unsigned int virq,
136 irq_hw_number_t hw)
137{
138 struct irq_desc *desc = get_irq_desc(virq);
139 int64_t err;
140
141 if ((err = beat_construct_and_connect_irq_plug(virq, hw)) < 0)
142 return -EIO;
143
144 desc->status |= IRQ_LEVEL;
145 set_irq_chip_and_handler(virq, &beatic_pic, handle_fasteoi_irq);
146 return 0;
147}
148
149/*
150 * Update binding hardware IRQ number (hw) and Virtuql
151 * IRQ number (virq). This is called only once for a given mapping.
152 */
153static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq,
154 irq_hw_number_t hw)
155{
156 beat_construct_and_connect_irq_plug(virq, hw);
157}
158
159/*
160 * Translate device-tree interrupt spec to irq_hw_number_t style (ulong),
161 * to pass away to irq_create_mapping().
162 *
163 * Called from irq_create_of_mapping() only.
164 * Note: We have only 1 entry to translate.
165 */
166static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct,
167 u32 *intspec, unsigned int intsize,
168 irq_hw_number_t *out_hwirq,
169 unsigned int *out_flags)
170{
171 u64 *intspec2 = (u64 *)intspec;
172
173 *out_hwirq = *intspec2;
174 *out_flags |= IRQ_TYPE_LEVEL_LOW;
175 return 0;
176}
177
178static struct irq_host_ops beatic_pic_host_ops = {
179 .map = beatic_pic_host_map,
180 .remap = beatic_pic_host_remap,
181 .unmap = beatic_pic_host_unmap,
182 .xlate = beatic_pic_host_xlate,
183};
184
185/*
186 * Get an IRQ number
187 * Note: returns VIRQ
188 */
189static inline unsigned int beatic_get_irq_plug(void)
190{
191 int i;
192 uint64_t pending[4], ub;
193
194 for (i = 0; i < MAX_IRQS; i += 256) {
195 beat_detect_pending_interrupts(i, pending);
196 __asm__ ("cntlzd %0,%1":"=r"(ub):
197 "r"(pending[0] & beatic_irq_mask_enable[i/64+0]
198 & beatic_irq_mask_ack[i/64+0]));
199 if (ub != 64)
200 return i + ub + 0;
201 __asm__ ("cntlzd %0,%1":"=r"(ub):
202 "r"(pending[1] & beatic_irq_mask_enable[i/64+1]
203 & beatic_irq_mask_ack[i/64+1]));
204 if (ub != 64)
205 return i + ub + 64;
206 __asm__ ("cntlzd %0,%1":"=r"(ub):
207 "r"(pending[2] & beatic_irq_mask_enable[i/64+2]
208 & beatic_irq_mask_ack[i/64+2]));
209 if (ub != 64)
210 return i + ub + 128;
211 __asm__ ("cntlzd %0,%1":"=r"(ub):
212 "r"(pending[3] & beatic_irq_mask_enable[i/64+3]
213 & beatic_irq_mask_ack[i/64+3]));
214 if (ub != 64)
215 return i + ub + 192;
216 }
217
218 return NO_IRQ;
219}
220unsigned int beatic_get_irq(void)
221{
222 unsigned int ret;
223
224 ret = beatic_get_irq_plug();
225 if (ret != NO_IRQ)
226 beatic_ack_irq(ret);
227 return ret;
228}
229
230/*
231 */
232void __init beatic_init_IRQ(void)
233{
234 int i;
235
236 memset(beatic_irq_mask_enable, 0, sizeof(beatic_irq_mask_enable));
237 memset(beatic_irq_mask_ack, 255, sizeof(beatic_irq_mask_ack));
238 for (i = 0; i < MAX_IRQS; i += 256)
239 beat_set_interrupt_mask(i, 0L, 0L, 0L, 0L);
240
241 /* Set out get_irq function */
242 ppc_md.get_irq = beatic_get_irq;
243
244 /* Allocate an irq host */
245 beatic_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0,
246 &beatic_pic_host_ops,
247 0);
248 BUG_ON(beatic_host == NULL);
249 irq_set_default_host(beatic_host);
250}
251
252#ifdef CONFIG_SMP
253
254/* Nullified to compile with SMP mode */
255void beatic_setup_cpu(int cpu)
256{
257}
258
259void beatic_cause_IPI(int cpu, int mesg)
260{
261}
262
263void beatic_request_IPIs(void)
264{
265}
266#endif /* CONFIG_SMP */
267
268void beatic_deinit_IRQ(void)
269{
270 int i;
271
272 for (i = 1; i < NR_IRQS; i++)
273 beat_destruct_irq_plug(i);
274}
diff --git a/arch/powerpc/platforms/celleb/interrupt.h b/arch/powerpc/platforms/celleb/interrupt.h
new file mode 100644
index 000000000000..b470fd0051f1
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/interrupt.h
@@ -0,0 +1,33 @@
1/*
2 * Celleb/Beat Interrupt controller
3 *
4 * (C) Copyright 2006 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#ifndef ASM_BEAT_PIC_H
22#define ASM_BEAT_PIC_H
23#ifdef __KERNEL__
24
25extern void beatic_init_IRQ(void);
26extern unsigned int beatic_get_irq(void);
27extern void beatic_cause_IPI(int cpu, int mesg);
28extern void beatic_request_IPIs(void);
29extern void beatic_setup_cpu(int);
30extern void beatic_deinit_IRQ(void);
31
32#endif
33#endif /* ASM_BEAT_PIC_H */
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c
new file mode 100644
index 000000000000..f63b94c65353
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/iommu.c
@@ -0,0 +1,104 @@
1/*
2 * Support for IOMMU on Celleb platform.
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/dma-mapping.h>
24#include <linux/pci.h>
25
26#include <asm/of_platform.h>
27
28#include "beat_wrapper.h"
29
30#define DMA_FLAGS 0xf800000000000000UL /* r/w permitted, coherency required,
31 strongest order */
32
33static int __init find_dma_window(u64 *io_space_id, u64 *ioid,
34 u64 *base, u64 *size, u64 *io_page_size)
35{
36 struct device_node *dn;
37 const unsigned long *dma_window;
38
39 for_each_node_by_type(dn, "ioif") {
40 dma_window = get_property(dn, "toshiba,dma-window", NULL);
41 if (dma_window) {
42 *io_space_id = (dma_window[0] >> 32) & 0xffffffffUL;
43 *ioid = dma_window[0] & 0x7ffUL;
44 *base = dma_window[1];
45 *size = dma_window[2];
46 *io_page_size = 1 << dma_window[3];
47 of_node_put(dn);
48 return 1;
49 }
50 }
51 return 0;
52}
53
54static void __init celleb_init_direct_mapping(void)
55{
56 u64 lpar_addr, io_addr;
57 u64 io_space_id, ioid, dma_base, dma_size, io_page_size;
58
59 if (!find_dma_window(&io_space_id, &ioid, &dma_base, &dma_size,
60 &io_page_size)) {
61 pr_info("No dma window found !\n");
62 return;
63 }
64
65 for (lpar_addr = 0; lpar_addr < dma_size; lpar_addr += io_page_size) {
66 io_addr = lpar_addr + dma_base;
67 (void)beat_put_iopte(io_space_id, io_addr, lpar_addr,
68 ioid, DMA_FLAGS);
69 }
70
71 dma_direct_offset = dma_base;
72}
73
74static int celleb_of_bus_notify(struct notifier_block *nb,
75 unsigned long action, void *data)
76{
77 struct device *dev = data;
78
79 /* We are only intereted in device addition */
80 if (action != BUS_NOTIFY_ADD_DEVICE)
81 return 0;
82
83 dev->archdata.dma_ops = pci_dma_ops;
84
85 return 0;
86}
87
88static struct notifier_block celleb_of_bus_notifier = {
89 .notifier_call = celleb_of_bus_notify
90};
91
92static int __init celleb_init_iommu(void)
93{
94 if (!machine_is(celleb))
95 return -ENODEV;
96
97 celleb_init_direct_mapping();
98 pci_dma_ops = &dma_direct_ops;
99 bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier);
100
101 return 0;
102}
103
104arch_initcall(celleb_init_iommu);
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c
new file mode 100644
index 000000000000..867f83a7d0c9
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/pci.c
@@ -0,0 +1,481 @@
1/*
2 * Support for PCI on Celleb platform.
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This code is based on arch/powerpc/kernel/rtas_pci.c:
7 * Copyright (C) 2001 Dave Engebretsen, IBM Corporation
8 * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (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 along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 */
24
25#undef DEBUG
26
27#include <linux/kernel.h>
28#include <linux/threads.h>
29#include <linux/pci.h>
30#include <linux/string.h>
31#include <linux/init.h>
32#include <linux/bootmem.h>
33#include <linux/pci_regs.h>
34
35#include <asm/io.h>
36#include <asm/irq.h>
37#include <asm/prom.h>
38#include <asm/machdep.h>
39#include <asm/pci-bridge.h>
40#include <asm/ppc-pci.h>
41
42#include "pci.h"
43#include "interrupt.h"
44
45#define MAX_PCI_DEVICES 32
46#define MAX_PCI_FUNCTIONS 8
47#define MAX_PCI_BASE_ADDRS 3 /* use 64 bit address */
48
49/* definition for fake pci configuration area for GbE, .... ,and etc. */
50
51struct celleb_pci_resource {
52 struct resource r[MAX_PCI_BASE_ADDRS];
53};
54
55struct celleb_pci_private {
56 unsigned char *fake_config[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS];
57 struct celleb_pci_resource *res[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS];
58};
59
60static inline u8 celleb_fake_config_readb(void *addr)
61{
62 u8 *p = addr;
63 return *p;
64}
65
66static inline u16 celleb_fake_config_readw(void *addr)
67{
68 u16 *p = addr;
69 return le16_to_cpu(*p);
70}
71
72static inline u32 celleb_fake_config_readl(void *addr)
73{
74 u32 *p = addr;
75 return le32_to_cpu(*p);
76}
77
78static inline void celleb_fake_config_writeb(u32 val, void *addr)
79{
80 u8 *p = addr;
81 *p = val;
82}
83
84static inline void celleb_fake_config_writew(u32 val, void *addr)
85{
86 u16 val16;
87 u16 *p = addr;
88 val16 = cpu_to_le16(val);
89 *p = val16;
90}
91
92static inline void celleb_fake_config_writel(u32 val, void *addr)
93{
94 u32 val32;
95 u32 *p = addr;
96 val32 = cpu_to_le32(val);
97 *p = val32;
98}
99
100static unsigned char *get_fake_config_start(struct pci_controller *hose,
101 int devno, int fn)
102{
103 struct celleb_pci_private *private = hose->private_data;
104
105 if (private == NULL)
106 return NULL;
107
108 return private->fake_config[devno][fn];
109}
110
111static struct celleb_pci_resource *get_resource_start(
112 struct pci_controller *hose,
113 int devno, int fn)
114{
115 struct celleb_pci_private *private = hose->private_data;
116
117 if (private == NULL)
118 return NULL;
119
120 return private->res[devno][fn];
121}
122
123
124static void celleb_config_read_fake(unsigned char *config, int where,
125 int size, u32 *val)
126{
127 char *p = config + where;
128
129 switch (size) {
130 case 1:
131 *val = celleb_fake_config_readb(p);
132 break;
133 case 2:
134 *val = celleb_fake_config_readw(p);
135 break;
136 case 4:
137 *val = celleb_fake_config_readl(p);
138 break;
139 }
140
141 return;
142}
143
144static void celleb_config_write_fake(unsigned char *config, int where,
145 int size, u32 val)
146{
147 char *p = config + where;
148
149 switch (size) {
150 case 1:
151 celleb_fake_config_writeb(val, p);
152 break;
153 case 2:
154 celleb_fake_config_writew(val, p);
155 break;
156 case 4:
157 celleb_fake_config_writel(val, p);
158 break;
159 }
160 return;
161}
162
163static int celleb_fake_pci_read_config(struct pci_bus *bus,
164 unsigned int devfn, int where, int size, u32 *val)
165{
166 char *config;
167 struct device_node *node;
168 struct pci_controller *hose;
169 unsigned int devno = devfn >> 3;
170 unsigned int fn = devfn & 0x7;
171
172 /* allignment check */
173 BUG_ON(where % size);
174
175 pr_debug(" fake read: bus=0x%x, ", bus->number);
176 node = (struct device_node *)bus->sysdata;
177 hose = pci_find_hose_for_OF_device(node);
178 config = get_fake_config_start(hose, devno, fn);
179
180 pr_debug("devno=0x%x, where=0x%x, size=0x%x, ", devno, where, size);
181 if (!config) {
182 pr_debug("failed\n");
183 return PCIBIOS_DEVICE_NOT_FOUND;
184 }
185
186 celleb_config_read_fake(config, where, size, val);
187 pr_debug("val=0x%x\n", *val);
188
189 return PCIBIOS_SUCCESSFUL;
190}
191
192
193static int celleb_fake_pci_write_config(struct pci_bus *bus,
194 unsigned int devfn, int where, int size, u32 val)
195{
196 char *config;
197 struct device_node *node;
198 struct pci_controller *hose;
199 struct celleb_pci_resource *res;
200 unsigned int devno = devfn >> 3;
201 unsigned int fn = devfn & 0x7;
202
203 /* allignment check */
204 BUG_ON(where % size);
205
206 node = (struct device_node *)bus->sysdata;
207 hose = pci_find_hose_for_OF_device(node);
208 config = get_fake_config_start(hose, devno, fn);
209
210 if (!config)
211 return PCIBIOS_DEVICE_NOT_FOUND;
212
213 if (val == ~0) {
214 int i = (where - PCI_BASE_ADDRESS_0) >> 3;
215
216 switch (where) {
217 case PCI_BASE_ADDRESS_0:
218 case PCI_BASE_ADDRESS_2:
219 if (size != 4)
220 return PCIBIOS_DEVICE_NOT_FOUND;
221 res = get_resource_start(hose, devno, fn);
222 if (!res)
223 return PCIBIOS_DEVICE_NOT_FOUND;
224 celleb_config_write_fake(config, where, size,
225 (res->r[i].end - res->r[i].start));
226 return PCIBIOS_SUCCESSFUL;
227 case PCI_BASE_ADDRESS_1:
228 case PCI_BASE_ADDRESS_3:
229 case PCI_BASE_ADDRESS_4:
230 case PCI_BASE_ADDRESS_5:
231 break;
232 default:
233 break;
234 }
235 }
236
237 celleb_config_write_fake(config, where, size, val);
238 pr_debug(" fake write: where=%x, size=%d, val=%x\n",
239 where, size, val);
240
241 return PCIBIOS_SUCCESSFUL;
242}
243
244static struct pci_ops celleb_fake_pci_ops = {
245 celleb_fake_pci_read_config,
246 celleb_fake_pci_write_config
247};
248
249static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose,
250 unsigned int devno, unsigned int fn,
251 unsigned int num_base_addr)
252{
253 u32 val;
254 unsigned char *config;
255 struct celleb_pci_resource *res;
256
257 config = get_fake_config_start(hose, devno, fn);
258 res = get_resource_start(hose, devno, fn);
259
260 if (!config || !res)
261 return;
262
263 switch (num_base_addr) {
264 case 3:
265 val = (res->r[2].start & 0xfffffff0)
266 | PCI_BASE_ADDRESS_MEM_TYPE_64;
267 celleb_config_write_fake(config, PCI_BASE_ADDRESS_4, 4, val);
268 val = res->r[2].start >> 32;
269 celleb_config_write_fake(config, PCI_BASE_ADDRESS_5, 4, val);
270 /* FALLTHROUGH */
271 case 2:
272 val = (res->r[1].start & 0xfffffff0)
273 | PCI_BASE_ADDRESS_MEM_TYPE_64;
274 celleb_config_write_fake(config, PCI_BASE_ADDRESS_2, 4, val);
275 val = res->r[1].start >> 32;
276 celleb_config_write_fake(config, PCI_BASE_ADDRESS_3, 4, val);
277 /* FALLTHROUGH */
278 case 1:
279 val = (res->r[0].start & 0xfffffff0)
280 | PCI_BASE_ADDRESS_MEM_TYPE_64;
281 celleb_config_write_fake(config, PCI_BASE_ADDRESS_0, 4, val);
282 val = res->r[0].start >> 32;
283 celleb_config_write_fake(config, PCI_BASE_ADDRESS_1, 4, val);
284 break;
285 }
286
287 val = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
288 celleb_config_write_fake(config, PCI_COMMAND, 2, val);
289}
290
291static int __devinit celleb_setup_fake_pci_device(struct device_node *node,
292 struct pci_controller *hose)
293{
294 unsigned int rlen;
295 int num_base_addr = 0;
296 u32 val;
297 const u32 *wi0, *wi1, *wi2, *wi3, *wi4;
298 unsigned int devno, fn;
299 struct celleb_pci_private *private = hose->private_data;
300 unsigned char **config = NULL;
301 struct celleb_pci_resource **res = NULL;
302 const char *name;
303 const unsigned long *li;
304 int size, result;
305
306 if (private == NULL) {
307 printk(KERN_ERR "PCI: "
308 "memory space for pci controller is not assigned\n");
309 goto error;
310 }
311
312 name = get_property(node, "model", &rlen);
313 if (!name) {
314 printk(KERN_ERR "PCI: model property not found.\n");
315 goto error;
316 }
317
318 wi4 = get_property(node, "reg", &rlen);
319 if (wi4 == NULL)
320 goto error;
321
322 devno = ((wi4[0] >> 8) & 0xff) >> 3;
323 fn = (wi4[0] >> 8) & 0x7;
324
325 pr_debug("PCI: celleb_setup_fake_pci() %s devno=%x fn=%x\n", name,
326 devno, fn);
327
328 size = 256;
329 config = &private->fake_config[devno][fn];
330 if (mem_init_done)
331 *config = kzalloc(size, GFP_KERNEL);
332 else
333 *config = alloc_bootmem(size);
334 if (*config == NULL) {
335 printk(KERN_ERR "PCI: "
336 "not enough memory for fake configuration space\n");
337 goto error;
338 }
339 pr_debug("PCI: fake config area assigned 0x%016lx\n",
340 (unsigned long)*config);
341
342 size = sizeof(struct celleb_pci_resource);
343 res = &private->res[devno][fn];
344 if (mem_init_done)
345 *res = kzalloc(size, GFP_KERNEL);
346 else
347 *res = alloc_bootmem(size);
348 if (*res == NULL) {
349 printk(KERN_ERR
350 "PCI: not enough memory for resource data space\n");
351 goto error;
352 }
353 pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res);
354
355 wi0 = get_property(node, "device-id", NULL);
356 wi1 = get_property(node, "vendor-id", NULL);
357 wi2 = get_property(node, "class-code", NULL);
358 wi3 = get_property(node, "revision-id", NULL);
359
360 celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff);
361 celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff);
362 pr_debug("class-code = 0x%08x\n", wi2[0]);
363
364 celleb_config_write_fake(*config, PCI_CLASS_PROG, 1, wi2[0] & 0xff);
365 celleb_config_write_fake(*config, PCI_CLASS_DEVICE, 2,
366 (wi2[0] >> 8) & 0xffff);
367 celleb_config_write_fake(*config, PCI_REVISION_ID, 1, wi3[0]);
368
369 while (num_base_addr < MAX_PCI_BASE_ADDRS) {
370 result = of_address_to_resource(node,
371 num_base_addr, &(*res)->r[num_base_addr]);
372 if (result)
373 break;
374 num_base_addr++;
375 }
376
377 celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr);
378
379 li = get_property(node, "interrupts", &rlen);
380 val = li[0];
381 celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1);
382 celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val);
383
384#ifdef DEBUG
385 pr_debug("PCI: %s irq=%ld\n", name, li[0]);
386 for (i = 0; i < 6; i++) {
387 celleb_config_read_fake(*config,
388 PCI_BASE_ADDRESS_0 + 0x4 * i, 4,
389 &val);
390 pr_debug("PCI: %s fn=%d base_address_%d=0x%x\n",
391 name, fn, i, val);
392 }
393#endif
394
395 celleb_config_write_fake(*config, PCI_HEADER_TYPE, 1,
396 PCI_HEADER_TYPE_NORMAL);
397
398 return 0;
399
400error:
401 if (mem_init_done) {
402 if (config && *config)
403 kfree(*config);
404 if (res && *res)
405 kfree(*res);
406
407 } else {
408 if (config && *config) {
409 size = 256;
410 free_bootmem((unsigned long)(*config), size);
411 }
412 if (res && *res) {
413 size = sizeof(struct celleb_pci_resource);
414 free_bootmem((unsigned long)(*res), size);
415 }
416 }
417
418 return 1;
419}
420
421static int __devinit phb_set_bus_ranges(struct device_node *dev,
422 struct pci_controller *phb)
423{
424 const int *bus_range;
425 unsigned int len;
426
427 bus_range = get_property(dev, "bus-range", &len);
428 if (bus_range == NULL || len < 2 * sizeof(int))
429 return 1;
430
431 phb->first_busno = bus_range[0];
432 phb->last_busno = bus_range[1];
433
434 return 0;
435}
436
437static void __devinit celleb_alloc_private_mem(struct pci_controller *hose)
438{
439 if (mem_init_done)
440 hose->private_data =
441 kzalloc(sizeof(struct celleb_pci_private), GFP_KERNEL);
442 else
443 hose->private_data =
444 alloc_bootmem(sizeof(struct celleb_pci_private));
445}
446
447int __devinit celleb_setup_phb(struct pci_controller *phb)
448{
449 const char *name;
450 struct device_node *dev = phb->arch_data;
451 struct device_node *node;
452 unsigned int rlen;
453
454 name = get_property(dev, "name", &rlen);
455 if (!name)
456 return 1;
457
458 pr_debug("PCI: celleb_setup_phb() %s\n", name);
459 phb_set_bus_ranges(dev, phb);
460
461 if (strcmp(name, "epci") == 0) {
462 phb->ops = &celleb_epci_ops;
463 return celleb_setup_epci(dev, phb);
464
465 } else if (strcmp(name, "pci-pseudo") == 0) {
466 phb->ops = &celleb_fake_pci_ops;
467 celleb_alloc_private_mem(phb);
468 for (node = of_get_next_child(dev, NULL);
469 node != NULL; node = of_get_next_child(dev, node))
470 celleb_setup_fake_pci_device(node, phb);
471
472 } else
473 return 1;
474
475 return 0;
476}
477
478int celleb_pci_probe_mode(struct pci_bus *bus)
479{
480 return PCI_PROBE_DEVTREE;
481}
diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/celleb/pci.h
new file mode 100644
index 000000000000..5340e348e297
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/pci.h
@@ -0,0 +1,35 @@
1/*
2 * pci prototypes for Celleb platform
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#ifndef _CELLEB_PCI_H
22#define _CELLEB_PCI_H
23
24#include <linux/pci.h>
25
26#include <asm/pci-bridge.h>
27#include <asm/prom.h>
28
29extern int celleb_setup_phb(struct pci_controller *);
30extern int celleb_pci_probe_mode(struct pci_bus *);
31
32extern struct pci_ops celleb_epci_ops;
33extern int celleb_setup_epci(struct device_node *, struct pci_controller *);
34
35#endif /* _CELLEB_PCI_H */
diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/celleb/scc.h
new file mode 100644
index 000000000000..e9ce8a7c1882
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc.h
@@ -0,0 +1,145 @@
1/*
2 * SCC (Super Companion Chip) definitions
3 *
4 * (C) Copyright 2004-2006 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#ifndef _CELLEB_SCC_H
22#define _CELLEB_SCC_H
23
24#define PCI_VENDOR_ID_TOSHIBA_2 0x102f
25#define PCI_DEVICE_ID_TOSHIBA_SCC_PCIEXC_BRIDGE 0x01b0
26#define PCI_DEVICE_ID_TOSHIBA_SCC_EPCI_BRIDGE 0x01b1
27#define PCI_DEVICE_ID_TOSHIBA_SCC_BRIDGE 0x01b2
28#define PCI_DEVICE_ID_TOSHIBA_SCC_GBE 0x01b3
29#define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4
30#define PCI_DEVICE_ID_TOSHIBA_SCC_USB2 0x01b5
31#define PCI_DEVICE_ID_TOSHIBA_SCC_USB 0x01b6
32#define PCI_DEVICE_ID_TOSHIBA_SCC_ENCDEC 0x01b7
33
34#define SCC_EPCI_REG 0x0000d000
35
36/* EPCI registers */
37#define SCC_EPCI_CNF10_REG 0x010
38#define SCC_EPCI_CNF14_REG 0x014
39#define SCC_EPCI_CNF18_REG 0x018
40#define SCC_EPCI_PVBAT 0x100
41#define SCC_EPCI_VPMBAT 0x104
42#define SCC_EPCI_VPIBAT 0x108
43#define SCC_EPCI_VCSR 0x110
44#define SCC_EPCI_VIENAB 0x114
45#define SCC_EPCI_VISTAT 0x118
46#define SCC_EPCI_VRDCOUNT 0x124
47#define SCC_EPCI_BAM0 0x12c
48#define SCC_EPCI_BAM1 0x134
49#define SCC_EPCI_BAM2 0x13c
50#define SCC_EPCI_IADR 0x164
51#define SCC_EPCI_CLKRST 0x800
52#define SCC_EPCI_INTSET 0x804
53#define SCC_EPCI_STATUS 0x808
54#define SCC_EPCI_ABTSET 0x80c
55#define SCC_EPCI_WATRP 0x810
56#define SCC_EPCI_DUMMYRADR 0x814
57#define SCC_EPCI_SWRESP 0x818
58#define SCC_EPCI_CNTOPT 0x81c
59#define SCC_EPCI_ECMODE 0xf00
60#define SCC_EPCI_IOM_AC_NUM 5
61#define SCC_EPCI_IOM_ACTE(n) (0xf10 + (n) * 4)
62#define SCC_EPCI_IOT_AC_NUM 4
63#define SCC_EPCI_IOT_ACTE(n) (0xf30 + (n) * 4)
64#define SCC_EPCI_MAEA 0xf50
65#define SCC_EPCI_MAEC 0xf54
66#define SCC_EPCI_CKCTRL 0xff0
67
68/* bits for SCC_EPCI_VCSR */
69#define SCC_EPCI_VCSR_FRE 0x00020000
70#define SCC_EPCI_VCSR_FWE 0x00010000
71#define SCC_EPCI_VCSR_DR 0x00000400
72#define SCC_EPCI_VCSR_SR 0x00000008
73#define SCC_EPCI_VCSR_AT 0x00000004
74
75/* bits for SCC_EPCI_VIENAB/SCC_EPCI_VISTAT */
76#define SCC_EPCI_VISTAT_PMPE 0x00000008
77#define SCC_EPCI_VISTAT_PMFE 0x00000004
78#define SCC_EPCI_VISTAT_PRA 0x00000002
79#define SCC_EPCI_VISTAT_PRD 0x00000001
80#define SCC_EPCI_VISTAT_ALL 0x0000000f
81
82#define SCC_EPCI_VIENAB_PMPEE 0x00000008
83#define SCC_EPCI_VIENAB_PMFEE 0x00000004
84#define SCC_EPCI_VIENAB_PRA 0x00000002
85#define SCC_EPCI_VIENAB_PRD 0x00000001
86#define SCC_EPCI_VIENAB_ALL 0x0000000f
87
88/* bits for SCC_EPCI_CLKRST */
89#define SCC_EPCI_CLKRST_CKS_MASK 0x00030000
90#define SCC_EPCI_CLKRST_CKS_2 0x00000000
91#define SCC_EPCI_CLKRST_CKS_4 0x00010000
92#define SCC_EPCI_CLKRST_CKS_8 0x00020000
93#define SCC_EPCI_CLKRST_PCICRST 0x00000400
94#define SCC_EPCI_CLKRST_BC 0x00000200
95#define SCC_EPCI_CLKRST_PCIRST 0x00000100
96#define SCC_EPCI_CLKRST_PCKEN 0x00000001
97
98/* bits for SCC_EPCI_INTSET/SCC_EPCI_STATUS */
99#define SCC_EPCI_INT_2M 0x01000000
100#define SCC_EPCI_INT_RERR 0x00200000
101#define SCC_EPCI_INT_SERR 0x00100000
102#define SCC_EPCI_INT_PRTER 0x00080000
103#define SCC_EPCI_INT_SER 0x00040000
104#define SCC_EPCI_INT_PER 0x00020000
105#define SCC_EPCI_INT_PAI 0x00010000
106#define SCC_EPCI_INT_1M 0x00000100
107#define SCC_EPCI_INT_PME 0x00000010
108#define SCC_EPCI_INT_INTD 0x00000008
109#define SCC_EPCI_INT_INTC 0x00000004
110#define SCC_EPCI_INT_INTB 0x00000002
111#define SCC_EPCI_INT_INTA 0x00000001
112#define SCC_EPCI_INT_DEVINT 0x0000000f
113#define SCC_EPCI_INT_ALL 0x003f001f
114#define SCC_EPCI_INT_ALLERR 0x003f0000
115
116/* bits for SCC_EPCI_CKCTRL */
117#define SCC_EPCI_CKCTRL_CRST0 0x00010000
118#define SCC_EPCI_CKCTRL_CRST1 0x00020000
119#define SCC_EPCI_CKCTRL_OCLKEN 0x00000100
120#define SCC_EPCI_CKCTRL_LCLKEN 0x00000001
121
122#define SCC_EPCI_IDSEL_AD_TO_SLOT(ad) ((ad) - 10)
123#define SCC_EPCI_MAX_DEVNU SCC_EPCI_IDSEL_AD_TO_SLOT(32)
124
125/* bits for SCC_EPCI_CNTOPT */
126#define SCC_EPCI_CNTOPT_O2PMB 0x00000002
127
128/* UHC registers */
129#define SCC_UHC_CKRCTRL 0xff0
130#define SCC_UHC_ECMODE 0xf00
131
132/* bits for SCC_UHC_CKRCTRL */
133#define SCC_UHC_F48MCKLEN 0x00000001
134#define SCC_UHC_P_SUSPEND 0x00000002
135#define SCC_UHC_PHY_SUSPEND_SEL 0x00000004
136#define SCC_UHC_HCLKEN 0x00000100
137#define SCC_UHC_USBEN 0x00010000
138#define SCC_UHC_USBCEN 0x00020000
139#define SCC_UHC_PHYEN 0x00040000
140
141/* bits for SCC_UHC_ECMODE */
142#define SCC_UHC_ECMODE_BY_BYTE 0x00000555
143#define SCC_UHC_ECMODE_BY_WORD 0x00000aaa
144
145#endif /* _CELLEB_SCC_H */
diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c
new file mode 100644
index 000000000000..0edbc0c4f338
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc_epci.c
@@ -0,0 +1,409 @@
1/*
2 * Support for SCC external PCI
3 *
4 * (C) Copyright 2004-2007 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#undef DEBUG
22
23#include <linux/kernel.h>
24#include <linux/threads.h>
25#include <linux/pci.h>
26#include <linux/init.h>
27#include <linux/pci_regs.h>
28#include <linux/bootmem.h>
29
30#include <asm/io.h>
31#include <asm/irq.h>
32#include <asm/prom.h>
33#include <asm/machdep.h>
34#include <asm/pci-bridge.h>
35#include <asm/ppc-pci.h>
36
37#include "scc.h"
38#include "pci.h"
39#include "interrupt.h"
40
41#define MAX_PCI_DEVICES 32
42#define MAX_PCI_FUNCTIONS 8
43
44#define iob() __asm__ __volatile__("eieio; sync":::"memory")
45
46
47#if 0 /* test code for epci dummy read */
48static void celleb_epci_dummy_read(struct pci_dev *dev)
49{
50 void *epci_base;
51 struct device_node *node;
52 struct pci_controller *hose;
53 u32 val;
54
55 node = (struct device_node *)dev->bus->sysdata;
56 hose = pci_find_hose_for_OF_device(node);
57
58 if (!hose)
59 return;
60
61 epci_base = (void *)hose->cfg_addr;
62
63 val = in_be32(epci_base + SCC_EPCI_WATRP);
64 iosync();
65
66 return;
67}
68#endif
69
70static inline void clear_and_disable_master_abort_interrupt(
71 struct pci_controller *hose)
72{
73 void __iomem *addr;
74 addr = (void *)hose->cfg_addr + PCI_COMMAND;
75 out_be32(addr, in_be32(addr) | (PCI_STATUS_REC_MASTER_ABORT << 16));
76}
77
78static int celleb_epci_check_abort(struct pci_controller *hose,
79 unsigned long addr)
80{
81 void __iomem *reg, *epci_base;
82 u32 val;
83
84 iob();
85 epci_base = (void *)hose->cfg_addr;
86
87 reg = epci_base + PCI_COMMAND;
88 val = in_be32(reg);
89
90 if (val & (PCI_STATUS_REC_MASTER_ABORT << 16)) {
91 out_be32(reg,
92 (val & 0xffff) | (PCI_STATUS_REC_MASTER_ABORT << 16));
93
94 /* clear PCI Controller error, FRE, PMFE */
95 reg = epci_base + SCC_EPCI_STATUS;
96 out_be32(reg, SCC_EPCI_INT_PAI);
97
98 reg = epci_base + SCC_EPCI_VCSR;
99 val = in_be32(reg) & 0xffff;
100 val |= SCC_EPCI_VCSR_FRE;
101 out_be32(reg, val);
102
103 reg = epci_base + SCC_EPCI_VISTAT;
104 out_be32(reg, SCC_EPCI_VISTAT_PMFE);
105 return PCIBIOS_DEVICE_NOT_FOUND;
106 }
107
108 return PCIBIOS_SUCCESSFUL;
109}
110
111static unsigned long celleb_epci_make_config_addr(struct pci_controller *hose,
112 unsigned int devfn, int where)
113{
114 unsigned long addr;
115 struct pci_bus *bus = hose->bus;
116
117 if (bus->self)
118 addr = (unsigned long)hose->cfg_data +
119 (((bus->number & 0xff) << 16)
120 | ((devfn & 0xff) << 8)
121 | (where & 0xff)
122 | 0x01000000);
123 else
124 addr = (unsigned long)hose->cfg_data +
125 (((devfn & 0xff) << 8) | (where & 0xff));
126
127 pr_debug("EPCI: config_addr = 0x%016lx\n", addr);
128
129 return addr;
130}
131
132static int celleb_epci_read_config(struct pci_bus *bus,
133 unsigned int devfn, int where, int size, u32 * val)
134{
135 unsigned long addr;
136 struct device_node *node;
137 struct pci_controller *hose;
138
139 /* allignment check */
140 BUG_ON(where % size);
141
142 node = (struct device_node *)bus->sysdata;
143 hose = pci_find_hose_for_OF_device(node);
144
145 if (!hose->cfg_data)
146 return PCIBIOS_DEVICE_NOT_FOUND;
147
148 if (bus->number == hose->first_busno && devfn == 0) {
149 /* EPCI controller self */
150
151 addr = (unsigned long)hose->cfg_addr + where;
152
153 switch (size) {
154 case 1:
155 *val = in_8((u8 *)addr);
156 break;
157 case 2:
158 *val = in_be16((u16 *)addr);
159 break;
160 case 4:
161 *val = in_be32((u32 *)addr);
162 break;
163 default:
164 return PCIBIOS_DEVICE_NOT_FOUND;
165 }
166
167 } else {
168
169 clear_and_disable_master_abort_interrupt(hose);
170 addr = celleb_epci_make_config_addr(hose, devfn, where);
171
172 switch (size) {
173 case 1:
174 *val = in_8((u8 *)addr);
175 break;
176 case 2:
177 *val = in_le16((u16 *)addr);
178 break;
179 case 4:
180 *val = in_le32((u32 *)addr);
181 break;
182 default:
183 return PCIBIOS_DEVICE_NOT_FOUND;
184 }
185 }
186
187 pr_debug("EPCI: "
188 "addr=0x%lx, devfn=0x%x, where=0x%x, size=0x%x, val=0x%x\n",
189 addr, devfn, where, size, *val);
190
191 return celleb_epci_check_abort(hose, 0);
192}
193
194static int celleb_epci_write_config(struct pci_bus *bus,
195 unsigned int devfn, int where, int size, u32 val)
196{
197 unsigned long addr;
198 struct device_node *node;
199 struct pci_controller *hose;
200
201 /* allignment check */
202 BUG_ON(where % size);
203
204 node = (struct device_node *)bus->sysdata;
205 hose = pci_find_hose_for_OF_device(node);
206
207 if (!hose->cfg_data)
208 return PCIBIOS_DEVICE_NOT_FOUND;
209
210 if (bus->number == hose->first_busno && devfn == 0) {
211 /* EPCI controller self */
212
213 addr = (unsigned long)hose->cfg_addr + where;
214
215 switch (size) {
216 case 1:
217 out_8((u8 *)addr, val);
218 break;
219 case 2:
220 out_be16((u16 *)addr, val);
221 break;
222 case 4:
223 out_be32((u32 *)addr, val);
224 break;
225 default:
226 return PCIBIOS_DEVICE_NOT_FOUND;
227 }
228
229 } else {
230
231 clear_and_disable_master_abort_interrupt(hose);
232 addr = celleb_epci_make_config_addr(hose, devfn, where);
233
234 switch (size) {
235 case 1:
236 out_8((u8 *)addr, val);
237 break;
238 case 2:
239 out_le16((u16 *)addr, val);
240 break;
241 case 4:
242 out_le32((u32 *)addr, val);
243 break;
244 default:
245 return PCIBIOS_DEVICE_NOT_FOUND;
246 }
247 }
248
249 return celleb_epci_check_abort(hose, addr);
250}
251
252struct pci_ops celleb_epci_ops = {
253 celleb_epci_read_config,
254 celleb_epci_write_config,
255};
256
257/* to be moved in FW */
258static int __devinit celleb_epci_init(struct pci_controller *hose)
259{
260 u32 val;
261 void __iomem *reg, *epci_base;
262 int hwres = 0;
263
264 epci_base = (void *)hose->cfg_addr;
265
266 /* PCI core reset(Internal bus and PCI clock) */
267 reg = epci_base + SCC_EPCI_CKCTRL;
268 val = in_be32(reg);
269 if (val == 0x00030101)
270 hwres = 1;
271 else {
272 val &= ~(SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1);
273 out_be32(reg, val);
274
275 /* set PCI core clock */
276 val = in_be32(reg);
277 val |= (SCC_EPCI_CKCTRL_OCLKEN | SCC_EPCI_CKCTRL_LCLKEN);
278 out_be32(reg, val);
279
280 /* release PCI core reset (internal bus) */
281 val = in_be32(reg);
282 val |= SCC_EPCI_CKCTRL_CRST0;
283 out_be32(reg, val);
284
285 /* set PCI clock select */
286 reg = epci_base + SCC_EPCI_CLKRST;
287 val = in_be32(reg);
288 val &= ~SCC_EPCI_CLKRST_CKS_MASK;
289 val |= SCC_EPCI_CLKRST_CKS_2;
290 out_be32(reg, val);
291
292 /* set arbiter */
293 reg = epci_base + SCC_EPCI_ABTSET;
294 out_be32(reg, 0x0f1f001f); /* temporary value */
295
296 /* buffer on */
297 reg = epci_base + SCC_EPCI_CLKRST;
298 val = in_be32(reg);
299 val |= SCC_EPCI_CLKRST_BC;
300 out_be32(reg, val);
301
302 /* PCI clock enable */
303 val = in_be32(reg);
304 val |= SCC_EPCI_CLKRST_PCKEN;
305 out_be32(reg, val);
306
307 /* release PCI core reset (all) */
308 reg = epci_base + SCC_EPCI_CKCTRL;
309 val = in_be32(reg);
310 val |= (SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1);
311 out_be32(reg, val);
312
313 /* set base translation registers. (already set by Beat) */
314
315 /* set base address masks. (already set by Beat) */
316 }
317
318 /* release interrupt masks and clear all interrupts */
319 reg = epci_base + SCC_EPCI_INTSET;
320 out_be32(reg, 0x013f011f); /* all interrupts enable */
321 reg = epci_base + SCC_EPCI_VIENAB;
322 val = SCC_EPCI_VIENAB_PMPEE | SCC_EPCI_VIENAB_PMFEE;
323 out_be32(reg, val);
324 reg = epci_base + SCC_EPCI_STATUS;
325 out_be32(reg, 0xffffffff);
326 reg = epci_base + SCC_EPCI_VISTAT;
327 out_be32(reg, 0xffffffff);
328
329 /* disable PCI->IB address translation */
330 reg = epci_base + SCC_EPCI_VCSR;
331 val = in_be32(reg);
332 val &= ~(SCC_EPCI_VCSR_DR | SCC_EPCI_VCSR_AT);
333 out_be32(reg, val);
334
335 /* set base addresses. (no need to set?) */
336
337 /* memory space, bus master enable */
338 reg = epci_base + PCI_COMMAND;
339 val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
340 out_be32(reg, val);
341
342 /* endian mode setup */
343 reg = epci_base + SCC_EPCI_ECMODE;
344 val = 0x00550155;
345 out_be32(reg, val);
346
347 /* set control option */
348 reg = epci_base + SCC_EPCI_CNTOPT;
349 val = in_be32(reg);
350 val |= SCC_EPCI_CNTOPT_O2PMB;
351 out_be32(reg, val);
352
353 /* XXX: temporay: set registers for address conversion setup */
354 reg = epci_base + SCC_EPCI_CNF10_REG;
355 out_be32(reg, 0x80000008);
356 reg = epci_base + SCC_EPCI_CNF14_REG;
357 out_be32(reg, 0x40000008);
358
359 reg = epci_base + SCC_EPCI_BAM0;
360 out_be32(reg, 0x80000000);
361 reg = epci_base + SCC_EPCI_BAM1;
362 out_be32(reg, 0xe0000000);
363
364 reg = epci_base + SCC_EPCI_PVBAT;
365 out_be32(reg, 0x80000000);
366
367 if (!hwres) {
368 /* release external PCI reset */
369 reg = epci_base + SCC_EPCI_CLKRST;
370 val = in_be32(reg);
371 val |= SCC_EPCI_CLKRST_PCIRST;
372 out_be32(reg, val);
373 }
374
375 return 0;
376}
377
378int __devinit celleb_setup_epci(struct device_node *node,
379 struct pci_controller *hose)
380{
381 struct resource r;
382
383 pr_debug("PCI: celleb_setup_epci()\n");
384
385 if (of_address_to_resource(node, 0, &r))
386 goto error;
387 hose->cfg_addr = ioremap(r.start, (r.end - r.start + 1));
388 if (!hose->cfg_addr)
389 goto error;
390 pr_debug("EPCI: cfg_addr map 0x%016lx->0x%016lx + 0x%016lx\n",
391 r.start, (unsigned long)hose->cfg_addr,
392 (r.end - r.start + 1));
393
394 if (of_address_to_resource(node, 2, &r))
395 goto error;
396 hose->cfg_data = ioremap(r.start, (r.end - r.start + 1));
397 if (!hose->cfg_data)
398 goto error;
399 pr_debug("EPCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n",
400 r.start, (unsigned long)hose->cfg_data,
401 (r.end - r.start + 1));
402
403 celleb_epci_init(hose);
404
405 return 0;
406
407error:
408 return 1;
409}
diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/celleb/scc_sio.c
new file mode 100644
index 000000000000..bcd25f54d986
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc_sio.c
@@ -0,0 +1,101 @@
1/*
2 * setup serial port in SCC
3 *
4 * (C) Copyright 2006 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <linux/tty.h>
22#include <linux/serial.h>
23#include <linux/serial_core.h>
24#include <linux/console.h>
25
26#include <asm/io.h>
27#include <asm/prom.h>
28
29/* sio irq0=0xb00010022 irq0=0xb00010023 irq2=0xb00010024
30 mmio=0xfff000-0x1000,0xff2000-0x1000 */
31static int txx9_serial_bitmap = 0;
32
33static struct {
34 uint32_t offset;
35 uint32_t index;
36} txx9_scc_tab[3] = {
37 { 0x300, 0 }, /* 0xFFF300 */
38 { 0x400, 0 }, /* 0xFFF400 */
39 { 0x800, 1 } /* 0xFF2800 */
40};
41
42static int txx9_serial_init(void)
43{
44 extern int early_serial_txx9_setup(struct uart_port *port);
45 struct device_node *node;
46 int i;
47 struct uart_port req;
48 struct of_irq irq;
49 struct resource res;
50
51 node = of_find_node_by_path("/ioif1/sio");
52 if (!node)
53 return 0;
54
55 for(i = 0; i < sizeof(txx9_scc_tab)/sizeof(txx9_scc_tab[0]); i++) {
56 if (!(txx9_serial_bitmap & (1<<i)))
57 continue;
58
59 if (of_irq_map_one(node, i, &irq))
60 continue;
61 if (of_address_to_resource(node, txx9_scc_tab[i].index, &res))
62 continue;
63
64 memset(&req, 0, sizeof(req));
65 req.line = i;
66 req.iotype = UPIO_MEM;
67 req.mapbase = res.start + txx9_scc_tab[i].offset;
68#ifdef CONFIG_SERIAL_TXX9_CONSOLE
69 req.membase = ioremap(req.mapbase, 0x24);
70#endif
71 req.irq = irq_create_of_mapping(irq.controller,
72 irq.specifier, irq.size);
73 req.flags |= UPF_IOREMAP | UPF_BUGGY_UART /*HAVE_CTS_LINE*/;
74 req.uartclk = 83300000;
75 early_serial_txx9_setup(&req);
76 }
77
78 of_node_put(node);
79 return 0;
80}
81
82static int txx9_serial_config(char *ptr)
83{
84 int i;
85
86 for (;;) {
87 switch(get_option(&ptr, &i)) {
88 default:
89 return 0;
90 case 2:
91 txx9_serial_bitmap |= 1 << i;
92 break;
93 case 1:
94 txx9_serial_bitmap |= 1 << i;
95 return 0;
96 }
97 }
98}
99__setup("txx9_serial=", txx9_serial_config);
100
101console_initcall(txx9_serial_init);
diff --git a/arch/powerpc/platforms/celleb/scc_uhc.c b/arch/powerpc/platforms/celleb/scc_uhc.c
new file mode 100644
index 000000000000..a7c548bde2e3
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/scc_uhc.c
@@ -0,0 +1,94 @@
1/*
2 * SCC (Super Companion Chip) UHC setup
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <linux/kernel.h>
22#include <linux/pci.h>
23
24#include <asm/delay.h>
25#include <asm/io.h>
26#include <asm/machdep.h>
27
28#include "scc.h"
29
30#define UHC_RESET_WAIT_MAX 10000
31
32static inline int uhc_clkctrl_ready(u32 val)
33{
34 const u32 mask = SCC_UHC_USBCEN | SCC_UHC_USBCEN;
35 return((val & mask) == mask);
36}
37
38/*
39 * UHC(usb host controler) enable function.
40 * affect to both of OHCI and EHCI core module.
41 */
42static void enable_scc_uhc(struct pci_dev *dev)
43{
44 void __iomem *uhc_base;
45 u32 __iomem *uhc_clkctrl;
46 u32 __iomem *uhc_ecmode;
47 u32 val = 0;
48 int i;
49
50 if (!machine_is(celleb))
51 return;
52
53 uhc_base = ioremap(pci_resource_start(dev, 0),
54 pci_resource_len(dev, 0));
55 if (!uhc_base) {
56 printk(KERN_ERR "failed to map UHC register base.\n");
57 return;
58 }
59 uhc_clkctrl = uhc_base + SCC_UHC_CKRCTRL;
60 uhc_ecmode = uhc_base + SCC_UHC_ECMODE;
61
62 /* setup for normal mode */
63 val |= SCC_UHC_F48MCKLEN;
64 out_be32(uhc_clkctrl, val);
65 val |= SCC_UHC_PHY_SUSPEND_SEL;
66 out_be32(uhc_clkctrl, val);
67 udelay(10);
68 val |= SCC_UHC_PHYEN;
69 out_be32(uhc_clkctrl, val);
70 udelay(50);
71
72 /* disable reset */
73 val |= SCC_UHC_HCLKEN;
74 out_be32(uhc_clkctrl, val);
75 val |= (SCC_UHC_USBCEN | SCC_UHC_USBEN);
76 out_be32(uhc_clkctrl, val);
77 i = 0;
78 while (!uhc_clkctrl_ready(in_be32(uhc_clkctrl))) {
79 udelay(10);
80 if (i++ > UHC_RESET_WAIT_MAX) {
81 printk(KERN_ERR "Failed to disable UHC reset %x\n",
82 in_be32(uhc_clkctrl));
83 break;
84 }
85 }
86
87 /* Endian Conversion Mode for Master ALL area */
88 out_be32(uhc_ecmode, SCC_UHC_ECMODE_BY_BYTE);
89
90 iounmap(uhc_base);
91}
92
93DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
94 PCI_DEVICE_ID_TOSHIBA_SCC_USB, enable_scc_uhc);
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c
new file mode 100644
index 000000000000..1de63acfda87
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/setup.c
@@ -0,0 +1,191 @@
1/*
2 * Celleb setup code
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This code is based on arch/powerpc/platforms/cell/setup.c:
7 * Copyright (C) 1995 Linus Torvalds
8 * Adapted from 'alpha' version by Gary Thomas
9 * Modified by Cort Dougan (cort@cs.nmt.edu)
10 * Modified by PPC64 Team, IBM Corp
11 * Modified by Cell Team, IBM Deutschland Entwicklung GmbH
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 */
27
28#undef DEBUG
29
30#include <linux/cpu.h>
31#include <linux/sched.h>
32#include <linux/kernel.h>
33#include <linux/mm.h>
34#include <linux/stddef.h>
35#include <linux/unistd.h>
36#include <linux/reboot.h>
37#include <linux/init.h>
38#include <linux/delay.h>
39#include <linux/irq.h>
40#include <linux/seq_file.h>
41#include <linux/root_dev.h>
42#include <linux/console.h>
43
44#include <asm/mmu.h>
45#include <asm/processor.h>
46#include <asm/io.h>
47#include <asm/kexec.h>
48#include <asm/prom.h>
49#include <asm/machdep.h>
50#include <asm/cputable.h>
51#include <asm/irq.h>
52#include <asm/spu_priv1.h>
53#include <asm/firmware.h>
54#include <asm/of_platform.h>
55
56#include "interrupt.h"
57#include "beat_wrapper.h"
58#include "beat.h"
59#include "pci.h"
60
61static char celleb_machine_type[128] = "Celleb";
62
63static void celleb_show_cpuinfo(struct seq_file *m)
64{
65 struct device_node *root;
66 const char *model = "";
67
68 root = of_find_node_by_path("/");
69 if (root)
70 model = get_property(root, "model", NULL);
71 /* using "CHRP" is to trick anaconda into installing FCx into Celleb */
72 seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model);
73 of_node_put(root);
74}
75
76static int celleb_machine_type_hack(char *ptr)
77{
78 strncpy(celleb_machine_type, ptr, sizeof(celleb_machine_type));
79 celleb_machine_type[sizeof(celleb_machine_type)-1] = 0;
80 return 0;
81}
82
83__setup("celleb_machine_type_hack", celleb_machine_type_hack);
84
85static void celleb_progress(char *s, unsigned short hex)
86{
87 printk("*** %04x : %s\n", hex, s ? s : "");
88}
89
90static void __init celleb_setup_arch(void)
91{
92#ifdef CONFIG_SPU_BASE
93 spu_priv1_ops = &spu_priv1_beat_ops;
94 spu_management_ops = &spu_management_of_ops;
95#endif
96
97#ifdef CONFIG_SMP
98 smp_init_celleb();
99#endif
100
101 /* init to some ~sane value until calibrate_delay() runs */
102 loops_per_jiffy = 50000000;
103
104 if (ROOT_DEV == 0) {
105 printk("No ramdisk, default root is /dev/hda2\n");
106 ROOT_DEV = Root_HDA2;
107 }
108
109#ifdef CONFIG_DUMMY_CONSOLE
110 conswitchp = &dummy_con;
111#endif
112}
113
114static void beat_power_save(void)
115{
116 beat_pause(0);
117}
118
119static int __init celleb_probe(void)
120{
121 unsigned long root = of_get_flat_dt_root();
122
123 if (!of_flat_dt_is_compatible(root, "Beat"))
124 return 0;
125
126 powerpc_firmware_features |= FW_FEATURE_CELLEB_POSSIBLE;
127 hpte_init_beat();
128 return 1;
129}
130
131/*
132 * Cell has no legacy IO; anything calling this function has to
133 * fail or bad things will happen
134 */
135static int celleb_check_legacy_ioport(unsigned int baseport)
136{
137 return -ENODEV;
138}
139
140static void celleb_kexec_cpu_down(int crash, int secondary)
141{
142 beatic_deinit_IRQ();
143}
144
145static struct of_device_id celleb_bus_ids[] = {
146 { .type = "scc", },
147 { .type = "ioif", }, /* old style */
148 {},
149};
150
151static int __init celleb_publish_devices(void)
152{
153 if (!machine_is(celleb))
154 return 0;
155
156 /* Publish OF platform devices for southbridge IOs */
157 of_platform_bus_probe(NULL, celleb_bus_ids, NULL);
158
159 return 0;
160}
161device_initcall(celleb_publish_devices);
162
163define_machine(celleb) {
164 .name = "Cell Reference Set",
165 .probe = celleb_probe,
166 .setup_arch = celleb_setup_arch,
167 .show_cpuinfo = celleb_show_cpuinfo,
168 .restart = beat_restart,
169 .power_off = beat_power_off,
170 .halt = beat_halt,
171 .get_rtc_time = beat_get_rtc_time,
172 .set_rtc_time = beat_set_rtc_time,
173 .calibrate_decr = generic_calibrate_decr,
174 .check_legacy_ioport = celleb_check_legacy_ioport,
175 .progress = celleb_progress,
176 .power_save = beat_power_save,
177 .nvram_size = beat_nvram_get_size,
178 .nvram_read = beat_nvram_read,
179 .nvram_write = beat_nvram_write,
180 .set_dabr = beat_set_xdabr,
181 .init_IRQ = beatic_init_IRQ,
182 .get_irq = beatic_get_irq,
183 .pci_probe_mode = celleb_pci_probe_mode,
184 .pci_setup_phb = celleb_setup_phb,
185#ifdef CONFIG_KEXEC
186 .kexec_cpu_down = celleb_kexec_cpu_down,
187 .machine_kexec = default_machine_kexec,
188 .machine_kexec_prepare = default_machine_kexec_prepare,
189 .machine_crash_shutdown = default_machine_crash_shutdown,
190#endif
191};
diff --git a/arch/powerpc/platforms/celleb/smp.c b/arch/powerpc/platforms/celleb/smp.c
new file mode 100644
index 000000000000..a7631250aeb4
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/smp.c
@@ -0,0 +1,124 @@
1/*
2 * SMP support for Celleb platform. (Incomplete)
3 *
4 * (C) Copyright 2006 TOSHIBA CORPORATION
5 *
6 * This code is based on arch/powerpc/platforms/cell/smp.c:
7 * Dave Engebretsen, Peter Bergner, and
8 * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com
9 * Plus various changes from other IBM teams...
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26#undef DEBUG
27
28#include <linux/kernel.h>
29#include <linux/smp.h>
30#include <linux/interrupt.h>
31#include <linux/init.h>
32#include <linux/threads.h>
33#include <linux/cpu.h>
34
35#include <asm/irq.h>
36#include <asm/smp.h>
37#include <asm/machdep.h>
38#include <asm/udbg.h>
39
40#include "interrupt.h"
41
42#ifdef DEBUG
43#define DBG(fmt...) udbg_printf(fmt)
44#else
45#define DBG(fmt...)
46#endif
47
48/*
49 * The primary thread of each non-boot processor is recorded here before
50 * smp init.
51 */
52/* static cpumask_t of_spin_map; */
53
54/**
55 * smp_startup_cpu() - start the given cpu
56 *
57 * At boot time, there is nothing to do for primary threads which were
58 * started from Open Firmware. For anything else, call RTAS with the
59 * appropriate start location.
60 *
61 * Returns:
62 * 0 - failure
63 * 1 - success
64 */
65static inline int __devinit smp_startup_cpu(unsigned int lcpu)
66{
67 return 0;
68}
69
70static void smp_beatic_message_pass(int target, int msg)
71{
72 unsigned int i;
73
74 if (target < NR_CPUS) {
75 beatic_cause_IPI(target, msg);
76 } else {
77 for_each_online_cpu(i) {
78 if (target == MSG_ALL_BUT_SELF
79 && i == smp_processor_id())
80 continue;
81 beatic_cause_IPI(i, msg);
82 }
83 }
84}
85
86static int __init smp_beatic_probe(void)
87{
88 return cpus_weight(cpu_possible_map);
89}
90
91static void __devinit smp_beatic_setup_cpu(int cpu)
92{
93 beatic_setup_cpu(cpu);
94}
95
96static void __devinit smp_celleb_kick_cpu(int nr)
97{
98 BUG_ON(nr < 0 || nr >= NR_CPUS);
99
100 if (!smp_startup_cpu(nr))
101 return;
102}
103
104static int smp_celleb_cpu_bootable(unsigned int nr)
105{
106 return 1;
107}
108static struct smp_ops_t bpa_beatic_smp_ops = {
109 .message_pass = smp_beatic_message_pass,
110 .probe = smp_beatic_probe,
111 .kick_cpu = smp_celleb_kick_cpu,
112 .setup_cpu = smp_beatic_setup_cpu,
113 .cpu_bootable = smp_celleb_cpu_bootable,
114};
115
116/* This is called very early */
117void __init smp_init_celleb(void)
118{
119 DBG(" -> smp_init_celleb()\n");
120
121 smp_ops = &bpa_beatic_smp_ops;
122
123 DBG(" <- smp_init_celleb()\n");
124}
diff --git a/arch/powerpc/platforms/celleb/spu_priv1.c b/arch/powerpc/platforms/celleb/spu_priv1.c
new file mode 100644
index 000000000000..2bf6700f747a
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/spu_priv1.c
@@ -0,0 +1,208 @@
1/*
2 * spu hypervisor abstraction for Beat
3 *
4 * (C) Copyright 2006-2007 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <linux/module.h>
22
23#include <asm/types.h>
24#include <asm/spu.h>
25#include <asm/spu_priv1.h>
26
27#include "beat_wrapper.h"
28
29static inline void _int_mask_set(struct spu *spu, int class, u64 mask)
30{
31 spu->shadow_int_mask_RW[class] = mask;
32 beat_set_irq_mask_for_spe(spu->spe_id, class, mask);
33}
34
35static inline u64 _int_mask_get(struct spu *spu, int class)
36{
37 return spu->shadow_int_mask_RW[class];
38}
39
40static void int_mask_set(struct spu *spu, int class, u64 mask)
41{
42 _int_mask_set(spu, class, mask);
43}
44
45static u64 int_mask_get(struct spu *spu, int class)
46{
47 return _int_mask_get(spu, class);
48}
49
50static void int_mask_and(struct spu *spu, int class, u64 mask)
51{
52 u64 old_mask;
53 old_mask = _int_mask_get(spu, class);
54 _int_mask_set(spu, class, old_mask & mask);
55}
56
57static void int_mask_or(struct spu *spu, int class, u64 mask)
58{
59 u64 old_mask;
60 old_mask = _int_mask_get(spu, class);
61 _int_mask_set(spu, class, old_mask | mask);
62}
63
64static void int_stat_clear(struct spu *spu, int class, u64 stat)
65{
66 beat_clear_interrupt_status_of_spe(spu->spe_id, class, stat);
67}
68
69static u64 int_stat_get(struct spu *spu, int class)
70{
71 u64 int_stat;
72 beat_get_interrupt_status_of_spe(spu->spe_id, class, &int_stat);
73 return int_stat;
74}
75
76static void cpu_affinity_set(struct spu *spu, int cpu)
77{
78 return;
79}
80
81static u64 mfc_dar_get(struct spu *spu)
82{
83 u64 dar;
84 beat_get_spe_privileged_state_1_registers(
85 spu->spe_id,
86 offsetof(struct spu_priv1, mfc_dar_RW), &dar);
87 return dar;
88}
89
90static u64 mfc_dsisr_get(struct spu *spu)
91{
92 u64 dsisr;
93 beat_get_spe_privileged_state_1_registers(
94 spu->spe_id,
95 offsetof(struct spu_priv1, mfc_dsisr_RW), &dsisr);
96 return dsisr;
97}
98
99static void mfc_dsisr_set(struct spu *spu, u64 dsisr)
100{
101 beat_set_spe_privileged_state_1_registers(
102 spu->spe_id,
103 offsetof(struct spu_priv1, mfc_dsisr_RW), dsisr);
104}
105
106static void mfc_sdr_setup(struct spu *spu)
107{
108 return;
109}
110
111static void mfc_sr1_set(struct spu *spu, u64 sr1)
112{
113 beat_set_spe_privileged_state_1_registers(
114 spu->spe_id,
115 offsetof(struct spu_priv1, mfc_sr1_RW), sr1);
116}
117
118static u64 mfc_sr1_get(struct spu *spu)
119{
120 u64 sr1;
121 beat_get_spe_privileged_state_1_registers(
122 spu->spe_id,
123 offsetof(struct spu_priv1, mfc_sr1_RW), &sr1);
124 return sr1;
125}
126
127static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id)
128{
129 beat_set_spe_privileged_state_1_registers(
130 spu->spe_id,
131 offsetof(struct spu_priv1, mfc_tclass_id_RW), tclass_id);
132}
133
134static u64 mfc_tclass_id_get(struct spu *spu)
135{
136 u64 tclass_id;
137 beat_get_spe_privileged_state_1_registers(
138 spu->spe_id,
139 offsetof(struct spu_priv1, mfc_tclass_id_RW), &tclass_id);
140 return tclass_id;
141}
142
143static void tlb_invalidate(struct spu *spu)
144{
145 beat_set_spe_privileged_state_1_registers(
146 spu->spe_id,
147 offsetof(struct spu_priv1, tlb_invalidate_entry_W), 0ul);
148}
149
150static void resource_allocation_groupID_set(struct spu *spu, u64 id)
151{
152 beat_set_spe_privileged_state_1_registers(
153 spu->spe_id,
154 offsetof(struct spu_priv1, resource_allocation_groupID_RW),
155 id);
156}
157
158static u64 resource_allocation_groupID_get(struct spu *spu)
159{
160 u64 id;
161 beat_get_spe_privileged_state_1_registers(
162 spu->spe_id,
163 offsetof(struct spu_priv1, resource_allocation_groupID_RW),
164 &id);
165 return id;
166}
167
168static void resource_allocation_enable_set(struct spu *spu, u64 enable)
169{
170 beat_set_spe_privileged_state_1_registers(
171 spu->spe_id,
172 offsetof(struct spu_priv1, resource_allocation_enable_RW),
173 enable);
174}
175
176static u64 resource_allocation_enable_get(struct spu *spu)
177{
178 u64 enable;
179 beat_get_spe_privileged_state_1_registers(
180 spu->spe_id,
181 offsetof(struct spu_priv1, resource_allocation_enable_RW),
182 &enable);
183 return enable;
184}
185
186const struct spu_priv1_ops spu_priv1_beat_ops =
187{
188 .int_mask_and = int_mask_and,
189 .int_mask_or = int_mask_or,
190 .int_mask_set = int_mask_set,
191 .int_mask_get = int_mask_get,
192 .int_stat_clear = int_stat_clear,
193 .int_stat_get = int_stat_get,
194 .cpu_affinity_set = cpu_affinity_set,
195 .mfc_dar_get = mfc_dar_get,
196 .mfc_dsisr_get = mfc_dsisr_get,
197 .mfc_dsisr_set = mfc_dsisr_set,
198 .mfc_sdr_setup = mfc_sdr_setup,
199 .mfc_sr1_set = mfc_sr1_set,
200 .mfc_sr1_get = mfc_sr1_get,
201 .mfc_tclass_id_set = mfc_tclass_id_set,
202 .mfc_tclass_id_get = mfc_tclass_id_get,
203 .tlb_invalidate = tlb_invalidate,
204 .resource_allocation_groupID_set = resource_allocation_groupID_set,
205 .resource_allocation_groupID_get = resource_allocation_groupID_get,
206 .resource_allocation_enable_set = resource_allocation_enable_set,
207 .resource_allocation_enable_get = resource_allocation_enable_get,
208};
diff --git a/arch/powerpc/platforms/celleb/udbg_beat.c b/arch/powerpc/platforms/celleb/udbg_beat.c
new file mode 100644
index 000000000000..d888c4674c62
--- /dev/null
+++ b/arch/powerpc/platforms/celleb/udbg_beat.c
@@ -0,0 +1,97 @@
1/*
2 * udbg function for Beat
3 *
4 * (C) Copyright 2006 TOSHIBA CORPORATION
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21#include <linux/kernel.h>
22#include <linux/console.h>
23
24#include <asm/machdep.h>
25#include <asm/prom.h>
26#include <asm/udbg.h>
27
28#include "beat.h"
29
30#define celleb_vtermno 0
31
32static void udbg_putc_beat(char c)
33{
34 unsigned long rc;
35
36 if (c == '\n')
37 udbg_putc_beat('\r');
38
39 rc = beat_put_term_char(celleb_vtermno, 1, (uint64_t)c << 56, 0);
40}
41
42/* Buffered chars getc */
43static long inbuflen;
44static long inbuf[2]; /* must be 2 longs */
45
46static int udbg_getc_poll_beat(void)
47{
48 /* The interface is tricky because it may return up to 16 chars.
49 * We save them statically for future calls to udbg_getc().
50 */
51 char ch, *buf = (char *)inbuf;
52 int i;
53 long rc;
54 if (inbuflen == 0) {
55 /* get some more chars. */
56 inbuflen = 0;
57 rc = beat_get_term_char(celleb_vtermno, &inbuflen, inbuf+0, inbuf+1);
58 if (rc != 0)
59 inbuflen = 0; /* otherwise inbuflen is garbage */
60 }
61 if (inbuflen <= 0 || inbuflen > 16) {
62 /* Catch error case as well as other oddities (corruption) */
63 inbuflen = 0;
64 return -1;
65 }
66 ch = buf[0];
67 for (i = 1; i < inbuflen; i++) /* shuffle them down. */
68 buf[i-1] = buf[i];
69 inbuflen--;
70 return ch;
71}
72
73static int udbg_getc_beat(void)
74{
75 int ch;
76 for (;;) {
77 ch = udbg_getc_poll_beat();
78 if (ch == -1) {
79 /* This shouldn't be needed...but... */
80 volatile unsigned long delay;
81 for (delay=0; delay < 2000000; delay++)
82 ;
83 } else {
84 return ch;
85 }
86 }
87}
88
89/* call this from early_init() for a working debug console on
90 * vterm capable LPAR machines
91 */
92void __init udbg_init_debug_beat(void)
93{
94 udbg_putc = udbg_putc_beat;
95 udbg_getc = udbg_getc_beat;
96 udbg_getc_poll = udbg_getc_poll_beat;
97}
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig
index b3c2ce4cb7a8..886c522d78e9 100644
--- a/arch/powerpc/platforms/embedded6xx/Kconfig
+++ b/arch/powerpc/platforms/embedded6xx/Kconfig
@@ -104,15 +104,6 @@ config RADSTONE_PPC7D
104config PAL4 104config PAL4
105 bool "SBS-Palomar4" 105 bool "SBS-Palomar4"
106 106
107config GEMINI
108 bool "Synergy-Gemini"
109 select PPC_INDIRECT_PCI
110 depends on BROKEN
111 help
112 Select Gemini if configuring for a Synergy Microsystems' Gemini
113 series Single Board Computer. More information is available at:
114 <http://www.synergymicro.com/PressRel/97_10_15.html>.
115
116config EST8260 107config EST8260
117 bool "EST8260" 108 bool "EST8260"
118 ---help--- 109 ---help---
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index 3f6a69f67195..73c59904697f 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -425,14 +425,6 @@ static void __init setup_u4_pcie(struct pci_controller* hose)
425 hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); 425 hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
426 hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); 426 hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
427 427
428 /* The bus contains a bridge from root -> device, we need to
429 * make it visible on bus 0 so that we pick the right type
430 * of config cycles. If we didn't, we would have to force all
431 * config cycles to be type 1. So we override the "bus-range"
432 * property here
433 */
434 hose->first_busno = 0x00;
435 hose->last_busno = 0xff;
436 u4_pcie = hose; 428 u4_pcie = hose;
437} 429}
438 430
@@ -560,13 +552,16 @@ void __init maple_pci_init(void)
560 return; 552 return;
561 } 553 }
562 for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { 554 for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) {
563 if (np->name == NULL) 555 if (!np->type)
564 continue; 556 continue;
565 if (!strcmp(np->name, "pci") || !strcmp(np->name, "pcie")) { 557 if (strcmp(np->type, "pci") && strcmp(np->type, "ht"))
566 if (add_bridge(np) == 0) 558 continue;
567 of_node_get(np); 559 if ((device_is_compatible(np, "u4-pcie") ||
568 } 560 device_is_compatible(np, "u3-agp")) &&
569 if (strcmp(np->name, "ht") == 0) { 561 add_bridge(np) == 0)
562 of_node_get(np);
563
564 if (device_is_compatible(np, "u3-ht")) {
570 of_node_get(np); 565 of_node_get(np);
571 ht = np; 566 ht = np;
572 } 567 }
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index 50855d4fd5a0..82d3f9e28d7c 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -62,6 +62,7 @@
62#include <asm/mpic.h> 62#include <asm/mpic.h>
63#include <asm/rtas.h> 63#include <asm/rtas.h>
64#include <asm/udbg.h> 64#include <asm/udbg.h>
65#include <asm/nvram.h>
65 66
66#include "maple.h" 67#include "maple.h"
67 68
@@ -195,6 +196,8 @@ void __init maple_setup_arch(void)
195 maple_use_rtas_reboot_and_halt_if_present(); 196 maple_use_rtas_reboot_and_halt_if_present();
196 197
197 printk(KERN_DEBUG "Using native/NAP idle loop\n"); 198 printk(KERN_DEBUG "Using native/NAP idle loop\n");
199
200 mmio_nvram_init();
198} 201}
199 202
200/* 203/*
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig
new file mode 100644
index 000000000000..68dc529dfd2f
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/Kconfig
@@ -0,0 +1,10 @@
1menu "PA Semi PWRficient options"
2 depends on PPC_PASEMI
3
4config PPC_PASEMI_IOMMU
5 bool "PA Semi IOMMU support"
6 depends on PPC_PASEMI
7 help
8 IOMMU support for PA6T-1682M
9
10endmenu
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile
index 1be1a993c5f5..e657ccae90a9 100644
--- a/arch/powerpc/platforms/pasemi/Makefile
+++ b/arch/powerpc/platforms/pasemi/Makefile
@@ -1 +1,2 @@
1obj-y += setup.o pci.o time.o 1obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o
2
diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c
new file mode 100644
index 000000000000..1ca3ff381591
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/idle.c
@@ -0,0 +1,88 @@
1/*
2 * Copyright (C) 2006-2007 PA Semi, Inc
3 *
4 * Maintained by: Olof Johansson <olof@lixom.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#undef DEBUG
22
23#include <linux/kernel.h>
24#include <linux/string.h>
25
26#include <asm/machdep.h>
27#include <asm/reg.h>
28
29#include "pasemi.h"
30
31struct sleep_mode {
32 char *name;
33 void (*entry)(void);
34};
35
36static struct sleep_mode modes[] = {
37 { .name = "spin", .entry = &idle_spin },
38 { .name = "doze", .entry = &idle_doze },
39};
40
41static int current_mode = 0;
42
43static int pasemi_system_reset_exception(struct pt_regs *regs)
44{
45 /* If we were woken up from power savings, we need to return
46 * to the calling function, since nip is not saved across
47 * all modes.
48 */
49
50 if (regs->msr & SRR1_WAKEMASK)
51 regs->nip = regs->link;
52
53 switch (regs->msr & SRR1_WAKEMASK) {
54 case SRR1_WAKEEE:
55 do_IRQ(regs);
56 break;
57 case SRR1_WAKEDEC:
58 timer_interrupt(regs);
59 break;
60 default:
61 /* do system reset */
62 return 0;
63 }
64 /* everything handled */
65 regs->msr |= MSR_RI;
66 return 1;
67}
68
69void __init pasemi_idle_init(void)
70{
71 ppc_md.system_reset_exception = pasemi_system_reset_exception;
72 ppc_md.power_save = modes[current_mode].entry;
73 printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name);
74}
75
76static int __init idle_param(char *p)
77{
78 int i;
79 for (i = 0; i < sizeof(modes)/sizeof(struct sleep_mode); i++) {
80 if (!strcmp(modes[i].name, p)) {
81 current_mode = i;
82 break;
83 }
84 }
85 return 0;
86}
87
88early_param("idle", idle_param);
diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c
new file mode 100644
index 000000000000..459a53b7d24d
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/iommu.c
@@ -0,0 +1,281 @@
1/*
2 * Copyright (C) 2005-2007, PA Semi, Inc
3 *
4 * Maintained by: Olof Johansson <olof@lixom.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#undef DEBUG
21
22#include <linux/types.h>
23#include <linux/spinlock.h>
24#include <linux/pci.h>
25#include <asm/iommu.h>
26#include <asm/machdep.h>
27#include <asm/abs_addr.h>
28
29
30#define IOBMAP_PAGE_SHIFT 12
31#define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT)
32#define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1)
33
34#define IOBMAP_PAGE_FACTOR (PAGE_SHIFT - IOBMAP_PAGE_SHIFT)
35
36#define IOB_BASE 0xe0000000
37#define IOB_SIZE 0x3000
38/* Configuration registers */
39#define IOBCAP_REG 0x10
40#define IOBCOM_REG 0x40
41/* Enable IOB address translation */
42#define IOBCOM_ATEN 0x00000100
43
44/* Address decode configuration register */
45#define IOB_AD_REG 0x53
46/* IOBCOM_AD_REG fields */
47#define IOB_AD_VGPRT 0x00000e00
48#define IOB_AD_VGAEN 0x00000100
49/* Direct mapping settings */
50#define IOB_AD_MPSEL_MASK 0x00000030
51#define IOB_AD_MPSEL_B38 0x00000000
52#define IOB_AD_MPSEL_B40 0x00000010
53#define IOB_AD_MPSEL_B42 0x00000020
54/* Translation window size / enable */
55#define IOB_AD_TRNG_MASK 0x00000003
56#define IOB_AD_TRNG_256M 0x00000000
57#define IOB_AD_TRNG_2G 0x00000001
58#define IOB_AD_TRNG_128G 0x00000003
59
60#define IOB_TABLEBASE_REG 0x55
61
62/* Base of the 64 4-byte L1 registers */
63#define IOB_XLT_L1_REGBASE 0xac0
64
65/* Register to invalidate TLB entries */
66#define IOB_AT_INVAL_TLB_REG 0xb40
67
68/* The top two bits of the level 1 entry contains valid and type flags */
69#define IOBMAP_L1E_V 0x40000000
70#define IOBMAP_L1E_V_B 0x80000000
71
72/* For big page entries, the bottom two bits contains flags */
73#define IOBMAP_L1E_BIG_CACHED 0x00000002
74#define IOBMAP_L1E_BIG_PRIORITY 0x00000001
75
76/* For regular level 2 entries, top 2 bits contain valid and cache flags */
77#define IOBMAP_L2E_V 0x80000000
78#define IOBMAP_L2E_V_CACHED 0xc0000000
79
80static u32 *iob;
81static u32 iob_l1_emptyval;
82static u32 iob_l2_emptyval;
83static u32 *iob_l2_base;
84
85static struct iommu_table iommu_table_iobmap;
86static int iommu_table_iobmap_inited;
87
88static void iobmap_build(struct iommu_table *tbl, long index,
89 long npages, unsigned long uaddr,
90 enum dma_data_direction direction)
91{
92 u32 *ip;
93 u32 rpn;
94 unsigned long bus_addr;
95
96 pr_debug("iobmap: build at: %lx, %lx, addr: %lx\n", index, npages, uaddr);
97
98 bus_addr = (tbl->it_offset + index) << PAGE_SHIFT;
99
100 npages <<= IOBMAP_PAGE_FACTOR;
101 index <<= IOBMAP_PAGE_FACTOR;
102
103 ip = ((u32 *)tbl->it_base) + index;
104
105 while (npages--) {
106 rpn = virt_to_abs(uaddr) >> IOBMAP_PAGE_SHIFT;
107
108 *(ip++) = IOBMAP_L2E_V | rpn;
109 /* invalidate tlb, can be optimized more */
110 out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);
111
112 uaddr += IOBMAP_PAGE_SIZE;
113 bus_addr += IOBMAP_PAGE_SIZE;
114 }
115}
116
117
118static void iobmap_free(struct iommu_table *tbl, long index,
119 long npages)
120{
121 u32 *ip;
122 unsigned long bus_addr;
123
124 pr_debug("iobmap: free at: %lx, %lx\n", index, npages);
125
126 bus_addr = (tbl->it_offset + index) << PAGE_SHIFT;
127
128 npages <<= IOBMAP_PAGE_FACTOR;
129 index <<= IOBMAP_PAGE_FACTOR;
130
131 ip = ((u32 *)tbl->it_base) + index;
132
133 while (npages--) {
134 *(ip++) = iob_l2_emptyval;
135 /* invalidate tlb, can be optimized more */
136 out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14);
137 bus_addr += IOBMAP_PAGE_SIZE;
138 }
139}
140
141
142static void iommu_table_iobmap_setup(void)
143{
144 pr_debug(" -> %s\n", __func__);
145 iommu_table_iobmap.it_busno = 0;
146 iommu_table_iobmap.it_offset = 0;
147 /* it_size is in number of entries */
148 iommu_table_iobmap.it_size = 0x80000000 >> PAGE_SHIFT;
149
150 /* Initialize the common IOMMU code */
151 iommu_table_iobmap.it_base = (unsigned long)iob_l2_base;
152 iommu_table_iobmap.it_index = 0;
153 /* XXXOJN tune this to avoid IOB cache invals.
154 * Should probably be 8 (64 bytes)
155 */
156 iommu_table_iobmap.it_blocksize = 4;
157 iommu_init_table(&iommu_table_iobmap, 0);
158 pr_debug(" <- %s\n", __func__);
159}
160
161
162
163static void pci_dma_bus_setup_pasemi(struct pci_bus *bus)
164{
165 struct device_node *dn;
166
167 pr_debug("pci_dma_bus_setup, bus %p, bus->self %p\n", bus, bus->self);
168
169 if (!iommu_table_iobmap_inited) {
170 iommu_table_iobmap_inited = 1;
171 iommu_table_iobmap_setup();
172 }
173
174 dn = pci_bus_to_OF_node(bus);
175
176 if (dn)
177 PCI_DN(dn)->iommu_table = &iommu_table_iobmap;
178
179}
180
181
182static void pci_dma_dev_setup_pasemi(struct pci_dev *dev)
183{
184 pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev));
185
186 /* DMA device is untranslated, but all other PCI-e goes through
187 * the IOMMU
188 */
189 if (dev->vendor == 0x1959 && dev->device == 0xa007)
190 dev->dev.archdata.dma_ops = &dma_direct_ops;
191 else
192 dev->dev.archdata.dma_data = &iommu_table_iobmap;
193}
194
195static void pci_dma_bus_setup_null(struct pci_bus *b) { }
196static void pci_dma_dev_setup_null(struct pci_dev *d) { }
197
198int iob_init(struct device_node *dn)
199{
200 unsigned long tmp;
201 u32 regword;
202 int i;
203
204 pr_debug(" -> %s\n", __func__);
205
206 /* Allocate a spare page to map all invalid IOTLB pages. */
207 tmp = lmb_alloc(IOBMAP_PAGE_SIZE, IOBMAP_PAGE_SIZE);
208 if (!tmp)
209 panic("IOBMAP: Cannot allocate spare page!");
210 /* Empty l1 is marked invalid */
211 iob_l1_emptyval = 0;
212 /* Empty l2 is mapped to dummy page */
213 iob_l2_emptyval = IOBMAP_L2E_V | (tmp >> IOBMAP_PAGE_SHIFT);
214
215 iob = ioremap(IOB_BASE, IOB_SIZE);
216 if (!iob)
217 panic("IOBMAP: Cannot map registers!");
218
219 /* setup direct mapping of the L1 entries */
220 for (i = 0; i < 64; i++) {
221 /* Each L1 covers 32MB, i.e. 8K entries = 32K of ram */
222 regword = IOBMAP_L1E_V | (__pa(iob_l2_base + i*0x2000) >> 12);
223 out_le32(iob+IOB_XLT_L1_REGBASE+i, regword);
224 }
225
226 /* set 2GB translation window, based at 0 */
227 regword = in_le32(iob+IOB_AD_REG);
228 regword &= ~IOB_AD_TRNG_MASK;
229 regword |= IOB_AD_TRNG_2G;
230 out_le32(iob+IOB_AD_REG, regword);
231
232 /* Enable translation */
233 regword = in_le32(iob+IOBCOM_REG);
234 regword |= IOBCOM_ATEN;
235 out_le32(iob+IOBCOM_REG, regword);
236
237 pr_debug(" <- %s\n", __func__);
238
239 return 0;
240}
241
242
243/* These are called very early. */
244void iommu_init_early_pasemi(void)
245{
246 int iommu_off;
247
248#ifndef CONFIG_PPC_PASEMI_IOMMU
249 iommu_off = 1;
250#else
251 iommu_off = of_chosen &&
252 get_property(of_chosen, "linux,iommu-off", NULL);
253#endif
254 if (iommu_off) {
255 /* Direct I/O, IOMMU off */
256 ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null;
257 ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null;
258 pci_dma_ops = &dma_direct_ops;
259
260 return;
261 }
262
263 iob_init(NULL);
264
265 ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pasemi;
266 ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi;
267 ppc_md.tce_build = iobmap_build;
268 ppc_md.tce_free = iobmap_free;
269 pci_dma_ops = &dma_iommu_ops;
270}
271
272void __init alloc_iobmap_l2(void)
273{
274#ifndef CONFIG_PPC_PASEMI_IOMMU
275 return;
276#endif
277 /* For 2G space, 8x64 pages (2^21 bytes) is max total l2 size */
278 iob_l2_base = (u32 *)abs_to_virt(lmb_alloc_base(1UL<<21, 1UL<<21, 0x80000000));
279
280 printk(KERN_INFO "IOBMAP L2 allocated at: %p\n", iob_l2_base);
281}
diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h
index 51c2a2397ecf..2d3927e6edb0 100644
--- a/arch/powerpc/platforms/pasemi/pasemi.h
+++ b/arch/powerpc/platforms/pasemi/pasemi.h
@@ -3,5 +3,17 @@
3 3
4extern unsigned long pas_get_boot_time(void); 4extern unsigned long pas_get_boot_time(void);
5extern void pas_pci_init(void); 5extern void pas_pci_init(void);
6extern void __devinit pas_pci_irq_fixup(struct pci_dev *dev);
7extern void __devinit pas_pci_dma_dev_setup(struct pci_dev *dev);
8
9extern void __init alloc_iobmap_l2(void);
10
11extern void __init pasemi_idle_init(void);
12
13/* Power savings modes, implemented in asm */
14extern void idle_spin(void);
15extern void idle_doze(void);
16
17
6 18
7#endif /* _PASEMI_PASEMI_H */ 19#endif /* _PASEMI_PASEMI_H */
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index faa618e04047..7ecb2ba24db9 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -163,6 +163,19 @@ static void __init pas_fixup_phb_resources(void)
163} 163}
164 164
165 165
166void __devinit pas_pci_irq_fixup(struct pci_dev *dev)
167{
168 /* DMA is special, 84 interrupts (128 -> 211), all but 128
169 * need to be mapped by hand here.
170 */
171 if (dev->vendor == 0x1959 && dev->device == 0xa007) {
172 int i;
173 for (i = 129; i < 212; i++)
174 irq_create_mapping(NULL, i);
175 }
176}
177
178
166void __init pas_pci_init(void) 179void __init pas_pci_init(void)
167{ 180{
168 struct device_node *np, *root; 181 struct device_node *np, *root;
diff --git a/arch/powerpc/platforms/pasemi/powersave.S b/arch/powerpc/platforms/pasemi/powersave.S
new file mode 100644
index 000000000000..6d0fba6aab17
--- /dev/null
+++ b/arch/powerpc/platforms/pasemi/powersave.S
@@ -0,0 +1,80 @@
1/*
2 * Copyright (C) 2006-2007 PA Semi, Inc
3 *
4 * Maintained by: Olof Johansson <olof@lixom.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 *
19 */
20
21#include <asm/processor.h>
22#include <asm/page.h>
23#include <asm/ppc_asm.h>
24#include <asm/cputable.h>
25#include <asm/cache.h>
26#include <asm/thread_info.h>
27#include <asm/asm-offsets.h>
28
29/* Power savings opcodes since not all binutils have them at this time */
30#define DOZE .long 0x4c000324
31#define NAP .long 0x4c000364
32#define SLEEP .long 0x4c0003a4
33#define RVW .long 0x4c0003e4
34
35/* Common sequence to do before going to any of the
36 * powersavings modes.
37 */
38
39#define PRE_SLEEP_SEQUENCE \
40 std r3,8(r1); \
41 ptesync ; \
42 ld r3,8(r1); \
431: cmpd r3,r3; \
44 bne 1b
45
46_doze:
47 PRE_SLEEP_SEQUENCE
48 DOZE
49 b .
50
51
52_GLOBAL(idle_spin)
53 blr
54
55_GLOBAL(idle_doze)
56 LOAD_REG_ADDR(r3, _doze)
57 b sleep_common
58
59/* Add more modes here later */
60
61sleep_common:
62 mflr r0
63 std r0, 16(r1)
64 stdu r1,-64(r1)
65
66 LOAD_REG_IMMEDIATE(r6,MSR_DR|MSR_IR|MSR_ME|MSR_EE)
67 mfmsr r4
68 andc r5,r4,r6
69 mtmsrd r5,0
70
71 mtctr r3
72 bctrl
73
74 mtmsrd r4,0
75
76 addi r1,r1,64
77 ld r0,16(r1)
78 mtlr r0
79 blr
80
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index bea7d1bb1a3b..449cf1a08291 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2006 PA Semi, Inc 2 * Copyright (C) 2006-2007 PA Semi, Inc
3 * 3 *
4 * Authors: Kip Walker, PA Semi 4 * Authors: Kip Walker, PA Semi
5 * Olof Johansson, PA Semi 5 * Olof Johansson, PA Semi
@@ -38,31 +38,46 @@
38 38
39#include "pasemi.h" 39#include "pasemi.h"
40 40
41static void __iomem *reset_reg;
42
41static void pas_restart(char *cmd) 43static void pas_restart(char *cmd)
42{ 44{
43 printk("restart unimplemented, looping...\n"); 45 printk("Restarting...\n");
44 for (;;) ; 46 while (1)
47 out_le32(reset_reg, 0x6000000);
45} 48}
46 49
47static void pas_power_off(void) 50#ifdef CONFIG_SMP
51static DEFINE_SPINLOCK(timebase_lock);
52
53static void __devinit pas_give_timebase(void)
48{ 54{
49 printk("power off unimplemented, looping...\n"); 55 unsigned long tb;
50 for (;;) ; 56
57 spin_lock(&timebase_lock);
58 mtspr(SPRN_TBCTL, TBCTL_FREEZE);
59 tb = mftb();
60 mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff));
61 mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32));
62 mtspr(SPRN_TBCTL, TBCTL_RESTART);
63 spin_unlock(&timebase_lock);
64 pr_debug("pas_give_timebase: cpu %d gave tb %lx\n",
65 smp_processor_id(), tb);
51} 66}
52 67
53static void pas_halt(void) 68static void __devinit pas_take_timebase(void)
54{ 69{
55 pas_power_off(); 70 pr_debug("pas_take_timebase: cpu %d has tb %lx\n",
71 smp_processor_id(), mftb());
56} 72}
57 73
58#ifdef CONFIG_SMP
59struct smp_ops_t pas_smp_ops = { 74struct smp_ops_t pas_smp_ops = {
60 .probe = smp_mpic_probe, 75 .probe = smp_mpic_probe,
61 .message_pass = smp_mpic_message_pass, 76 .message_pass = smp_mpic_message_pass,
62 .kick_cpu = smp_generic_kick_cpu, 77 .kick_cpu = smp_generic_kick_cpu,
63 .setup_cpu = smp_mpic_setup_cpu, 78 .setup_cpu = smp_mpic_setup_cpu,
64 .give_timebase = smp_generic_give_timebase, 79 .give_timebase = pas_give_timebase,
65 .take_timebase = smp_generic_take_timebase, 80 .take_timebase = pas_take_timebase,
66}; 81};
67#endif /* CONFIG_SMP */ 82#endif /* CONFIG_SMP */
68 83
@@ -72,9 +87,6 @@ void __init pas_setup_arch(void)
72 /* Setup SMP callback */ 87 /* Setup SMP callback */
73 smp_ops = &pas_smp_ops; 88 smp_ops = &pas_smp_ops;
74#endif 89#endif
75 /* no iommu yet */
76 pci_dma_ops = &dma_direct_ops;
77
78 /* Lookup PCI hosts */ 90 /* Lookup PCI hosts */
79 pas_pci_init(); 91 pas_pci_init();
80 92
@@ -82,7 +94,11 @@ void __init pas_setup_arch(void)
82 conswitchp = &dummy_con; 94 conswitchp = &dummy_con;
83#endif 95#endif
84 96
85 printk(KERN_DEBUG "Using default idle loop\n"); 97 /* Remap SDC register for doing reset */
98 /* XXXOJN This should maybe come out of the device tree */
99 reset_reg = ioremap(0xfc101100, 4);
100
101 pasemi_idle_init();
86} 102}
87 103
88/* No legacy IO on our parts */ 104/* No legacy IO on our parts */
@@ -130,8 +146,9 @@ static __init void pas_init_IRQ(void)
130 openpic_addr = of_read_number(opprop, naddr); 146 openpic_addr = of_read_number(opprop, naddr);
131 printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); 147 printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
132 148
133 mpic = mpic_alloc(mpic_node, openpic_addr, MPIC_PRIMARY, 0, 0, 149 mpic = mpic_alloc(mpic_node, openpic_addr,
134 " PAS-OPIC "); 150 MPIC_PRIMARY|MPIC_LARGE_VECTORS,
151 0, 0, " PAS-OPIC ");
135 BUG_ON(!mpic); 152 BUG_ON(!mpic);
136 153
137 mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); 154 mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
@@ -146,6 +163,53 @@ static void __init pas_progress(char *s, unsigned short hex)
146} 163}
147 164
148 165
166static int pas_machine_check_handler(struct pt_regs *regs)
167{
168 int cpu = smp_processor_id();
169 unsigned long srr0, srr1, dsisr;
170
171 srr0 = regs->nip;
172 srr1 = regs->msr;
173 dsisr = mfspr(SPRN_DSISR);
174 printk(KERN_ERR "Machine Check on CPU %d\n", cpu);
175 printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1);
176 printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar);
177 printk(KERN_ERR "Cause:\n");
178
179 if (srr1 & 0x200000)
180 printk(KERN_ERR "Signalled by SDC\n");
181 if (srr1 & 0x100000) {
182 printk(KERN_ERR "Load/Store detected error:\n");
183 if (dsisr & 0x8000)
184 printk(KERN_ERR "D-cache ECC double-bit error or bus error\n");
185 if (dsisr & 0x4000)
186 printk(KERN_ERR "LSU snoop response error\n");
187 if (dsisr & 0x2000)
188 printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n");
189 if (dsisr & 0x1000)
190 printk(KERN_ERR "Recoverable Duptags\n");
191 if (dsisr & 0x800)
192 printk(KERN_ERR "Recoverable D-cache parity error count overflow\n");
193 if (dsisr & 0x400)
194 printk(KERN_ERR "TLB parity error count overflow\n");
195 }
196 if (srr1 & 0x80000)
197 printk(KERN_ERR "Bus Error\n");
198 if (srr1 & 0x40000)
199 printk(KERN_ERR "I-side SLB multiple hit\n");
200 if (srr1 & 0x20000)
201 printk(KERN_ERR "I-cache parity error hit\n");
202
203 /* SRR1[62] is from MSR[62] if recoverable, so pass that back */
204 return !!(srr1 & 0x2);
205}
206
207static void __init pas_init_early(void)
208{
209 iommu_init_early_pasemi();
210}
211
212
149/* 213/*
150 * Called very early, MMU is off, device-tree isn't unflattened 214 * Called very early, MMU is off, device-tree isn't unflattened
151 */ 215 */
@@ -158,6 +222,8 @@ static int __init pas_probe(void)
158 222
159 hpte_init_native(); 223 hpte_init_native();
160 224
225 alloc_iobmap_l2();
226
161 return 1; 227 return 1;
162} 228}
163 229
@@ -165,13 +231,14 @@ define_machine(pas) {
165 .name = "PA Semi PA6T-1682M", 231 .name = "PA Semi PA6T-1682M",
166 .probe = pas_probe, 232 .probe = pas_probe,
167 .setup_arch = pas_setup_arch, 233 .setup_arch = pas_setup_arch,
234 .init_early = pas_init_early,
168 .init_IRQ = pas_init_IRQ, 235 .init_IRQ = pas_init_IRQ,
169 .get_irq = mpic_get_irq, 236 .get_irq = mpic_get_irq,
170 .restart = pas_restart, 237 .restart = pas_restart,
171 .power_off = pas_power_off,
172 .halt = pas_halt,
173 .get_boot_time = pas_get_boot_time, 238 .get_boot_time = pas_get_boot_time,
174 .calibrate_decr = generic_calibrate_decr, 239 .calibrate_decr = generic_calibrate_decr,
175 .check_legacy_ioport = pas_check_legacy_ioport, 240 .check_legacy_ioport = pas_check_legacy_ioport,
176 .progress = pas_progress, 241 .progress = pas_progress,
242 .machine_check_exception = pas_machine_check_handler,
243 .pci_irq_fixup = pas_pci_irq_fixup,
177}; 244};
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index eeb2ae5ffc58..d73fb73802bb 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -795,7 +795,6 @@ static void __devinit smp_core99_kick_cpu(int nr)
795 ppc_md.progress("smp_core99_kick_cpu", 0x346); 795 ppc_md.progress("smp_core99_kick_cpu", 0x346);
796 796
797 local_irq_save(flags); 797 local_irq_save(flags);
798 local_irq_disable();
799 798
800 /* Save reset vector */ 799 /* Save reset vector */
801 save_vector = *vector; 800 save_vector = *vector;
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile
index 1994904f580f..a0048fcf0866 100644
--- a/arch/powerpc/platforms/ps3/Makefile
+++ b/arch/powerpc/platforms/ps3/Makefile
@@ -1,5 +1,6 @@
1obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o 1obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o
2obj-y += interrupt.o exports.o os-area.o 2obj-y += interrupt.o exports.o os-area.o
3obj-y += system-bus.o
3 4
4obj-$(CONFIG_SMP) += smp.o 5obj-$(CONFIG_SMP) += smp.o
5obj-$(CONFIG_SPU_BASE) += spu.o 6obj-$(CONFIG_SPU_BASE) += spu.o
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c
index 8fe1769655a3..a4b5a1bc60f4 100644
--- a/arch/powerpc/platforms/ps3/htab.c
+++ b/arch/powerpc/platforms/ps3/htab.c
@@ -23,7 +23,6 @@
23#include <asm/machdep.h> 23#include <asm/machdep.h>
24#include <asm/lmb.h> 24#include <asm/lmb.h>
25#include <asm/udbg.h> 25#include <asm/udbg.h>
26#include <asm/ps3.h>
27#include <asm/lv1call.h> 26#include <asm/lv1call.h>
28 27
29#include "platform.h" 28#include "platform.h"
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 6f5de438b980..bb17283275aa 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -24,7 +24,6 @@
24 24
25#include <asm/machdep.h> 25#include <asm/machdep.h>
26#include <asm/udbg.h> 26#include <asm/udbg.h>
27#include <asm/ps3.h>
28#include <asm/lv1call.h> 27#include <asm/lv1call.h>
29 28
30#include "platform.h" 29#include "platform.h"
@@ -36,15 +35,148 @@
36#endif 35#endif
37 36
38/** 37/**
38 * struct ps3_bmp - a per cpu irq status and mask bitmap structure
39 * @status: 256 bit status bitmap indexed by plug
40 * @unused_1:
41 * @mask: 256 bit mask bitmap indexed by plug
42 * @unused_2:
43 * @lock:
44 * @ipi_debug_brk_mask:
45 *
46 * The HV mantains per SMT thread mappings of HV outlet to HV plug on
47 * behalf of the guest. These mappings are implemented as 256 bit guest
48 * supplied bitmaps indexed by plug number. The addresses of the bitmaps
49 * are registered with the HV through lv1_configure_irq_state_bitmap().
50 * The HV requires that the 512 bits of status + mask not cross a page
51 * boundary. PS3_BMP_MINALIGN is used to define this minimal 64 byte
52 * alignment.
53 *
54 * The HV supports 256 plugs per thread, assigned as {0..255}, for a total
55 * of 512 plugs supported on a processor. To simplify the logic this
56 * implementation equates HV plug value to Linux virq value, constrains each
57 * interrupt to have a system wide unique plug number, and limits the range
58 * of the plug values to map into the first dword of the bitmaps. This
59 * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note
60 * that there is no constraint on how many in this set an individual thread
61 * can acquire.
62 */
63
64#define PS3_BMP_MINALIGN 64
65
66struct ps3_bmp {
67 struct {
68 u64 status;
69 u64 unused_1[3];
70 u64 mask;
71 u64 unused_2[3];
72 };
73 u64 ipi_debug_brk_mask;
74 spinlock_t lock;
75};
76
77/**
78 * struct ps3_private - a per cpu data structure
79 * @bmp: ps3_bmp structure
80 * @node: HV logical_ppe_id
81 * @cpu: HV thread_id
82 */
83
84struct ps3_private {
85 struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
86 u64 node;
87 unsigned int cpu;
88};
89
90static DEFINE_PER_CPU(struct ps3_private, ps3_private);
91
92int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
93 unsigned int *virq)
94{
95 int result;
96 struct ps3_private *pd;
97
98 /* This defines the default interrupt distribution policy. */
99
100 if (cpu == PS3_BINDING_CPU_ANY)
101 cpu = 0;
102
103 pd = &per_cpu(ps3_private, cpu);
104
105 *virq = irq_create_mapping(NULL, outlet);
106
107 if (*virq == NO_IRQ) {
108 pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n",
109 __func__, __LINE__, outlet);
110 result = -ENOMEM;
111 goto fail_create;
112 }
113
114 /* Binds outlet to cpu + virq. */
115
116 result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
117
118 if (result) {
119 pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
120 __func__, __LINE__, ps3_result(result));
121 result = -EPERM;
122 goto fail_connect;
123 }
124
125 pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
126 outlet, cpu, *virq);
127
128 result = set_irq_chip_data(*virq, pd);
129
130 if (result) {
131 pr_debug("%s:%d: set_irq_chip_data failed\n",
132 __func__, __LINE__);
133 goto fail_set;
134 }
135
136 return result;
137
138fail_set:
139 lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq);
140fail_connect:
141 irq_dispose_mapping(*virq);
142fail_create:
143 return result;
144}
145EXPORT_SYMBOL_GPL(ps3_alloc_irq);
146
147int ps3_free_irq(unsigned int virq)
148{
149 int result;
150 const struct ps3_private *pd = get_irq_chip_data(virq);
151
152 pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
153 pd->node, pd->cpu, virq);
154
155 result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
156
157 if (result)
158 pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
159 __func__, __LINE__, ps3_result(result));
160
161 set_irq_chip_data(virq, NULL);
162 irq_dispose_mapping(virq);
163 return result;
164}
165EXPORT_SYMBOL_GPL(ps3_free_irq);
166
167/**
39 * ps3_alloc_io_irq - Assign a virq to a system bus device. 168 * ps3_alloc_io_irq - Assign a virq to a system bus device.
40 * interrupt_id: The device interrupt id read from the system repository. 169 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
170 * serviced on.
171 * @interrupt_id: The device interrupt id read from the system repository.
41 * @virq: The assigned Linux virq. 172 * @virq: The assigned Linux virq.
42 * 173 *
43 * An io irq represents a non-virtualized device interrupt. interrupt_id 174 * An io irq represents a non-virtualized device interrupt. interrupt_id
44 * coresponds to the interrupt number of the interrupt controller. 175 * coresponds to the interrupt number of the interrupt controller.
45 */ 176 */
46 177
47int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq) 178int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
179 unsigned int *virq)
48{ 180{
49 int result; 181 int result;
50 unsigned long outlet; 182 unsigned long outlet;
@@ -57,12 +189,10 @@ int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq)
57 return result; 189 return result;
58 } 190 }
59 191
60 *virq = irq_create_mapping(NULL, outlet); 192 result = ps3_alloc_irq(cpu, outlet, virq);
61 193 BUG_ON(result);
62 pr_debug("%s:%d: interrupt_id %u => outlet %lu, virq %u\n",
63 __func__, __LINE__, interrupt_id, outlet, *virq);
64 194
65 return 0; 195 return result;
66} 196}
67 197
68int ps3_free_io_irq(unsigned int virq) 198int ps3_free_io_irq(unsigned int virq)
@@ -75,13 +205,15 @@ int ps3_free_io_irq(unsigned int virq)
75 pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", 205 pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
76 __func__, __LINE__, ps3_result(result)); 206 __func__, __LINE__, ps3_result(result));
77 207
78 irq_dispose_mapping(virq); 208 ps3_free_irq(virq);
79 209
80 return result; 210 return result;
81} 211}
82 212
83/** 213/**
84 * ps3_alloc_event_irq - Allocate a virq for use with a system event. 214 * ps3_alloc_event_irq - Allocate a virq for use with a system event.
215 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
216 * serviced on.
85 * @virq: The assigned Linux virq. 217 * @virq: The assigned Linux virq.
86 * 218 *
87 * The virq can be used with lv1_connect_interrupt_event_receive_port() to 219 * The virq can be used with lv1_connect_interrupt_event_receive_port() to
@@ -89,7 +221,7 @@ int ps3_free_io_irq(unsigned int virq)
89 * events. 221 * events.
90 */ 222 */
91 223
92int ps3_alloc_event_irq(unsigned int *virq) 224int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
93{ 225{
94 int result; 226 int result;
95 unsigned long outlet; 227 unsigned long outlet;
@@ -103,12 +235,10 @@ int ps3_alloc_event_irq(unsigned int *virq)
103 return result; 235 return result;
104 } 236 }
105 237
106 *virq = irq_create_mapping(NULL, outlet); 238 result = ps3_alloc_irq(cpu, outlet, virq);
107 239 BUG_ON(result);
108 pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, outlet,
109 *virq);
110 240
111 return 0; 241 return result;
112} 242}
113 243
114int ps3_free_event_irq(unsigned int virq) 244int ps3_free_event_irq(unsigned int virq)
@@ -123,7 +253,7 @@ int ps3_free_event_irq(unsigned int virq)
123 pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", 253 pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
124 __func__, __LINE__, ps3_result(result)); 254 __func__, __LINE__, ps3_result(result));
125 255
126 irq_dispose_mapping(virq); 256 ps3_free_irq(virq);
127 257
128 pr_debug(" <- %s:%d\n", __func__, __LINE__); 258 pr_debug(" <- %s:%d\n", __func__, __LINE__);
129 return result; 259 return result;
@@ -136,6 +266,8 @@ int ps3_send_event_locally(unsigned int virq)
136 266
137/** 267/**
138 * ps3_connect_event_irq - Assign a virq to a system bus device. 268 * ps3_connect_event_irq - Assign a virq to a system bus device.
269 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
270 * serviced on.
139 * @did: The HV device identifier read from the system repository. 271 * @did: The HV device identifier read from the system repository.
140 * @interrupt_id: The device interrupt id read from the system repository. 272 * @interrupt_id: The device interrupt id read from the system repository.
141 * @virq: The assigned Linux virq. 273 * @virq: The assigned Linux virq.
@@ -144,12 +276,13 @@ int ps3_send_event_locally(unsigned int virq)
144 * coresponds to the software interrupt number. 276 * coresponds to the software interrupt number.
145 */ 277 */
146 278
147int ps3_connect_event_irq(const struct ps3_device_id *did, 279int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
148 unsigned int interrupt_id, unsigned int *virq) 280 const struct ps3_device_id *did, unsigned int interrupt_id,
281 unsigned int *virq)
149{ 282{
150 int result; 283 int result;
151 284
152 result = ps3_alloc_event_irq(virq); 285 result = ps3_alloc_event_irq(cpu, virq);
153 286
154 if (result) 287 if (result)
155 return result; 288 return result;
@@ -196,6 +329,8 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
196 329
197/** 330/**
198 * ps3_alloc_vuart_irq - Configure the system virtual uart virq. 331 * ps3_alloc_vuart_irq - Configure the system virtual uart virq.
332 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
333 * serviced on.
199 * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. 334 * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap.
200 * @virq: The assigned Linux virq. 335 * @virq: The assigned Linux virq.
201 * 336 *
@@ -203,13 +338,14 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did,
203 * freeing the interrupt will return a wrong state error. 338 * freeing the interrupt will return a wrong state error.
204 */ 339 */
205 340
206int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq) 341int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
342 unsigned int *virq)
207{ 343{
208 int result; 344 int result;
209 unsigned long outlet; 345 unsigned long outlet;
210 unsigned long lpar_addr; 346 u64 lpar_addr;
211 347
212 BUG_ON(!is_kernel_addr((unsigned long)virt_addr_bmp)); 348 BUG_ON(!is_kernel_addr((u64)virt_addr_bmp));
213 349
214 lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); 350 lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp));
215 351
@@ -221,12 +357,10 @@ int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq)
221 return result; 357 return result;
222 } 358 }
223 359
224 *virq = irq_create_mapping(NULL, outlet); 360 result = ps3_alloc_irq(cpu, outlet, virq);
225 361 BUG_ON(result);
226 pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__,
227 outlet, *virq);
228 362
229 return 0; 363 return result;
230} 364}
231 365
232int ps3_free_vuart_irq(unsigned int virq) 366int ps3_free_vuart_irq(unsigned int virq)
@@ -241,21 +375,23 @@ int ps3_free_vuart_irq(unsigned int virq)
241 return result; 375 return result;
242 } 376 }
243 377
244 irq_dispose_mapping(virq); 378 ps3_free_irq(virq);
245 379
246 return result; 380 return result;
247} 381}
248 382
249/** 383/**
250 * ps3_alloc_spe_irq - Configure an spe virq. 384 * ps3_alloc_spe_irq - Configure an spe virq.
385 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
386 * serviced on.
251 * @spe_id: The spe_id returned from lv1_construct_logical_spe(). 387 * @spe_id: The spe_id returned from lv1_construct_logical_spe().
252 * @class: The spe interrupt class {0,1,2}. 388 * @class: The spe interrupt class {0,1,2}.
253 * @virq: The assigned Linux virq. 389 * @virq: The assigned Linux virq.
254 * 390 *
255 */ 391 */
256 392
257int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class, 393int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
258 unsigned int *virq) 394 unsigned int class, unsigned int *virq)
259{ 395{
260 int result; 396 int result;
261 unsigned long outlet; 397 unsigned long outlet;
@@ -270,73 +406,24 @@ int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class,
270 return result; 406 return result;
271 } 407 }
272 408
273 *virq = irq_create_mapping(NULL, outlet); 409 result = ps3_alloc_irq(cpu, outlet, virq);
274 410 BUG_ON(result);
275 pr_debug("%s:%d: spe_id %lu, class %u, outlet %lu, virq %u\n",
276 __func__, __LINE__, spe_id, class, outlet, *virq);
277 411
278 return 0; 412 return result;
279} 413}
280 414
281int ps3_free_spe_irq(unsigned int virq) 415int ps3_free_spe_irq(unsigned int virq)
282{ 416{
283 irq_dispose_mapping(virq); 417 ps3_free_irq(virq);
284 return 0; 418 return 0;
285} 419}
286 420
421
287#define PS3_INVALID_OUTLET ((irq_hw_number_t)-1) 422#define PS3_INVALID_OUTLET ((irq_hw_number_t)-1)
288#define PS3_PLUG_MAX 63 423#define PS3_PLUG_MAX 63
289 424
290/**
291 * struct bmp - a per cpu irq status and mask bitmap structure
292 * @status: 256 bit status bitmap indexed by plug
293 * @unused_1:
294 * @mask: 256 bit mask bitmap indexed by plug
295 * @unused_2:
296 * @lock:
297 * @ipi_debug_brk_mask:
298 *
299 * The HV mantains per SMT thread mappings of HV outlet to HV plug on
300 * behalf of the guest. These mappings are implemented as 256 bit guest
301 * supplied bitmaps indexed by plug number. The address of the bitmaps are
302 * registered with the HV through lv1_configure_irq_state_bitmap().
303 *
304 * The HV supports 256 plugs per thread, assigned as {0..255}, for a total
305 * of 512 plugs supported on a processor. To simplify the logic this
306 * implementation equates HV plug value to linux virq value, constrains each
307 * interrupt to have a system wide unique plug number, and limits the range
308 * of the plug values to map into the first dword of the bitmaps. This
309 * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note
310 * that there is no constraint on how many in this set an individual thread
311 * can aquire.
312 */
313
314struct bmp {
315 struct {
316 unsigned long status;
317 unsigned long unused_1[3];
318 unsigned long mask;
319 unsigned long unused_2[3];
320 } __attribute__ ((packed));
321 spinlock_t lock;
322 unsigned long ipi_debug_brk_mask;
323};
324
325/**
326 * struct private - a per cpu data structure
327 * @node: HV node id
328 * @cpu: HV thread id
329 * @bmp: an HV bmp structure
330 */
331
332struct private {
333 unsigned long node;
334 unsigned int cpu;
335 struct bmp bmp;
336};
337
338#if defined(DEBUG) 425#if defined(DEBUG)
339static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cpu, 426static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
340 const char* func, int line) 427 const char* func, int line)
341{ 428{
342 pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n", 429 pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n",
@@ -346,14 +433,14 @@ static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cp
346} 433}
347 434
348static void __attribute__ ((unused)) _dump_256_bmp(const char *header, 435static void __attribute__ ((unused)) _dump_256_bmp(const char *header,
349 const unsigned long *p, unsigned cpu, const char* func, int line) 436 const u64 *p, unsigned cpu, const char* func, int line)
350{ 437{
351 pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", 438 pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n",
352 func, line, header, cpu, p[0], p[1], p[2], p[3]); 439 func, line, header, cpu, p[0], p[1], p[2], p[3]);
353} 440}
354 441
355#define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__) 442#define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__)
356static void _dump_bmp(struct private* pd, const char* func, int line) 443static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
357{ 444{
358 unsigned long flags; 445 unsigned long flags;
359 446
@@ -364,7 +451,7 @@ static void _dump_bmp(struct private* pd, const char* func, int line)
364} 451}
365 452
366#define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) 453#define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
367static void __attribute__ ((unused)) _dump_mask(struct private* pd, 454static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd,
368 const char* func, int line) 455 const char* func, int line)
369{ 456{
370 unsigned long flags; 457 unsigned long flags;
@@ -374,109 +461,94 @@ static void __attribute__ ((unused)) _dump_mask(struct private* pd,
374 spin_unlock_irqrestore(&pd->bmp.lock, flags); 461 spin_unlock_irqrestore(&pd->bmp.lock, flags);
375} 462}
376#else 463#else
377static void dump_bmp(struct private* pd) {}; 464static void dump_bmp(struct ps3_private* pd) {};
378#endif /* defined(DEBUG) */ 465#endif /* defined(DEBUG) */
379 466
380static void chip_mask(unsigned int virq) 467static void ps3_chip_mask(unsigned int virq)
381{ 468{
469 struct ps3_private *pd = get_irq_chip_data(virq);
470 u64 bit = 0x8000000000000000UL >> virq;
471 u64 *p = &pd->bmp.mask;
472 u64 old;
382 unsigned long flags; 473 unsigned long flags;
383 struct private *pd = get_irq_chip_data(virq);
384 474
385 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); 475 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
386 476
387 BUG_ON(virq < NUM_ISA_INTERRUPTS); 477 local_irq_save(flags);
388 BUG_ON(virq > PS3_PLUG_MAX); 478 asm volatile(
389 479 "1: ldarx %0,0,%3\n"
390 spin_lock_irqsave(&pd->bmp.lock, flags); 480 "andc %0,%0,%2\n"
391 pd->bmp.mask &= ~(0x8000000000000000UL >> virq); 481 "stdcx. %0,0,%3\n"
392 spin_unlock_irqrestore(&pd->bmp.lock, flags); 482 "bne- 1b"
483 : "=&r" (old), "+m" (*p)
484 : "r" (bit), "r" (p)
485 : "cc" );
393 486
394 lv1_did_update_interrupt_mask(pd->node, pd->cpu); 487 lv1_did_update_interrupt_mask(pd->node, pd->cpu);
488 local_irq_restore(flags);
395} 489}
396 490
397static void chip_unmask(unsigned int virq) 491static void ps3_chip_unmask(unsigned int virq)
398{ 492{
493 struct ps3_private *pd = get_irq_chip_data(virq);
494 u64 bit = 0x8000000000000000UL >> virq;
495 u64 *p = &pd->bmp.mask;
496 u64 old;
399 unsigned long flags; 497 unsigned long flags;
400 struct private *pd = get_irq_chip_data(virq);
401 498
402 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); 499 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
403 500
404 BUG_ON(virq < NUM_ISA_INTERRUPTS); 501 local_irq_save(flags);
405 BUG_ON(virq > PS3_PLUG_MAX); 502 asm volatile(
406 503 "1: ldarx %0,0,%3\n"
407 spin_lock_irqsave(&pd->bmp.lock, flags); 504 "or %0,%0,%2\n"
408 pd->bmp.mask |= (0x8000000000000000UL >> virq); 505 "stdcx. %0,0,%3\n"
409 spin_unlock_irqrestore(&pd->bmp.lock, flags); 506 "bne- 1b"
507 : "=&r" (old), "+m" (*p)
508 : "r" (bit), "r" (p)
509 : "cc" );
410 510
411 lv1_did_update_interrupt_mask(pd->node, pd->cpu); 511 lv1_did_update_interrupt_mask(pd->node, pd->cpu);
512 local_irq_restore(flags);
412} 513}
413 514
414static void chip_eoi(unsigned int virq) 515static void ps3_chip_eoi(unsigned int virq)
415{ 516{
416 lv1_end_of_interrupt(virq); 517 const struct ps3_private *pd = get_irq_chip_data(virq);
518 lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq);
417} 519}
418 520
419static struct irq_chip irq_chip = { 521static struct irq_chip irq_chip = {
420 .typename = "ps3", 522 .typename = "ps3",
421 .mask = chip_mask, 523 .mask = ps3_chip_mask,
422 .unmask = chip_unmask, 524 .unmask = ps3_chip_unmask,
423 .eoi = chip_eoi, 525 .eoi = ps3_chip_eoi,
424}; 526};
425 527
426static void host_unmap(struct irq_host *h, unsigned int virq) 528static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
427{ 529{
428 int result; 530 set_irq_chip_data(virq, NULL);
429
430 pr_debug("%s:%d: virq %d\n", __func__, __LINE__, virq);
431
432 lv1_disconnect_irq_plug(virq);
433
434 result = set_irq_chip_data(virq, NULL);
435 BUG_ON(result);
436} 531}
437 532
438static DEFINE_PER_CPU(struct private, private); 533static int ps3_host_map(struct irq_host *h, unsigned int virq,
439
440static int host_map(struct irq_host *h, unsigned int virq,
441 irq_hw_number_t hwirq) 534 irq_hw_number_t hwirq)
442{ 535{
443 int result; 536 pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
444 unsigned int cpu;
445
446 pr_debug(" -> %s:%d\n", __func__, __LINE__);
447 pr_debug("%s:%d: hwirq %lu => virq %u\n", __func__, __LINE__, hwirq,
448 virq); 537 virq);
449 538
450 /* bind this virq to a cpu */
451
452 preempt_disable();
453 cpu = smp_processor_id();
454 result = lv1_connect_irq_plug(virq, hwirq);
455 preempt_enable();
456
457 if (result) {
458 pr_info("%s:%d: lv1_connect_irq_plug failed:"
459 " %s\n", __func__, __LINE__, ps3_result(result));
460 return -EPERM;
461 }
462
463 result = set_irq_chip_data(virq, &per_cpu(private, cpu));
464 BUG_ON(result);
465
466 set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); 539 set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq);
467 540
468 pr_debug(" <- %s:%d\n", __func__, __LINE__); 541 return 0;
469 return result;
470} 542}
471 543
472static struct irq_host_ops host_ops = { 544static struct irq_host_ops ps3_host_ops = {
473 .map = host_map, 545 .map = ps3_host_map,
474 .unmap = host_unmap, 546 .unmap = ps3_host_unmap,
475}; 547};
476 548
477void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) 549void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
478{ 550{
479 struct private *pd = &per_cpu(private, cpu); 551 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
480 552
481 pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq; 553 pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq;
482 554
@@ -484,57 +556,32 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
484 cpu, virq, pd->bmp.ipi_debug_brk_mask); 556 cpu, virq, pd->bmp.ipi_debug_brk_mask);
485} 557}
486 558
487static int bmp_get_and_clear_status_bit(struct bmp *m) 559unsigned int ps3_get_irq(void)
488{ 560{
489 unsigned long flags; 561 struct ps3_private *pd = &__get_cpu_var(ps3_private);
490 unsigned int bit; 562 u64 x = (pd->bmp.status & pd->bmp.mask);
491 unsigned long x; 563 unsigned int plug;
492
493 spin_lock_irqsave(&m->lock, flags);
494 564
495 /* check for ipi break first to stop this cpu ASAP */ 565 /* check for ipi break first to stop this cpu ASAP */
496 566
497 if (m->status & m->ipi_debug_brk_mask) { 567 if (x & pd->bmp.ipi_debug_brk_mask)
498 m->status &= ~m->ipi_debug_brk_mask; 568 x &= pd->bmp.ipi_debug_brk_mask;
499 spin_unlock_irqrestore(&m->lock, flags);
500 return __ilog2(m->ipi_debug_brk_mask);
501 }
502
503 x = (m->status & m->mask);
504 569
505 for (bit = NUM_ISA_INTERRUPTS, x <<= bit; x; bit++, x <<= 1) 570 asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
506 if (x & 0x8000000000000000UL) { 571 plug &= 0x3f;
507 m->status &= ~(0x8000000000000000UL >> bit);
508 spin_unlock_irqrestore(&m->lock, flags);
509 return bit;
510 }
511 572
512 spin_unlock_irqrestore(&m->lock, flags); 573 if (unlikely(plug) == NO_IRQ) {
513
514 pr_debug("%s:%d: not found\n", __func__, __LINE__);
515 return -1;
516}
517
518unsigned int ps3_get_irq(void)
519{
520 int plug;
521
522 struct private *pd = &__get_cpu_var(private);
523
524 plug = bmp_get_and_clear_status_bit(&pd->bmp);
525
526 if (plug < 1) {
527 pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__, 574 pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__,
528 pd->cpu); 575 pd->cpu);
529 dump_bmp(&per_cpu(private, 0)); 576 dump_bmp(&per_cpu(ps3_private, 0));
530 dump_bmp(&per_cpu(private, 1)); 577 dump_bmp(&per_cpu(ps3_private, 1));
531 return NO_IRQ; 578 return NO_IRQ;
532 } 579 }
533 580
534#if defined(DEBUG) 581#if defined(DEBUG)
535 if (plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX) { 582 if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) {
536 dump_bmp(&per_cpu(private, 0)); 583 dump_bmp(&per_cpu(ps3_private, 0));
537 dump_bmp(&per_cpu(private, 1)); 584 dump_bmp(&per_cpu(ps3_private, 1));
538 BUG(); 585 BUG();
539 } 586 }
540#endif 587#endif
@@ -544,26 +591,27 @@ unsigned int ps3_get_irq(void)
544void __init ps3_init_IRQ(void) 591void __init ps3_init_IRQ(void)
545{ 592{
546 int result; 593 int result;
547 unsigned long node;
548 unsigned cpu; 594 unsigned cpu;
549 struct irq_host *host; 595 struct irq_host *host;
550 596
551 lv1_get_logical_ppe_id(&node); 597 host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops,
552
553 host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &host_ops,
554 PS3_INVALID_OUTLET); 598 PS3_INVALID_OUTLET);
555 irq_set_default_host(host); 599 irq_set_default_host(host);
556 irq_set_virq_count(PS3_PLUG_MAX + 1); 600 irq_set_virq_count(PS3_PLUG_MAX + 1);
557 601
558 for_each_possible_cpu(cpu) { 602 for_each_possible_cpu(cpu) {
559 struct private *pd = &per_cpu(private, cpu); 603 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
560 604
561 pd->node = node; 605 lv1_get_logical_ppe_id(&pd->node);
562 pd->cpu = cpu; 606 pd->cpu = get_hard_smp_processor_id(cpu);
563 spin_lock_init(&pd->bmp.lock); 607 spin_lock_init(&pd->bmp.lock);
564 608
565 result = lv1_configure_irq_state_bitmap(node, cpu, 609 pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__,
566 ps3_mm_phys_to_lpar(__pa(&pd->bmp.status))); 610 __LINE__, pd->node, pd->cpu,
611 ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
612
613 result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu,
614 ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
567 615
568 if (result) 616 if (result)
569 pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" 617 pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:"
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c
index 49c0d010d491..42354de3f557 100644
--- a/arch/powerpc/platforms/ps3/mm.c
+++ b/arch/powerpc/platforms/ps3/mm.c
@@ -25,7 +25,6 @@
25#include <asm/firmware.h> 25#include <asm/firmware.h>
26#include <asm/lmb.h> 26#include <asm/lmb.h>
27#include <asm/udbg.h> 27#include <asm/udbg.h>
28#include <asm/ps3.h>
29#include <asm/lv1call.h> 28#include <asm/lv1call.h>
30 29
31#include "platform.h" 30#include "platform.h"
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c
index 58358305dc10..5c3da08bc0c4 100644
--- a/arch/powerpc/platforms/ps3/os-area.c
+++ b/arch/powerpc/platforms/ps3/os-area.c
@@ -22,7 +22,6 @@
22#include <linux/io.h> 22#include <linux/io.h>
23 23
24#include <asm/lmb.h> 24#include <asm/lmb.h>
25#include <asm/ps3.h>
26 25
27#include "platform.h" 26#include "platform.h"
28 27
@@ -59,7 +58,7 @@ struct os_area_header {
59 u32 ldr_format; 58 u32 ldr_format;
60 u32 ldr_size; 59 u32 ldr_size;
61 u32 _reserved_2[6]; 60 u32 _reserved_2[6];
62} __attribute__ ((packed)); 61};
63 62
64enum { 63enum {
65 PARAM_BOOT_FLAG_GAME_OS = 0, 64 PARAM_BOOT_FLAG_GAME_OS = 0,
@@ -67,13 +66,6 @@ enum {
67}; 66};
68 67
69enum { 68enum {
70 PARAM_AV_MULTI_OUT_NTSC = 0,
71 PARAM_AV_MULTI_OUT_PAL_RGB = 1,
72 PARAM_AV_MULTI_OUT_PAL_YCBCR = 2,
73 PARAM_AV_MULTI_OUT_SECAM = 3,
74};
75
76enum {
77 PARAM_CTRL_BUTTON_O_IS_YES = 0, 69 PARAM_CTRL_BUTTON_O_IS_YES = 0,
78 PARAM_CTRL_BUTTON_X_IS_YES = 1, 70 PARAM_CTRL_BUTTON_X_IS_YES = 1,
79}; 71};
@@ -114,7 +106,7 @@ struct os_area_params {
114 u8 dns_primary[4]; 106 u8 dns_primary[4];
115 u8 dns_secondary[4]; 107 u8 dns_secondary[4];
116 u8 _reserved_5[8]; 108 u8 _reserved_5[8];
117} __attribute__ ((packed)); 109};
118 110
119/** 111/**
120 * struct saved_params - Static working copies of data from the 'Other OS' area. 112 * struct saved_params - Static working copies of data from the 'Other OS' area.
@@ -257,3 +249,13 @@ u64 ps3_os_area_rtc_diff(void)
257{ 249{
258 return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL; 250 return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL;
259} 251}
252
253/**
254 * ps3_os_area_get_av_multi_out - Returns the default video mode.
255 */
256
257enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void)
258{
259 return saved_params.av_multi_out;
260}
261EXPORT_SYMBOL_GPL(ps3_os_area_get_av_multi_out);
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h
index 23b111bea9d0..ca04f03305c7 100644
--- a/arch/powerpc/platforms/ps3/platform.h
+++ b/arch/powerpc/platforms/ps3/platform.h
@@ -22,6 +22,9 @@
22#define _PS3_PLATFORM_H 22#define _PS3_PLATFORM_H
23 23
24#include <linux/rtc.h> 24#include <linux/rtc.h>
25#include <scsi/scsi.h>
26
27#include <asm/ps3.h>
25 28
26/* htab */ 29/* htab */
27 30
@@ -65,4 +68,152 @@ void ps3_spu_set_platform (void);
65static inline void ps3_spu_set_platform (void) {} 68static inline void ps3_spu_set_platform (void) {}
66#endif 69#endif
67 70
71/* repository bus info */
72
73enum ps3_bus_type {
74 PS3_BUS_TYPE_SB = 4,
75 PS3_BUS_TYPE_STORAGE = 5,
76};
77
78enum ps3_dev_type {
79 PS3_DEV_TYPE_STOR_DISK = TYPE_DISK, /* 0 */
80 PS3_DEV_TYPE_SB_GELIC = 3,
81 PS3_DEV_TYPE_SB_USB = 4,
82 PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */
83 PS3_DEV_TYPE_SB_GPIO = 6,
84 PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */
85};
86
87int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str,
88 u64 *value);
89int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id);
90int ps3_repository_read_bus_type(unsigned int bus_index,
91 enum ps3_bus_type *bus_type);
92int ps3_repository_read_bus_num_dev(unsigned int bus_index,
93 unsigned int *num_dev);
94
95/* repository bus device info */
96
97enum ps3_interrupt_type {
98 PS3_INTERRUPT_TYPE_EVENT_PORT = 2,
99 PS3_INTERRUPT_TYPE_SB_OHCI = 3,
100 PS3_INTERRUPT_TYPE_SB_EHCI = 4,
101 PS3_INTERRUPT_TYPE_OTHER = 5,
102};
103
104enum ps3_reg_type {
105 PS3_REG_TYPE_SB_OHCI = 3,
106 PS3_REG_TYPE_SB_EHCI = 4,
107 PS3_REG_TYPE_SB_GPIO = 5,
108};
109
110int ps3_repository_read_dev_str(unsigned int bus_index,
111 unsigned int dev_index, const char *dev_str, u64 *value);
112int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index,
113 unsigned int *dev_id);
114int ps3_repository_read_dev_type(unsigned int bus_index,
115 unsigned int dev_index, enum ps3_dev_type *dev_type);
116int ps3_repository_read_dev_intr(unsigned int bus_index,
117 unsigned int dev_index, unsigned int intr_index,
118 enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id);
119int ps3_repository_read_dev_reg_type(unsigned int bus_index,
120 unsigned int dev_index, unsigned int reg_index,
121 enum ps3_reg_type *reg_type);
122int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
123 unsigned int dev_index, unsigned int reg_index, u64 *bus_addr,
124 u64 *len);
125int ps3_repository_read_dev_reg(unsigned int bus_index,
126 unsigned int dev_index, unsigned int reg_index,
127 enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len);
128
129/* repository bus enumerators */
130
131struct ps3_repository_device {
132 unsigned int bus_index;
133 unsigned int dev_index;
134 struct ps3_device_id did;
135};
136
137int ps3_repository_find_device(enum ps3_bus_type bus_type,
138 enum ps3_dev_type dev_type,
139 const struct ps3_repository_device *start_dev,
140 struct ps3_repository_device *dev);
141static inline int ps3_repository_find_first_device(
142 enum ps3_bus_type bus_type, enum ps3_dev_type dev_type,
143 struct ps3_repository_device *dev)
144{
145 return ps3_repository_find_device(bus_type, dev_type, NULL, dev);
146}
147int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
148 enum ps3_interrupt_type intr_type, unsigned int *interrupt_id);
149int ps3_repository_find_reg(const struct ps3_repository_device *dev,
150 enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len);
151
152/* repository block device info */
153
154int ps3_repository_read_stor_dev_port(unsigned int bus_index,
155 unsigned int dev_index, u64 *port);
156int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
157 unsigned int dev_index, u64 *blk_size);
158int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
159 unsigned int dev_index, u64 *num_blocks);
160int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
161 unsigned int dev_index, unsigned int *num_regions);
162int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
163 unsigned int dev_index, unsigned int region_index,
164 unsigned int *region_id);
165int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
166 unsigned int dev_index, unsigned int region_index, u64 *region_size);
167int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
168 unsigned int dev_index, unsigned int region_index, u64 *region_start);
169int ps3_repository_read_stor_dev_info(unsigned int bus_index,
170 unsigned int dev_index, u64 *port, u64 *blk_size,
171 u64 *num_blocks, unsigned int *num_regions);
172int ps3_repository_read_stor_dev_region(unsigned int bus_index,
173 unsigned int dev_index, unsigned int region_index,
174 unsigned int *region_id, u64 *region_start, u64 *region_size);
175
176/* repository pu and memory info */
177
178int ps3_repository_read_num_pu(unsigned int *num_pu);
179int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id);
180int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base);
181int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size);
182int ps3_repository_read_region_total(u64 *region_total);
183int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size,
184 u64 *region_total);
185
186/* repository pme info */
187
188int ps3_repository_read_num_be(unsigned int *num_be);
189int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id);
190int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq);
191int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq);
192
193/* repository 'Other OS' area */
194
195int ps3_repository_read_boot_dat_addr(u64 *lpar_addr);
196int ps3_repository_read_boot_dat_size(unsigned int *size);
197int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size);
198
199/* repository spu info */
200
201/**
202 * enum spu_resource_type - Type of spu resource.
203 * @spu_resource_type_shared: Logical spu is shared with other partions.
204 * @spu_resource_type_exclusive: Logical spu is not shared with other partions.
205 *
206 * Returned by ps3_repository_read_spu_resource_id().
207 */
208
209enum ps3_spu_resource_type {
210 PS3_SPU_RESOURCE_TYPE_SHARED = 0,
211 PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL,
212};
213
214int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved);
215int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id);
216int ps3_repository_read_spu_resource_id(unsigned int res_index,
217 enum ps3_spu_resource_type* resource_type, unsigned int *resource_id);
218
68#endif 219#endif
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c
index 273a0d621bdd..ae586a0e5d3f 100644
--- a/arch/powerpc/platforms/ps3/repository.c
+++ b/arch/powerpc/platforms/ps3/repository.c
@@ -18,9 +18,10 @@
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */ 19 */
20 20
21#include <asm/ps3.h>
22#include <asm/lv1call.h> 21#include <asm/lv1call.h>
23 22
23#include "platform.h"
24
24enum ps3_vendor_id { 25enum ps3_vendor_id {
25 PS3_VENDOR_ID_NONE = 0, 26 PS3_VENDOR_ID_NONE = 0,
26 PS3_VENDOR_ID_SONY = 0x8000000000000000UL, 27 PS3_VENDOR_ID_SONY = 0x8000000000000000UL,
@@ -257,7 +258,7 @@ int ps3_repository_read_dev_type(unsigned int bus_index,
257 258
258int ps3_repository_read_dev_intr(unsigned int bus_index, 259int ps3_repository_read_dev_intr(unsigned int bus_index,
259 unsigned int dev_index, unsigned int intr_index, 260 unsigned int dev_index, unsigned int intr_index,
260 unsigned int *intr_type, unsigned int* interrupt_id) 261 enum ps3_interrupt_type *intr_type, unsigned int* interrupt_id)
261{ 262{
262 int result; 263 int result;
263 u64 v1; 264 u64 v1;
@@ -275,7 +276,8 @@ int ps3_repository_read_dev_intr(unsigned int bus_index,
275} 276}
276 277
277int ps3_repository_read_dev_reg_type(unsigned int bus_index, 278int ps3_repository_read_dev_reg_type(unsigned int bus_index,
278 unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type) 279 unsigned int dev_index, unsigned int reg_index,
280 enum ps3_reg_type *reg_type)
279{ 281{
280 int result; 282 int result;
281 u64 v1; 283 u64 v1;
@@ -302,8 +304,8 @@ int ps3_repository_read_dev_reg_addr(unsigned int bus_index,
302} 304}
303 305
304int ps3_repository_read_dev_reg(unsigned int bus_index, 306int ps3_repository_read_dev_reg(unsigned int bus_index,
305 unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type, 307 unsigned int dev_index, unsigned int reg_index,
306 u64 *bus_addr, u64 *len) 308 enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len)
307{ 309{
308 int result = ps3_repository_read_dev_reg_type(bus_index, dev_index, 310 int result = ps3_repository_read_dev_reg_type(bus_index, dev_index,
309 reg_index, reg_type); 311 reg_index, reg_type);
@@ -343,7 +345,7 @@ int ps3_repository_dump_resource_info(unsigned int bus_index,
343 } 345 }
344 346
345 for (res_index = 0; res_index < 10; res_index++) { 347 for (res_index = 0; res_index < 10; res_index++) {
346 enum ps3_region_type reg_type; 348 enum ps3_reg_type reg_type;
347 u64 bus_addr; 349 u64 bus_addr;
348 u64 len; 350 u64 len;
349 351
@@ -367,7 +369,55 @@ int ps3_repository_dump_resource_info(unsigned int bus_index,
367 return result; 369 return result;
368} 370}
369 371
370static int dump_device_info(unsigned int bus_index, unsigned int num_dev) 372static int dump_stor_dev_info(unsigned int bus_index, unsigned int dev_index)
373{
374 int result = 0;
375 unsigned int num_regions, region_index;
376 u64 port, blk_size, num_blocks;
377
378 pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__,
379 bus_index, dev_index);
380
381 result = ps3_repository_read_stor_dev_info(bus_index, dev_index, &port,
382 &blk_size, &num_blocks, &num_regions);
383 if (result) {
384 pr_debug("%s:%d ps3_repository_read_stor_dev_info"
385 " (%u:%u) failed\n", __func__, __LINE__,
386 bus_index, dev_index);
387 goto out;
388 }
389
390 pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks "
391 "%lu, num_regions %u\n",
392 __func__, __LINE__, bus_index, dev_index, port,
393 blk_size, num_blocks, num_regions);
394
395 for (region_index = 0; region_index < num_regions; region_index++) {
396 unsigned int region_id;
397 u64 region_start, region_size;
398
399 result = ps3_repository_read_stor_dev_region(bus_index,
400 dev_index, region_index, &region_id, &region_start,
401 &region_size);
402 if (result) {
403 pr_debug("%s:%d ps3_repository_read_stor_dev_region"
404 " (%u:%u) failed\n", __func__, __LINE__,
405 bus_index, dev_index);
406 break;
407 }
408
409 pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n",
410 __func__, __LINE__, bus_index, dev_index, region_id,
411 region_start, region_size);
412 }
413
414out:
415 pr_debug(" <- %s:%d\n", __func__, __LINE__);
416 return result;
417}
418
419static int dump_device_info(unsigned int bus_index, enum ps3_bus_type bus_type,
420 unsigned int num_dev)
371{ 421{
372 int result = 0; 422 int result = 0;
373 unsigned int dev_index; 423 unsigned int dev_index;
@@ -402,6 +452,9 @@ static int dump_device_info(unsigned int bus_index, unsigned int num_dev)
402 __LINE__, bus_index, dev_index, dev_type, dev_id); 452 __LINE__, bus_index, dev_index, dev_type, dev_id);
403 453
404 ps3_repository_dump_resource_info(bus_index, dev_index); 454 ps3_repository_dump_resource_info(bus_index, dev_index);
455
456 if (bus_type == PS3_BUS_TYPE_STORAGE)
457 dump_stor_dev_info(bus_index, dev_index);
405 } 458 }
406 459
407 pr_debug(" <- %s:%d\n", __func__, __LINE__); 460 pr_debug(" <- %s:%d\n", __func__, __LINE__);
@@ -452,7 +505,7 @@ int ps3_repository_dump_bus_info(void)
452 __func__, __LINE__, bus_index, bus_type, bus_id, 505 __func__, __LINE__, bus_index, bus_type, bus_id,
453 num_dev); 506 num_dev);
454 507
455 dump_device_info(bus_index, num_dev); 508 dump_device_info(bus_index, bus_type, num_dev);
456 } 509 }
457 510
458 pr_debug(" <- %s:%d\n", __func__, __LINE__); 511 pr_debug(" <- %s:%d\n", __func__, __LINE__);
@@ -487,7 +540,8 @@ static int find_device(unsigned int bus_index, unsigned int num_dev,
487 break; 540 break;
488 } 541 }
489 542
490 BUG_ON(dev_index == num_dev); 543 if (dev_index == num_dev)
544 return -1;
491 545
492 pr_debug("%s:%d: found dev_type %u at dev_index %u\n", 546 pr_debug("%s:%d: found dev_type %u at dev_index %u\n",
493 __func__, __LINE__, dev_type, dev_index); 547 __func__, __LINE__, dev_type, dev_index);
@@ -521,7 +575,7 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
521 pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__, 575 pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__,
522 bus_type, dev_type); 576 bus_type, dev_type);
523 577
524 dev->bus_index = UINT_MAX; 578 BUG_ON(start_dev && start_dev->bus_index > 10);
525 579
526 for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10; 580 for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10;
527 bus_index++) { 581 bus_index++) {
@@ -532,13 +586,15 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type,
532 if (result) { 586 if (result) {
533 pr_debug("%s:%d read_bus_type failed\n", 587 pr_debug("%s:%d read_bus_type failed\n",
534 __func__, __LINE__); 588 __func__, __LINE__);
589 dev->bus_index = UINT_MAX;
535 return result; 590 return result;
536 } 591 }
537 if (x == bus_type) 592 if (x == bus_type)
538 break; 593 break;
539 } 594 }
540 595
541 BUG_ON(bus_index == 10); 596 if (bus_index >= 10)
597 return -ENODEV;
542 598
543 pr_debug("%s:%d: found bus_type %u at bus_index %u\n", 599 pr_debug("%s:%d: found bus_type %u at bus_index %u\n",
544 __func__, __LINE__, bus_type, bus_index); 600 __func__, __LINE__, bus_type, bus_index);
@@ -604,7 +660,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
604 } 660 }
605 } 661 }
606 662
607 BUG_ON(res_index == 10); 663 if (res_index == 10)
664 return -ENODEV;
608 665
609 pr_debug("%s:%d: found intr_type %u at res_index %u\n", 666 pr_debug("%s:%d: found intr_type %u at res_index %u\n",
610 __func__, __LINE__, intr_type, res_index); 667 __func__, __LINE__, intr_type, res_index);
@@ -612,8 +669,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev,
612 return result; 669 return result;
613} 670}
614 671
615int ps3_repository_find_region(const struct ps3_repository_device *dev, 672int ps3_repository_find_reg(const struct ps3_repository_device *dev,
616 enum ps3_region_type reg_type, u64 *bus_addr, u64 *len) 673 enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len)
617{ 674{
618 int result = 0; 675 int result = 0;
619 unsigned int res_index; 676 unsigned int res_index;
@@ -623,7 +680,7 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev,
623 *bus_addr = *len = 0; 680 *bus_addr = *len = 0;
624 681
625 for (res_index = 0; res_index < 10; res_index++) { 682 for (res_index = 0; res_index < 10; res_index++) {
626 enum ps3_region_type t; 683 enum ps3_reg_type t;
627 u64 a; 684 u64 a;
628 u64 l; 685 u64 l;
629 686
@@ -643,7 +700,8 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev,
643 } 700 }
644 } 701 }
645 702
646 BUG_ON(res_index == 10); 703 if (res_index == 10)
704 return -ENODEV;
647 705
648 pr_debug("%s:%d: found reg_type %u at res_index %u\n", 706 pr_debug("%s:%d: found reg_type %u at res_index %u\n",
649 __func__, __LINE__, reg_type, res_index); 707 __func__, __LINE__, reg_type, res_index);
@@ -651,6 +709,136 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev,
651 return result; 709 return result;
652} 710}
653 711
712int ps3_repository_read_stor_dev_port(unsigned int bus_index,
713 unsigned int dev_index, u64 *port)
714{
715 return read_node(PS3_LPAR_ID_PME,
716 make_first_field("bus", bus_index),
717 make_field("dev", dev_index),
718 make_field("port", 0),
719 0, port, 0);
720}
721
722int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index,
723 unsigned int dev_index, u64 *blk_size)
724{
725 return read_node(PS3_LPAR_ID_PME,
726 make_first_field("bus", bus_index),
727 make_field("dev", dev_index),
728 make_field("blk_size", 0),
729 0, blk_size, 0);
730}
731
732int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index,
733 unsigned int dev_index, u64 *num_blocks)
734{
735 return read_node(PS3_LPAR_ID_PME,
736 make_first_field("bus", bus_index),
737 make_field("dev", dev_index),
738 make_field("n_blocks", 0),
739 0, num_blocks, 0);
740}
741
742int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index,
743 unsigned int dev_index, unsigned int *num_regions)
744{
745 int result;
746 u64 v1;
747
748 result = read_node(PS3_LPAR_ID_PME,
749 make_first_field("bus", bus_index),
750 make_field("dev", dev_index),
751 make_field("n_regs", 0),
752 0, &v1, 0);
753 *num_regions = v1;
754 return result;
755}
756
757int ps3_repository_read_stor_dev_region_id(unsigned int bus_index,
758 unsigned int dev_index, unsigned int region_index,
759 unsigned int *region_id)
760{
761 int result;
762 u64 v1;
763
764 result = read_node(PS3_LPAR_ID_PME,
765 make_first_field("bus", bus_index),
766 make_field("dev", dev_index),
767 make_field("region", region_index),
768 make_field("id", 0),
769 &v1, 0);
770 *region_id = v1;
771 return result;
772}
773
774int ps3_repository_read_stor_dev_region_size(unsigned int bus_index,
775 unsigned int dev_index, unsigned int region_index, u64 *region_size)
776{
777 return read_node(PS3_LPAR_ID_PME,
778 make_first_field("bus", bus_index),
779 make_field("dev", dev_index),
780 make_field("region", region_index),
781 make_field("size", 0),
782 region_size, 0);
783}
784
785int ps3_repository_read_stor_dev_region_start(unsigned int bus_index,
786 unsigned int dev_index, unsigned int region_index, u64 *region_start)
787{
788 return read_node(PS3_LPAR_ID_PME,
789 make_first_field("bus", bus_index),
790 make_field("dev", dev_index),
791 make_field("region", region_index),
792 make_field("start", 0),
793 region_start, 0);
794}
795
796int ps3_repository_read_stor_dev_info(unsigned int bus_index,
797 unsigned int dev_index, u64 *port, u64 *blk_size,
798 u64 *num_blocks, unsigned int *num_regions)
799{
800 int result;
801
802 result = ps3_repository_read_stor_dev_port(bus_index, dev_index, port);
803 if (result)
804 return result;
805
806 result = ps3_repository_read_stor_dev_blk_size(bus_index, dev_index,
807 blk_size);
808 if (result)
809 return result;
810
811 result = ps3_repository_read_stor_dev_num_blocks(bus_index, dev_index,
812 num_blocks);
813 if (result)
814 return result;
815
816 result = ps3_repository_read_stor_dev_num_regions(bus_index, dev_index,
817 num_regions);
818 return result;
819}
820
821int ps3_repository_read_stor_dev_region(unsigned int bus_index,
822 unsigned int dev_index, unsigned int region_index,
823 unsigned int *region_id, u64 *region_start, u64 *region_size)
824{
825 int result;
826
827 result = ps3_repository_read_stor_dev_region_id(bus_index, dev_index,
828 region_index, region_id);
829 if (result)
830 return result;
831
832 result = ps3_repository_read_stor_dev_region_start(bus_index, dev_index,
833 region_index, region_start);
834 if (result)
835 return result;
836
837 result = ps3_repository_read_stor_dev_region_size(bus_index, dev_index,
838 region_index, region_size);
839 return result;
840}
841
654int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) 842int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size)
655{ 843{
656 return read_node(PS3_LPAR_ID_CURRENT, 844 return read_node(PS3_LPAR_ID_CURRENT,
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c
index d8b5cadbe80e..e62505e18813 100644
--- a/arch/powerpc/platforms/ps3/setup.c
+++ b/arch/powerpc/platforms/ps3/setup.c
@@ -41,10 +41,18 @@
41#define DBG(fmt...) do{if(0)printk(fmt);}while(0) 41#define DBG(fmt...) do{if(0)printk(fmt);}while(0)
42#endif 42#endif
43 43
44static void ps3_show_cpuinfo(struct seq_file *m) 44int ps3_get_firmware_version(union ps3_firmware_version *v)
45{ 45{
46 seq_printf(m, "machine\t\t: %s\n", ppc_md.name); 46 int result = lv1_get_version_info(&v->raw);
47
48 if (result) {
49 v->raw = 0;
50 return -1;
51 }
52
53 return result;
47} 54}
55EXPORT_SYMBOL_GPL(ps3_get_firmware_version);
48 56
49static void ps3_power_save(void) 57static void ps3_power_save(void)
50{ 58{
@@ -74,8 +82,14 @@ static void ps3_panic(char *str)
74 82
75static void __init ps3_setup_arch(void) 83static void __init ps3_setup_arch(void)
76{ 84{
85 union ps3_firmware_version v;
86
77 DBG(" -> %s:%d\n", __func__, __LINE__); 87 DBG(" -> %s:%d\n", __func__, __LINE__);
78 88
89 ps3_get_firmware_version(&v);
90 printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", v.major, v.minor,
91 v.rev);
92
79 ps3_spu_set_platform(); 93 ps3_spu_set_platform();
80 ps3_map_htab(); 94 ps3_map_htab();
81 95
@@ -156,7 +170,6 @@ define_machine(ps3) {
156 .name = "PS3", 170 .name = "PS3",
157 .probe = ps3_probe, 171 .probe = ps3_probe,
158 .setup_arch = ps3_setup_arch, 172 .setup_arch = ps3_setup_arch,
159 .show_cpuinfo = ps3_show_cpuinfo,
160 .init_IRQ = ps3_init_IRQ, 173 .init_IRQ = ps3_init_IRQ,
161 .panic = ps3_panic, 174 .panic = ps3_panic,
162 .get_boot_time = ps3_get_boot_time, 175 .get_boot_time = ps3_get_boot_time,
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c
index 11d2080607ed..6fb887961a6d 100644
--- a/arch/powerpc/platforms/ps3/smp.c
+++ b/arch/powerpc/platforms/ps3/smp.c
@@ -23,7 +23,6 @@
23 23
24#include <asm/machdep.h> 24#include <asm/machdep.h>
25#include <asm/udbg.h> 25#include <asm/udbg.h>
26#include <asm/ps3.h>
27 26
28#include "platform.h" 27#include "platform.h"
29 28
@@ -111,7 +110,7 @@ static void __init ps3_smp_setup_cpu(int cpu)
111 BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); 110 BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3);
112 111
113 for (i = 0; i < MSG_COUNT; i++) { 112 for (i = 0; i < MSG_COUNT; i++) {
114 result = ps3_alloc_event_irq(&virqs[i]); 113 result = ps3_alloc_event_irq(cpu, &virqs[i]);
115 114
116 if (result) 115 if (result)
117 continue; 116 continue;
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c
index 644532c3b7c4..d1929721b0e4 100644
--- a/arch/powerpc/platforms/ps3/spu.c
+++ b/arch/powerpc/platforms/ps3/spu.c
@@ -26,9 +26,10 @@
26 26
27#include <asm/spu.h> 27#include <asm/spu.h>
28#include <asm/spu_priv1.h> 28#include <asm/spu_priv1.h>
29#include <asm/ps3.h>
30#include <asm/lv1call.h> 29#include <asm/lv1call.h>
31 30
31#include "platform.h"
32
32/* spu_management_ops */ 33/* spu_management_ops */
33 34
34/** 35/**
@@ -50,7 +51,7 @@ enum spe_type {
50 */ 51 */
51 52
52struct spe_shadow { 53struct spe_shadow {
53 u8 padding_0000[0x0140]; 54 u8 padding_0140[0x0140];
54 u64 int_status_class0_RW; /* 0x0140 */ 55 u64 int_status_class0_RW; /* 0x0140 */
55 u64 int_status_class1_RW; /* 0x0148 */ 56 u64 int_status_class1_RW; /* 0x0148 */
56 u64 int_status_class2_RW; /* 0x0150 */ 57 u64 int_status_class2_RW; /* 0x0150 */
@@ -67,8 +68,7 @@ struct spe_shadow {
67 u8 padding_0c08[0x0f00-0x0c08]; 68 u8 padding_0c08[0x0f00-0x0c08];
68 u64 spe_execution_status; /* 0x0f00 */ 69 u64 spe_execution_status; /* 0x0f00 */
69 u8 padding_0f08[0x1000-0x0f08]; 70 u8 padding_0f08[0x1000-0x0f08];
70} __attribute__ ((packed)); 71};
71
72 72
73/** 73/**
74 * enum spe_ex_state - Logical spe execution state. 74 * enum spe_ex_state - Logical spe execution state.
@@ -268,20 +268,20 @@ static int __init setup_interrupts(struct spu *spu)
268{ 268{
269 int result; 269 int result;
270 270
271 result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 0, 271 result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
272 &spu->irqs[0]); 272 0, &spu->irqs[0]);
273 273
274 if (result) 274 if (result)
275 goto fail_alloc_0; 275 goto fail_alloc_0;
276 276
277 result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 1, 277 result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
278 &spu->irqs[1]); 278 1, &spu->irqs[1]);
279 279
280 if (result) 280 if (result)
281 goto fail_alloc_1; 281 goto fail_alloc_1;
282 282
283 result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 2, 283 result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id,
284 &spu->irqs[2]); 284 2, &spu->irqs[2]);
285 285
286 if (result) 286 if (result)
287 goto fail_alloc_2; 287 goto fail_alloc_2;
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c
new file mode 100644
index 000000000000..bce6136cbce7
--- /dev/null
+++ b/arch/powerpc/platforms/ps3/system-bus.c
@@ -0,0 +1,382 @@
1/*
2 * PS3 system bus driver.
3 *
4 * Copyright (C) 2006 Sony Computer Entertainment Inc.
5 * Copyright 2006 Sony Corp.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/module.h>
24#include <linux/dma-mapping.h>
25#include <linux/err.h>
26
27#include <asm/udbg.h>
28#include <asm/lv1call.h>
29#include <asm/firmware.h>
30
31#include "platform.h"
32
33#define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__)
34static void _dump_mmio_region(const struct ps3_mmio_region* r,
35 const char* func, int line)
36{
37 pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id,
38 r->did.dev_id);
39 pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr);
40 pr_debug("%s:%d: len %lxh\n", func, line, r->len);
41 pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr);
42}
43
44int ps3_mmio_region_create(struct ps3_mmio_region *r)
45{
46 int result;
47
48 result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id,
49 r->bus_addr, r->len, r->page_size, &r->lpar_addr);
50
51 if (result) {
52 pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n",
53 __func__, __LINE__, ps3_result(result));
54 r->lpar_addr = 0;
55 }
56
57 dump_mmio_region(r);
58 return result;
59}
60
61int ps3_free_mmio_region(struct ps3_mmio_region *r)
62{
63 int result;
64
65 result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id,
66 r->lpar_addr);
67
68 if (result)
69 pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n",
70 __func__, __LINE__, ps3_result(result));
71
72 r->lpar_addr = 0;
73 return result;
74}
75
76static int ps3_system_bus_match(struct device *_dev,
77 struct device_driver *_drv)
78{
79 int result;
80 struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv);
81 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
82
83 result = dev->match_id == drv->match_id;
84
85 pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__,
86 dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name,
87 (result ? "match" : "miss"));
88 return result;
89}
90
91static int ps3_system_bus_probe(struct device *_dev)
92{
93 int result;
94 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
95 struct ps3_system_bus_driver *drv =
96 to_ps3_system_bus_driver(_dev->driver);
97
98 result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0);
99
100 if (result) {
101 pr_debug("%s:%d: lv1_open_device failed (%d)\n",
102 __func__, __LINE__, result);
103 result = -EACCES;
104 goto clean_none;
105 }
106
107 if (dev->d_region->did.bus_id) {
108 result = ps3_dma_region_create(dev->d_region);
109
110 if (result) {
111 pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n",
112 __func__, __LINE__, result);
113 BUG_ON("check region type");
114 result = -EINVAL;
115 goto clean_device;
116 }
117 }
118
119 BUG_ON(!drv);
120
121 if (drv->probe)
122 result = drv->probe(dev);
123 else
124 pr_info("%s:%d: %s no probe method\n", __func__, __LINE__,
125 dev->core.bus_id);
126
127 if (result) {
128 pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__);
129 goto clean_dma;
130 }
131
132 return result;
133
134clean_dma:
135 ps3_dma_region_free(dev->d_region);
136clean_device:
137 lv1_close_device(dev->did.bus_id, dev->did.dev_id);
138clean_none:
139 return result;
140}
141
142static int ps3_system_bus_remove(struct device *_dev)
143{
144 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
145 struct ps3_system_bus_driver *drv =
146 to_ps3_system_bus_driver(_dev->driver);
147
148 if (drv->remove)
149 drv->remove(dev);
150 else
151 pr_info("%s:%d: %s no remove method\n", __func__, __LINE__,
152 dev->core.bus_id);
153
154 ps3_dma_region_free(dev->d_region);
155 ps3_free_mmio_region(dev->m_region);
156 lv1_close_device(dev->did.bus_id, dev->did.dev_id);
157
158 return 0;
159}
160
161struct bus_type ps3_system_bus_type = {
162 .name = "ps3_system_bus",
163 .match = ps3_system_bus_match,
164 .probe = ps3_system_bus_probe,
165 .remove = ps3_system_bus_remove,
166};
167
168int __init ps3_system_bus_init(void)
169{
170 int result;
171
172 if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
173 return 0;
174
175 result = bus_register(&ps3_system_bus_type);
176 BUG_ON(result);
177 return result;
178}
179
180core_initcall(ps3_system_bus_init);
181
182/* Allocates a contiguous real buffer and creates mappings over it.
183 * Returns the virtual address of the buffer and sets dma_handle
184 * to the dma address (mapping) of the first page.
185 */
186
187static void * ps3_alloc_coherent(struct device *_dev, size_t size,
188 dma_addr_t *dma_handle, gfp_t flag)
189{
190 int result;
191 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
192 unsigned long virt_addr;
193
194 BUG_ON(!dev->d_region->bus_addr);
195
196 flag &= ~(__GFP_DMA | __GFP_HIGHMEM);
197 flag |= __GFP_ZERO;
198
199 virt_addr = __get_free_pages(flag, get_order(size));
200
201 if (!virt_addr) {
202 pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__);
203 goto clean_none;
204 }
205
206 result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle);
207
208 if (result) {
209 pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
210 __func__, __LINE__, result);
211 BUG_ON("check region type");
212 goto clean_alloc;
213 }
214
215 return (void*)virt_addr;
216
217clean_alloc:
218 free_pages(virt_addr, get_order(size));
219clean_none:
220 dma_handle = NULL;
221 return NULL;
222}
223
224static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr,
225 dma_addr_t dma_handle)
226{
227 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
228
229 ps3_dma_unmap(dev->d_region, dma_handle, size);
230 free_pages((unsigned long)vaddr, get_order(size));
231}
232
233/* Creates TCEs for a user provided buffer. The user buffer must be
234 * contiguous real kernel storage (not vmalloc). The address of the buffer
235 * passed here is the kernel (virtual) address of the buffer. The buffer
236 * need not be page aligned, the dma_addr_t returned will point to the same
237 * byte within the page as vaddr.
238 */
239
240static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size,
241 enum dma_data_direction direction)
242{
243 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
244 int result;
245 unsigned long bus_addr;
246
247 result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size,
248 &bus_addr);
249
250 if (result) {
251 pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
252 __func__, __LINE__, result);
253 }
254
255 return bus_addr;
256}
257
258static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr,
259 size_t size, enum dma_data_direction direction)
260{
261 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
262 int result;
263
264 result = ps3_dma_unmap(dev->d_region, dma_addr, size);
265
266 if (result) {
267 pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n",
268 __func__, __LINE__, result);
269 }
270}
271
272static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents,
273 enum dma_data_direction direction)
274{
275 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
276 int i;
277
278#if defined(CONFIG_PS3_DYNAMIC_DMA)
279 BUG_ON("do");
280 return -EPERM;
281#else
282 for (i = 0; i < nents; i++, sg++) {
283 int result = ps3_dma_map(dev->d_region,
284 page_to_phys(sg->page) + sg->offset, sg->length,
285 &sg->dma_address);
286
287 if (result) {
288 pr_debug("%s:%d: ps3_dma_map failed (%d)\n",
289 __func__, __LINE__, result);
290 return -EINVAL;
291 }
292
293 sg->dma_length = sg->length;
294 }
295
296 return nents;
297#endif
298}
299
300static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg,
301 int nents, enum dma_data_direction direction)
302{
303#if defined(CONFIG_PS3_DYNAMIC_DMA)
304 BUG_ON("do");
305#endif
306}
307
308static int ps3_dma_supported(struct device *_dev, u64 mask)
309{
310 return mask >= DMA_32BIT_MASK;
311}
312
313static struct dma_mapping_ops ps3_dma_ops = {
314 .alloc_coherent = ps3_alloc_coherent,
315 .free_coherent = ps3_free_coherent,
316 .map_single = ps3_map_single,
317 .unmap_single = ps3_unmap_single,
318 .map_sg = ps3_map_sg,
319 .unmap_sg = ps3_unmap_sg,
320 .dma_supported = ps3_dma_supported
321};
322
323/**
324 * ps3_system_bus_release_device - remove a device from the system bus
325 */
326
327static void ps3_system_bus_release_device(struct device *_dev)
328{
329 struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev);
330 kfree(dev);
331}
332
333/**
334 * ps3_system_bus_device_register - add a device to the system bus
335 *
336 * ps3_system_bus_device_register() expects the dev object to be allocated
337 * dynamically by the caller. The system bus takes ownership of the dev
338 * object and frees the object in ps3_system_bus_release_device().
339 */
340
341int ps3_system_bus_device_register(struct ps3_system_bus_device *dev)
342{
343 int result;
344 static unsigned int dev_count = 1;
345
346 dev->core.parent = NULL;
347 dev->core.bus = &ps3_system_bus_type;
348 dev->core.release = ps3_system_bus_release_device;
349
350 dev->core.archdata.of_node = NULL;
351 dev->core.archdata.dma_ops = &ps3_dma_ops;
352 dev->core.archdata.numa_node = 0;
353
354 snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x",
355 dev_count++);
356
357 pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id);
358
359 result = device_register(&dev->core);
360 return result;
361}
362
363EXPORT_SYMBOL_GPL(ps3_system_bus_device_register);
364
365int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv)
366{
367 int result;
368
369 drv->core.bus = &ps3_system_bus_type;
370
371 result = driver_register(&drv->core);
372 return result;
373}
374
375EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register);
376
377void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv)
378{
379 driver_unregister(&drv->core);
380}
381
382EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister);
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index da6e5362e7cd..9437f48cc9e7 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -747,6 +747,7 @@ struct eeh_early_enable_info {
747/* Enable eeh for the given device node. */ 747/* Enable eeh for the given device node. */
748static void *early_enable_eeh(struct device_node *dn, void *data) 748static void *early_enable_eeh(struct device_node *dn, void *data)
749{ 749{
750 unsigned int rets[3];
750 struct eeh_early_enable_info *info = data; 751 struct eeh_early_enable_info *info = data;
751 int ret; 752 int ret;
752 const char *status = get_property(dn, "status", NULL); 753 const char *status = get_property(dn, "status", NULL);
@@ -803,16 +804,14 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
803 regs[0], info->buid_hi, info->buid_lo, 804 regs[0], info->buid_hi, info->buid_lo,
804 EEH_ENABLE); 805 EEH_ENABLE);
805 806
807 enable = 0;
806 if (ret == 0) { 808 if (ret == 0) {
807 eeh_subsystem_enabled = 1;
808 pdn->eeh_mode |= EEH_MODE_SUPPORTED;
809 pdn->eeh_config_addr = regs[0]; 809 pdn->eeh_config_addr = regs[0];
810 810
811 /* If the newer, better, ibm,get-config-addr-info is supported, 811 /* If the newer, better, ibm,get-config-addr-info is supported,
812 * then use that instead. */ 812 * then use that instead. */
813 pdn->eeh_pe_config_addr = 0; 813 pdn->eeh_pe_config_addr = 0;
814 if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { 814 if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
815 unsigned int rets[2];
816 ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, 815 ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets,
817 pdn->eeh_config_addr, 816 pdn->eeh_config_addr,
818 info->buid_hi, info->buid_lo, 817 info->buid_hi, info->buid_lo,
@@ -820,6 +819,20 @@ static void *early_enable_eeh(struct device_node *dn, void *data)
820 if (ret == 0) 819 if (ret == 0)
821 pdn->eeh_pe_config_addr = rets[0]; 820 pdn->eeh_pe_config_addr = rets[0];
822 } 821 }
822
823 /* Some older systems (Power4) allow the
824 * ibm,set-eeh-option call to succeed even on nodes
825 * where EEH is not supported. Verify support
826 * explicitly. */
827 ret = read_slot_reset_state(pdn, rets);
828 if ((ret == 0) && (rets[1] == 1))
829 enable = 1;
830 }
831
832 if (enable) {
833 eeh_subsystem_enabled = 1;
834 pdn->eeh_mode |= EEH_MODE_SUPPORTED;
835
823#ifdef DEBUG 836#ifdef DEBUG
824 printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n", 837 printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n",
825 dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr); 838 dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr);
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index cbd6b0711ab4..a4c0bf84ef2e 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -446,7 +446,8 @@ excess_failures:
446 */ 446 */
447 printk(KERN_ERR 447 printk(KERN_ERR
448 "EEH: PCI device at location=%s driver=%s pci addr=%s \n" 448 "EEH: PCI device at location=%s driver=%s pci addr=%s \n"
449 "has failed %d times and has been permanently disabled. \n" 449 "has failed %d times in the last hour "
450 "and has been permanently disabled. \n"
450 "Please try reseating this device or replacing it.\n", 451 "Please try reseating this device or replacing it.\n",
451 location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); 452 location, drv_str, pci_str, frozen_pdn->eeh_freeze_count);
452 goto perm_error; 453 goto perm_error;
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 1c7b2baa5f73..90522e3c9d46 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -59,6 +59,7 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = {
59 {FW_FEATURE_XDABR, "hcall-xdabr"}, 59 {FW_FEATURE_XDABR, "hcall-xdabr"},
60 {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, 60 {FW_FEATURE_MULTITCE, "hcall-multi-tce"},
61 {FW_FEATURE_SPLPAR, "hcall-splpar"}, 61 {FW_FEATURE_SPLPAR, "hcall-splpar"},
62 {FW_FEATURE_BULK_REMOVE, "hcall-bulk"},
62}; 63};
63 64
64/* Build up the firmware features bitmask using the contents of 65/* Build up the firmware features bitmask using the contents of
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index 721436db3ef0..7496005566ef 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -502,23 +502,70 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va,
502 BUG_ON(lpar_rc != H_SUCCESS); 502 BUG_ON(lpar_rc != H_SUCCESS);
503} 503}
504 504
505/* Flag bits for H_BULK_REMOVE */
506#define HBR_REQUEST 0x4000000000000000UL
507#define HBR_RESPONSE 0x8000000000000000UL
508#define HBR_END 0xc000000000000000UL
509#define HBR_AVPN 0x0200000000000000UL
510#define HBR_ANDCOND 0x0100000000000000UL
511
505/* 512/*
506 * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie 513 * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie
507 * lock. 514 * lock.
508 */ 515 */
509static void pSeries_lpar_flush_hash_range(unsigned long number, int local) 516static void pSeries_lpar_flush_hash_range(unsigned long number, int local)
510{ 517{
511 int i; 518 unsigned long i, pix, rc;
512 unsigned long flags = 0; 519 unsigned long flags = 0;
513 struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); 520 struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch);
514 int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); 521 int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE);
522 unsigned long param[9];
523 unsigned long va;
524 unsigned long hash, index, shift, hidx, slot;
525 real_pte_t pte;
526 int psize;
515 527
516 if (lock_tlbie) 528 if (lock_tlbie)
517 spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); 529 spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags);
518 530
519 for (i = 0; i < number; i++) 531 psize = batch->psize;
520 flush_hash_page(batch->vaddr[i], batch->pte[i], 532 pix = 0;
521 batch->psize, local); 533 for (i = 0; i < number; i++) {
534 va = batch->vaddr[i];
535 pte = batch->pte[i];
536 pte_iterate_hashed_subpages(pte, psize, va, index, shift) {
537 hash = hpt_hash(va, shift);
538 hidx = __rpte_to_hidx(pte, index);
539 if (hidx & _PTEIDX_SECONDARY)
540 hash = ~hash;
541 slot = (hash & htab_hash_mask) * HPTES_PER_GROUP;
542 slot += hidx & _PTEIDX_GROUP_IX;
543 if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) {
544 pSeries_lpar_hpte_invalidate(slot, va, psize,
545 local);
546 } else {
547 param[pix] = HBR_REQUEST | HBR_AVPN | slot;
548 param[pix+1] = hpte_encode_v(va, psize) &
549 HPTE_V_AVPN;
550 pix += 2;
551 if (pix == 8) {
552 rc = plpar_hcall9(H_BULK_REMOVE, param,
553 param[0], param[1], param[2],
554 param[3], param[4], param[5],
555 param[6], param[7]);
556 BUG_ON(rc != H_SUCCESS);
557 pix = 0;
558 }
559 }
560 } pte_iterate_hashed_end();
561 }
562 if (pix) {
563 param[pix] = HBR_END;
564 rc = plpar_hcall9(H_BULK_REMOVE, param, param[0], param[1],
565 param[2], param[3], param[4], param[5],
566 param[6], param[7]);
567 BUG_ON(rc != H_SUCCESS);
568 }
522 569
523 if (lock_tlbie) 570 if (lock_tlbie)
524 spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); 571 spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags);
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 715db5c89908..c69bd15ced9c 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -77,7 +77,7 @@ void __init pSeries_final_fixup(void)
77 77
78/* 78/*
79 * Assume the winbond 82c105 is the IDE controller on a 79 * Assume the winbond 82c105 is the IDE controller on a
80 * p610. We should probably be more careful in case 80 * p610/p615/p630. We should probably be more careful in case
81 * someone tries to plug in a similar adapter. 81 * someone tries to plug in a similar adapter.
82 */ 82 */
83static void fixup_winbond_82c105(struct pci_dev* dev) 83static void fixup_winbond_82c105(struct pci_dev* dev)