diff options
Diffstat (limited to 'arch/powerpc/sysdev')
34 files changed, 4114 insertions, 447 deletions
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig new file mode 100644 index 000000000000..72fb35b9ebca --- /dev/null +++ b/arch/powerpc/sysdev/Kconfig | |||
@@ -0,0 +1,8 @@ | |||
1 | # For a description of the syntax of this configuration file, | ||
2 | # see Documentation/kbuild/kconfig-language.txt. | ||
3 | # | ||
4 | |||
5 | config PPC4xx_PCI_EXPRESS | ||
6 | bool | ||
7 | depends on PCI && 4xx | ||
8 | default n | ||
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 99a77d743d48..15f3e8527d77 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile | |||
@@ -2,7 +2,7 @@ ifeq ($(CONFIG_PPC64),y) | |||
2 | EXTRA_CFLAGS += -mno-minimal-toc | 2 | EXTRA_CFLAGS += -mno-minimal-toc |
3 | endif | 3 | endif |
4 | 4 | ||
5 | mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o | 5 | mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o |
6 | obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) | 6 | obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) |
7 | 7 | ||
8 | obj-$(CONFIG_PPC_MPC106) += grackle.o | 8 | obj-$(CONFIG_PPC_MPC106) += grackle.o |
@@ -12,6 +12,7 @@ obj-$(CONFIG_U3_DART) += dart_iommu.o | |||
12 | obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o | 12 | obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o |
13 | obj-$(CONFIG_FSL_SOC) += fsl_soc.o | 13 | obj-$(CONFIG_FSL_SOC) += fsl_soc.o |
14 | obj-$(CONFIG_FSL_PCI) += fsl_pci.o | 14 | obj-$(CONFIG_FSL_PCI) += fsl_pci.o |
15 | obj-$(CONFIG_RAPIDIO) += fsl_rio.o | ||
15 | obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o | 16 | obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o |
16 | obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ | 17 | obj-$(CONFIG_QUICC_ENGINE) += qe_lib/ |
17 | obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ | 18 | obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ |
@@ -24,16 +25,20 @@ obj-$(CONFIG_AXON_RAM) += axonram.o | |||
24 | ifeq ($(CONFIG_PPC_MERGE),y) | 25 | ifeq ($(CONFIG_PPC_MERGE),y) |
25 | obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o | 26 | obj-$(CONFIG_PPC_INDIRECT_PCI) += indirect_pci.o |
26 | obj-$(CONFIG_PPC_I8259) += i8259.o | 27 | obj-$(CONFIG_PPC_I8259) += i8259.o |
27 | obj-$(CONFIG_PPC_83xx) += ipic.o | 28 | obj-$(CONFIG_IPIC) += ipic.o |
28 | obj-$(CONFIG_4xx) += uic.o | 29 | obj-$(CONFIG_4xx) += uic.o |
29 | obj-$(CONFIG_XILINX_VIRTEX) += xilinx_intc.o | 30 | obj-$(CONFIG_XILINX_VIRTEX) += xilinx_intc.o |
31 | obj-$(CONFIG_OF_RTC) += of_rtc.o | ||
32 | ifeq ($(CONFIG_PCI),y) | ||
33 | obj-$(CONFIG_4xx) += ppc4xx_pci.o | ||
34 | endif | ||
30 | endif | 35 | endif |
31 | 36 | ||
32 | # Temporary hack until we have migrated to asm-powerpc | 37 | # Temporary hack until we have migrated to asm-powerpc |
33 | ifeq ($(ARCH),powerpc) | 38 | ifeq ($(ARCH),powerpc) |
34 | obj-$(CONFIG_CPM) += cpm_common.o | 39 | obj-$(CONFIG_CPM) += cpm_common.o |
35 | obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o | 40 | obj-$(CONFIG_CPM2) += cpm2.o cpm2_pic.o |
36 | obj-$(CONFIG_PPC_DCR) += dcr.o | 41 | obj-$(CONFIG_PPC_DCR) += dcr.o |
37 | obj-$(CONFIG_8xx) += mpc8xx_pic.o commproc.o | 42 | obj-$(CONFIG_8xx) += mpc8xx_pic.o cpm1.o |
38 | obj-$(CONFIG_UCODE_PATCH) += micropatch.o | 43 | obj-$(CONFIG_UCODE_PATCH) += micropatch.o |
39 | endif | 44 | endif |
diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index 5eaf3e3f4b8b..d359d6e92975 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c | |||
@@ -42,8 +42,9 @@ | |||
42 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
43 | #include <linux/string.h> | 43 | #include <linux/string.h> |
44 | #include <linux/types.h> | 44 | #include <linux/types.h> |
45 | #include <asm/of_device.h> | 45 | #include <linux/of_device.h> |
46 | #include <asm/of_platform.h> | 46 | #include <linux/of_platform.h> |
47 | |||
47 | #include <asm/page.h> | 48 | #include <asm/page.h> |
48 | #include <asm/prom.h> | 49 | #include <asm/prom.h> |
49 | 50 | ||
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.c b/arch/powerpc/sysdev/bestcomm/bestcomm.c index 740ad73ce5cc..f589999361e0 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.c +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.c | |||
@@ -29,11 +29,17 @@ | |||
29 | 29 | ||
30 | #define DRIVER_NAME "bestcomm-core" | 30 | #define DRIVER_NAME "bestcomm-core" |
31 | 31 | ||
32 | /* MPC5200 device tree match tables */ | ||
33 | static struct of_device_id mpc52xx_sram_ids[] __devinitdata = { | ||
34 | { .compatible = "fsl,mpc5200-sram", }, | ||
35 | { .compatible = "mpc5200-sram", }, | ||
36 | {} | ||
37 | }; | ||
38 | |||
32 | 39 | ||
33 | struct bcom_engine *bcom_eng = NULL; | 40 | struct bcom_engine *bcom_eng = NULL; |
34 | EXPORT_SYMBOL_GPL(bcom_eng); /* needed for inline functions */ | 41 | EXPORT_SYMBOL_GPL(bcom_eng); /* needed for inline functions */ |
35 | 42 | ||
36 | |||
37 | /* ======================================================================== */ | 43 | /* ======================================================================== */ |
38 | /* Public and private API */ | 44 | /* Public and private API */ |
39 | /* ======================================================================== */ | 45 | /* ======================================================================== */ |
@@ -373,7 +379,7 @@ mpc52xx_bcom_probe(struct of_device *op, const struct of_device_id *match) | |||
373 | of_node_get(op->node); | 379 | of_node_get(op->node); |
374 | 380 | ||
375 | /* Prepare SRAM */ | 381 | /* Prepare SRAM */ |
376 | ofn_sram = of_find_compatible_node(NULL, "sram", "mpc5200-sram"); | 382 | ofn_sram = of_find_matching_node(NULL, mpc52xx_sram_ids); |
377 | if (!ofn_sram) { | 383 | if (!ofn_sram) { |
378 | printk(KERN_ERR DRIVER_NAME ": " | 384 | printk(KERN_ERR DRIVER_NAME ": " |
379 | "No SRAM found in device tree\n"); | 385 | "No SRAM found in device tree\n"); |
@@ -478,10 +484,8 @@ mpc52xx_bcom_remove(struct of_device *op) | |||
478 | } | 484 | } |
479 | 485 | ||
480 | static struct of_device_id mpc52xx_bcom_of_match[] = { | 486 | static struct of_device_id mpc52xx_bcom_of_match[] = { |
481 | { | 487 | { .type = "dma-controller", .compatible = "fsl,mpc5200-bestcomm", }, |
482 | .type = "dma-controller", | 488 | { .type = "dma-controller", .compatible = "mpc5200-bestcomm", }, |
483 | .compatible = "mpc5200-bestcomm", | ||
484 | }, | ||
485 | {}, | 489 | {}, |
486 | }; | 490 | }; |
487 | 491 | ||
diff --git a/arch/powerpc/sysdev/bestcomm/bestcomm.h b/arch/powerpc/sysdev/bestcomm/bestcomm.h index e802cb4eb69a..c960a8b49655 100644 --- a/arch/powerpc/sysdev/bestcomm/bestcomm.h +++ b/arch/powerpc/sysdev/bestcomm/bestcomm.h | |||
@@ -20,7 +20,7 @@ struct bcom_bd; /* defined later on ... */ | |||
20 | 20 | ||
21 | 21 | ||
22 | /* ======================================================================== */ | 22 | /* ======================================================================== */ |
23 | /* Generic task managment */ | 23 | /* Generic task management */ |
24 | /* ======================================================================== */ | 24 | /* ======================================================================== */ |
25 | 25 | ||
26 | /** | 26 | /** |
diff --git a/arch/powerpc/sysdev/commproc.h b/arch/powerpc/sysdev/commproc.h deleted file mode 100644 index 9155ba467274..000000000000 --- a/arch/powerpc/sysdev/commproc.h +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | #ifndef _POWERPC_SYSDEV_COMMPROC_H | ||
2 | #define _POWERPC_SYSDEV_COMMPROC_H | ||
3 | |||
4 | extern void cpm_reset(void); | ||
5 | extern void mpc8xx_restart(char *cmd); | ||
6 | extern void mpc8xx_calibrate_decr(void); | ||
7 | extern int mpc8xx_set_rtc_time(struct rtc_time *tm); | ||
8 | extern void mpc8xx_get_rtc_time(struct rtc_time *tm); | ||
9 | extern void m8xx_pic_init(void); | ||
10 | extern unsigned int mpc8xx_get_irq(void); | ||
11 | |||
12 | #endif | ||
diff --git a/arch/powerpc/sysdev/commproc.c b/arch/powerpc/sysdev/cpm1.c index f6a63780bbde..df8bd2b64796 100644 --- a/arch/powerpc/sysdev/commproc.c +++ b/arch/powerpc/sysdev/cpm1.c | |||
@@ -30,11 +30,10 @@ | |||
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/irq.h> | 31 | #include <linux/irq.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <asm/mpc8xx.h> | ||
34 | #include <asm/page.h> | 33 | #include <asm/page.h> |
35 | #include <asm/pgtable.h> | 34 | #include <asm/pgtable.h> |
36 | #include <asm/8xx_immap.h> | 35 | #include <asm/8xx_immap.h> |
37 | #include <asm/commproc.h> | 36 | #include <asm/cpm1.h> |
38 | #include <asm/io.h> | 37 | #include <asm/io.h> |
39 | #include <asm/tlbflush.h> | 38 | #include <asm/tlbflush.h> |
40 | #include <asm/rheap.h> | 39 | #include <asm/rheap.h> |
@@ -48,8 +47,6 @@ | |||
48 | #ifndef CONFIG_PPC_CPM_NEW_BINDING | 47 | #ifndef CONFIG_PPC_CPM_NEW_BINDING |
49 | static void m8xx_cpm_dpinit(void); | 48 | static void m8xx_cpm_dpinit(void); |
50 | #endif | 49 | #endif |
51 | static uint host_buffer; /* One page of host buffer */ | ||
52 | static uint host_end; /* end + 1 */ | ||
53 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ | 50 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ |
54 | immap_t __iomem *mpc8xx_immr; | 51 | immap_t __iomem *mpc8xx_immr; |
55 | static cpic8xx_t __iomem *cpic_reg; | 52 | static cpic8xx_t __iomem *cpic_reg; |
@@ -240,40 +237,33 @@ void __init cpm_reset(void) | |||
240 | #endif | 237 | #endif |
241 | } | 238 | } |
242 | 239 | ||
243 | /* We used to do this earlier, but have to postpone as long as possible | 240 | static DEFINE_SPINLOCK(cmd_lock); |
244 | * to ensure the kernel VM is now running. | ||
245 | */ | ||
246 | static void | ||
247 | alloc_host_memory(void) | ||
248 | { | ||
249 | dma_addr_t physaddr; | ||
250 | 241 | ||
251 | /* Set the host page for allocation. | 242 | #define MAX_CR_CMD_LOOPS 10000 |
252 | */ | ||
253 | host_buffer = (uint)dma_alloc_coherent(NULL, PAGE_SIZE, &physaddr, | ||
254 | GFP_KERNEL); | ||
255 | host_end = host_buffer + PAGE_SIZE; | ||
256 | } | ||
257 | 243 | ||
258 | /* We also own one page of host buffer space for the allocation of | 244 | int cpm_command(u32 command, u8 opcode) |
259 | * UART "fifos" and the like. | ||
260 | */ | ||
261 | uint | ||
262 | m8xx_cpm_hostalloc(uint size) | ||
263 | { | 245 | { |
264 | uint retloc; | 246 | int i, ret; |
247 | unsigned long flags; | ||
265 | 248 | ||
266 | if (host_buffer == 0) | 249 | if (command & 0xffffff0f) |
267 | alloc_host_memory(); | 250 | return -EINVAL; |
268 | 251 | ||
269 | if ((host_buffer + size) >= host_end) | 252 | spin_lock_irqsave(&cmd_lock, flags); |
270 | return(0); | ||
271 | 253 | ||
272 | retloc = host_buffer; | 254 | ret = 0; |
273 | host_buffer += size; | 255 | out_be16(&cpmp->cp_cpcr, command | CPM_CR_FLG | (opcode << 8)); |
256 | for (i = 0; i < MAX_CR_CMD_LOOPS; i++) | ||
257 | if ((in_be16(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0) | ||
258 | goto out; | ||
274 | 259 | ||
275 | return(retloc); | 260 | printk(KERN_ERR "%s(): Not able to issue CPM command\n", __FUNCTION__); |
261 | ret = -EIO; | ||
262 | out: | ||
263 | spin_unlock_irqrestore(&cmd_lock, flags); | ||
264 | return ret; | ||
276 | } | 265 | } |
266 | EXPORT_SYMBOL(cpm_command); | ||
277 | 267 | ||
278 | /* Set a baud rate generator. This needs lots of work. There are | 268 | /* Set a baud rate generator. This needs lots of work. There are |
279 | * four BRGs, any of which can be wired to any channel. | 269 | * four BRGs, any of which can be wired to any channel. |
@@ -300,7 +290,7 @@ cpm_setbrg(uint brg, uint rate) | |||
300 | out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); | 290 | out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); |
301 | else | 291 | else |
302 | out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | | 292 | out_be32(bp, (((BRG_UART_CLK_DIV16 / rate) - 1) << 1) | |
303 | CPM_BRG_EN | CPM_BRG_DIV16); | 293 | CPM_BRG_EN | CPM_BRG_DIV16); |
304 | } | 294 | } |
305 | 295 | ||
306 | #ifndef CONFIG_PPC_CPM_NEW_BINDING | 296 | #ifndef CONFIG_PPC_CPM_NEW_BINDING |
@@ -408,7 +398,7 @@ EXPORT_SYMBOL(cpm_dpram_phys); | |||
408 | #endif /* !CONFIG_PPC_CPM_NEW_BINDING */ | 398 | #endif /* !CONFIG_PPC_CPM_NEW_BINDING */ |
409 | 399 | ||
410 | struct cpm_ioport16 { | 400 | struct cpm_ioport16 { |
411 | __be16 dir, par, sor, dat, intr; | 401 | __be16 dir, par, odr_sor, dat, intr; |
412 | __be16 res[3]; | 402 | __be16 res[3]; |
413 | }; | 403 | }; |
414 | 404 | ||
@@ -438,6 +428,13 @@ static void cpm1_set_pin32(int port, int pin, int flags) | |||
438 | else | 428 | else |
439 | clrbits32(&iop->par, pin); | 429 | clrbits32(&iop->par, pin); |
440 | 430 | ||
431 | if (port == CPM_PORTB) { | ||
432 | if (flags & CPM_PIN_OPENDRAIN) | ||
433 | setbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); | ||
434 | else | ||
435 | clrbits16(&mpc8xx_immr->im_cpm.cp_pbodr, pin); | ||
436 | } | ||
437 | |||
441 | if (port == CPM_PORTE) { | 438 | if (port == CPM_PORTE) { |
442 | if (flags & CPM_PIN_SECONDARY) | 439 | if (flags & CPM_PIN_SECONDARY) |
443 | setbits32(&iop->sor, pin); | 440 | setbits32(&iop->sor, pin); |
@@ -471,11 +468,17 @@ static void cpm1_set_pin16(int port, int pin, int flags) | |||
471 | else | 468 | else |
472 | clrbits16(&iop->par, pin); | 469 | clrbits16(&iop->par, pin); |
473 | 470 | ||
471 | if (port == CPM_PORTA) { | ||
472 | if (flags & CPM_PIN_OPENDRAIN) | ||
473 | setbits16(&iop->odr_sor, pin); | ||
474 | else | ||
475 | clrbits16(&iop->odr_sor, pin); | ||
476 | } | ||
474 | if (port == CPM_PORTC) { | 477 | if (port == CPM_PORTC) { |
475 | if (flags & CPM_PIN_SECONDARY) | 478 | if (flags & CPM_PIN_SECONDARY) |
476 | setbits16(&iop->sor, pin); | 479 | setbits16(&iop->odr_sor, pin); |
477 | else | 480 | else |
478 | clrbits16(&iop->sor, pin); | 481 | clrbits16(&iop->odr_sor, pin); |
479 | } | 482 | } |
480 | } | 483 | } |
481 | 484 | ||
diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2.c index c1d824032020..7be711232124 100644 --- a/arch/powerpc/sysdev/cpm2_common.c +++ b/arch/powerpc/sysdev/cpm2.c | |||
@@ -82,6 +82,31 @@ void __init cpm2_reset(void) | |||
82 | cpmp = &cpm2_immr->im_cpm; | 82 | cpmp = &cpm2_immr->im_cpm; |
83 | } | 83 | } |
84 | 84 | ||
85 | static DEFINE_SPINLOCK(cmd_lock); | ||
86 | |||
87 | #define MAX_CR_CMD_LOOPS 10000 | ||
88 | |||
89 | int cpm_command(u32 command, u8 opcode) | ||
90 | { | ||
91 | int i, ret; | ||
92 | unsigned long flags; | ||
93 | |||
94 | spin_lock_irqsave(&cmd_lock, flags); | ||
95 | |||
96 | ret = 0; | ||
97 | out_be32(&cpmp->cp_cpcr, command | opcode | CPM_CR_FLG); | ||
98 | for (i = 0; i < MAX_CR_CMD_LOOPS; i++) | ||
99 | if ((in_be32(&cpmp->cp_cpcr) & CPM_CR_FLG) == 0) | ||
100 | goto out; | ||
101 | |||
102 | printk(KERN_ERR "%s(): Not able to issue CPM command\n", __FUNCTION__); | ||
103 | ret = -EIO; | ||
104 | out: | ||
105 | spin_unlock_irqrestore(&cmd_lock, flags); | ||
106 | return ret; | ||
107 | } | ||
108 | EXPORT_SYMBOL(cpm_command); | ||
109 | |||
85 | /* Set a baud rate generator. This needs lots of work. There are | 110 | /* Set a baud rate generator. This needs lots of work. There are |
86 | * eight BRGs, which can be connected to the CPM channels or output | 111 | * eight BRGs, which can be connected to the CPM channels or output |
87 | * as clocks. The BRGs are in two different block of internal | 112 | * as clocks. The BRGs are in two different block of internal |
@@ -128,8 +153,7 @@ cpm2_fastbrg(uint brg, uint rate, int div16) | |||
128 | 153 | ||
129 | if (brg < 4) { | 154 | if (brg < 4) { |
130 | bp = cpm2_map_size(im_brgc1, 16); | 155 | bp = cpm2_map_size(im_brgc1, 16); |
131 | } | 156 | } else { |
132 | else { | ||
133 | bp = cpm2_map_size(im_brgc5, 16); | 157 | bp = cpm2_map_size(im_brgc5, 16); |
134 | brg -= 4; | 158 | brg -= 4; |
135 | } | 159 | } |
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index 33df4c347ca7..bf13c2174a4e 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c | |||
@@ -33,8 +33,8 @@ void __init setup_pci_atmu(struct pci_controller *hose, struct resource *rsrc) | |||
33 | struct ccsr_pci __iomem *pci; | 33 | struct ccsr_pci __iomem *pci; |
34 | int i; | 34 | int i; |
35 | 35 | ||
36 | pr_debug("PCI memory map start 0x%x, size 0x%x\n", rsrc->start, | 36 | pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n", |
37 | rsrc->end - rsrc->start + 1); | 37 | (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1); |
38 | pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); | 38 | pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1); |
39 | 39 | ||
40 | /* Disable all windows (except powar0 since its ignored) */ | 40 | /* Disable all windows (except powar0 since its ignored) */ |
@@ -46,17 +46,17 @@ void __init setup_pci_atmu(struct pci_controller *hose, struct resource *rsrc) | |||
46 | /* Setup outbound MEM window */ | 46 | /* Setup outbound MEM window */ |
47 | for(i = 0; i < 3; i++) | 47 | for(i = 0; i < 3; i++) |
48 | if (hose->mem_resources[i].flags & IORESOURCE_MEM){ | 48 | if (hose->mem_resources[i].flags & IORESOURCE_MEM){ |
49 | pr_debug("PCI MEM resource start 0x%08x, size 0x%08x.\n", | 49 | resource_size_t pci_addr_start = |
50 | hose->mem_resources[i].start, | 50 | hose->mem_resources[i].start - |
51 | hose->mem_resources[i].end | 51 | hose->pci_mem_offset; |
52 | - hose->mem_resources[i].start + 1); | 52 | pr_debug("PCI MEM resource start 0x%016llx, size 0x%016llx.\n", |
53 | out_be32(&pci->pow[i+1].potar, | 53 | (u64)hose->mem_resources[i].start, |
54 | (hose->mem_resources[i].start >> 12) | 54 | (u64)hose->mem_resources[i].end |
55 | & 0x000fffff); | 55 | - (u64)hose->mem_resources[i].start + 1); |
56 | out_be32(&pci->pow[i+1].potar, (pci_addr_start >> 12)); | ||
56 | out_be32(&pci->pow[i+1].potear, 0); | 57 | out_be32(&pci->pow[i+1].potear, 0); |
57 | out_be32(&pci->pow[i+1].powbar, | 58 | out_be32(&pci->pow[i+1].powbar, |
58 | (hose->mem_resources[i].start >> 12) | 59 | (hose->mem_resources[i].start >> 12)); |
59 | & 0x000fffff); | ||
60 | /* Enable, Mem R/W */ | 60 | /* Enable, Mem R/W */ |
61 | out_be32(&pci->pow[i+1].powar, 0x80044000 | 61 | out_be32(&pci->pow[i+1].powar, 0x80044000 |
62 | | (__ilog2(hose->mem_resources[i].end | 62 | | (__ilog2(hose->mem_resources[i].end |
@@ -65,15 +65,14 @@ void __init setup_pci_atmu(struct pci_controller *hose, struct resource *rsrc) | |||
65 | 65 | ||
66 | /* Setup outbound IO window */ | 66 | /* Setup outbound IO window */ |
67 | if (hose->io_resource.flags & IORESOURCE_IO){ | 67 | if (hose->io_resource.flags & IORESOURCE_IO){ |
68 | pr_debug("PCI IO resource start 0x%08x, size 0x%08x, phy base 0x%08x.\n", | 68 | pr_debug("PCI IO resource start 0x%016llx, size 0x%016llx, " |
69 | hose->io_resource.start, | 69 | "phy base 0x%016llx.\n", |
70 | hose->io_resource.end - hose->io_resource.start + 1, | 70 | (u64)hose->io_resource.start, |
71 | hose->io_base_phys); | 71 | (u64)hose->io_resource.end - (u64)hose->io_resource.start + 1, |
72 | out_be32(&pci->pow[i+1].potar, (hose->io_resource.start >> 12) | 72 | (u64)hose->io_base_phys); |
73 | & 0x000fffff); | 73 | out_be32(&pci->pow[i+1].potar, (hose->io_resource.start >> 12)); |
74 | out_be32(&pci->pow[i+1].potear, 0); | 74 | out_be32(&pci->pow[i+1].potear, 0); |
75 | out_be32(&pci->pow[i+1].powbar, (hose->io_base_phys >> 12) | 75 | out_be32(&pci->pow[i+1].powbar, (hose->io_base_phys >> 12)); |
76 | & 0x000fffff); | ||
77 | /* Enable, IO R/W */ | 76 | /* Enable, IO R/W */ |
78 | out_be32(&pci->pow[i+1].powar, 0x80088000 | 77 | out_be32(&pci->pow[i+1].powar, 0x80088000 |
79 | | (__ilog2(hose->io_resource.end | 78 | | (__ilog2(hose->io_resource.end |
@@ -107,55 +106,17 @@ void __init setup_pci_cmd(struct pci_controller *hose) | |||
107 | } | 106 | } |
108 | } | 107 | } |
109 | 108 | ||
110 | static void __init quirk_fsl_pcie_transparent(struct pci_dev *dev) | 109 | static int fsl_pcie_bus_fixup; |
111 | { | ||
112 | struct resource *res; | ||
113 | int i, res_idx = PCI_BRIDGE_RESOURCES; | ||
114 | struct pci_controller *hose; | ||
115 | 110 | ||
111 | static void __init quirk_fsl_pcie_header(struct pci_dev *dev) | ||
112 | { | ||
116 | /* if we aren't a PCIe don't bother */ | 113 | /* if we aren't a PCIe don't bother */ |
117 | if (!pci_find_capability(dev, PCI_CAP_ID_EXP)) | 114 | if (!pci_find_capability(dev, PCI_CAP_ID_EXP)) |
118 | return ; | 115 | return ; |
119 | 116 | ||
120 | /* | 117 | dev->class = PCI_CLASS_BRIDGE_PCI << 8; |
121 | * Make the bridge be transparent. | 118 | fsl_pcie_bus_fixup = 1; |
122 | */ | 119 | return ; |
123 | dev->transparent = 1; | ||
124 | |||
125 | hose = pci_bus_to_host(dev->bus); | ||
126 | if (!hose) { | ||
127 | printk(KERN_ERR "Can't find hose for bus %d\n", | ||
128 | dev->bus->number); | ||
129 | return; | ||
130 | } | ||
131 | |||
132 | /* Clear out any of the virtual P2P bridge registers */ | ||
133 | pci_write_config_word(dev, PCI_IO_BASE_UPPER16, 0); | ||
134 | pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16, 0); | ||
135 | pci_write_config_byte(dev, PCI_IO_BASE, 0x10); | ||
136 | pci_write_config_byte(dev, PCI_IO_LIMIT, 0); | ||
137 | pci_write_config_word(dev, PCI_MEMORY_BASE, 0x10); | ||
138 | pci_write_config_word(dev, PCI_MEMORY_LIMIT, 0); | ||
139 | pci_write_config_word(dev, PCI_PREF_BASE_UPPER32, 0x0); | ||
140 | pci_write_config_word(dev, PCI_PREF_LIMIT_UPPER32, 0x0); | ||
141 | pci_write_config_word(dev, PCI_PREF_MEMORY_BASE, 0x10); | ||
142 | pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT, 0); | ||
143 | |||
144 | if (hose->io_resource.flags) { | ||
145 | res = &dev->resource[res_idx++]; | ||
146 | res->start = hose->io_resource.start; | ||
147 | res->end = hose->io_resource.end; | ||
148 | res->flags = hose->io_resource.flags; | ||
149 | update_bridge_resource(dev, res); | ||
150 | } | ||
151 | |||
152 | for (i = 0; i < 3; i++) { | ||
153 | res = &dev->resource[res_idx + i]; | ||
154 | res->start = hose->mem_resources[i].start; | ||
155 | res->end = hose->mem_resources[i].end; | ||
156 | res->flags = hose->mem_resources[i].flags; | ||
157 | update_bridge_resource(dev, res); | ||
158 | } | ||
159 | } | 120 | } |
160 | 121 | ||
161 | int __init fsl_pcie_check_link(struct pci_controller *hose) | 122 | int __init fsl_pcie_check_link(struct pci_controller *hose) |
@@ -172,11 +133,24 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus) | |||
172 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | 133 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; |
173 | int i; | 134 | int i; |
174 | 135 | ||
175 | /* deal with bogus pci_bus when we don't have anything connected on PCIe */ | 136 | if ((bus->parent == hose->bus) && |
176 | if (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK) { | 137 | ((fsl_pcie_bus_fixup && |
177 | if (bus->parent) { | 138 | early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) || |
178 | for (i = 0; i < 4; ++i) | 139 | (hose->indirect_type & PPC_INDIRECT_TYPE_NO_PCIE_LINK))) |
179 | bus->resource[i] = bus->parent->resource[i]; | 140 | { |
141 | for (i = 0; i < 4; ++i) { | ||
142 | struct resource *res = bus->resource[i]; | ||
143 | struct resource *par = bus->parent->resource[i]; | ||
144 | if (res) { | ||
145 | res->start = 0; | ||
146 | res->end = 0; | ||
147 | res->flags = 0; | ||
148 | } | ||
149 | if (res && par) { | ||
150 | res->start = par->start; | ||
151 | res->end = par->end; | ||
152 | res->flags = par->flags; | ||
153 | } | ||
180 | } | 154 | } |
181 | } | 155 | } |
182 | } | 156 | } |
@@ -202,7 +176,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) | |||
202 | printk(KERN_WARNING "Can't get bus-range for %s, assume" | 176 | printk(KERN_WARNING "Can't get bus-range for %s, assume" |
203 | " bus 0\n", dev->full_name); | 177 | " bus 0\n", dev->full_name); |
204 | 178 | ||
205 | pci_assign_all_buses = 1; | 179 | ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; |
206 | hose = pcibios_alloc_controller(dev); | 180 | hose = pcibios_alloc_controller(dev); |
207 | if (!hose) | 181 | if (!hose) |
208 | return -ENOMEM; | 182 | return -ENOMEM; |
@@ -222,7 +196,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) | |||
222 | hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK; | 196 | hose->indirect_type |= PPC_INDIRECT_TYPE_NO_PCIE_LINK; |
223 | } | 197 | } |
224 | 198 | ||
225 | printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx." | 199 | printk(KERN_INFO "Found FSL PCI host bridge at 0x%016llx. " |
226 | "Firmware bus number: %d->%d\n", | 200 | "Firmware bus number: %d->%d\n", |
227 | (unsigned long long)rsrc.start, hose->first_busno, | 201 | (unsigned long long)rsrc.start, hose->first_busno, |
228 | hose->last_busno); | 202 | hose->last_busno); |
@@ -240,23 +214,23 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) | |||
240 | return 0; | 214 | return 0; |
241 | } | 215 | } |
242 | 216 | ||
243 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8548E, quirk_fsl_pcie_transparent); | 217 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8548E, quirk_fsl_pcie_header); |
244 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8548, quirk_fsl_pcie_transparent); | 218 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8548, quirk_fsl_pcie_header); |
245 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8543E, quirk_fsl_pcie_transparent); | 219 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8543E, quirk_fsl_pcie_header); |
246 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8543, quirk_fsl_pcie_transparent); | 220 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8543, quirk_fsl_pcie_header); |
247 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8547E, quirk_fsl_pcie_transparent); | 221 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8547E, quirk_fsl_pcie_header); |
248 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8545E, quirk_fsl_pcie_transparent); | 222 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8545E, quirk_fsl_pcie_header); |
249 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8545, quirk_fsl_pcie_transparent); | 223 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8545, quirk_fsl_pcie_header); |
250 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8568E, quirk_fsl_pcie_transparent); | 224 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8568E, quirk_fsl_pcie_header); |
251 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8568, quirk_fsl_pcie_transparent); | 225 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8568, quirk_fsl_pcie_header); |
252 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8567E, quirk_fsl_pcie_transparent); | 226 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8567E, quirk_fsl_pcie_header); |
253 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8567, quirk_fsl_pcie_transparent); | 227 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8567, quirk_fsl_pcie_header); |
254 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8533E, quirk_fsl_pcie_transparent); | 228 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8533E, quirk_fsl_pcie_header); |
255 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8533, quirk_fsl_pcie_transparent); | 229 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8533, quirk_fsl_pcie_header); |
256 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8544E, quirk_fsl_pcie_transparent); | 230 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8544E, quirk_fsl_pcie_header); |
257 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8544, quirk_fsl_pcie_transparent); | 231 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8544, quirk_fsl_pcie_header); |
258 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8572E, quirk_fsl_pcie_transparent); | 232 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8572E, quirk_fsl_pcie_header); |
259 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8572, quirk_fsl_pcie_transparent); | 233 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8572, quirk_fsl_pcie_header); |
260 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_transparent); | 234 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_header); |
261 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_transparent); | 235 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header); |
262 | DECLARE_PCI_FIXUP_EARLY(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_transparent); | 236 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header); |
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c new file mode 100644 index 000000000000..af2425e4655f --- /dev/null +++ b/arch/powerpc/sysdev/fsl_rio.c | |||
@@ -0,0 +1,932 @@ | |||
1 | /* | ||
2 | * MPC85xx RapidIO support | ||
3 | * | ||
4 | * Copyright 2005 MontaVista Software, Inc. | ||
5 | * Matt Porter <mporter@kernel.crashing.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/rio.h> | ||
19 | #include <linux/rio_drv.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | |||
23 | #define RIO_REGS_BASE (CCSRBAR + 0xc0000) | ||
24 | #define RIO_ATMU_REGS_OFFSET 0x10c00 | ||
25 | #define RIO_MSG_REGS_OFFSET 0x11000 | ||
26 | #define RIO_MAINT_WIN_SIZE 0x400000 | ||
27 | #define RIO_DBELL_WIN_SIZE 0x1000 | ||
28 | |||
29 | #define RIO_MSG_OMR_MUI 0x00000002 | ||
30 | #define RIO_MSG_OSR_TE 0x00000080 | ||
31 | #define RIO_MSG_OSR_QOI 0x00000020 | ||
32 | #define RIO_MSG_OSR_QFI 0x00000010 | ||
33 | #define RIO_MSG_OSR_MUB 0x00000004 | ||
34 | #define RIO_MSG_OSR_EOMI 0x00000002 | ||
35 | #define RIO_MSG_OSR_QEI 0x00000001 | ||
36 | |||
37 | #define RIO_MSG_IMR_MI 0x00000002 | ||
38 | #define RIO_MSG_ISR_TE 0x00000080 | ||
39 | #define RIO_MSG_ISR_QFI 0x00000010 | ||
40 | #define RIO_MSG_ISR_DIQI 0x00000001 | ||
41 | |||
42 | #define RIO_MSG_DESC_SIZE 32 | ||
43 | #define RIO_MSG_BUFFER_SIZE 4096 | ||
44 | #define RIO_MIN_TX_RING_SIZE 2 | ||
45 | #define RIO_MAX_TX_RING_SIZE 2048 | ||
46 | #define RIO_MIN_RX_RING_SIZE 2 | ||
47 | #define RIO_MAX_RX_RING_SIZE 2048 | ||
48 | |||
49 | #define DOORBELL_DMR_DI 0x00000002 | ||
50 | #define DOORBELL_DSR_TE 0x00000080 | ||
51 | #define DOORBELL_DSR_QFI 0x00000010 | ||
52 | #define DOORBELL_DSR_DIQI 0x00000001 | ||
53 | #define DOORBELL_TID_OFFSET 0x03 | ||
54 | #define DOORBELL_SID_OFFSET 0x05 | ||
55 | #define DOORBELL_INFO_OFFSET 0x06 | ||
56 | |||
57 | #define DOORBELL_MESSAGE_SIZE 0x08 | ||
58 | #define DBELL_SID(x) (*(u8 *)(x + DOORBELL_SID_OFFSET)) | ||
59 | #define DBELL_TID(x) (*(u8 *)(x + DOORBELL_TID_OFFSET)) | ||
60 | #define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) | ||
61 | |||
62 | struct rio_atmu_regs { | ||
63 | u32 rowtar; | ||
64 | u32 pad1; | ||
65 | u32 rowbar; | ||
66 | u32 pad2; | ||
67 | u32 rowar; | ||
68 | u32 pad3[3]; | ||
69 | }; | ||
70 | |||
71 | struct rio_msg_regs { | ||
72 | u32 omr; | ||
73 | u32 osr; | ||
74 | u32 pad1; | ||
75 | u32 odqdpar; | ||
76 | u32 pad2; | ||
77 | u32 osar; | ||
78 | u32 odpr; | ||
79 | u32 odatr; | ||
80 | u32 odcr; | ||
81 | u32 pad3; | ||
82 | u32 odqepar; | ||
83 | u32 pad4[13]; | ||
84 | u32 imr; | ||
85 | u32 isr; | ||
86 | u32 pad5; | ||
87 | u32 ifqdpar; | ||
88 | u32 pad6; | ||
89 | u32 ifqepar; | ||
90 | u32 pad7[250]; | ||
91 | u32 dmr; | ||
92 | u32 dsr; | ||
93 | u32 pad8; | ||
94 | u32 dqdpar; | ||
95 | u32 pad9; | ||
96 | u32 dqepar; | ||
97 | u32 pad10[26]; | ||
98 | u32 pwmr; | ||
99 | u32 pwsr; | ||
100 | u32 pad11; | ||
101 | u32 pwqbar; | ||
102 | }; | ||
103 | |||
104 | struct rio_tx_desc { | ||
105 | u32 res1; | ||
106 | u32 saddr; | ||
107 | u32 dport; | ||
108 | u32 dattr; | ||
109 | u32 res2; | ||
110 | u32 res3; | ||
111 | u32 dwcnt; | ||
112 | u32 res4; | ||
113 | }; | ||
114 | |||
115 | static u32 regs_win; | ||
116 | static struct rio_atmu_regs *atmu_regs; | ||
117 | static struct rio_atmu_regs *maint_atmu_regs; | ||
118 | static struct rio_atmu_regs *dbell_atmu_regs; | ||
119 | static u32 dbell_win; | ||
120 | static u32 maint_win; | ||
121 | static struct rio_msg_regs *msg_regs; | ||
122 | |||
123 | static struct rio_dbell_ring { | ||
124 | void *virt; | ||
125 | dma_addr_t phys; | ||
126 | } dbell_ring; | ||
127 | |||
128 | static struct rio_msg_tx_ring { | ||
129 | void *virt; | ||
130 | dma_addr_t phys; | ||
131 | void *virt_buffer[RIO_MAX_TX_RING_SIZE]; | ||
132 | dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE]; | ||
133 | int tx_slot; | ||
134 | int size; | ||
135 | void *dev_id; | ||
136 | } msg_tx_ring; | ||
137 | |||
138 | static struct rio_msg_rx_ring { | ||
139 | void *virt; | ||
140 | dma_addr_t phys; | ||
141 | void *virt_buffer[RIO_MAX_RX_RING_SIZE]; | ||
142 | int rx_slot; | ||
143 | int size; | ||
144 | void *dev_id; | ||
145 | } msg_rx_ring; | ||
146 | |||
147 | /** | ||
148 | * mpc85xx_rio_doorbell_send - Send a MPC85xx doorbell message | ||
149 | * @index: ID of RapidIO interface | ||
150 | * @destid: Destination ID of target device | ||
151 | * @data: 16-bit info field of RapidIO doorbell message | ||
152 | * | ||
153 | * Sends a MPC85xx doorbell message. Returns %0 on success or | ||
154 | * %-EINVAL on failure. | ||
155 | */ | ||
156 | static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data) | ||
157 | { | ||
158 | pr_debug("mpc85xx_doorbell_send: index %d destid %4.4x data %4.4x\n", | ||
159 | index, destid, data); | ||
160 | out_be32((void *)&dbell_atmu_regs->rowtar, destid << 22); | ||
161 | out_be16((void *)(dbell_win), data); | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | /** | ||
167 | * mpc85xx_local_config_read - Generate a MPC85xx local config space read | ||
168 | * @index: ID of RapdiIO interface | ||
169 | * @offset: Offset into configuration space | ||
170 | * @len: Length (in bytes) of the maintenance transaction | ||
171 | * @data: Value to be read into | ||
172 | * | ||
173 | * Generates a MPC85xx local configuration space read. Returns %0 on | ||
174 | * success or %-EINVAL on failure. | ||
175 | */ | ||
176 | static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data) | ||
177 | { | ||
178 | pr_debug("mpc85xx_local_config_read: index %d offset %8.8x\n", index, | ||
179 | offset); | ||
180 | *data = in_be32((void *)(regs_win + offset)); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * mpc85xx_local_config_write - Generate a MPC85xx local config space write | ||
187 | * @index: ID of RapdiIO interface | ||
188 | * @offset: Offset into configuration space | ||
189 | * @len: Length (in bytes) of the maintenance transaction | ||
190 | * @data: Value to be written | ||
191 | * | ||
192 | * Generates a MPC85xx local configuration space write. Returns %0 on | ||
193 | * success or %-EINVAL on failure. | ||
194 | */ | ||
195 | static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data) | ||
196 | { | ||
197 | pr_debug | ||
198 | ("mpc85xx_local_config_write: index %d offset %8.8x data %8.8x\n", | ||
199 | index, offset, data); | ||
200 | out_be32((void *)(regs_win + offset), data); | ||
201 | |||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * mpc85xx_rio_config_read - Generate a MPC85xx read maintenance transaction | ||
207 | * @index: ID of RapdiIO interface | ||
208 | * @destid: Destination ID of transaction | ||
209 | * @hopcount: Number of hops to target device | ||
210 | * @offset: Offset into configuration space | ||
211 | * @len: Length (in bytes) of the maintenance transaction | ||
212 | * @val: Location to be read into | ||
213 | * | ||
214 | * Generates a MPC85xx read maintenance transaction. Returns %0 on | ||
215 | * success or %-EINVAL on failure. | ||
216 | */ | ||
217 | static int | ||
218 | mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len, | ||
219 | u32 * val) | ||
220 | { | ||
221 | u8 *data; | ||
222 | |||
223 | pr_debug | ||
224 | ("mpc85xx_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n", | ||
225 | index, destid, hopcount, offset, len); | ||
226 | out_be32((void *)&maint_atmu_regs->rowtar, | ||
227 | (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); | ||
228 | |||
229 | data = (u8 *) maint_win + offset; | ||
230 | switch (len) { | ||
231 | case 1: | ||
232 | *val = in_8((u8 *) data); | ||
233 | break; | ||
234 | case 2: | ||
235 | *val = in_be16((u16 *) data); | ||
236 | break; | ||
237 | default: | ||
238 | *val = in_be32((u32 *) data); | ||
239 | break; | ||
240 | } | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | /** | ||
246 | * mpc85xx_rio_config_write - Generate a MPC85xx write maintenance transaction | ||
247 | * @index: ID of RapdiIO interface | ||
248 | * @destid: Destination ID of transaction | ||
249 | * @hopcount: Number of hops to target device | ||
250 | * @offset: Offset into configuration space | ||
251 | * @len: Length (in bytes) of the maintenance transaction | ||
252 | * @val: Value to be written | ||
253 | * | ||
254 | * Generates an MPC85xx write maintenance transaction. Returns %0 on | ||
255 | * success or %-EINVAL on failure. | ||
256 | */ | ||
257 | static int | ||
258 | mpc85xx_rio_config_write(int index, u16 destid, u8 hopcount, u32 offset, | ||
259 | int len, u32 val) | ||
260 | { | ||
261 | u8 *data; | ||
262 | pr_debug | ||
263 | ("mpc85xx_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", | ||
264 | index, destid, hopcount, offset, len, val); | ||
265 | out_be32((void *)&maint_atmu_regs->rowtar, | ||
266 | (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9)); | ||
267 | |||
268 | data = (u8 *) maint_win + offset; | ||
269 | switch (len) { | ||
270 | case 1: | ||
271 | out_8((u8 *) data, val); | ||
272 | break; | ||
273 | case 2: | ||
274 | out_be16((u16 *) data, val); | ||
275 | break; | ||
276 | default: | ||
277 | out_be32((u32 *) data, val); | ||
278 | break; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * rio_hw_add_outb_message - Add message to the MPC85xx outbound message queue | ||
286 | * @mport: Master port with outbound message queue | ||
287 | * @rdev: Target of outbound message | ||
288 | * @mbox: Outbound mailbox | ||
289 | * @buffer: Message to add to outbound queue | ||
290 | * @len: Length of message | ||
291 | * | ||
292 | * Adds the @buffer message to the MPC85xx outbound message queue. Returns | ||
293 | * %0 on success or %-EINVAL on failure. | ||
294 | */ | ||
295 | int | ||
296 | rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, | ||
297 | void *buffer, size_t len) | ||
298 | { | ||
299 | u32 omr; | ||
300 | struct rio_tx_desc *desc = | ||
301 | (struct rio_tx_desc *)msg_tx_ring.virt + msg_tx_ring.tx_slot; | ||
302 | int ret = 0; | ||
303 | |||
304 | pr_debug | ||
305 | ("RIO: rio_hw_add_outb_message(): destid %4.4x mbox %d buffer %8.8x len %8.8x\n", | ||
306 | rdev->destid, mbox, (int)buffer, len); | ||
307 | |||
308 | if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { | ||
309 | ret = -EINVAL; | ||
310 | goto out; | ||
311 | } | ||
312 | |||
313 | /* Copy and clear rest of buffer */ | ||
314 | memcpy(msg_tx_ring.virt_buffer[msg_tx_ring.tx_slot], buffer, len); | ||
315 | if (len < (RIO_MAX_MSG_SIZE - 4)) | ||
316 | memset((void *)((u32) msg_tx_ring. | ||
317 | virt_buffer[msg_tx_ring.tx_slot] + len), 0, | ||
318 | RIO_MAX_MSG_SIZE - len); | ||
319 | |||
320 | /* Set mbox field for message */ | ||
321 | desc->dport = mbox & 0x3; | ||
322 | |||
323 | /* Enable EOMI interrupt, set priority, and set destid */ | ||
324 | desc->dattr = 0x28000000 | (rdev->destid << 2); | ||
325 | |||
326 | /* Set transfer size aligned to next power of 2 (in double words) */ | ||
327 | desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len); | ||
328 | |||
329 | /* Set snooping and source buffer address */ | ||
330 | desc->saddr = 0x00000004 | msg_tx_ring.phys_buffer[msg_tx_ring.tx_slot]; | ||
331 | |||
332 | /* Increment enqueue pointer */ | ||
333 | omr = in_be32((void *)&msg_regs->omr); | ||
334 | out_be32((void *)&msg_regs->omr, omr | RIO_MSG_OMR_MUI); | ||
335 | |||
336 | /* Go to next descriptor */ | ||
337 | if (++msg_tx_ring.tx_slot == msg_tx_ring.size) | ||
338 | msg_tx_ring.tx_slot = 0; | ||
339 | |||
340 | out: | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | EXPORT_SYMBOL_GPL(rio_hw_add_outb_message); | ||
345 | |||
346 | /** | ||
347 | * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler | ||
348 | * @irq: Linux interrupt number | ||
349 | * @dev_instance: Pointer to interrupt-specific data | ||
350 | * | ||
351 | * Handles outbound message interrupts. Executes a register outbound | ||
352 | * mailbox event handler and acks the interrupt occurrence. | ||
353 | */ | ||
354 | static irqreturn_t | ||
355 | mpc85xx_rio_tx_handler(int irq, void *dev_instance) | ||
356 | { | ||
357 | int osr; | ||
358 | struct rio_mport *port = (struct rio_mport *)dev_instance; | ||
359 | |||
360 | osr = in_be32((void *)&msg_regs->osr); | ||
361 | |||
362 | if (osr & RIO_MSG_OSR_TE) { | ||
363 | pr_info("RIO: outbound message transmission error\n"); | ||
364 | out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_TE); | ||
365 | goto out; | ||
366 | } | ||
367 | |||
368 | if (osr & RIO_MSG_OSR_QOI) { | ||
369 | pr_info("RIO: outbound message queue overflow\n"); | ||
370 | out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_QOI); | ||
371 | goto out; | ||
372 | } | ||
373 | |||
374 | if (osr & RIO_MSG_OSR_EOMI) { | ||
375 | u32 dqp = in_be32((void *)&msg_regs->odqdpar); | ||
376 | int slot = (dqp - msg_tx_ring.phys) >> 5; | ||
377 | port->outb_msg[0].mcback(port, msg_tx_ring.dev_id, -1, slot); | ||
378 | |||
379 | /* Ack the end-of-message interrupt */ | ||
380 | out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_EOMI); | ||
381 | } | ||
382 | |||
383 | out: | ||
384 | return IRQ_HANDLED; | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * rio_open_outb_mbox - Initialize MPC85xx outbound mailbox | ||
389 | * @mport: Master port implementing the outbound message unit | ||
390 | * @dev_id: Device specific pointer to pass on event | ||
391 | * @mbox: Mailbox to open | ||
392 | * @entries: Number of entries in the outbound mailbox ring | ||
393 | * | ||
394 | * Initializes buffer ring, request the outbound message interrupt, | ||
395 | * and enables the outbound message unit. Returns %0 on success and | ||
396 | * %-EINVAL or %-ENOMEM on failure. | ||
397 | */ | ||
398 | int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) | ||
399 | { | ||
400 | int i, j, rc = 0; | ||
401 | |||
402 | if ((entries < RIO_MIN_TX_RING_SIZE) || | ||
403 | (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) { | ||
404 | rc = -EINVAL; | ||
405 | goto out; | ||
406 | } | ||
407 | |||
408 | /* Initialize shadow copy ring */ | ||
409 | msg_tx_ring.dev_id = dev_id; | ||
410 | msg_tx_ring.size = entries; | ||
411 | |||
412 | for (i = 0; i < msg_tx_ring.size; i++) { | ||
413 | if (! | ||
414 | (msg_tx_ring.virt_buffer[i] = | ||
415 | dma_alloc_coherent(NULL, RIO_MSG_BUFFER_SIZE, | ||
416 | &msg_tx_ring.phys_buffer[i], | ||
417 | GFP_KERNEL))) { | ||
418 | rc = -ENOMEM; | ||
419 | for (j = 0; j < msg_tx_ring.size; j++) | ||
420 | if (msg_tx_ring.virt_buffer[j]) | ||
421 | dma_free_coherent(NULL, | ||
422 | RIO_MSG_BUFFER_SIZE, | ||
423 | msg_tx_ring. | ||
424 | virt_buffer[j], | ||
425 | msg_tx_ring. | ||
426 | phys_buffer[j]); | ||
427 | goto out; | ||
428 | } | ||
429 | } | ||
430 | |||
431 | /* Initialize outbound message descriptor ring */ | ||
432 | if (!(msg_tx_ring.virt = dma_alloc_coherent(NULL, | ||
433 | msg_tx_ring.size * | ||
434 | RIO_MSG_DESC_SIZE, | ||
435 | &msg_tx_ring.phys, | ||
436 | GFP_KERNEL))) { | ||
437 | rc = -ENOMEM; | ||
438 | goto out_dma; | ||
439 | } | ||
440 | memset(msg_tx_ring.virt, 0, msg_tx_ring.size * RIO_MSG_DESC_SIZE); | ||
441 | msg_tx_ring.tx_slot = 0; | ||
442 | |||
443 | /* Point dequeue/enqueue pointers at first entry in ring */ | ||
444 | out_be32((void *)&msg_regs->odqdpar, msg_tx_ring.phys); | ||
445 | out_be32((void *)&msg_regs->odqepar, msg_tx_ring.phys); | ||
446 | |||
447 | /* Configure for snooping */ | ||
448 | out_be32((void *)&msg_regs->osar, 0x00000004); | ||
449 | |||
450 | /* Clear interrupt status */ | ||
451 | out_be32((void *)&msg_regs->osr, 0x000000b3); | ||
452 | |||
453 | /* Hook up outbound message handler */ | ||
454 | if ((rc = | ||
455 | request_irq(MPC85xx_IRQ_RIO_TX, mpc85xx_rio_tx_handler, 0, | ||
456 | "msg_tx", (void *)mport)) < 0) | ||
457 | goto out_irq; | ||
458 | |||
459 | /* | ||
460 | * Configure outbound message unit | ||
461 | * Snooping | ||
462 | * Interrupts (all enabled, except QEIE) | ||
463 | * Chaining mode | ||
464 | * Disable | ||
465 | */ | ||
466 | out_be32((void *)&msg_regs->omr, 0x00100220); | ||
467 | |||
468 | /* Set number of entries */ | ||
469 | out_be32((void *)&msg_regs->omr, | ||
470 | in_be32((void *)&msg_regs->omr) | | ||
471 | ((get_bitmask_order(entries) - 2) << 12)); | ||
472 | |||
473 | /* Now enable the unit */ | ||
474 | out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 0x1); | ||
475 | |||
476 | out: | ||
477 | return rc; | ||
478 | |||
479 | out_irq: | ||
480 | dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE, | ||
481 | msg_tx_ring.virt, msg_tx_ring.phys); | ||
482 | |||
483 | out_dma: | ||
484 | for (i = 0; i < msg_tx_ring.size; i++) | ||
485 | dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, | ||
486 | msg_tx_ring.virt_buffer[i], | ||
487 | msg_tx_ring.phys_buffer[i]); | ||
488 | |||
489 | return rc; | ||
490 | } | ||
491 | |||
492 | /** | ||
493 | * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox | ||
494 | * @mport: Master port implementing the outbound message unit | ||
495 | * @mbox: Mailbox to close | ||
496 | * | ||
497 | * Disables the outbound message unit, free all buffers, and | ||
498 | * frees the outbound message interrupt. | ||
499 | */ | ||
500 | void rio_close_outb_mbox(struct rio_mport *mport, int mbox) | ||
501 | { | ||
502 | /* Disable inbound message unit */ | ||
503 | out_be32((void *)&msg_regs->omr, 0); | ||
504 | |||
505 | /* Free ring */ | ||
506 | dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE, | ||
507 | msg_tx_ring.virt, msg_tx_ring.phys); | ||
508 | |||
509 | /* Free interrupt */ | ||
510 | free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport); | ||
511 | } | ||
512 | |||
513 | /** | ||
514 | * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler | ||
515 | * @irq: Linux interrupt number | ||
516 | * @dev_instance: Pointer to interrupt-specific data | ||
517 | * | ||
518 | * Handles inbound message interrupts. Executes a registered inbound | ||
519 | * mailbox event handler and acks the interrupt occurrence. | ||
520 | */ | ||
521 | static irqreturn_t | ||
522 | mpc85xx_rio_rx_handler(int irq, void *dev_instance) | ||
523 | { | ||
524 | int isr; | ||
525 | struct rio_mport *port = (struct rio_mport *)dev_instance; | ||
526 | |||
527 | isr = in_be32((void *)&msg_regs->isr); | ||
528 | |||
529 | if (isr & RIO_MSG_ISR_TE) { | ||
530 | pr_info("RIO: inbound message reception error\n"); | ||
531 | out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE); | ||
532 | goto out; | ||
533 | } | ||
534 | |||
535 | /* XXX Need to check/dispatch until queue empty */ | ||
536 | if (isr & RIO_MSG_ISR_DIQI) { | ||
537 | /* | ||
538 | * We implement *only* mailbox 0, but can receive messages | ||
539 | * for any mailbox/letter to that mailbox destination. So, | ||
540 | * make the callback with an unknown/invalid mailbox number | ||
541 | * argument. | ||
542 | */ | ||
543 | port->inb_msg[0].mcback(port, msg_rx_ring.dev_id, -1, -1); | ||
544 | |||
545 | /* Ack the queueing interrupt */ | ||
546 | out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI); | ||
547 | } | ||
548 | |||
549 | out: | ||
550 | return IRQ_HANDLED; | ||
551 | } | ||
552 | |||
553 | /** | ||
554 | * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox | ||
555 | * @mport: Master port implementing the inbound message unit | ||
556 | * @dev_id: Device specific pointer to pass on event | ||
557 | * @mbox: Mailbox to open | ||
558 | * @entries: Number of entries in the inbound mailbox ring | ||
559 | * | ||
560 | * Initializes buffer ring, request the inbound message interrupt, | ||
561 | * and enables the inbound message unit. Returns %0 on success | ||
562 | * and %-EINVAL or %-ENOMEM on failure. | ||
563 | */ | ||
564 | int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries) | ||
565 | { | ||
566 | int i, rc = 0; | ||
567 | |||
568 | if ((entries < RIO_MIN_RX_RING_SIZE) || | ||
569 | (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) { | ||
570 | rc = -EINVAL; | ||
571 | goto out; | ||
572 | } | ||
573 | |||
574 | /* Initialize client buffer ring */ | ||
575 | msg_rx_ring.dev_id = dev_id; | ||
576 | msg_rx_ring.size = entries; | ||
577 | msg_rx_ring.rx_slot = 0; | ||
578 | for (i = 0; i < msg_rx_ring.size; i++) | ||
579 | msg_rx_ring.virt_buffer[i] = NULL; | ||
580 | |||
581 | /* Initialize inbound message ring */ | ||
582 | if (!(msg_rx_ring.virt = dma_alloc_coherent(NULL, | ||
583 | msg_rx_ring.size * | ||
584 | RIO_MAX_MSG_SIZE, | ||
585 | &msg_rx_ring.phys, | ||
586 | GFP_KERNEL))) { | ||
587 | rc = -ENOMEM; | ||
588 | goto out; | ||
589 | } | ||
590 | |||
591 | /* Point dequeue/enqueue pointers at first entry in ring */ | ||
592 | out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys); | ||
593 | out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys); | ||
594 | |||
595 | /* Clear interrupt status */ | ||
596 | out_be32((void *)&msg_regs->isr, 0x00000091); | ||
597 | |||
598 | /* Hook up inbound message handler */ | ||
599 | if ((rc = | ||
600 | request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0, | ||
601 | "msg_rx", (void *)mport)) < 0) { | ||
602 | dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE, | ||
603 | msg_tx_ring.virt_buffer[i], | ||
604 | msg_tx_ring.phys_buffer[i]); | ||
605 | goto out; | ||
606 | } | ||
607 | |||
608 | /* | ||
609 | * Configure inbound message unit: | ||
610 | * Snooping | ||
611 | * 4KB max message size | ||
612 | * Unmask all interrupt sources | ||
613 | * Disable | ||
614 | */ | ||
615 | out_be32((void *)&msg_regs->imr, 0x001b0060); | ||
616 | |||
617 | /* Set number of queue entries */ | ||
618 | out_be32((void *)&msg_regs->imr, | ||
619 | in_be32((void *)&msg_regs->imr) | | ||
620 | ((get_bitmask_order(entries) - 2) << 12)); | ||
621 | |||
622 | /* Now enable the unit */ | ||
623 | out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 0x1); | ||
624 | |||
625 | out: | ||
626 | return rc; | ||
627 | } | ||
628 | |||
629 | /** | ||
630 | * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox | ||
631 | * @mport: Master port implementing the inbound message unit | ||
632 | * @mbox: Mailbox to close | ||
633 | * | ||
634 | * Disables the inbound message unit, free all buffers, and | ||
635 | * frees the inbound message interrupt. | ||
636 | */ | ||
637 | void rio_close_inb_mbox(struct rio_mport *mport, int mbox) | ||
638 | { | ||
639 | /* Disable inbound message unit */ | ||
640 | out_be32((void *)&msg_regs->imr, 0); | ||
641 | |||
642 | /* Free ring */ | ||
643 | dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE, | ||
644 | msg_rx_ring.virt, msg_rx_ring.phys); | ||
645 | |||
646 | /* Free interrupt */ | ||
647 | free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport); | ||
648 | } | ||
649 | |||
650 | /** | ||
651 | * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message queue | ||
652 | * @mport: Master port implementing the inbound message unit | ||
653 | * @mbox: Inbound mailbox number | ||
654 | * @buf: Buffer to add to inbound queue | ||
655 | * | ||
656 | * Adds the @buf buffer to the MPC85xx inbound message queue. Returns | ||
657 | * %0 on success or %-EINVAL on failure. | ||
658 | */ | ||
659 | int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf) | ||
660 | { | ||
661 | int rc = 0; | ||
662 | |||
663 | pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n", | ||
664 | msg_rx_ring.rx_slot); | ||
665 | |||
666 | if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) { | ||
667 | printk(KERN_ERR | ||
668 | "RIO: error adding inbound buffer %d, buffer exists\n", | ||
669 | msg_rx_ring.rx_slot); | ||
670 | rc = -EINVAL; | ||
671 | goto out; | ||
672 | } | ||
673 | |||
674 | msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] = buf; | ||
675 | if (++msg_rx_ring.rx_slot == msg_rx_ring.size) | ||
676 | msg_rx_ring.rx_slot = 0; | ||
677 | |||
678 | out: | ||
679 | return rc; | ||
680 | } | ||
681 | |||
682 | EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer); | ||
683 | |||
684 | /** | ||
685 | * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx message unit | ||
686 | * @mport: Master port implementing the inbound message unit | ||
687 | * @mbox: Inbound mailbox number | ||
688 | * | ||
689 | * Gets the next available inbound message from the inbound message queue. | ||
690 | * A pointer to the message is returned on success or NULL on failure. | ||
691 | */ | ||
692 | void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox) | ||
693 | { | ||
694 | u32 imr; | ||
695 | u32 phys_buf, virt_buf; | ||
696 | void *buf = NULL; | ||
697 | int buf_idx; | ||
698 | |||
699 | phys_buf = in_be32((void *)&msg_regs->ifqdpar); | ||
700 | |||
701 | /* If no more messages, then bail out */ | ||
702 | if (phys_buf == in_be32((void *)&msg_regs->ifqepar)) | ||
703 | goto out2; | ||
704 | |||
705 | virt_buf = (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys); | ||
706 | buf_idx = (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; | ||
707 | buf = msg_rx_ring.virt_buffer[buf_idx]; | ||
708 | |||
709 | if (!buf) { | ||
710 | printk(KERN_ERR | ||
711 | "RIO: inbound message copy failed, no buffers\n"); | ||
712 | goto out1; | ||
713 | } | ||
714 | |||
715 | /* Copy max message size, caller is expected to allocate that big */ | ||
716 | memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE); | ||
717 | |||
718 | /* Clear the available buffer */ | ||
719 | msg_rx_ring.virt_buffer[buf_idx] = NULL; | ||
720 | |||
721 | out1: | ||
722 | imr = in_be32((void *)&msg_regs->imr); | ||
723 | out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI); | ||
724 | |||
725 | out2: | ||
726 | return buf; | ||
727 | } | ||
728 | |||
729 | EXPORT_SYMBOL_GPL(rio_hw_get_inb_message); | ||
730 | |||
731 | /** | ||
732 | * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler | ||
733 | * @irq: Linux interrupt number | ||
734 | * @dev_instance: Pointer to interrupt-specific data | ||
735 | * | ||
736 | * Handles doorbell interrupts. Parses a list of registered | ||
737 | * doorbell event handlers and executes a matching event handler. | ||
738 | */ | ||
739 | static irqreturn_t | ||
740 | mpc85xx_rio_dbell_handler(int irq, void *dev_instance) | ||
741 | { | ||
742 | int dsr; | ||
743 | struct rio_mport *port = (struct rio_mport *)dev_instance; | ||
744 | |||
745 | dsr = in_be32((void *)&msg_regs->dsr); | ||
746 | |||
747 | if (dsr & DOORBELL_DSR_TE) { | ||
748 | pr_info("RIO: doorbell reception error\n"); | ||
749 | out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE); | ||
750 | goto out; | ||
751 | } | ||
752 | |||
753 | if (dsr & DOORBELL_DSR_QFI) { | ||
754 | pr_info("RIO: doorbell queue full\n"); | ||
755 | out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI); | ||
756 | goto out; | ||
757 | } | ||
758 | |||
759 | /* XXX Need to check/dispatch until queue empty */ | ||
760 | if (dsr & DOORBELL_DSR_DIQI) { | ||
761 | u32 dmsg = | ||
762 | (u32) dbell_ring.virt + | ||
763 | (in_be32((void *)&msg_regs->dqdpar) & 0xfff); | ||
764 | u32 dmr; | ||
765 | struct rio_dbell *dbell; | ||
766 | int found = 0; | ||
767 | |||
768 | pr_debug | ||
769 | ("RIO: processing doorbell, sid %2.2x tid %2.2x info %4.4x\n", | ||
770 | DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); | ||
771 | |||
772 | list_for_each_entry(dbell, &port->dbells, node) { | ||
773 | if ((dbell->res->start <= DBELL_INF(dmsg)) && | ||
774 | (dbell->res->end >= DBELL_INF(dmsg))) { | ||
775 | found = 1; | ||
776 | break; | ||
777 | } | ||
778 | } | ||
779 | if (found) { | ||
780 | dbell->dinb(port, dbell->dev_id, DBELL_SID(dmsg), DBELL_TID(dmsg), | ||
781 | DBELL_INF(dmsg)); | ||
782 | } else { | ||
783 | pr_debug | ||
784 | ("RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n", | ||
785 | DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); | ||
786 | } | ||
787 | dmr = in_be32((void *)&msg_regs->dmr); | ||
788 | out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI); | ||
789 | out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI); | ||
790 | } | ||
791 | |||
792 | out: | ||
793 | return IRQ_HANDLED; | ||
794 | } | ||
795 | |||
796 | /** | ||
797 | * mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init | ||
798 | * @mport: Master port implementing the inbound doorbell unit | ||
799 | * | ||
800 | * Initializes doorbell unit hardware and inbound DMA buffer | ||
801 | * ring. Called from mpc85xx_rio_setup(). Returns %0 on success | ||
802 | * or %-ENOMEM on failure. | ||
803 | */ | ||
804 | static int mpc85xx_rio_doorbell_init(struct rio_mport *mport) | ||
805 | { | ||
806 | int rc = 0; | ||
807 | |||
808 | /* Map outbound doorbell window immediately after maintenance window */ | ||
809 | if (!(dbell_win = | ||
810 | (u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE, | ||
811 | RIO_DBELL_WIN_SIZE))) { | ||
812 | printk(KERN_ERR | ||
813 | "RIO: unable to map outbound doorbell window\n"); | ||
814 | rc = -ENOMEM; | ||
815 | goto out; | ||
816 | } | ||
817 | |||
818 | /* Initialize inbound doorbells */ | ||
819 | if (!(dbell_ring.virt = dma_alloc_coherent(NULL, | ||
820 | 512 * DOORBELL_MESSAGE_SIZE, | ||
821 | &dbell_ring.phys, | ||
822 | GFP_KERNEL))) { | ||
823 | printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n"); | ||
824 | rc = -ENOMEM; | ||
825 | iounmap((void *)dbell_win); | ||
826 | goto out; | ||
827 | } | ||
828 | |||
829 | /* Point dequeue/enqueue pointers at first entry in ring */ | ||
830 | out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys); | ||
831 | out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys); | ||
832 | |||
833 | /* Clear interrupt status */ | ||
834 | out_be32((void *)&msg_regs->dsr, 0x00000091); | ||
835 | |||
836 | /* Hook up doorbell handler */ | ||
837 | if ((rc = | ||
838 | request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0, | ||
839 | "dbell_rx", (void *)mport) < 0)) { | ||
840 | iounmap((void *)dbell_win); | ||
841 | dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE, | ||
842 | dbell_ring.virt, dbell_ring.phys); | ||
843 | printk(KERN_ERR | ||
844 | "MPC85xx RIO: unable to request inbound doorbell irq"); | ||
845 | goto out; | ||
846 | } | ||
847 | |||
848 | /* Configure doorbells for snooping, 512 entries, and enable */ | ||
849 | out_be32((void *)&msg_regs->dmr, 0x00108161); | ||
850 | |||
851 | out: | ||
852 | return rc; | ||
853 | } | ||
854 | |||
855 | static char *cmdline = NULL; | ||
856 | |||
857 | static int mpc85xx_rio_get_hdid(int index) | ||
858 | { | ||
859 | /* XXX Need to parse multiple entries in some format */ | ||
860 | if (!cmdline) | ||
861 | return -1; | ||
862 | |||
863 | return simple_strtol(cmdline, NULL, 0); | ||
864 | } | ||
865 | |||
866 | static int mpc85xx_rio_get_cmdline(char *s) | ||
867 | { | ||
868 | if (!s) | ||
869 | return 0; | ||
870 | |||
871 | cmdline = s; | ||
872 | return 1; | ||
873 | } | ||
874 | |||
875 | __setup("riohdid=", mpc85xx_rio_get_cmdline); | ||
876 | |||
877 | /** | ||
878 | * mpc85xx_rio_setup - Setup MPC85xx RapidIO interface | ||
879 | * @law_start: Starting physical address of RapidIO LAW | ||
880 | * @law_size: Size of RapidIO LAW | ||
881 | * | ||
882 | * Initializes MPC85xx RapidIO hardware interface, configures | ||
883 | * master port with system-specific info, and registers the | ||
884 | * master port with the RapidIO subsystem. | ||
885 | */ | ||
886 | void mpc85xx_rio_setup(int law_start, int law_size) | ||
887 | { | ||
888 | struct rio_ops *ops; | ||
889 | struct rio_mport *port; | ||
890 | |||
891 | ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL); | ||
892 | ops->lcread = mpc85xx_local_config_read; | ||
893 | ops->lcwrite = mpc85xx_local_config_write; | ||
894 | ops->cread = mpc85xx_rio_config_read; | ||
895 | ops->cwrite = mpc85xx_rio_config_write; | ||
896 | ops->dsend = mpc85xx_rio_doorbell_send; | ||
897 | |||
898 | port = kmalloc(sizeof(struct rio_mport), GFP_KERNEL); | ||
899 | port->id = 0; | ||
900 | port->index = 0; | ||
901 | INIT_LIST_HEAD(&port->dbells); | ||
902 | port->iores.start = law_start; | ||
903 | port->iores.end = law_start + law_size; | ||
904 | port->iores.flags = IORESOURCE_MEM; | ||
905 | |||
906 | rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff); | ||
907 | rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0); | ||
908 | rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0); | ||
909 | strcpy(port->name, "RIO0 mport"); | ||
910 | |||
911 | port->ops = ops; | ||
912 | port->host_deviceid = mpc85xx_rio_get_hdid(port->id); | ||
913 | |||
914 | rio_register_mport(port); | ||
915 | |||
916 | regs_win = (u32) ioremap(RIO_REGS_BASE, 0x20000); | ||
917 | atmu_regs = (struct rio_atmu_regs *)(regs_win + RIO_ATMU_REGS_OFFSET); | ||
918 | maint_atmu_regs = atmu_regs + 1; | ||
919 | dbell_atmu_regs = atmu_regs + 2; | ||
920 | msg_regs = (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET); | ||
921 | |||
922 | /* Configure maintenance transaction window */ | ||
923 | out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000); | ||
924 | out_be32((void *)&maint_atmu_regs->rowar, 0x80077015); | ||
925 | |||
926 | maint_win = (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE); | ||
927 | |||
928 | /* Configure outbound doorbell window */ | ||
929 | out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400); | ||
930 | out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b); | ||
931 | mpc85xx_rio_doorbell_init(port); | ||
932 | } | ||
diff --git a/arch/powerpc/sysdev/fsl_rio.h b/arch/powerpc/sysdev/fsl_rio.h new file mode 100644 index 000000000000..6d3ff30b1579 --- /dev/null +++ b/arch/powerpc/sysdev/fsl_rio.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * MPC85xx RapidIO definitions | ||
3 | * | ||
4 | * Copyright 2005 MontaVista Software, Inc. | ||
5 | * Matt Porter <mporter@kernel.crashing.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef __PPC_SYSLIB_PPC85XX_RIO_H | ||
14 | #define __PPC_SYSLIB_PPC85XX_RIO_H | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | |||
18 | extern void mpc85xx_rio_setup(int law_start, int law_size); | ||
19 | |||
20 | #endif /* __PPC_SYSLIB_PPC85XX_RIO_H */ | ||
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 3ace7474809e..e48b20e934ca 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/of_platform.h> | 25 | #include <linux/of_platform.h> |
26 | #include <linux/phy.h> | 26 | #include <linux/phy.h> |
27 | #include <linux/phy_fixed.h> | ||
27 | #include <linux/spi/spi.h> | 28 | #include <linux/spi/spi.h> |
28 | #include <linux/fsl_devices.h> | 29 | #include <linux/fsl_devices.h> |
29 | #include <linux/fs_enet_pd.h> | 30 | #include <linux/fs_enet_pd.h> |
@@ -54,10 +55,18 @@ phys_addr_t get_immrbase(void) | |||
54 | soc = of_find_node_by_type(NULL, "soc"); | 55 | soc = of_find_node_by_type(NULL, "soc"); |
55 | if (soc) { | 56 | if (soc) { |
56 | int size; | 57 | int size; |
57 | const void *prop = of_get_property(soc, "reg", &size); | 58 | u32 naddr; |
59 | const u32 *prop = of_get_property(soc, "#address-cells", &size); | ||
58 | 60 | ||
61 | if (prop && size == 4) | ||
62 | naddr = *prop; | ||
63 | else | ||
64 | naddr = 2; | ||
65 | |||
66 | prop = of_get_property(soc, "ranges", &size); | ||
59 | if (prop) | 67 | if (prop) |
60 | immrbase = of_translate_address(soc, prop); | 68 | immrbase = of_translate_address(soc, prop + naddr); |
69 | |||
61 | of_node_put(soc); | 70 | of_node_put(soc); |
62 | } | 71 | } |
63 | 72 | ||
@@ -66,7 +75,7 @@ phys_addr_t get_immrbase(void) | |||
66 | 75 | ||
67 | EXPORT_SYMBOL(get_immrbase); | 76 | EXPORT_SYMBOL(get_immrbase); |
68 | 77 | ||
69 | #if defined(CONFIG_CPM2) || defined(CONFIG_8xx) | 78 | #if defined(CONFIG_CPM2) || defined(CONFIG_QUICC_ENGINE) || defined(CONFIG_8xx) |
70 | 79 | ||
71 | static u32 brgfreq = -1; | 80 | static u32 brgfreq = -1; |
72 | 81 | ||
@@ -91,11 +100,21 @@ u32 get_brgfreq(void) | |||
91 | 100 | ||
92 | /* Legacy device binding -- will go away when no users are left. */ | 101 | /* Legacy device binding -- will go away when no users are left. */ |
93 | node = of_find_node_by_type(NULL, "cpm"); | 102 | node = of_find_node_by_type(NULL, "cpm"); |
103 | if (!node) | ||
104 | node = of_find_compatible_node(NULL, NULL, "fsl,qe"); | ||
105 | if (!node) | ||
106 | node = of_find_node_by_type(NULL, "qe"); | ||
107 | |||
94 | if (node) { | 108 | if (node) { |
95 | prop = of_get_property(node, "brg-frequency", &size); | 109 | prop = of_get_property(node, "brg-frequency", &size); |
96 | if (prop && size == 4) | 110 | if (prop && size == 4) |
97 | brgfreq = *prop; | 111 | brgfreq = *prop; |
98 | 112 | ||
113 | if (brgfreq == -1 || brgfreq == 0) { | ||
114 | prop = of_get_property(node, "bus-frequency", &size); | ||
115 | if (prop && size == 4) | ||
116 | brgfreq = *prop / 2; | ||
117 | } | ||
99 | of_node_put(node); | 118 | of_node_put(node); |
100 | } | 119 | } |
101 | 120 | ||
@@ -130,17 +149,51 @@ u32 get_baudrate(void) | |||
130 | EXPORT_SYMBOL(get_baudrate); | 149 | EXPORT_SYMBOL(get_baudrate); |
131 | #endif /* CONFIG_CPM2 */ | 150 | #endif /* CONFIG_CPM2 */ |
132 | 151 | ||
133 | static int __init gfar_mdio_of_init(void) | 152 | #ifdef CONFIG_FIXED_PHY |
153 | static int __init of_add_fixed_phys(void) | ||
134 | { | 154 | { |
155 | int ret; | ||
135 | struct device_node *np; | 156 | struct device_node *np; |
136 | unsigned int i; | 157 | u32 *fixed_link; |
158 | struct fixed_phy_status status = {}; | ||
159 | |||
160 | for_each_node_by_name(np, "ethernet") { | ||
161 | fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL); | ||
162 | if (!fixed_link) | ||
163 | continue; | ||
164 | |||
165 | status.link = 1; | ||
166 | status.duplex = fixed_link[1]; | ||
167 | status.speed = fixed_link[2]; | ||
168 | status.pause = fixed_link[3]; | ||
169 | status.asym_pause = fixed_link[4]; | ||
170 | |||
171 | ret = fixed_phy_add(PHY_POLL, fixed_link[0], &status); | ||
172 | if (ret) { | ||
173 | of_node_put(np); | ||
174 | return ret; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | arch_initcall(of_add_fixed_phys); | ||
181 | #endif /* CONFIG_FIXED_PHY */ | ||
182 | |||
183 | static int __init gfar_mdio_of_init(void) | ||
184 | { | ||
185 | struct device_node *np = NULL; | ||
137 | struct platform_device *mdio_dev; | 186 | struct platform_device *mdio_dev; |
138 | struct resource res; | 187 | struct resource res; |
139 | int ret; | 188 | int ret; |
140 | 189 | ||
141 | for (np = NULL, i = 0; | 190 | np = of_find_compatible_node(np, NULL, "fsl,gianfar-mdio"); |
142 | (np = of_find_compatible_node(np, "mdio", "gianfar")) != NULL; | 191 | |
143 | i++) { | 192 | /* try the deprecated version */ |
193 | if (!np) | ||
194 | np = of_find_compatible_node(np, "mdio", "gianfar"); | ||
195 | |||
196 | if (np) { | ||
144 | int k; | 197 | int k; |
145 | struct device_node *child = NULL; | 198 | struct device_node *child = NULL; |
146 | struct gianfar_mdio_data mdio_data; | 199 | struct gianfar_mdio_data mdio_data; |
@@ -179,11 +232,13 @@ static int __init gfar_mdio_of_init(void) | |||
179 | goto unreg; | 232 | goto unreg; |
180 | } | 233 | } |
181 | 234 | ||
235 | of_node_put(np); | ||
182 | return 0; | 236 | return 0; |
183 | 237 | ||
184 | unreg: | 238 | unreg: |
185 | platform_device_unregister(mdio_dev); | 239 | platform_device_unregister(mdio_dev); |
186 | err: | 240 | err: |
241 | of_node_put(np); | ||
187 | return ret; | 242 | return ret; |
188 | } | 243 | } |
189 | 244 | ||
@@ -193,7 +248,6 @@ static const char *gfar_tx_intr = "tx"; | |||
193 | static const char *gfar_rx_intr = "rx"; | 248 | static const char *gfar_rx_intr = "rx"; |
194 | static const char *gfar_err_intr = "error"; | 249 | static const char *gfar_err_intr = "error"; |
195 | 250 | ||
196 | |||
197 | static int __init gfar_of_init(void) | 251 | static int __init gfar_of_init(void) |
198 | { | 252 | { |
199 | struct device_node *np; | 253 | struct device_node *np; |
@@ -277,29 +331,43 @@ static int __init gfar_of_init(void) | |||
277 | gfar_data.interface = PHY_INTERFACE_MODE_MII; | 331 | gfar_data.interface = PHY_INTERFACE_MODE_MII; |
278 | 332 | ||
279 | ph = of_get_property(np, "phy-handle", NULL); | 333 | ph = of_get_property(np, "phy-handle", NULL); |
280 | phy = of_find_node_by_phandle(*ph); | 334 | if (ph == NULL) { |
335 | u32 *fixed_link; | ||
281 | 336 | ||
282 | if (phy == NULL) { | 337 | fixed_link = (u32 *)of_get_property(np, "fixed-link", |
283 | ret = -ENODEV; | 338 | NULL); |
284 | goto unreg; | 339 | if (!fixed_link) { |
285 | } | 340 | ret = -ENODEV; |
341 | goto unreg; | ||
342 | } | ||
286 | 343 | ||
287 | mdio = of_get_parent(phy); | 344 | gfar_data.bus_id = 0; |
345 | gfar_data.phy_id = fixed_link[0]; | ||
346 | } else { | ||
347 | phy = of_find_node_by_phandle(*ph); | ||
348 | |||
349 | if (phy == NULL) { | ||
350 | ret = -ENODEV; | ||
351 | goto unreg; | ||
352 | } | ||
353 | |||
354 | mdio = of_get_parent(phy); | ||
355 | |||
356 | id = of_get_property(phy, "reg", NULL); | ||
357 | ret = of_address_to_resource(mdio, 0, &res); | ||
358 | if (ret) { | ||
359 | of_node_put(phy); | ||
360 | of_node_put(mdio); | ||
361 | goto unreg; | ||
362 | } | ||
363 | |||
364 | gfar_data.phy_id = *id; | ||
365 | gfar_data.bus_id = res.start; | ||
288 | 366 | ||
289 | id = of_get_property(phy, "reg", NULL); | ||
290 | ret = of_address_to_resource(mdio, 0, &res); | ||
291 | if (ret) { | ||
292 | of_node_put(phy); | 367 | of_node_put(phy); |
293 | of_node_put(mdio); | 368 | of_node_put(mdio); |
294 | goto unreg; | ||
295 | } | 369 | } |
296 | 370 | ||
297 | gfar_data.phy_id = *id; | ||
298 | gfar_data.bus_id = res.start; | ||
299 | |||
300 | of_node_put(phy); | ||
301 | of_node_put(mdio); | ||
302 | |||
303 | ret = | 371 | ret = |
304 | platform_device_add_data(gfar_dev, &gfar_data, | 372 | platform_device_add_data(gfar_dev, &gfar_data, |
305 | sizeof(struct | 373 | sizeof(struct |
@@ -390,13 +458,11 @@ static void __init of_register_i2c_devices(struct device_node *adap_node, | |||
390 | static int __init fsl_i2c_of_init(void) | 458 | static int __init fsl_i2c_of_init(void) |
391 | { | 459 | { |
392 | struct device_node *np; | 460 | struct device_node *np; |
393 | unsigned int i; | 461 | unsigned int i = 0; |
394 | struct platform_device *i2c_dev; | 462 | struct platform_device *i2c_dev; |
395 | int ret; | 463 | int ret; |
396 | 464 | ||
397 | for (np = NULL, i = 0; | 465 | for_each_compatible_node(np, NULL, "fsl-i2c") { |
398 | (np = of_find_compatible_node(np, "i2c", "fsl-i2c")) != NULL; | ||
399 | i++) { | ||
400 | struct resource r[2]; | 466 | struct resource r[2]; |
401 | struct fsl_i2c_platform_data i2c_data; | 467 | struct fsl_i2c_platform_data i2c_data; |
402 | const unsigned char *flags = NULL; | 468 | const unsigned char *flags = NULL; |
@@ -432,7 +498,7 @@ static int __init fsl_i2c_of_init(void) | |||
432 | if (ret) | 498 | if (ret) |
433 | goto unreg; | 499 | goto unreg; |
434 | 500 | ||
435 | of_register_i2c_devices(np, i); | 501 | of_register_i2c_devices(np, i++); |
436 | } | 502 | } |
437 | 503 | ||
438 | return 0; | 504 | return 0; |
@@ -528,14 +594,12 @@ static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) | |||
528 | static int __init fsl_usb_of_init(void) | 594 | static int __init fsl_usb_of_init(void) |
529 | { | 595 | { |
530 | struct device_node *np; | 596 | struct device_node *np; |
531 | unsigned int i; | 597 | unsigned int i = 0; |
532 | struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL, | 598 | struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL, |
533 | *usb_dev_dr_client = NULL; | 599 | *usb_dev_dr_client = NULL; |
534 | int ret; | 600 | int ret; |
535 | 601 | ||
536 | for (np = NULL, i = 0; | 602 | for_each_compatible_node(np, NULL, "fsl-usb2-mph") { |
537 | (np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL; | ||
538 | i++) { | ||
539 | struct resource r[2]; | 603 | struct resource r[2]; |
540 | struct fsl_usb2_platform_data usb_data; | 604 | struct fsl_usb2_platform_data usb_data; |
541 | const unsigned char *prop = NULL; | 605 | const unsigned char *prop = NULL; |
@@ -578,11 +642,10 @@ static int __init fsl_usb_of_init(void) | |||
578 | fsl_usb2_platform_data)); | 642 | fsl_usb2_platform_data)); |
579 | if (ret) | 643 | if (ret) |
580 | goto unreg_mph; | 644 | goto unreg_mph; |
645 | i++; | ||
581 | } | 646 | } |
582 | 647 | ||
583 | for (np = NULL; | 648 | for_each_compatible_node(np, NULL, "fsl-usb2-dr") { |
584 | (np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL; | ||
585 | i++) { | ||
586 | struct resource r[2]; | 649 | struct resource r[2]; |
587 | struct fsl_usb2_platform_data usb_data; | 650 | struct fsl_usb2_platform_data usb_data; |
588 | const unsigned char *prop = NULL; | 651 | const unsigned char *prop = NULL; |
@@ -654,6 +717,7 @@ static int __init fsl_usb_of_init(void) | |||
654 | fsl_usb2_platform_data)))) | 717 | fsl_usb2_platform_data)))) |
655 | goto unreg_dr; | 718 | goto unreg_dr; |
656 | } | 719 | } |
720 | i++; | ||
657 | } | 721 | } |
658 | return 0; | 722 | return 0; |
659 | 723 | ||
@@ -1125,13 +1189,12 @@ arch_initcall(fs_enet_of_init); | |||
1125 | 1189 | ||
1126 | static int __init fsl_pcmcia_of_init(void) | 1190 | static int __init fsl_pcmcia_of_init(void) |
1127 | { | 1191 | { |
1128 | struct device_node *np = NULL; | 1192 | struct device_node *np; |
1129 | /* | 1193 | /* |
1130 | * Register all the devices which type is "pcmcia" | 1194 | * Register all the devices which type is "pcmcia" |
1131 | */ | 1195 | */ |
1132 | while ((np = of_find_compatible_node(np, | 1196 | for_each_compatible_node(np, "pcmcia", "fsl,pq-pcmcia") |
1133 | "pcmcia", "fsl,pq-pcmcia")) != NULL) | 1197 | of_platform_device_create(np, "m8xx-pcmcia", NULL); |
1134 | of_platform_device_create(np, "m8xx-pcmcia", NULL); | ||
1135 | return 0; | 1198 | return 0; |
1136 | } | 1199 | } |
1137 | 1200 | ||
@@ -1213,31 +1276,17 @@ arch_initcall(cpm_smc_uart_of_init); | |||
1213 | #endif /* CONFIG_8xx */ | 1276 | #endif /* CONFIG_8xx */ |
1214 | #endif /* CONFIG_PPC_CPM_NEW_BINDING */ | 1277 | #endif /* CONFIG_PPC_CPM_NEW_BINDING */ |
1215 | 1278 | ||
1216 | int __init fsl_spi_init(struct spi_board_info *board_infos, | 1279 | static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk, |
1217 | unsigned int num_board_infos, | 1280 | struct spi_board_info *board_infos, |
1218 | void (*activate_cs)(u8 cs, u8 polarity), | 1281 | unsigned int num_board_infos, |
1219 | void (*deactivate_cs)(u8 cs, u8 polarity)) | 1282 | void (*activate_cs)(u8 cs, u8 polarity), |
1283 | void (*deactivate_cs)(u8 cs, u8 polarity)) | ||
1220 | { | 1284 | { |
1221 | struct device_node *np; | 1285 | struct device_node *np; |
1222 | unsigned int i; | 1286 | unsigned int i = 0; |
1223 | const u32 *sysclk; | ||
1224 | |||
1225 | /* SPI controller is either clocked from QE or SoC clock */ | ||
1226 | np = of_find_node_by_type(NULL, "qe"); | ||
1227 | if (!np) | ||
1228 | np = of_find_node_by_type(NULL, "soc"); | ||
1229 | |||
1230 | if (!np) | ||
1231 | return -ENODEV; | ||
1232 | |||
1233 | sysclk = of_get_property(np, "bus-frequency", NULL); | ||
1234 | if (!sysclk) | ||
1235 | return -ENODEV; | ||
1236 | 1287 | ||
1237 | for (np = NULL, i = 1; | 1288 | for_each_compatible_node(np, type, compatible) { |
1238 | (np = of_find_compatible_node(np, "spi", "fsl_spi")) != NULL; | 1289 | int ret; |
1239 | i++) { | ||
1240 | int ret = 0; | ||
1241 | unsigned int j; | 1290 | unsigned int j; |
1242 | const void *prop; | 1291 | const void *prop; |
1243 | struct resource res[2]; | 1292 | struct resource res[2]; |
@@ -1249,13 +1298,17 @@ int __init fsl_spi_init(struct spi_board_info *board_infos, | |||
1249 | 1298 | ||
1250 | memset(res, 0, sizeof(res)); | 1299 | memset(res, 0, sizeof(res)); |
1251 | 1300 | ||
1252 | pdata.sysclk = *sysclk; | 1301 | pdata.sysclk = sysclk; |
1253 | 1302 | ||
1254 | prop = of_get_property(np, "reg", NULL); | 1303 | prop = of_get_property(np, "reg", NULL); |
1255 | if (!prop) | 1304 | if (!prop) |
1256 | goto err; | 1305 | goto err; |
1257 | pdata.bus_num = *(u32 *)prop; | 1306 | pdata.bus_num = *(u32 *)prop; |
1258 | 1307 | ||
1308 | prop = of_get_property(np, "cell-index", NULL); | ||
1309 | if (prop) | ||
1310 | i = *(u32 *)prop; | ||
1311 | |||
1259 | prop = of_get_property(np, "mode", NULL); | 1312 | prop = of_get_property(np, "mode", NULL); |
1260 | if (prop && !strcmp(prop, "cpu-qe")) | 1313 | if (prop && !strcmp(prop, "cpu-qe")) |
1261 | pdata.qe_mode = 1; | 1314 | pdata.qe_mode = 1; |
@@ -1266,7 +1319,7 @@ int __init fsl_spi_init(struct spi_board_info *board_infos, | |||
1266 | } | 1319 | } |
1267 | 1320 | ||
1268 | if (!pdata.max_chipselect) | 1321 | if (!pdata.max_chipselect) |
1269 | goto err; | 1322 | continue; |
1270 | 1323 | ||
1271 | ret = of_address_to_resource(np, 0, &res[0]); | 1324 | ret = of_address_to_resource(np, 0, &res[0]); |
1272 | if (ret) | 1325 | if (ret) |
@@ -1293,13 +1346,58 @@ int __init fsl_spi_init(struct spi_board_info *board_infos, | |||
1293 | if (ret) | 1346 | if (ret) |
1294 | goto unreg; | 1347 | goto unreg; |
1295 | 1348 | ||
1296 | continue; | 1349 | goto next; |
1297 | unreg: | 1350 | unreg: |
1298 | platform_device_del(pdev); | 1351 | platform_device_del(pdev); |
1299 | err: | 1352 | err: |
1300 | continue; | 1353 | pr_err("%s: registration failed\n", np->full_name); |
1354 | next: | ||
1355 | i++; | ||
1356 | } | ||
1357 | |||
1358 | return i; | ||
1359 | } | ||
1360 | |||
1361 | int __init fsl_spi_init(struct spi_board_info *board_infos, | ||
1362 | unsigned int num_board_infos, | ||
1363 | void (*activate_cs)(u8 cs, u8 polarity), | ||
1364 | void (*deactivate_cs)(u8 cs, u8 polarity)) | ||
1365 | { | ||
1366 | u32 sysclk = -1; | ||
1367 | int ret; | ||
1368 | |||
1369 | #ifdef CONFIG_QUICC_ENGINE | ||
1370 | /* SPI controller is either clocked from QE or SoC clock */ | ||
1371 | sysclk = get_brgfreq(); | ||
1372 | #endif | ||
1373 | if (sysclk == -1) { | ||
1374 | struct device_node *np; | ||
1375 | const u32 *freq; | ||
1376 | int size; | ||
1377 | |||
1378 | np = of_find_node_by_type(NULL, "soc"); | ||
1379 | if (!np) | ||
1380 | return -ENODEV; | ||
1381 | |||
1382 | freq = of_get_property(np, "clock-frequency", &size); | ||
1383 | if (!freq || size != sizeof(*freq) || *freq == 0) { | ||
1384 | freq = of_get_property(np, "bus-frequency", &size); | ||
1385 | if (!freq || size != sizeof(*freq) || *freq == 0) { | ||
1386 | of_node_put(np); | ||
1387 | return -ENODEV; | ||
1388 | } | ||
1389 | } | ||
1390 | |||
1391 | sysclk = *freq; | ||
1392 | of_node_put(np); | ||
1301 | } | 1393 | } |
1302 | 1394 | ||
1395 | ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos, | ||
1396 | num_board_infos, activate_cs, deactivate_cs); | ||
1397 | if (!ret) | ||
1398 | of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos, | ||
1399 | num_board_infos, activate_cs, deactivate_cs); | ||
1400 | |||
1303 | return spi_register_board_info(board_infos, num_board_infos); | 1401 | return spi_register_board_info(board_infos, num_board_infos); |
1304 | } | 1402 | } |
1305 | 1403 | ||
diff --git a/arch/powerpc/sysdev/grackle.c b/arch/powerpc/sysdev/grackle.c index 11ad5622eb76..d502927644c6 100644 --- a/arch/powerpc/sysdev/grackle.c +++ b/arch/powerpc/sysdev/grackle.c | |||
@@ -57,7 +57,7 @@ void __init setup_grackle(struct pci_controller *hose) | |||
57 | { | 57 | { |
58 | setup_indirect_pci(hose, 0xfec00000, 0xfee00000, 0); | 58 | setup_indirect_pci(hose, 0xfec00000, 0xfee00000, 0); |
59 | if (machine_is_compatible("PowerMac1,1")) | 59 | if (machine_is_compatible("PowerMac1,1")) |
60 | pci_assign_all_buses = 1; | 60 | ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; |
61 | if (machine_is_compatible("AAPL,PowerBook1998")) | 61 | if (machine_is_compatible("AAPL,PowerBook1998")) |
62 | grackle_set_loop_snoop(hose, 1); | 62 | grackle_set_loop_snoop(hose, 1); |
63 | #if 0 /* Disabled for now, HW problems ??? */ | 63 | #if 0 /* Disabled for now, HW problems ??? */ |
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index e898ff4d2b97..ae0dbf4c1d66 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c | |||
@@ -30,11 +30,67 @@ | |||
30 | #include "ipic.h" | 30 | #include "ipic.h" |
31 | 31 | ||
32 | static struct ipic * primary_ipic; | 32 | static struct ipic * primary_ipic; |
33 | static struct irq_chip ipic_level_irq_chip, ipic_edge_irq_chip; | ||
33 | static DEFINE_SPINLOCK(ipic_lock); | 34 | static DEFINE_SPINLOCK(ipic_lock); |
34 | 35 | ||
35 | static struct ipic_info ipic_info[] = { | 36 | static struct ipic_info ipic_info[] = { |
37 | [1] = { | ||
38 | .mask = IPIC_SIMSR_H, | ||
39 | .prio = IPIC_SIPRR_C, | ||
40 | .force = IPIC_SIFCR_H, | ||
41 | .bit = 16, | ||
42 | .prio_mask = 0, | ||
43 | }, | ||
44 | [2] = { | ||
45 | .mask = IPIC_SIMSR_H, | ||
46 | .prio = IPIC_SIPRR_C, | ||
47 | .force = IPIC_SIFCR_H, | ||
48 | .bit = 17, | ||
49 | .prio_mask = 1, | ||
50 | }, | ||
51 | [3] = { | ||
52 | .mask = IPIC_SIMSR_H, | ||
53 | .prio = IPIC_SIPRR_C, | ||
54 | .force = IPIC_SIFCR_H, | ||
55 | .bit = 18, | ||
56 | .prio_mask = 2, | ||
57 | }, | ||
58 | [4] = { | ||
59 | .mask = IPIC_SIMSR_H, | ||
60 | .prio = IPIC_SIPRR_C, | ||
61 | .force = IPIC_SIFCR_H, | ||
62 | .bit = 19, | ||
63 | .prio_mask = 3, | ||
64 | }, | ||
65 | [5] = { | ||
66 | .mask = IPIC_SIMSR_H, | ||
67 | .prio = IPIC_SIPRR_C, | ||
68 | .force = IPIC_SIFCR_H, | ||
69 | .bit = 20, | ||
70 | .prio_mask = 4, | ||
71 | }, | ||
72 | [6] = { | ||
73 | .mask = IPIC_SIMSR_H, | ||
74 | .prio = IPIC_SIPRR_C, | ||
75 | .force = IPIC_SIFCR_H, | ||
76 | .bit = 21, | ||
77 | .prio_mask = 5, | ||
78 | }, | ||
79 | [7] = { | ||
80 | .mask = IPIC_SIMSR_H, | ||
81 | .prio = IPIC_SIPRR_C, | ||
82 | .force = IPIC_SIFCR_H, | ||
83 | .bit = 22, | ||
84 | .prio_mask = 6, | ||
85 | }, | ||
86 | [8] = { | ||
87 | .mask = IPIC_SIMSR_H, | ||
88 | .prio = IPIC_SIPRR_C, | ||
89 | .force = IPIC_SIFCR_H, | ||
90 | .bit = 23, | ||
91 | .prio_mask = 7, | ||
92 | }, | ||
36 | [9] = { | 93 | [9] = { |
37 | .pend = IPIC_SIPNR_H, | ||
38 | .mask = IPIC_SIMSR_H, | 94 | .mask = IPIC_SIMSR_H, |
39 | .prio = IPIC_SIPRR_D, | 95 | .prio = IPIC_SIPRR_D, |
40 | .force = IPIC_SIFCR_H, | 96 | .force = IPIC_SIFCR_H, |
@@ -42,7 +98,6 @@ static struct ipic_info ipic_info[] = { | |||
42 | .prio_mask = 0, | 98 | .prio_mask = 0, |
43 | }, | 99 | }, |
44 | [10] = { | 100 | [10] = { |
45 | .pend = IPIC_SIPNR_H, | ||
46 | .mask = IPIC_SIMSR_H, | 101 | .mask = IPIC_SIMSR_H, |
47 | .prio = IPIC_SIPRR_D, | 102 | .prio = IPIC_SIPRR_D, |
48 | .force = IPIC_SIFCR_H, | 103 | .force = IPIC_SIFCR_H, |
@@ -50,15 +105,27 @@ static struct ipic_info ipic_info[] = { | |||
50 | .prio_mask = 1, | 105 | .prio_mask = 1, |
51 | }, | 106 | }, |
52 | [11] = { | 107 | [11] = { |
53 | .pend = IPIC_SIPNR_H, | ||
54 | .mask = IPIC_SIMSR_H, | 108 | .mask = IPIC_SIMSR_H, |
55 | .prio = IPIC_SIPRR_D, | 109 | .prio = IPIC_SIPRR_D, |
56 | .force = IPIC_SIFCR_H, | 110 | .force = IPIC_SIFCR_H, |
57 | .bit = 26, | 111 | .bit = 26, |
58 | .prio_mask = 2, | 112 | .prio_mask = 2, |
59 | }, | 113 | }, |
114 | [12] = { | ||
115 | .mask = IPIC_SIMSR_H, | ||
116 | .prio = IPIC_SIPRR_D, | ||
117 | .force = IPIC_SIFCR_H, | ||
118 | .bit = 27, | ||
119 | .prio_mask = 3, | ||
120 | }, | ||
121 | [13] = { | ||
122 | .mask = IPIC_SIMSR_H, | ||
123 | .prio = IPIC_SIPRR_D, | ||
124 | .force = IPIC_SIFCR_H, | ||
125 | .bit = 28, | ||
126 | .prio_mask = 4, | ||
127 | }, | ||
60 | [14] = { | 128 | [14] = { |
61 | .pend = IPIC_SIPNR_H, | ||
62 | .mask = IPIC_SIMSR_H, | 129 | .mask = IPIC_SIMSR_H, |
63 | .prio = IPIC_SIPRR_D, | 130 | .prio = IPIC_SIPRR_D, |
64 | .force = IPIC_SIFCR_H, | 131 | .force = IPIC_SIFCR_H, |
@@ -66,7 +133,6 @@ static struct ipic_info ipic_info[] = { | |||
66 | .prio_mask = 5, | 133 | .prio_mask = 5, |
67 | }, | 134 | }, |
68 | [15] = { | 135 | [15] = { |
69 | .pend = IPIC_SIPNR_H, | ||
70 | .mask = IPIC_SIMSR_H, | 136 | .mask = IPIC_SIMSR_H, |
71 | .prio = IPIC_SIPRR_D, | 137 | .prio = IPIC_SIPRR_D, |
72 | .force = IPIC_SIFCR_H, | 138 | .force = IPIC_SIFCR_H, |
@@ -74,7 +140,6 @@ static struct ipic_info ipic_info[] = { | |||
74 | .prio_mask = 6, | 140 | .prio_mask = 6, |
75 | }, | 141 | }, |
76 | [16] = { | 142 | [16] = { |
77 | .pend = IPIC_SIPNR_H, | ||
78 | .mask = IPIC_SIMSR_H, | 143 | .mask = IPIC_SIMSR_H, |
79 | .prio = IPIC_SIPRR_D, | 144 | .prio = IPIC_SIPRR_D, |
80 | .force = IPIC_SIFCR_H, | 145 | .force = IPIC_SIFCR_H, |
@@ -82,7 +147,7 @@ static struct ipic_info ipic_info[] = { | |||
82 | .prio_mask = 7, | 147 | .prio_mask = 7, |
83 | }, | 148 | }, |
84 | [17] = { | 149 | [17] = { |
85 | .pend = IPIC_SEPNR, | 150 | .ack = IPIC_SEPNR, |
86 | .mask = IPIC_SEMSR, | 151 | .mask = IPIC_SEMSR, |
87 | .prio = IPIC_SMPRR_A, | 152 | .prio = IPIC_SMPRR_A, |
88 | .force = IPIC_SEFCR, | 153 | .force = IPIC_SEFCR, |
@@ -90,7 +155,7 @@ static struct ipic_info ipic_info[] = { | |||
90 | .prio_mask = 5, | 155 | .prio_mask = 5, |
91 | }, | 156 | }, |
92 | [18] = { | 157 | [18] = { |
93 | .pend = IPIC_SEPNR, | 158 | .ack = IPIC_SEPNR, |
94 | .mask = IPIC_SEMSR, | 159 | .mask = IPIC_SEMSR, |
95 | .prio = IPIC_SMPRR_A, | 160 | .prio = IPIC_SMPRR_A, |
96 | .force = IPIC_SEFCR, | 161 | .force = IPIC_SEFCR, |
@@ -98,7 +163,7 @@ static struct ipic_info ipic_info[] = { | |||
98 | .prio_mask = 6, | 163 | .prio_mask = 6, |
99 | }, | 164 | }, |
100 | [19] = { | 165 | [19] = { |
101 | .pend = IPIC_SEPNR, | 166 | .ack = IPIC_SEPNR, |
102 | .mask = IPIC_SEMSR, | 167 | .mask = IPIC_SEMSR, |
103 | .prio = IPIC_SMPRR_A, | 168 | .prio = IPIC_SMPRR_A, |
104 | .force = IPIC_SEFCR, | 169 | .force = IPIC_SEFCR, |
@@ -106,7 +171,7 @@ static struct ipic_info ipic_info[] = { | |||
106 | .prio_mask = 7, | 171 | .prio_mask = 7, |
107 | }, | 172 | }, |
108 | [20] = { | 173 | [20] = { |
109 | .pend = IPIC_SEPNR, | 174 | .ack = IPIC_SEPNR, |
110 | .mask = IPIC_SEMSR, | 175 | .mask = IPIC_SEMSR, |
111 | .prio = IPIC_SMPRR_B, | 176 | .prio = IPIC_SMPRR_B, |
112 | .force = IPIC_SEFCR, | 177 | .force = IPIC_SEFCR, |
@@ -114,7 +179,7 @@ static struct ipic_info ipic_info[] = { | |||
114 | .prio_mask = 4, | 179 | .prio_mask = 4, |
115 | }, | 180 | }, |
116 | [21] = { | 181 | [21] = { |
117 | .pend = IPIC_SEPNR, | 182 | .ack = IPIC_SEPNR, |
118 | .mask = IPIC_SEMSR, | 183 | .mask = IPIC_SEMSR, |
119 | .prio = IPIC_SMPRR_B, | 184 | .prio = IPIC_SMPRR_B, |
120 | .force = IPIC_SEFCR, | 185 | .force = IPIC_SEFCR, |
@@ -122,7 +187,7 @@ static struct ipic_info ipic_info[] = { | |||
122 | .prio_mask = 5, | 187 | .prio_mask = 5, |
123 | }, | 188 | }, |
124 | [22] = { | 189 | [22] = { |
125 | .pend = IPIC_SEPNR, | 190 | .ack = IPIC_SEPNR, |
126 | .mask = IPIC_SEMSR, | 191 | .mask = IPIC_SEMSR, |
127 | .prio = IPIC_SMPRR_B, | 192 | .prio = IPIC_SMPRR_B, |
128 | .force = IPIC_SEFCR, | 193 | .force = IPIC_SEFCR, |
@@ -130,7 +195,7 @@ static struct ipic_info ipic_info[] = { | |||
130 | .prio_mask = 6, | 195 | .prio_mask = 6, |
131 | }, | 196 | }, |
132 | [23] = { | 197 | [23] = { |
133 | .pend = IPIC_SEPNR, | 198 | .ack = IPIC_SEPNR, |
134 | .mask = IPIC_SEMSR, | 199 | .mask = IPIC_SEMSR, |
135 | .prio = IPIC_SMPRR_B, | 200 | .prio = IPIC_SMPRR_B, |
136 | .force = IPIC_SEFCR, | 201 | .force = IPIC_SEFCR, |
@@ -138,7 +203,6 @@ static struct ipic_info ipic_info[] = { | |||
138 | .prio_mask = 7, | 203 | .prio_mask = 7, |
139 | }, | 204 | }, |
140 | [32] = { | 205 | [32] = { |
141 | .pend = IPIC_SIPNR_H, | ||
142 | .mask = IPIC_SIMSR_H, | 206 | .mask = IPIC_SIMSR_H, |
143 | .prio = IPIC_SIPRR_A, | 207 | .prio = IPIC_SIPRR_A, |
144 | .force = IPIC_SIFCR_H, | 208 | .force = IPIC_SIFCR_H, |
@@ -146,7 +210,6 @@ static struct ipic_info ipic_info[] = { | |||
146 | .prio_mask = 0, | 210 | .prio_mask = 0, |
147 | }, | 211 | }, |
148 | [33] = { | 212 | [33] = { |
149 | .pend = IPIC_SIPNR_H, | ||
150 | .mask = IPIC_SIMSR_H, | 213 | .mask = IPIC_SIMSR_H, |
151 | .prio = IPIC_SIPRR_A, | 214 | .prio = IPIC_SIPRR_A, |
152 | .force = IPIC_SIFCR_H, | 215 | .force = IPIC_SIFCR_H, |
@@ -154,7 +217,6 @@ static struct ipic_info ipic_info[] = { | |||
154 | .prio_mask = 1, | 217 | .prio_mask = 1, |
155 | }, | 218 | }, |
156 | [34] = { | 219 | [34] = { |
157 | .pend = IPIC_SIPNR_H, | ||
158 | .mask = IPIC_SIMSR_H, | 220 | .mask = IPIC_SIMSR_H, |
159 | .prio = IPIC_SIPRR_A, | 221 | .prio = IPIC_SIPRR_A, |
160 | .force = IPIC_SIFCR_H, | 222 | .force = IPIC_SIFCR_H, |
@@ -162,7 +224,6 @@ static struct ipic_info ipic_info[] = { | |||
162 | .prio_mask = 2, | 224 | .prio_mask = 2, |
163 | }, | 225 | }, |
164 | [35] = { | 226 | [35] = { |
165 | .pend = IPIC_SIPNR_H, | ||
166 | .mask = IPIC_SIMSR_H, | 227 | .mask = IPIC_SIMSR_H, |
167 | .prio = IPIC_SIPRR_A, | 228 | .prio = IPIC_SIPRR_A, |
168 | .force = IPIC_SIFCR_H, | 229 | .force = IPIC_SIFCR_H, |
@@ -170,7 +231,6 @@ static struct ipic_info ipic_info[] = { | |||
170 | .prio_mask = 3, | 231 | .prio_mask = 3, |
171 | }, | 232 | }, |
172 | [36] = { | 233 | [36] = { |
173 | .pend = IPIC_SIPNR_H, | ||
174 | .mask = IPIC_SIMSR_H, | 234 | .mask = IPIC_SIMSR_H, |
175 | .prio = IPIC_SIPRR_A, | 235 | .prio = IPIC_SIPRR_A, |
176 | .force = IPIC_SIFCR_H, | 236 | .force = IPIC_SIFCR_H, |
@@ -178,7 +238,6 @@ static struct ipic_info ipic_info[] = { | |||
178 | .prio_mask = 4, | 238 | .prio_mask = 4, |
179 | }, | 239 | }, |
180 | [37] = { | 240 | [37] = { |
181 | .pend = IPIC_SIPNR_H, | ||
182 | .mask = IPIC_SIMSR_H, | 241 | .mask = IPIC_SIMSR_H, |
183 | .prio = IPIC_SIPRR_A, | 242 | .prio = IPIC_SIPRR_A, |
184 | .force = IPIC_SIFCR_H, | 243 | .force = IPIC_SIFCR_H, |
@@ -186,7 +245,6 @@ static struct ipic_info ipic_info[] = { | |||
186 | .prio_mask = 5, | 245 | .prio_mask = 5, |
187 | }, | 246 | }, |
188 | [38] = { | 247 | [38] = { |
189 | .pend = IPIC_SIPNR_H, | ||
190 | .mask = IPIC_SIMSR_H, | 248 | .mask = IPIC_SIMSR_H, |
191 | .prio = IPIC_SIPRR_A, | 249 | .prio = IPIC_SIPRR_A, |
192 | .force = IPIC_SIFCR_H, | 250 | .force = IPIC_SIFCR_H, |
@@ -194,15 +252,69 @@ static struct ipic_info ipic_info[] = { | |||
194 | .prio_mask = 6, | 252 | .prio_mask = 6, |
195 | }, | 253 | }, |
196 | [39] = { | 254 | [39] = { |
197 | .pend = IPIC_SIPNR_H, | ||
198 | .mask = IPIC_SIMSR_H, | 255 | .mask = IPIC_SIMSR_H, |
199 | .prio = IPIC_SIPRR_A, | 256 | .prio = IPIC_SIPRR_A, |
200 | .force = IPIC_SIFCR_H, | 257 | .force = IPIC_SIFCR_H, |
201 | .bit = 7, | 258 | .bit = 7, |
202 | .prio_mask = 7, | 259 | .prio_mask = 7, |
203 | }, | 260 | }, |
261 | [40] = { | ||
262 | .mask = IPIC_SIMSR_H, | ||
263 | .prio = IPIC_SIPRR_B, | ||
264 | .force = IPIC_SIFCR_H, | ||
265 | .bit = 8, | ||
266 | .prio_mask = 0, | ||
267 | }, | ||
268 | [41] = { | ||
269 | .mask = IPIC_SIMSR_H, | ||
270 | .prio = IPIC_SIPRR_B, | ||
271 | .force = IPIC_SIFCR_H, | ||
272 | .bit = 9, | ||
273 | .prio_mask = 1, | ||
274 | }, | ||
275 | [42] = { | ||
276 | .mask = IPIC_SIMSR_H, | ||
277 | .prio = IPIC_SIPRR_B, | ||
278 | .force = IPIC_SIFCR_H, | ||
279 | .bit = 10, | ||
280 | .prio_mask = 2, | ||
281 | }, | ||
282 | [43] = { | ||
283 | .mask = IPIC_SIMSR_H, | ||
284 | .prio = IPIC_SIPRR_B, | ||
285 | .force = IPIC_SIFCR_H, | ||
286 | .bit = 11, | ||
287 | .prio_mask = 3, | ||
288 | }, | ||
289 | [44] = { | ||
290 | .mask = IPIC_SIMSR_H, | ||
291 | .prio = IPIC_SIPRR_B, | ||
292 | .force = IPIC_SIFCR_H, | ||
293 | .bit = 12, | ||
294 | .prio_mask = 4, | ||
295 | }, | ||
296 | [45] = { | ||
297 | .mask = IPIC_SIMSR_H, | ||
298 | .prio = IPIC_SIPRR_B, | ||
299 | .force = IPIC_SIFCR_H, | ||
300 | .bit = 13, | ||
301 | .prio_mask = 5, | ||
302 | }, | ||
303 | [46] = { | ||
304 | .mask = IPIC_SIMSR_H, | ||
305 | .prio = IPIC_SIPRR_B, | ||
306 | .force = IPIC_SIFCR_H, | ||
307 | .bit = 14, | ||
308 | .prio_mask = 6, | ||
309 | }, | ||
310 | [47] = { | ||
311 | .mask = IPIC_SIMSR_H, | ||
312 | .prio = IPIC_SIPRR_B, | ||
313 | .force = IPIC_SIFCR_H, | ||
314 | .bit = 15, | ||
315 | .prio_mask = 7, | ||
316 | }, | ||
204 | [48] = { | 317 | [48] = { |
205 | .pend = IPIC_SEPNR, | ||
206 | .mask = IPIC_SEMSR, | 318 | .mask = IPIC_SEMSR, |
207 | .prio = IPIC_SMPRR_A, | 319 | .prio = IPIC_SMPRR_A, |
208 | .force = IPIC_SEFCR, | 320 | .force = IPIC_SEFCR, |
@@ -210,7 +322,6 @@ static struct ipic_info ipic_info[] = { | |||
210 | .prio_mask = 4, | 322 | .prio_mask = 4, |
211 | }, | 323 | }, |
212 | [64] = { | 324 | [64] = { |
213 | .pend = IPIC_SIPNR_L, | ||
214 | .mask = IPIC_SIMSR_L, | 325 | .mask = IPIC_SIMSR_L, |
215 | .prio = IPIC_SMPRR_A, | 326 | .prio = IPIC_SMPRR_A, |
216 | .force = IPIC_SIFCR_L, | 327 | .force = IPIC_SIFCR_L, |
@@ -218,7 +329,6 @@ static struct ipic_info ipic_info[] = { | |||
218 | .prio_mask = 0, | 329 | .prio_mask = 0, |
219 | }, | 330 | }, |
220 | [65] = { | 331 | [65] = { |
221 | .pend = IPIC_SIPNR_L, | ||
222 | .mask = IPIC_SIMSR_L, | 332 | .mask = IPIC_SIMSR_L, |
223 | .prio = IPIC_SMPRR_A, | 333 | .prio = IPIC_SMPRR_A, |
224 | .force = IPIC_SIFCR_L, | 334 | .force = IPIC_SIFCR_L, |
@@ -226,7 +336,6 @@ static struct ipic_info ipic_info[] = { | |||
226 | .prio_mask = 1, | 336 | .prio_mask = 1, |
227 | }, | 337 | }, |
228 | [66] = { | 338 | [66] = { |
229 | .pend = IPIC_SIPNR_L, | ||
230 | .mask = IPIC_SIMSR_L, | 339 | .mask = IPIC_SIMSR_L, |
231 | .prio = IPIC_SMPRR_A, | 340 | .prio = IPIC_SMPRR_A, |
232 | .force = IPIC_SIFCR_L, | 341 | .force = IPIC_SIFCR_L, |
@@ -234,7 +343,6 @@ static struct ipic_info ipic_info[] = { | |||
234 | .prio_mask = 2, | 343 | .prio_mask = 2, |
235 | }, | 344 | }, |
236 | [67] = { | 345 | [67] = { |
237 | .pend = IPIC_SIPNR_L, | ||
238 | .mask = IPIC_SIMSR_L, | 346 | .mask = IPIC_SIMSR_L, |
239 | .prio = IPIC_SMPRR_A, | 347 | .prio = IPIC_SMPRR_A, |
240 | .force = IPIC_SIFCR_L, | 348 | .force = IPIC_SIFCR_L, |
@@ -242,7 +350,6 @@ static struct ipic_info ipic_info[] = { | |||
242 | .prio_mask = 3, | 350 | .prio_mask = 3, |
243 | }, | 351 | }, |
244 | [68] = { | 352 | [68] = { |
245 | .pend = IPIC_SIPNR_L, | ||
246 | .mask = IPIC_SIMSR_L, | 353 | .mask = IPIC_SIMSR_L, |
247 | .prio = IPIC_SMPRR_B, | 354 | .prio = IPIC_SMPRR_B, |
248 | .force = IPIC_SIFCR_L, | 355 | .force = IPIC_SIFCR_L, |
@@ -250,7 +357,6 @@ static struct ipic_info ipic_info[] = { | |||
250 | .prio_mask = 0, | 357 | .prio_mask = 0, |
251 | }, | 358 | }, |
252 | [69] = { | 359 | [69] = { |
253 | .pend = IPIC_SIPNR_L, | ||
254 | .mask = IPIC_SIMSR_L, | 360 | .mask = IPIC_SIMSR_L, |
255 | .prio = IPIC_SMPRR_B, | 361 | .prio = IPIC_SMPRR_B, |
256 | .force = IPIC_SIFCR_L, | 362 | .force = IPIC_SIFCR_L, |
@@ -258,7 +364,6 @@ static struct ipic_info ipic_info[] = { | |||
258 | .prio_mask = 1, | 364 | .prio_mask = 1, |
259 | }, | 365 | }, |
260 | [70] = { | 366 | [70] = { |
261 | .pend = IPIC_SIPNR_L, | ||
262 | .mask = IPIC_SIMSR_L, | 367 | .mask = IPIC_SIMSR_L, |
263 | .prio = IPIC_SMPRR_B, | 368 | .prio = IPIC_SMPRR_B, |
264 | .force = IPIC_SIFCR_L, | 369 | .force = IPIC_SIFCR_L, |
@@ -266,7 +371,6 @@ static struct ipic_info ipic_info[] = { | |||
266 | .prio_mask = 2, | 371 | .prio_mask = 2, |
267 | }, | 372 | }, |
268 | [71] = { | 373 | [71] = { |
269 | .pend = IPIC_SIPNR_L, | ||
270 | .mask = IPIC_SIMSR_L, | 374 | .mask = IPIC_SIMSR_L, |
271 | .prio = IPIC_SMPRR_B, | 375 | .prio = IPIC_SMPRR_B, |
272 | .force = IPIC_SIFCR_L, | 376 | .force = IPIC_SIFCR_L, |
@@ -274,96 +378,131 @@ static struct ipic_info ipic_info[] = { | |||
274 | .prio_mask = 3, | 378 | .prio_mask = 3, |
275 | }, | 379 | }, |
276 | [72] = { | 380 | [72] = { |
277 | .pend = IPIC_SIPNR_L, | ||
278 | .mask = IPIC_SIMSR_L, | 381 | .mask = IPIC_SIMSR_L, |
279 | .prio = 0, | 382 | .prio = 0, |
280 | .force = IPIC_SIFCR_L, | 383 | .force = IPIC_SIFCR_L, |
281 | .bit = 8, | 384 | .bit = 8, |
282 | }, | 385 | }, |
283 | [73] = { | 386 | [73] = { |
284 | .pend = IPIC_SIPNR_L, | ||
285 | .mask = IPIC_SIMSR_L, | 387 | .mask = IPIC_SIMSR_L, |
286 | .prio = 0, | 388 | .prio = 0, |
287 | .force = IPIC_SIFCR_L, | 389 | .force = IPIC_SIFCR_L, |
288 | .bit = 9, | 390 | .bit = 9, |
289 | }, | 391 | }, |
290 | [74] = { | 392 | [74] = { |
291 | .pend = IPIC_SIPNR_L, | ||
292 | .mask = IPIC_SIMSR_L, | 393 | .mask = IPIC_SIMSR_L, |
293 | .prio = 0, | 394 | .prio = 0, |
294 | .force = IPIC_SIFCR_L, | 395 | .force = IPIC_SIFCR_L, |
295 | .bit = 10, | 396 | .bit = 10, |
296 | }, | 397 | }, |
297 | [75] = { | 398 | [75] = { |
298 | .pend = IPIC_SIPNR_L, | ||
299 | .mask = IPIC_SIMSR_L, | 399 | .mask = IPIC_SIMSR_L, |
300 | .prio = 0, | 400 | .prio = 0, |
301 | .force = IPIC_SIFCR_L, | 401 | .force = IPIC_SIFCR_L, |
302 | .bit = 11, | 402 | .bit = 11, |
303 | }, | 403 | }, |
304 | [76] = { | 404 | [76] = { |
305 | .pend = IPIC_SIPNR_L, | ||
306 | .mask = IPIC_SIMSR_L, | 405 | .mask = IPIC_SIMSR_L, |
307 | .prio = 0, | 406 | .prio = 0, |
308 | .force = IPIC_SIFCR_L, | 407 | .force = IPIC_SIFCR_L, |
309 | .bit = 12, | 408 | .bit = 12, |
310 | }, | 409 | }, |
311 | [77] = { | 410 | [77] = { |
312 | .pend = IPIC_SIPNR_L, | ||
313 | .mask = IPIC_SIMSR_L, | 411 | .mask = IPIC_SIMSR_L, |
314 | .prio = 0, | 412 | .prio = 0, |
315 | .force = IPIC_SIFCR_L, | 413 | .force = IPIC_SIFCR_L, |
316 | .bit = 13, | 414 | .bit = 13, |
317 | }, | 415 | }, |
318 | [78] = { | 416 | [78] = { |
319 | .pend = IPIC_SIPNR_L, | ||
320 | .mask = IPIC_SIMSR_L, | 417 | .mask = IPIC_SIMSR_L, |
321 | .prio = 0, | 418 | .prio = 0, |
322 | .force = IPIC_SIFCR_L, | 419 | .force = IPIC_SIFCR_L, |
323 | .bit = 14, | 420 | .bit = 14, |
324 | }, | 421 | }, |
325 | [79] = { | 422 | [79] = { |
326 | .pend = IPIC_SIPNR_L, | ||
327 | .mask = IPIC_SIMSR_L, | 423 | .mask = IPIC_SIMSR_L, |
328 | .prio = 0, | 424 | .prio = 0, |
329 | .force = IPIC_SIFCR_L, | 425 | .force = IPIC_SIFCR_L, |
330 | .bit = 15, | 426 | .bit = 15, |
331 | }, | 427 | }, |
332 | [80] = { | 428 | [80] = { |
333 | .pend = IPIC_SIPNR_L, | ||
334 | .mask = IPIC_SIMSR_L, | 429 | .mask = IPIC_SIMSR_L, |
335 | .prio = 0, | 430 | .prio = 0, |
336 | .force = IPIC_SIFCR_L, | 431 | .force = IPIC_SIFCR_L, |
337 | .bit = 16, | 432 | .bit = 16, |
338 | }, | 433 | }, |
434 | [81] = { | ||
435 | .mask = IPIC_SIMSR_L, | ||
436 | .prio = 0, | ||
437 | .force = IPIC_SIFCR_L, | ||
438 | .bit = 17, | ||
439 | }, | ||
440 | [82] = { | ||
441 | .mask = IPIC_SIMSR_L, | ||
442 | .prio = 0, | ||
443 | .force = IPIC_SIFCR_L, | ||
444 | .bit = 18, | ||
445 | }, | ||
446 | [83] = { | ||
447 | .mask = IPIC_SIMSR_L, | ||
448 | .prio = 0, | ||
449 | .force = IPIC_SIFCR_L, | ||
450 | .bit = 19, | ||
451 | }, | ||
339 | [84] = { | 452 | [84] = { |
340 | .pend = IPIC_SIPNR_L, | ||
341 | .mask = IPIC_SIMSR_L, | 453 | .mask = IPIC_SIMSR_L, |
342 | .prio = 0, | 454 | .prio = 0, |
343 | .force = IPIC_SIFCR_L, | 455 | .force = IPIC_SIFCR_L, |
344 | .bit = 20, | 456 | .bit = 20, |
345 | }, | 457 | }, |
346 | [85] = { | 458 | [85] = { |
347 | .pend = IPIC_SIPNR_L, | ||
348 | .mask = IPIC_SIMSR_L, | 459 | .mask = IPIC_SIMSR_L, |
349 | .prio = 0, | 460 | .prio = 0, |
350 | .force = IPIC_SIFCR_L, | 461 | .force = IPIC_SIFCR_L, |
351 | .bit = 21, | 462 | .bit = 21, |
352 | }, | 463 | }, |
464 | [86] = { | ||
465 | .mask = IPIC_SIMSR_L, | ||
466 | .prio = 0, | ||
467 | .force = IPIC_SIFCR_L, | ||
468 | .bit = 22, | ||
469 | }, | ||
470 | [87] = { | ||
471 | .mask = IPIC_SIMSR_L, | ||
472 | .prio = 0, | ||
473 | .force = IPIC_SIFCR_L, | ||
474 | .bit = 23, | ||
475 | }, | ||
476 | [88] = { | ||
477 | .mask = IPIC_SIMSR_L, | ||
478 | .prio = 0, | ||
479 | .force = IPIC_SIFCR_L, | ||
480 | .bit = 24, | ||
481 | }, | ||
482 | [89] = { | ||
483 | .mask = IPIC_SIMSR_L, | ||
484 | .prio = 0, | ||
485 | .force = IPIC_SIFCR_L, | ||
486 | .bit = 25, | ||
487 | }, | ||
353 | [90] = { | 488 | [90] = { |
354 | .pend = IPIC_SIPNR_L, | ||
355 | .mask = IPIC_SIMSR_L, | 489 | .mask = IPIC_SIMSR_L, |
356 | .prio = 0, | 490 | .prio = 0, |
357 | .force = IPIC_SIFCR_L, | 491 | .force = IPIC_SIFCR_L, |
358 | .bit = 26, | 492 | .bit = 26, |
359 | }, | 493 | }, |
360 | [91] = { | 494 | [91] = { |
361 | .pend = IPIC_SIPNR_L, | ||
362 | .mask = IPIC_SIMSR_L, | 495 | .mask = IPIC_SIMSR_L, |
363 | .prio = 0, | 496 | .prio = 0, |
364 | .force = IPIC_SIFCR_L, | 497 | .force = IPIC_SIFCR_L, |
365 | .bit = 27, | 498 | .bit = 27, |
366 | }, | 499 | }, |
500 | [94] = { | ||
501 | .mask = IPIC_SIMSR_L, | ||
502 | .prio = 0, | ||
503 | .force = IPIC_SIFCR_L, | ||
504 | .bit = 30, | ||
505 | }, | ||
367 | }; | 506 | }; |
368 | 507 | ||
369 | static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg) | 508 | static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg) |
@@ -412,6 +551,10 @@ static void ipic_mask_irq(unsigned int virq) | |||
412 | temp &= ~(1 << (31 - ipic_info[src].bit)); | 551 | temp &= ~(1 << (31 - ipic_info[src].bit)); |
413 | ipic_write(ipic->regs, ipic_info[src].mask, temp); | 552 | ipic_write(ipic->regs, ipic_info[src].mask, temp); |
414 | 553 | ||
554 | /* mb() can't guarantee that masking is finished. But it does finish | ||
555 | * for nearly all cases. */ | ||
556 | mb(); | ||
557 | |||
415 | spin_unlock_irqrestore(&ipic_lock, flags); | 558 | spin_unlock_irqrestore(&ipic_lock, flags); |
416 | } | 559 | } |
417 | 560 | ||
@@ -424,9 +567,13 @@ static void ipic_ack_irq(unsigned int virq) | |||
424 | 567 | ||
425 | spin_lock_irqsave(&ipic_lock, flags); | 568 | spin_lock_irqsave(&ipic_lock, flags); |
426 | 569 | ||
427 | temp = ipic_read(ipic->regs, ipic_info[src].pend); | 570 | temp = ipic_read(ipic->regs, ipic_info[src].ack); |
428 | temp |= (1 << (31 - ipic_info[src].bit)); | 571 | temp |= (1 << (31 - ipic_info[src].bit)); |
429 | ipic_write(ipic->regs, ipic_info[src].pend, temp); | 572 | ipic_write(ipic->regs, ipic_info[src].ack, temp); |
573 | |||
574 | /* mb() can't guarantee that ack is finished. But it does finish | ||
575 | * for nearly all cases. */ | ||
576 | mb(); | ||
430 | 577 | ||
431 | spin_unlock_irqrestore(&ipic_lock, flags); | 578 | spin_unlock_irqrestore(&ipic_lock, flags); |
432 | } | 579 | } |
@@ -444,9 +591,13 @@ static void ipic_mask_irq_and_ack(unsigned int virq) | |||
444 | temp &= ~(1 << (31 - ipic_info[src].bit)); | 591 | temp &= ~(1 << (31 - ipic_info[src].bit)); |
445 | ipic_write(ipic->regs, ipic_info[src].mask, temp); | 592 | ipic_write(ipic->regs, ipic_info[src].mask, temp); |
446 | 593 | ||
447 | temp = ipic_read(ipic->regs, ipic_info[src].pend); | 594 | temp = ipic_read(ipic->regs, ipic_info[src].ack); |
448 | temp |= (1 << (31 - ipic_info[src].bit)); | 595 | temp |= (1 << (31 - ipic_info[src].bit)); |
449 | ipic_write(ipic->regs, ipic_info[src].pend, temp); | 596 | ipic_write(ipic->regs, ipic_info[src].ack, temp); |
597 | |||
598 | /* mb() can't guarantee that ack is finished. But it does finish | ||
599 | * for nearly all cases. */ | ||
600 | mb(); | ||
450 | 601 | ||
451 | spin_unlock_irqrestore(&ipic_lock, flags); | 602 | spin_unlock_irqrestore(&ipic_lock, flags); |
452 | } | 603 | } |
@@ -468,14 +619,22 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
468 | flow_type); | 619 | flow_type); |
469 | return -EINVAL; | 620 | return -EINVAL; |
470 | } | 621 | } |
622 | /* ipic supports only edge mode on external interrupts */ | ||
623 | if ((flow_type & IRQ_TYPE_EDGE_FALLING) && !ipic_info[src].ack) { | ||
624 | printk(KERN_ERR "ipic: edge sense not supported on internal " | ||
625 | "interrupts\n"); | ||
626 | return -EINVAL; | ||
627 | } | ||
471 | 628 | ||
472 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | 629 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); |
473 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | 630 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; |
474 | if (flow_type & IRQ_TYPE_LEVEL_LOW) { | 631 | if (flow_type & IRQ_TYPE_LEVEL_LOW) { |
475 | desc->status |= IRQ_LEVEL; | 632 | desc->status |= IRQ_LEVEL; |
476 | desc->handle_irq = handle_level_irq; | 633 | desc->handle_irq = handle_level_irq; |
634 | desc->chip = &ipic_level_irq_chip; | ||
477 | } else { | 635 | } else { |
478 | desc->handle_irq = handle_edge_irq; | 636 | desc->handle_irq = handle_edge_irq; |
637 | desc->chip = &ipic_edge_irq_chip; | ||
479 | } | 638 | } |
480 | 639 | ||
481 | /* only EXT IRQ senses are programmable on ipic | 640 | /* only EXT IRQ senses are programmable on ipic |
@@ -500,7 +659,16 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
500 | return 0; | 659 | return 0; |
501 | } | 660 | } |
502 | 661 | ||
503 | static struct irq_chip ipic_irq_chip = { | 662 | /* level interrupts and edge interrupts have different ack operations */ |
663 | static struct irq_chip ipic_level_irq_chip = { | ||
664 | .typename = " IPIC ", | ||
665 | .unmask = ipic_unmask_irq, | ||
666 | .mask = ipic_mask_irq, | ||
667 | .mask_ack = ipic_mask_irq, | ||
668 | .set_type = ipic_set_irq_type, | ||
669 | }; | ||
670 | |||
671 | static struct irq_chip ipic_edge_irq_chip = { | ||
504 | .typename = " IPIC ", | 672 | .typename = " IPIC ", |
505 | .unmask = ipic_unmask_irq, | 673 | .unmask = ipic_unmask_irq, |
506 | .mask = ipic_mask_irq, | 674 | .mask = ipic_mask_irq, |
@@ -519,13 +687,9 @@ static int ipic_host_map(struct irq_host *h, unsigned int virq, | |||
519 | irq_hw_number_t hw) | 687 | irq_hw_number_t hw) |
520 | { | 688 | { |
521 | struct ipic *ipic = h->host_data; | 689 | struct ipic *ipic = h->host_data; |
522 | struct irq_chip *chip; | ||
523 | |||
524 | /* Default chip */ | ||
525 | chip = &ipic->hc_irq; | ||
526 | 690 | ||
527 | set_irq_chip_data(virq, ipic); | 691 | set_irq_chip_data(virq, ipic); |
528 | set_irq_chip_and_handler(virq, chip, handle_level_irq); | 692 | set_irq_chip_and_handler(virq, &ipic_level_irq_chip, handle_level_irq); |
529 | 693 | ||
530 | /* Set default irq type */ | 694 | /* Set default irq type */ |
531 | set_irq_type(virq, IRQ_TYPE_NONE); | 695 | set_irq_type(virq, IRQ_TYPE_NONE); |
@@ -584,7 +748,6 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) | |||
584 | ipic->regs = ioremap(res.start, res.end - res.start + 1); | 748 | ipic->regs = ioremap(res.start, res.end - res.start + 1); |
585 | 749 | ||
586 | ipic->irqhost->host_data = ipic; | 750 | ipic->irqhost->host_data = ipic; |
587 | ipic->hc_irq = ipic_irq_chip; | ||
588 | 751 | ||
589 | /* init hw */ | 752 | /* init hw */ |
590 | ipic_write(ipic->regs, IPIC_SICNR, 0x0); | 753 | ipic_write(ipic->regs, IPIC_SICNR, 0x0); |
@@ -593,6 +756,10 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) | |||
593 | * configure SICFR accordingly */ | 756 | * configure SICFR accordingly */ |
594 | if (flags & IPIC_SPREADMODE_GRP_A) | 757 | if (flags & IPIC_SPREADMODE_GRP_A) |
595 | temp |= SICFR_IPSA; | 758 | temp |= SICFR_IPSA; |
759 | if (flags & IPIC_SPREADMODE_GRP_B) | ||
760 | temp |= SICFR_IPSB; | ||
761 | if (flags & IPIC_SPREADMODE_GRP_C) | ||
762 | temp |= SICFR_IPSC; | ||
596 | if (flags & IPIC_SPREADMODE_GRP_D) | 763 | if (flags & IPIC_SPREADMODE_GRP_D) |
597 | temp |= SICFR_IPSD; | 764 | temp |= SICFR_IPSD; |
598 | if (flags & IPIC_SPREADMODE_MIX_A) | 765 | if (flags & IPIC_SPREADMODE_MIX_A) |
@@ -600,7 +767,7 @@ struct ipic * __init ipic_init(struct device_node *node, unsigned int flags) | |||
600 | if (flags & IPIC_SPREADMODE_MIX_B) | 767 | if (flags & IPIC_SPREADMODE_MIX_B) |
601 | temp |= SICFR_MPSB; | 768 | temp |= SICFR_MPSB; |
602 | 769 | ||
603 | ipic_write(ipic->regs, IPIC_SICNR, temp); | 770 | ipic_write(ipic->regs, IPIC_SICFR, temp); |
604 | 771 | ||
605 | /* handle MCP route */ | 772 | /* handle MCP route */ |
606 | temp = 0; | 773 | temp = 0; |
@@ -672,10 +839,12 @@ void ipic_set_highest_priority(unsigned int virq) | |||
672 | 839 | ||
673 | void ipic_set_default_priority(void) | 840 | void ipic_set_default_priority(void) |
674 | { | 841 | { |
675 | ipic_write(primary_ipic->regs, IPIC_SIPRR_A, IPIC_SIPRR_A_DEFAULT); | 842 | ipic_write(primary_ipic->regs, IPIC_SIPRR_A, IPIC_PRIORITY_DEFAULT); |
676 | ipic_write(primary_ipic->regs, IPIC_SIPRR_D, IPIC_SIPRR_D_DEFAULT); | 843 | ipic_write(primary_ipic->regs, IPIC_SIPRR_B, IPIC_PRIORITY_DEFAULT); |
677 | ipic_write(primary_ipic->regs, IPIC_SMPRR_A, IPIC_SMPRR_A_DEFAULT); | 844 | ipic_write(primary_ipic->regs, IPIC_SIPRR_C, IPIC_PRIORITY_DEFAULT); |
678 | ipic_write(primary_ipic->regs, IPIC_SMPRR_B, IPIC_SMPRR_B_DEFAULT); | 845 | ipic_write(primary_ipic->regs, IPIC_SIPRR_D, IPIC_PRIORITY_DEFAULT); |
846 | ipic_write(primary_ipic->regs, IPIC_SMPRR_A, IPIC_PRIORITY_DEFAULT); | ||
847 | ipic_write(primary_ipic->regs, IPIC_SMPRR_B, IPIC_PRIORITY_DEFAULT); | ||
679 | } | 848 | } |
680 | 849 | ||
681 | void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq) | 850 | void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq) |
diff --git a/arch/powerpc/sysdev/ipic.h b/arch/powerpc/sysdev/ipic.h index bb309a501b2d..9391c57b0c51 100644 --- a/arch/powerpc/sysdev/ipic.h +++ b/arch/powerpc/sysdev/ipic.h | |||
@@ -23,13 +23,12 @@ | |||
23 | #define IPIC_IRQ_EXT7 23 | 23 | #define IPIC_IRQ_EXT7 23 |
24 | 24 | ||
25 | /* Default Priority Registers */ | 25 | /* Default Priority Registers */ |
26 | #define IPIC_SIPRR_A_DEFAULT 0x05309770 | 26 | #define IPIC_PRIORITY_DEFAULT 0x05309770 |
27 | #define IPIC_SIPRR_D_DEFAULT 0x05309770 | ||
28 | #define IPIC_SMPRR_A_DEFAULT 0x05309770 | ||
29 | #define IPIC_SMPRR_B_DEFAULT 0x05309770 | ||
30 | 27 | ||
31 | /* System Global Interrupt Configuration Register */ | 28 | /* System Global Interrupt Configuration Register */ |
32 | #define SICFR_IPSA 0x00010000 | 29 | #define SICFR_IPSA 0x00010000 |
30 | #define SICFR_IPSB 0x00020000 | ||
31 | #define SICFR_IPSC 0x00040000 | ||
33 | #define SICFR_IPSD 0x00080000 | 32 | #define SICFR_IPSD 0x00080000 |
34 | #define SICFR_MPSA 0x00200000 | 33 | #define SICFR_MPSA 0x00200000 |
35 | #define SICFR_MPSB 0x00400000 | 34 | #define SICFR_MPSB 0x00400000 |
@@ -45,13 +44,11 @@ struct ipic { | |||
45 | 44 | ||
46 | /* The remapper for this IPIC */ | 45 | /* The remapper for this IPIC */ |
47 | struct irq_host *irqhost; | 46 | struct irq_host *irqhost; |
48 | |||
49 | /* The "linux" controller struct */ | ||
50 | struct irq_chip hc_irq; | ||
51 | }; | 47 | }; |
52 | 48 | ||
53 | struct ipic_info { | 49 | struct ipic_info { |
54 | u8 pend; /* pending register offset from base */ | 50 | u8 ack; /* pending register offset from base if the irq |
51 | supports ack operation */ | ||
55 | u8 mask; /* mask register offset from base */ | 52 | u8 mask; /* mask register offset from base */ |
56 | u8 prio; /* priority register offset from base */ | 53 | u8 prio; /* priority register offset from base */ |
57 | u8 force; /* force register offset from base */ | 54 | u8 force; /* force register offset from base */ |
diff --git a/arch/powerpc/sysdev/micropatch.c b/arch/powerpc/sysdev/micropatch.c index 712b10a55f87..d8d602840757 100644 --- a/arch/powerpc/sysdev/micropatch.c +++ b/arch/powerpc/sysdev/micropatch.c | |||
@@ -16,7 +16,7 @@ | |||
16 | #include <asm/page.h> | 16 | #include <asm/page.h> |
17 | #include <asm/pgtable.h> | 17 | #include <asm/pgtable.h> |
18 | #include <asm/8xx_immap.h> | 18 | #include <asm/8xx_immap.h> |
19 | #include <asm/commproc.h> | 19 | #include <asm/cpm1.h> |
20 | 20 | ||
21 | /* | 21 | /* |
22 | * I2C/SPI relocation patch arrays. | 22 | * I2C/SPI relocation patch arrays. |
diff --git a/arch/powerpc/sysdev/mmio_nvram.c b/arch/powerpc/sysdev/mmio_nvram.c index e073e246293d..7b49633a4bd0 100644 --- a/arch/powerpc/sysdev/mmio_nvram.c +++ b/arch/powerpc/sysdev/mmio_nvram.c | |||
@@ -99,7 +99,7 @@ int __init mmio_nvram_init(void) | |||
99 | nvram_addr = r.start; | 99 | nvram_addr = r.start; |
100 | mmio_nvram_len = r.end - r.start + 1; | 100 | mmio_nvram_len = r.end - r.start + 1; |
101 | if ( (!mmio_nvram_len) || (!nvram_addr) ) { | 101 | if ( (!mmio_nvram_len) || (!nvram_addr) ) { |
102 | printk(KERN_WARNING "nvram: address or lenght is 0\n"); | 102 | printk(KERN_WARNING "nvram: address or length is 0\n"); |
103 | ret = -EIO; | 103 | ret = -EIO; |
104 | goto out; | 104 | goto out; |
105 | } | 105 | } |
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 7aa4ff5f5ec8..0e74a4bd9827 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c | |||
@@ -10,7 +10,6 @@ | |||
10 | #include <asm/irq.h> | 10 | #include <asm/irq.h> |
11 | #include <asm/io.h> | 11 | #include <asm/io.h> |
12 | #include <asm/8xx_immap.h> | 12 | #include <asm/8xx_immap.h> |
13 | #include <asm/mpc8xx.h> | ||
14 | 13 | ||
15 | #include "mpc8xx_pic.h" | 14 | #include "mpc8xx_pic.h" |
16 | 15 | ||
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 212a94f5d34b..6ffdda244bb1 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -83,6 +83,7 @@ static u32 mpic_infos[][MPIC_IDX_END] = { | |||
83 | MPIC_CPU_WHOAMI, | 83 | MPIC_CPU_WHOAMI, |
84 | MPIC_CPU_INTACK, | 84 | MPIC_CPU_INTACK, |
85 | MPIC_CPU_EOI, | 85 | MPIC_CPU_EOI, |
86 | MPIC_CPU_MCACK, | ||
86 | 87 | ||
87 | MPIC_IRQ_BASE, | 88 | MPIC_IRQ_BASE, |
88 | MPIC_IRQ_STRIDE, | 89 | MPIC_IRQ_STRIDE, |
@@ -121,6 +122,7 @@ static u32 mpic_infos[][MPIC_IDX_END] = { | |||
121 | TSI108_CPU_WHOAMI, | 122 | TSI108_CPU_WHOAMI, |
122 | TSI108_CPU_INTACK, | 123 | TSI108_CPU_INTACK, |
123 | TSI108_CPU_EOI, | 124 | TSI108_CPU_EOI, |
125 | TSI108_CPU_MCACK, | ||
124 | 126 | ||
125 | TSI108_IRQ_BASE, | 127 | TSI108_IRQ_BASE, |
126 | TSI108_IRQ_STRIDE, | 128 | TSI108_IRQ_STRIDE, |
@@ -265,7 +267,7 @@ static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no, | |||
265 | */ | 267 | */ |
266 | 268 | ||
267 | 269 | ||
268 | static void _mpic_map_mmio(struct mpic *mpic, unsigned long phys_addr, | 270 | static void _mpic_map_mmio(struct mpic *mpic, phys_addr_t phys_addr, |
269 | struct mpic_reg_bank *rb, unsigned int offset, | 271 | struct mpic_reg_bank *rb, unsigned int offset, |
270 | unsigned int size) | 272 | unsigned int size) |
271 | { | 273 | { |
@@ -285,7 +287,7 @@ static void _mpic_map_dcr(struct mpic *mpic, struct mpic_reg_bank *rb, | |||
285 | BUG_ON(!DCR_MAP_OK(rb->dhost)); | 287 | BUG_ON(!DCR_MAP_OK(rb->dhost)); |
286 | } | 288 | } |
287 | 289 | ||
288 | static inline void mpic_map(struct mpic *mpic, unsigned long phys_addr, | 290 | static inline void mpic_map(struct mpic *mpic, phys_addr_t phys_addr, |
289 | struct mpic_reg_bank *rb, unsigned int offset, | 291 | struct mpic_reg_bank *rb, unsigned int offset, |
290 | unsigned int size) | 292 | unsigned int size) |
291 | { | 293 | { |
@@ -612,12 +614,11 @@ static inline void mpic_eoi(struct mpic *mpic) | |||
612 | } | 614 | } |
613 | 615 | ||
614 | #ifdef CONFIG_SMP | 616 | #ifdef CONFIG_SMP |
615 | static irqreturn_t mpic_ipi_action(int irq, void *dev_id) | 617 | static irqreturn_t mpic_ipi_action(int irq, void *data) |
616 | { | 618 | { |
617 | struct mpic *mpic; | 619 | long ipi = (long)data; |
618 | 620 | ||
619 | mpic = mpic_find(irq, NULL); | 621 | smp_message_recv(ipi); |
620 | smp_message_recv(mpic_irq_to_hw(irq) - mpic->ipi_vecs[0]); | ||
621 | 622 | ||
622 | return IRQ_HANDLED; | 623 | return IRQ_HANDLED; |
623 | } | 624 | } |
@@ -842,6 +843,24 @@ int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
842 | return 0; | 843 | return 0; |
843 | } | 844 | } |
844 | 845 | ||
846 | void mpic_set_vector(unsigned int virq, unsigned int vector) | ||
847 | { | ||
848 | struct mpic *mpic = mpic_from_irq(virq); | ||
849 | unsigned int src = mpic_irq_to_hw(virq); | ||
850 | unsigned int vecpri; | ||
851 | |||
852 | DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", | ||
853 | mpic, virq, src, vector); | ||
854 | |||
855 | if (src >= mpic->irq_count) | ||
856 | return; | ||
857 | |||
858 | vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); | ||
859 | vecpri = vecpri & ~MPIC_INFO(VECPRI_VECTOR_MASK); | ||
860 | vecpri |= vector; | ||
861 | mpic_irq_write(src, MPIC_INFO(IRQ_VECTOR_PRI), vecpri); | ||
862 | } | ||
863 | |||
845 | static struct irq_chip mpic_irq_chip = { | 864 | static struct irq_chip mpic_irq_chip = { |
846 | .mask = mpic_mask_irq, | 865 | .mask = mpic_mask_irq, |
847 | .unmask = mpic_unmask_irq, | 866 | .unmask = mpic_unmask_irq, |
@@ -1109,6 +1128,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1109 | mb(); | 1128 | mb(); |
1110 | } | 1129 | } |
1111 | 1130 | ||
1131 | if (flags & MPIC_ENABLE_MCK) | ||
1132 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), | ||
1133 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | ||
1134 | | MPIC_GREG_GCONF_MCK); | ||
1135 | |||
1112 | /* Read feature register, calculate num CPUs and, for non-ISU | 1136 | /* Read feature register, calculate num CPUs and, for non-ISU |
1113 | * MPICs, num sources as well. On ISU MPICs, sources are counted | 1137 | * MPICs, num sources as well. On ISU MPICs, sources are counted |
1114 | * as ISUs are added | 1138 | * as ISUs are added |
@@ -1230,6 +1254,8 @@ void __init mpic_init(struct mpic *mpic) | |||
1230 | mpic_u3msi_init(mpic); | 1254 | mpic_u3msi_init(mpic); |
1231 | } | 1255 | } |
1232 | 1256 | ||
1257 | mpic_pasemi_msi_init(mpic); | ||
1258 | |||
1233 | for (i = 0; i < mpic->num_sources; i++) { | 1259 | for (i = 0; i < mpic->num_sources; i++) { |
1234 | /* start with vector = source number, and masked */ | 1260 | /* start with vector = source number, and masked */ |
1235 | u32 vecpri = MPIC_VECPRI_MASK | i | | 1261 | u32 vecpri = MPIC_VECPRI_MASK | i | |
@@ -1253,6 +1279,11 @@ void __init mpic_init(struct mpic *mpic) | |||
1253 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | 1279 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) |
1254 | | MPIC_GREG_GCONF_8259_PTHROU_DIS); | 1280 | | MPIC_GREG_GCONF_8259_PTHROU_DIS); |
1255 | 1281 | ||
1282 | if (mpic->flags & MPIC_NO_BIAS) | ||
1283 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), | ||
1284 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | ||
1285 | | MPIC_GREG_GCONF_NO_BIAS); | ||
1286 | |||
1256 | /* Set current processor priority to 0 */ | 1287 | /* Set current processor priority to 0 */ |
1257 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); | 1288 | mpic_cpu_write(MPIC_INFO(CPU_CURRENT_TASK_PRI), 0); |
1258 | 1289 | ||
@@ -1419,13 +1450,13 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) | |||
1419 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); | 1450 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); |
1420 | } | 1451 | } |
1421 | 1452 | ||
1422 | unsigned int mpic_get_one_irq(struct mpic *mpic) | 1453 | static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) |
1423 | { | 1454 | { |
1424 | u32 src; | 1455 | u32 src; |
1425 | 1456 | ||
1426 | src = mpic_cpu_read(MPIC_INFO(CPU_INTACK)) & MPIC_INFO(VECPRI_VECTOR_MASK); | 1457 | src = mpic_cpu_read(reg) & MPIC_INFO(VECPRI_VECTOR_MASK); |
1427 | #ifdef DEBUG_LOW | 1458 | #ifdef DEBUG_LOW |
1428 | DBG("%s: get_one_irq(): %d\n", mpic->name, src); | 1459 | DBG("%s: get_one_irq(reg 0x%x): %d\n", mpic->name, reg, src); |
1429 | #endif | 1460 | #endif |
1430 | if (unlikely(src == mpic->spurious_vec)) { | 1461 | if (unlikely(src == mpic->spurious_vec)) { |
1431 | if (mpic->flags & MPIC_SPV_EOI) | 1462 | if (mpic->flags & MPIC_SPV_EOI) |
@@ -1443,6 +1474,11 @@ unsigned int mpic_get_one_irq(struct mpic *mpic) | |||
1443 | return irq_linear_revmap(mpic->irqhost, src); | 1474 | return irq_linear_revmap(mpic->irqhost, src); |
1444 | } | 1475 | } |
1445 | 1476 | ||
1477 | unsigned int mpic_get_one_irq(struct mpic *mpic) | ||
1478 | { | ||
1479 | return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK)); | ||
1480 | } | ||
1481 | |||
1446 | unsigned int mpic_get_irq(void) | 1482 | unsigned int mpic_get_irq(void) |
1447 | { | 1483 | { |
1448 | struct mpic *mpic = mpic_primary; | 1484 | struct mpic *mpic = mpic_primary; |
@@ -1452,12 +1488,20 @@ unsigned int mpic_get_irq(void) | |||
1452 | return mpic_get_one_irq(mpic); | 1488 | return mpic_get_one_irq(mpic); |
1453 | } | 1489 | } |
1454 | 1490 | ||
1491 | unsigned int mpic_get_mcirq(void) | ||
1492 | { | ||
1493 | struct mpic *mpic = mpic_primary; | ||
1494 | |||
1495 | BUG_ON(mpic == NULL); | ||
1496 | |||
1497 | return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_MCACK)); | ||
1498 | } | ||
1455 | 1499 | ||
1456 | #ifdef CONFIG_SMP | 1500 | #ifdef CONFIG_SMP |
1457 | void mpic_request_ipis(void) | 1501 | void mpic_request_ipis(void) |
1458 | { | 1502 | { |
1459 | struct mpic *mpic = mpic_primary; | 1503 | struct mpic *mpic = mpic_primary; |
1460 | int i, err; | 1504 | long i, err; |
1461 | static char *ipi_names[] = { | 1505 | static char *ipi_names[] = { |
1462 | "IPI0 (call function)", | 1506 | "IPI0 (call function)", |
1463 | "IPI1 (reschedule)", | 1507 | "IPI1 (reschedule)", |
@@ -1472,14 +1516,14 @@ void mpic_request_ipis(void) | |||
1472 | unsigned int vipi = irq_create_mapping(mpic->irqhost, | 1516 | unsigned int vipi = irq_create_mapping(mpic->irqhost, |
1473 | mpic->ipi_vecs[0] + i); | 1517 | mpic->ipi_vecs[0] + i); |
1474 | if (vipi == NO_IRQ) { | 1518 | if (vipi == NO_IRQ) { |
1475 | printk(KERN_ERR "Failed to map IPI %d\n", i); | 1519 | printk(KERN_ERR "Failed to map IPI %ld\n", i); |
1476 | break; | 1520 | break; |
1477 | } | 1521 | } |
1478 | err = request_irq(vipi, mpic_ipi_action, | 1522 | err = request_irq(vipi, mpic_ipi_action, |
1479 | IRQF_DISABLED|IRQF_PERCPU, | 1523 | IRQF_DISABLED|IRQF_PERCPU, |
1480 | ipi_names[i], mpic); | 1524 | ipi_names[i], (void *)i); |
1481 | if (err) { | 1525 | if (err) { |
1482 | printk(KERN_ERR "Request of irq %d for IPI %d failed\n", | 1526 | printk(KERN_ERR "Request of irq %d for IPI %ld failed\n", |
1483 | vipi, i); | 1527 | vipi, i); |
1484 | break; | 1528 | break; |
1485 | } | 1529 | } |
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h index 1cb6bd841027..fbf8a266941c 100644 --- a/arch/powerpc/sysdev/mpic.h +++ b/arch/powerpc/sysdev/mpic.h | |||
@@ -17,6 +17,7 @@ extern int mpic_msi_init_allocator(struct mpic *mpic); | |||
17 | extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num); | 17 | extern irq_hw_number_t mpic_msi_alloc_hwirqs(struct mpic *mpic, int num); |
18 | extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num); | 18 | extern void mpic_msi_free_hwirqs(struct mpic *mpic, int offset, int num); |
19 | extern int mpic_u3msi_init(struct mpic *mpic); | 19 | extern int mpic_u3msi_init(struct mpic *mpic); |
20 | extern int mpic_pasemi_msi_init(struct mpic *mpic); | ||
20 | #else | 21 | #else |
21 | static inline void mpic_msi_reserve_hwirq(struct mpic *mpic, | 22 | static inline void mpic_msi_reserve_hwirq(struct mpic *mpic, |
22 | irq_hw_number_t hwirq) | 23 | irq_hw_number_t hwirq) |
@@ -28,12 +29,15 @@ static inline int mpic_u3msi_init(struct mpic *mpic) | |||
28 | { | 29 | { |
29 | return -1; | 30 | return -1; |
30 | } | 31 | } |
32 | |||
33 | static inline int mpic_pasemi_msi_init(struct mpic *mpic) | ||
34 | { | ||
35 | return -1; | ||
36 | } | ||
31 | #endif | 37 | #endif |
32 | 38 | ||
33 | extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); | 39 | extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); |
34 | extern void mpic_end_irq(unsigned int irq); | 40 | extern void mpic_set_vector(unsigned int virq, unsigned int vector); |
35 | extern void mpic_mask_irq(unsigned int irq); | ||
36 | extern void mpic_unmask_irq(unsigned int irq); | ||
37 | extern void mpic_set_affinity(unsigned int irq, cpumask_t cpumask); | 41 | extern void mpic_set_affinity(unsigned int irq, cpumask_t cpumask); |
38 | 42 | ||
39 | #endif /* _POWERPC_SYSDEV_MPIC_H */ | 43 | #endif /* _POWERPC_SYSDEV_MPIC_H */ |
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c new file mode 100644 index 000000000000..d6bfda30ac87 --- /dev/null +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c | |||
@@ -0,0 +1,172 @@ | |||
1 | /* | ||
2 | * Copyright 2007, Olof Johansson, PA Semi | ||
3 | * | ||
4 | * Based on arch/powerpc/sysdev/mpic_u3msi.c: | ||
5 | * | ||
6 | * Copyright 2006, Segher Boessenkool, IBM Corporation. | ||
7 | * Copyright 2006-2007, Michael Ellerman, IBM Corporation. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; version 2 of the | ||
12 | * License. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #undef DEBUG | ||
17 | |||
18 | #include <linux/irq.h> | ||
19 | #include <linux/bootmem.h> | ||
20 | #include <linux/msi.h> | ||
21 | #include <asm/mpic.h> | ||
22 | #include <asm/prom.h> | ||
23 | #include <asm/hw_irq.h> | ||
24 | #include <asm/ppc-pci.h> | ||
25 | |||
26 | #include "mpic.h" | ||
27 | |||
28 | /* Allocate 16 interrupts per device, to give an alignment of 16, | ||
29 | * since that's the size of the grouping w.r.t. affinity. If someone | ||
30 | * needs more than 32 MSI's down the road we'll have to rethink this, | ||
31 | * but it should be OK for now. | ||
32 | */ | ||
33 | #define ALLOC_CHUNK 16 | ||
34 | |||
35 | #define PASEMI_MSI_ADDR 0xfc080000 | ||
36 | |||
37 | /* A bit ugly, can we get this from the pci_dev somehow? */ | ||
38 | static struct mpic *msi_mpic; | ||
39 | |||
40 | |||
41 | static void mpic_pasemi_msi_mask_irq(unsigned int irq) | ||
42 | { | ||
43 | pr_debug("mpic_pasemi_msi_mask_irq %d\n", irq); | ||
44 | mask_msi_irq(irq); | ||
45 | mpic_mask_irq(irq); | ||
46 | } | ||
47 | |||
48 | static void mpic_pasemi_msi_unmask_irq(unsigned int irq) | ||
49 | { | ||
50 | pr_debug("mpic_pasemi_msi_unmask_irq %d\n", irq); | ||
51 | mpic_unmask_irq(irq); | ||
52 | unmask_msi_irq(irq); | ||
53 | } | ||
54 | |||
55 | static struct irq_chip mpic_pasemi_msi_chip = { | ||
56 | .shutdown = mpic_pasemi_msi_mask_irq, | ||
57 | .mask = mpic_pasemi_msi_mask_irq, | ||
58 | .unmask = mpic_pasemi_msi_unmask_irq, | ||
59 | .eoi = mpic_end_irq, | ||
60 | .set_type = mpic_set_irq_type, | ||
61 | .set_affinity = mpic_set_affinity, | ||
62 | .typename = "PASEMI-MSI ", | ||
63 | }; | ||
64 | |||
65 | static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type) | ||
66 | { | ||
67 | if (type == PCI_CAP_ID_MSIX) | ||
68 | pr_debug("pasemi_msi: MSI-X untested, trying anyway\n"); | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev) | ||
74 | { | ||
75 | struct msi_desc *entry; | ||
76 | |||
77 | pr_debug("pasemi_msi_teardown_msi_irqs, pdev %p\n", pdev); | ||
78 | |||
79 | list_for_each_entry(entry, &pdev->msi_list, list) { | ||
80 | if (entry->irq == NO_IRQ) | ||
81 | continue; | ||
82 | |||
83 | set_irq_msi(entry->irq, NULL); | ||
84 | mpic_msi_free_hwirqs(msi_mpic, virq_to_hw(entry->irq), | ||
85 | ALLOC_CHUNK); | ||
86 | irq_dispose_mapping(entry->irq); | ||
87 | } | ||
88 | |||
89 | return; | ||
90 | } | ||
91 | |||
92 | static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | ||
93 | { | ||
94 | irq_hw_number_t hwirq; | ||
95 | unsigned int virq; | ||
96 | struct msi_desc *entry; | ||
97 | struct msi_msg msg; | ||
98 | u64 addr; | ||
99 | |||
100 | pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n", | ||
101 | pdev, nvec, type); | ||
102 | |||
103 | msg.address_hi = 0; | ||
104 | msg.address_lo = PASEMI_MSI_ADDR; | ||
105 | |||
106 | list_for_each_entry(entry, &pdev->msi_list, list) { | ||
107 | /* Allocate 16 interrupts for now, since that's the grouping for | ||
108 | * affinity. This can be changed later if it turns out 32 is too | ||
109 | * few MSIs for someone, but restrictions will apply to how the | ||
110 | * sources can be changed independently. | ||
111 | */ | ||
112 | hwirq = mpic_msi_alloc_hwirqs(msi_mpic, ALLOC_CHUNK); | ||
113 | if (hwirq < 0) { | ||
114 | pr_debug("pasemi_msi: failed allocating hwirq\n"); | ||
115 | return hwirq; | ||
116 | } | ||
117 | |||
118 | virq = irq_create_mapping(msi_mpic->irqhost, hwirq); | ||
119 | if (virq == NO_IRQ) { | ||
120 | pr_debug("pasemi_msi: failed mapping hwirq 0x%lx\n", hwirq); | ||
121 | mpic_msi_free_hwirqs(msi_mpic, hwirq, ALLOC_CHUNK); | ||
122 | return -ENOSPC; | ||
123 | } | ||
124 | |||
125 | /* Vector on MSI is really an offset, the hardware adds | ||
126 | * it to the value written at the magic address. So set | ||
127 | * it to 0 to remain sane. | ||
128 | */ | ||
129 | mpic_set_vector(virq, 0); | ||
130 | |||
131 | set_irq_msi(virq, entry); | ||
132 | set_irq_chip(virq, &mpic_pasemi_msi_chip); | ||
133 | set_irq_type(virq, IRQ_TYPE_EDGE_RISING); | ||
134 | |||
135 | pr_debug("pasemi_msi: allocated virq 0x%x (hw 0x%lx) addr 0x%lx\n", | ||
136 | virq, hwirq, addr); | ||
137 | |||
138 | /* Likewise, the device writes [0...511] into the target | ||
139 | * register to generate MSI [512...1023] | ||
140 | */ | ||
141 | msg.data = hwirq-0x200; | ||
142 | write_msi_msg(virq, &msg); | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | int mpic_pasemi_msi_init(struct mpic *mpic) | ||
149 | { | ||
150 | int rc; | ||
151 | |||
152 | if (!mpic->irqhost->of_node || | ||
153 | !of_device_is_compatible(mpic->irqhost->of_node, | ||
154 | "pasemi,pwrficient-openpic")) | ||
155 | return -ENODEV; | ||
156 | |||
157 | rc = mpic_msi_init_allocator(mpic); | ||
158 | if (rc) { | ||
159 | pr_debug("pasemi_msi: Error allocating bitmap!\n"); | ||
160 | return rc; | ||
161 | } | ||
162 | |||
163 | pr_debug("pasemi_msi: Registering PA Semi MPIC MSI callbacks\n"); | ||
164 | |||
165 | msi_mpic = mpic; | ||
166 | WARN_ON(ppc_md.setup_msi_irqs); | ||
167 | ppc_md.setup_msi_irqs = pasemi_msi_setup_msi_irqs; | ||
168 | ppc_md.teardown_msi_irqs = pasemi_msi_teardown_msi_irqs; | ||
169 | ppc_md.msi_check_device = pasemi_msi_check_device; | ||
170 | |||
171 | return 0; | ||
172 | } | ||
diff --git a/arch/powerpc/sysdev/mv64x60_dev.c b/arch/powerpc/sysdev/mv64x60_dev.c index 4316f5a48a0f..efda0028909d 100644 --- a/arch/powerpc/sysdev/mv64x60_dev.c +++ b/arch/powerpc/sysdev/mv64x60_dev.c | |||
@@ -241,7 +241,7 @@ static int __init mv64x60_eth_device_setup(struct device_node *np, int id) | |||
241 | 241 | ||
242 | /* only register the shared platform device the first time through */ | 242 | /* only register the shared platform device the first time through */ |
243 | if (id == 0 && (err = eth_register_shared_pdev(np))) | 243 | if (id == 0 && (err = eth_register_shared_pdev(np))) |
244 | return err;; | 244 | return err; |
245 | 245 | ||
246 | memset(r, 0, sizeof(r)); | 246 | memset(r, 0, sizeof(r)); |
247 | of_irq_to_resource(np, 0, &r[0]); | 247 | of_irq_to_resource(np, 0, &r[0]); |
@@ -445,22 +445,19 @@ static int __init mv64x60_device_setup(void) | |||
445 | int id; | 445 | int id; |
446 | int err; | 446 | int err; |
447 | 447 | ||
448 | for (id = 0; | 448 | id = 0; |
449 | (np = of_find_compatible_node(np, "serial", "marvell,mpsc")); id++) | 449 | for_each_compatible_node(np, "serial", "marvell,mpsc") |
450 | if ((err = mv64x60_mpsc_device_setup(np, id))) | 450 | if ((err = mv64x60_mpsc_device_setup(np, id++))) |
451 | goto error; | 451 | goto error; |
452 | 452 | ||
453 | for (id = 0; | 453 | id = 0; |
454 | (np = of_find_compatible_node(np, "network", | 454 | for_each_compatible_node(np, "network", "marvell,mv64x60-eth") |
455 | "marvell,mv64x60-eth")); | 455 | if ((err = mv64x60_eth_device_setup(np, id++))) |
456 | id++) | ||
457 | if ((err = mv64x60_eth_device_setup(np, id))) | ||
458 | goto error; | 456 | goto error; |
459 | 457 | ||
460 | for (id = 0; | 458 | id = 0; |
461 | (np = of_find_compatible_node(np, "i2c", "marvell,mv64x60-i2c")); | 459 | for_each_compatible_node(np, "i2c", "marvell,mv64x60-i2c") |
462 | id++) | 460 | if ((err = mv64x60_i2c_device_setup(np, id++))) |
463 | if ((err = mv64x60_i2c_device_setup(np, id))) | ||
464 | goto error; | 461 | goto error; |
465 | 462 | ||
466 | /* support up to one watchdog timer */ | 463 | /* support up to one watchdog timer */ |
@@ -471,7 +468,6 @@ static int __init mv64x60_device_setup(void) | |||
471 | of_node_put(np); | 468 | of_node_put(np); |
472 | } | 469 | } |
473 | 470 | ||
474 | |||
475 | return 0; | 471 | return 0; |
476 | 472 | ||
477 | error: | 473 | error: |
diff --git a/arch/powerpc/sysdev/mv64x60_pci.c b/arch/powerpc/sysdev/mv64x60_pci.c index 6933f9c73b43..d21ab8fa4993 100644 --- a/arch/powerpc/sysdev/mv64x60_pci.c +++ b/arch/powerpc/sysdev/mv64x60_pci.c | |||
@@ -164,8 +164,8 @@ static int __init mv64x60_add_bridge(struct device_node *dev) | |||
164 | 164 | ||
165 | void __init mv64x60_pci_init(void) | 165 | void __init mv64x60_pci_init(void) |
166 | { | 166 | { |
167 | struct device_node *np = NULL; | 167 | struct device_node *np; |
168 | 168 | ||
169 | while ((np = of_find_compatible_node(np, "pci", "marvell,mv64x60-pci"))) | 169 | for_each_compatible_node(np, "pci", "marvell,mv64x60-pci") |
170 | mv64x60_add_bridge(np); | 170 | mv64x60_add_bridge(np); |
171 | } | 171 | } |
diff --git a/arch/powerpc/sysdev/mv64x60_udbg.c b/arch/powerpc/sysdev/mv64x60_udbg.c index 367e7b13ec00..35c77c7d0616 100644 --- a/arch/powerpc/sysdev/mv64x60_udbg.c +++ b/arch/powerpc/sysdev/mv64x60_udbg.c | |||
@@ -85,10 +85,10 @@ static void mv64x60_udbg_init(void) | |||
85 | if (!stdout) | 85 | if (!stdout) |
86 | return; | 86 | return; |
87 | 87 | ||
88 | for (np = NULL; | 88 | for_each_compatible_node(np, "serial", "marvell,mpsc") { |
89 | (np = of_find_compatible_node(np, "serial", "marvell,mpsc")); ) | ||
90 | if (np == stdout) | 89 | if (np == stdout) |
91 | break; | 90 | break; |
91 | } | ||
92 | 92 | ||
93 | of_node_put(stdout); | 93 | of_node_put(stdout); |
94 | if (!np) | 94 | if (!np) |
diff --git a/arch/powerpc/sysdev/of_rtc.c b/arch/powerpc/sysdev/of_rtc.c new file mode 100644 index 000000000000..3d54450640c1 --- /dev/null +++ b/arch/powerpc/sysdev/of_rtc.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * Instantiate mmio-mapped RTC chips based on device tree information | ||
3 | * | ||
4 | * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/of.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/of_platform.h> | ||
15 | |||
16 | static __initdata struct { | ||
17 | const char *compatible; | ||
18 | char *plat_name; | ||
19 | } of_rtc_table[] = { | ||
20 | { "ds1743-nvram", "rtc-ds1742" }, | ||
21 | }; | ||
22 | |||
23 | void __init of_instantiate_rtc(void) | ||
24 | { | ||
25 | struct device_node *node; | ||
26 | int err; | ||
27 | int i; | ||
28 | |||
29 | for (i = 0; i < ARRAY_SIZE(of_rtc_table); i++) { | ||
30 | char *plat_name = of_rtc_table[i].plat_name; | ||
31 | |||
32 | for_each_compatible_node(node, NULL, | ||
33 | of_rtc_table[i].compatible) { | ||
34 | struct resource *res; | ||
35 | |||
36 | res = kmalloc(sizeof(*res), GFP_KERNEL); | ||
37 | if (!res) { | ||
38 | printk(KERN_ERR "OF RTC: Out of memory " | ||
39 | "allocating resource structure for %s\n", | ||
40 | node->full_name); | ||
41 | continue; | ||
42 | } | ||
43 | |||
44 | err = of_address_to_resource(node, 0, res); | ||
45 | if (err) { | ||
46 | printk(KERN_ERR "OF RTC: Error " | ||
47 | "translating resources for %s\n", | ||
48 | node->full_name); | ||
49 | continue; | ||
50 | } | ||
51 | |||
52 | printk(KERN_INFO "OF_RTC: %s is a %s @ 0x%llx-0x%llx\n", | ||
53 | node->full_name, plat_name, | ||
54 | (unsigned long long)res->start, | ||
55 | (unsigned long long)res->end); | ||
56 | platform_device_register_simple(plat_name, -1, res, 1); | ||
57 | } | ||
58 | } | ||
59 | } | ||
diff --git a/arch/powerpc/sysdev/pmi.c b/arch/powerpc/sysdev/pmi.c index 20edd1e94eff..c858749263e0 100644 --- a/arch/powerpc/sysdev/pmi.c +++ b/arch/powerpc/sysdev/pmi.c | |||
@@ -28,9 +28,9 @@ | |||
28 | #include <linux/completion.h> | 28 | #include <linux/completion.h> |
29 | #include <linux/spinlock.h> | 29 | #include <linux/spinlock.h> |
30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
31 | #include <linux/of_device.h> | ||
32 | #include <linux/of_platform.h> | ||
31 | 33 | ||
32 | #include <asm/of_device.h> | ||
33 | #include <asm/of_platform.h> | ||
34 | #include <asm/io.h> | 34 | #include <asm/io.h> |
35 | #include <asm/pmi.h> | 35 | #include <asm/pmi.h> |
36 | #include <asm/prom.h> | 36 | #include <asm/prom.h> |
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c new file mode 100644 index 000000000000..5abfcd157483 --- /dev/null +++ b/arch/powerpc/sysdev/ppc4xx_pci.c | |||
@@ -0,0 +1,1528 @@ | |||
1 | /* | ||
2 | * PCI / PCI-X / PCI-Express support for 4xx parts | ||
3 | * | ||
4 | * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. | ||
5 | * | ||
6 | * Most PCI Express code is coming from Stefan Roese implementation for | ||
7 | * arch/ppc in the Denx tree, slightly reworked by me. | ||
8 | * | ||
9 | * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de> | ||
10 | * | ||
11 | * Some of that comes itself from a previous implementation for 440SPE only | ||
12 | * by Roland Dreier: | ||
13 | * | ||
14 | * Copyright (c) 2005 Cisco Systems. All rights reserved. | ||
15 | * Roland Dreier <rolandd@cisco.com> | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #undef DEBUG | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/bootmem.h> | ||
26 | #include <linux/delay.h> | ||
27 | |||
28 | #include <asm/io.h> | ||
29 | #include <asm/pci-bridge.h> | ||
30 | #include <asm/machdep.h> | ||
31 | #include <asm/dcr.h> | ||
32 | #include <asm/dcr-regs.h> | ||
33 | |||
34 | #include "ppc4xx_pci.h" | ||
35 | |||
36 | static int dma_offset_set; | ||
37 | |||
38 | /* Move that to a useable header */ | ||
39 | extern unsigned long total_memory; | ||
40 | |||
41 | #define U64_TO_U32_LOW(val) ((u32)((val) & 0x00000000ffffffffULL)) | ||
42 | #define U64_TO_U32_HIGH(val) ((u32)((val) >> 32)) | ||
43 | |||
44 | #ifdef CONFIG_RESOURCES_64BIT | ||
45 | #define RES_TO_U32_LOW(val) U64_TO_U32_LOW(val) | ||
46 | #define RES_TO_U32_HIGH(val) U64_TO_U32_HIGH(val) | ||
47 | #else | ||
48 | #define RES_TO_U32_LOW(val) (val) | ||
49 | #define RES_TO_U32_HIGH(val) (0) | ||
50 | #endif | ||
51 | |||
52 | static inline int ppc440spe_revA(void) | ||
53 | { | ||
54 | /* Catch both 440SPe variants, with and without RAID6 support */ | ||
55 | if ((mfspr(SPRN_PVR) & 0xffefffff) == 0x53421890) | ||
56 | return 1; | ||
57 | else | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev) | ||
62 | { | ||
63 | struct pci_controller *hose; | ||
64 | int i; | ||
65 | |||
66 | if (dev->devfn != 0 || dev->bus->self != NULL) | ||
67 | return; | ||
68 | |||
69 | hose = pci_bus_to_host(dev->bus); | ||
70 | if (hose == NULL) | ||
71 | return; | ||
72 | |||
73 | if (!of_device_is_compatible(hose->dn, "ibm,plb-pciex") && | ||
74 | !of_device_is_compatible(hose->dn, "ibm,plb-pcix") && | ||
75 | !of_device_is_compatible(hose->dn, "ibm,plb-pci")) | ||
76 | return; | ||
77 | |||
78 | /* Hide the PCI host BARs from the kernel as their content doesn't | ||
79 | * fit well in the resource management | ||
80 | */ | ||
81 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | ||
82 | dev->resource[i].start = dev->resource[i].end = 0; | ||
83 | dev->resource[i].flags = 0; | ||
84 | } | ||
85 | |||
86 | printk(KERN_INFO "PCI: Hiding 4xx host bridge resources %s\n", | ||
87 | pci_name(dev)); | ||
88 | } | ||
89 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_ppc4xx_pci_bridge); | ||
90 | |||
91 | static int __init ppc4xx_parse_dma_ranges(struct pci_controller *hose, | ||
92 | void __iomem *reg, | ||
93 | struct resource *res) | ||
94 | { | ||
95 | u64 size; | ||
96 | const u32 *ranges; | ||
97 | int rlen; | ||
98 | int pna = of_n_addr_cells(hose->dn); | ||
99 | int np = pna + 5; | ||
100 | |||
101 | /* Default */ | ||
102 | res->start = 0; | ||
103 | res->end = size = 0x80000000; | ||
104 | res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH; | ||
105 | |||
106 | /* Get dma-ranges property */ | ||
107 | ranges = of_get_property(hose->dn, "dma-ranges", &rlen); | ||
108 | if (ranges == NULL) | ||
109 | goto out; | ||
110 | |||
111 | /* Walk it */ | ||
112 | while ((rlen -= np * 4) >= 0) { | ||
113 | u32 pci_space = ranges[0]; | ||
114 | u64 pci_addr = of_read_number(ranges + 1, 2); | ||
115 | u64 cpu_addr = of_translate_dma_address(hose->dn, ranges + 3); | ||
116 | size = of_read_number(ranges + pna + 3, 2); | ||
117 | ranges += np; | ||
118 | if (cpu_addr == OF_BAD_ADDR || size == 0) | ||
119 | continue; | ||
120 | |||
121 | /* We only care about memory */ | ||
122 | if ((pci_space & 0x03000000) != 0x02000000) | ||
123 | continue; | ||
124 | |||
125 | /* We currently only support memory at 0, and pci_addr | ||
126 | * within 32 bits space | ||
127 | */ | ||
128 | if (cpu_addr != 0 || pci_addr > 0xffffffff) { | ||
129 | printk(KERN_WARNING "%s: Ignored unsupported dma range" | ||
130 | " 0x%016llx...0x%016llx -> 0x%016llx\n", | ||
131 | hose->dn->full_name, | ||
132 | pci_addr, pci_addr + size - 1, cpu_addr); | ||
133 | continue; | ||
134 | } | ||
135 | |||
136 | /* Check if not prefetchable */ | ||
137 | if (!(pci_space & 0x40000000)) | ||
138 | res->flags &= ~IORESOURCE_PREFETCH; | ||
139 | |||
140 | |||
141 | /* Use that */ | ||
142 | res->start = pci_addr; | ||
143 | #ifndef CONFIG_RESOURCES_64BIT | ||
144 | /* Beware of 32 bits resources */ | ||
145 | if ((pci_addr + size) > 0x100000000ull) | ||
146 | res->end = 0xffffffff; | ||
147 | else | ||
148 | #endif | ||
149 | res->end = res->start + size - 1; | ||
150 | break; | ||
151 | } | ||
152 | |||
153 | /* We only support one global DMA offset */ | ||
154 | if (dma_offset_set && pci_dram_offset != res->start) { | ||
155 | printk(KERN_ERR "%s: dma-ranges(s) mismatch\n", | ||
156 | hose->dn->full_name); | ||
157 | return -ENXIO; | ||
158 | } | ||
159 | |||
160 | /* Check that we can fit all of memory as we don't support | ||
161 | * DMA bounce buffers | ||
162 | */ | ||
163 | if (size < total_memory) { | ||
164 | printk(KERN_ERR "%s: dma-ranges too small " | ||
165 | "(size=%llx total_memory=%lx)\n", | ||
166 | hose->dn->full_name, size, total_memory); | ||
167 | return -ENXIO; | ||
168 | } | ||
169 | |||
170 | /* Check we are a power of 2 size and that base is a multiple of size*/ | ||
171 | if (!is_power_of_2(size) || | ||
172 | (res->start & (size - 1)) != 0) { | ||
173 | printk(KERN_ERR "%s: dma-ranges unaligned\n", | ||
174 | hose->dn->full_name); | ||
175 | return -ENXIO; | ||
176 | } | ||
177 | |||
178 | /* Check that we are fully contained within 32 bits space */ | ||
179 | if (res->end > 0xffffffff) { | ||
180 | printk(KERN_ERR "%s: dma-ranges outside of 32 bits space\n", | ||
181 | hose->dn->full_name); | ||
182 | return -ENXIO; | ||
183 | } | ||
184 | out: | ||
185 | dma_offset_set = 1; | ||
186 | pci_dram_offset = res->start; | ||
187 | |||
188 | printk(KERN_INFO "4xx PCI DMA offset set to 0x%08lx\n", | ||
189 | pci_dram_offset); | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | /* | ||
194 | * 4xx PCI 2.x part | ||
195 | */ | ||
196 | |||
197 | static void __init ppc4xx_configure_pci_PMMs(struct pci_controller *hose, | ||
198 | void __iomem *reg) | ||
199 | { | ||
200 | u32 la, ma, pcila, pciha; | ||
201 | int i, j; | ||
202 | |||
203 | /* Setup outbound memory windows */ | ||
204 | for (i = j = 0; i < 3; i++) { | ||
205 | struct resource *res = &hose->mem_resources[i]; | ||
206 | |||
207 | /* we only care about memory windows */ | ||
208 | if (!(res->flags & IORESOURCE_MEM)) | ||
209 | continue; | ||
210 | if (j > 2) { | ||
211 | printk(KERN_WARNING "%s: Too many ranges\n", | ||
212 | hose->dn->full_name); | ||
213 | break; | ||
214 | } | ||
215 | |||
216 | /* Calculate register values */ | ||
217 | la = res->start; | ||
218 | pciha = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); | ||
219 | pcila = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); | ||
220 | |||
221 | ma = res->end + 1 - res->start; | ||
222 | if (!is_power_of_2(ma) || ma < 0x1000 || ma > 0xffffffffu) { | ||
223 | printk(KERN_WARNING "%s: Resource out of range\n", | ||
224 | hose->dn->full_name); | ||
225 | continue; | ||
226 | } | ||
227 | ma = (0xffffffffu << ilog2(ma)) | 0x1; | ||
228 | if (res->flags & IORESOURCE_PREFETCH) | ||
229 | ma |= 0x2; | ||
230 | |||
231 | /* Program register values */ | ||
232 | writel(la, reg + PCIL0_PMM0LA + (0x10 * j)); | ||
233 | writel(pcila, reg + PCIL0_PMM0PCILA + (0x10 * j)); | ||
234 | writel(pciha, reg + PCIL0_PMM0PCIHA + (0x10 * j)); | ||
235 | writel(ma, reg + PCIL0_PMM0MA + (0x10 * j)); | ||
236 | j++; | ||
237 | } | ||
238 | } | ||
239 | |||
240 | static void __init ppc4xx_configure_pci_PTMs(struct pci_controller *hose, | ||
241 | void __iomem *reg, | ||
242 | const struct resource *res) | ||
243 | { | ||
244 | resource_size_t size = res->end - res->start + 1; | ||
245 | u32 sa; | ||
246 | |||
247 | /* Calculate window size */ | ||
248 | sa = (0xffffffffu << ilog2(size)) | 1; | ||
249 | sa |= 0x1; | ||
250 | |||
251 | /* RAM is always at 0 local for now */ | ||
252 | writel(0, reg + PCIL0_PTM1LA); | ||
253 | writel(sa, reg + PCIL0_PTM1MS); | ||
254 | |||
255 | /* Map on PCI side */ | ||
256 | early_write_config_dword(hose, hose->first_busno, 0, | ||
257 | PCI_BASE_ADDRESS_1, res->start); | ||
258 | early_write_config_dword(hose, hose->first_busno, 0, | ||
259 | PCI_BASE_ADDRESS_2, 0x00000000); | ||
260 | early_write_config_word(hose, hose->first_busno, 0, | ||
261 | PCI_COMMAND, 0x0006); | ||
262 | } | ||
263 | |||
264 | static void __init ppc4xx_probe_pci_bridge(struct device_node *np) | ||
265 | { | ||
266 | /* NYI */ | ||
267 | struct resource rsrc_cfg; | ||
268 | struct resource rsrc_reg; | ||
269 | struct resource dma_window; | ||
270 | struct pci_controller *hose = NULL; | ||
271 | void __iomem *reg = NULL; | ||
272 | const int *bus_range; | ||
273 | int primary = 0; | ||
274 | |||
275 | /* Fetch config space registers address */ | ||
276 | if (of_address_to_resource(np, 0, &rsrc_cfg)) { | ||
277 | printk(KERN_ERR "%s:Can't get PCI config register base !", | ||
278 | np->full_name); | ||
279 | return; | ||
280 | } | ||
281 | /* Fetch host bridge internal registers address */ | ||
282 | if (of_address_to_resource(np, 3, &rsrc_reg)) { | ||
283 | printk(KERN_ERR "%s: Can't get PCI internal register base !", | ||
284 | np->full_name); | ||
285 | return; | ||
286 | } | ||
287 | |||
288 | /* Check if primary bridge */ | ||
289 | if (of_get_property(np, "primary", NULL)) | ||
290 | primary = 1; | ||
291 | |||
292 | /* Get bus range if any */ | ||
293 | bus_range = of_get_property(np, "bus-range", NULL); | ||
294 | |||
295 | /* Map registers */ | ||
296 | reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start); | ||
297 | if (reg == NULL) { | ||
298 | printk(KERN_ERR "%s: Can't map registers !", np->full_name); | ||
299 | goto fail; | ||
300 | } | ||
301 | |||
302 | /* Allocate the host controller data structure */ | ||
303 | hose = pcibios_alloc_controller(np); | ||
304 | if (!hose) | ||
305 | goto fail; | ||
306 | |||
307 | hose->first_busno = bus_range ? bus_range[0] : 0x0; | ||
308 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
309 | |||
310 | /* Setup config space */ | ||
311 | setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4, 0); | ||
312 | |||
313 | /* Disable all windows */ | ||
314 | writel(0, reg + PCIL0_PMM0MA); | ||
315 | writel(0, reg + PCIL0_PMM1MA); | ||
316 | writel(0, reg + PCIL0_PMM2MA); | ||
317 | writel(0, reg + PCIL0_PTM1MS); | ||
318 | writel(0, reg + PCIL0_PTM2MS); | ||
319 | |||
320 | /* Parse outbound mapping resources */ | ||
321 | pci_process_bridge_OF_ranges(hose, np, primary); | ||
322 | |||
323 | /* Parse inbound mapping resources */ | ||
324 | if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0) | ||
325 | goto fail; | ||
326 | |||
327 | /* Configure outbound ranges POMs */ | ||
328 | ppc4xx_configure_pci_PMMs(hose, reg); | ||
329 | |||
330 | /* Configure inbound ranges PIMs */ | ||
331 | ppc4xx_configure_pci_PTMs(hose, reg, &dma_window); | ||
332 | |||
333 | /* We don't need the registers anymore */ | ||
334 | iounmap(reg); | ||
335 | return; | ||
336 | |||
337 | fail: | ||
338 | if (hose) | ||
339 | pcibios_free_controller(hose); | ||
340 | if (reg) | ||
341 | iounmap(reg); | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * 4xx PCI-X part | ||
346 | */ | ||
347 | |||
348 | static void __init ppc4xx_configure_pcix_POMs(struct pci_controller *hose, | ||
349 | void __iomem *reg) | ||
350 | { | ||
351 | u32 lah, lal, pciah, pcial, sa; | ||
352 | int i, j; | ||
353 | |||
354 | /* Setup outbound memory windows */ | ||
355 | for (i = j = 0; i < 3; i++) { | ||
356 | struct resource *res = &hose->mem_resources[i]; | ||
357 | |||
358 | /* we only care about memory windows */ | ||
359 | if (!(res->flags & IORESOURCE_MEM)) | ||
360 | continue; | ||
361 | if (j > 1) { | ||
362 | printk(KERN_WARNING "%s: Too many ranges\n", | ||
363 | hose->dn->full_name); | ||
364 | break; | ||
365 | } | ||
366 | |||
367 | /* Calculate register values */ | ||
368 | lah = RES_TO_U32_HIGH(res->start); | ||
369 | lal = RES_TO_U32_LOW(res->start); | ||
370 | pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); | ||
371 | pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); | ||
372 | sa = res->end + 1 - res->start; | ||
373 | if (!is_power_of_2(sa) || sa < 0x100000 || | ||
374 | sa > 0xffffffffu) { | ||
375 | printk(KERN_WARNING "%s: Resource out of range\n", | ||
376 | hose->dn->full_name); | ||
377 | continue; | ||
378 | } | ||
379 | sa = (0xffffffffu << ilog2(sa)) | 0x1; | ||
380 | |||
381 | /* Program register values */ | ||
382 | if (j == 0) { | ||
383 | writel(lah, reg + PCIX0_POM0LAH); | ||
384 | writel(lal, reg + PCIX0_POM0LAL); | ||
385 | writel(pciah, reg + PCIX0_POM0PCIAH); | ||
386 | writel(pcial, reg + PCIX0_POM0PCIAL); | ||
387 | writel(sa, reg + PCIX0_POM0SA); | ||
388 | } else { | ||
389 | writel(lah, reg + PCIX0_POM1LAH); | ||
390 | writel(lal, reg + PCIX0_POM1LAL); | ||
391 | writel(pciah, reg + PCIX0_POM1PCIAH); | ||
392 | writel(pcial, reg + PCIX0_POM1PCIAL); | ||
393 | writel(sa, reg + PCIX0_POM1SA); | ||
394 | } | ||
395 | j++; | ||
396 | } | ||
397 | } | ||
398 | |||
399 | static void __init ppc4xx_configure_pcix_PIMs(struct pci_controller *hose, | ||
400 | void __iomem *reg, | ||
401 | const struct resource *res, | ||
402 | int big_pim, | ||
403 | int enable_msi_hole) | ||
404 | { | ||
405 | resource_size_t size = res->end - res->start + 1; | ||
406 | u32 sa; | ||
407 | |||
408 | /* RAM is always at 0 */ | ||
409 | writel(0x00000000, reg + PCIX0_PIM0LAH); | ||
410 | writel(0x00000000, reg + PCIX0_PIM0LAL); | ||
411 | |||
412 | /* Calculate window size */ | ||
413 | sa = (0xffffffffu << ilog2(size)) | 1; | ||
414 | sa |= 0x1; | ||
415 | if (res->flags & IORESOURCE_PREFETCH) | ||
416 | sa |= 0x2; | ||
417 | if (enable_msi_hole) | ||
418 | sa |= 0x4; | ||
419 | writel(sa, reg + PCIX0_PIM0SA); | ||
420 | if (big_pim) | ||
421 | writel(0xffffffff, reg + PCIX0_PIM0SAH); | ||
422 | |||
423 | /* Map on PCI side */ | ||
424 | writel(0x00000000, reg + PCIX0_BAR0H); | ||
425 | writel(res->start, reg + PCIX0_BAR0L); | ||
426 | writew(0x0006, reg + PCIX0_COMMAND); | ||
427 | } | ||
428 | |||
429 | static void __init ppc4xx_probe_pcix_bridge(struct device_node *np) | ||
430 | { | ||
431 | struct resource rsrc_cfg; | ||
432 | struct resource rsrc_reg; | ||
433 | struct resource dma_window; | ||
434 | struct pci_controller *hose = NULL; | ||
435 | void __iomem *reg = NULL; | ||
436 | const int *bus_range; | ||
437 | int big_pim = 0, msi = 0, primary = 0; | ||
438 | |||
439 | /* Fetch config space registers address */ | ||
440 | if (of_address_to_resource(np, 0, &rsrc_cfg)) { | ||
441 | printk(KERN_ERR "%s:Can't get PCI-X config register base !", | ||
442 | np->full_name); | ||
443 | return; | ||
444 | } | ||
445 | /* Fetch host bridge internal registers address */ | ||
446 | if (of_address_to_resource(np, 3, &rsrc_reg)) { | ||
447 | printk(KERN_ERR "%s: Can't get PCI-X internal register base !", | ||
448 | np->full_name); | ||
449 | return; | ||
450 | } | ||
451 | |||
452 | /* Check if it supports large PIMs (440GX) */ | ||
453 | if (of_get_property(np, "large-inbound-windows", NULL)) | ||
454 | big_pim = 1; | ||
455 | |||
456 | /* Check if we should enable MSIs inbound hole */ | ||
457 | if (of_get_property(np, "enable-msi-hole", NULL)) | ||
458 | msi = 1; | ||
459 | |||
460 | /* Check if primary bridge */ | ||
461 | if (of_get_property(np, "primary", NULL)) | ||
462 | primary = 1; | ||
463 | |||
464 | /* Get bus range if any */ | ||
465 | bus_range = of_get_property(np, "bus-range", NULL); | ||
466 | |||
467 | /* Map registers */ | ||
468 | reg = ioremap(rsrc_reg.start, rsrc_reg.end + 1 - rsrc_reg.start); | ||
469 | if (reg == NULL) { | ||
470 | printk(KERN_ERR "%s: Can't map registers !", np->full_name); | ||
471 | goto fail; | ||
472 | } | ||
473 | |||
474 | /* Allocate the host controller data structure */ | ||
475 | hose = pcibios_alloc_controller(np); | ||
476 | if (!hose) | ||
477 | goto fail; | ||
478 | |||
479 | hose->first_busno = bus_range ? bus_range[0] : 0x0; | ||
480 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
481 | |||
482 | /* Setup config space */ | ||
483 | setup_indirect_pci(hose, rsrc_cfg.start, rsrc_cfg.start + 0x4, 0); | ||
484 | |||
485 | /* Disable all windows */ | ||
486 | writel(0, reg + PCIX0_POM0SA); | ||
487 | writel(0, reg + PCIX0_POM1SA); | ||
488 | writel(0, reg + PCIX0_POM2SA); | ||
489 | writel(0, reg + PCIX0_PIM0SA); | ||
490 | writel(0, reg + PCIX0_PIM1SA); | ||
491 | writel(0, reg + PCIX0_PIM2SA); | ||
492 | if (big_pim) { | ||
493 | writel(0, reg + PCIX0_PIM0SAH); | ||
494 | writel(0, reg + PCIX0_PIM2SAH); | ||
495 | } | ||
496 | |||
497 | /* Parse outbound mapping resources */ | ||
498 | pci_process_bridge_OF_ranges(hose, np, primary); | ||
499 | |||
500 | /* Parse inbound mapping resources */ | ||
501 | if (ppc4xx_parse_dma_ranges(hose, reg, &dma_window) != 0) | ||
502 | goto fail; | ||
503 | |||
504 | /* Configure outbound ranges POMs */ | ||
505 | ppc4xx_configure_pcix_POMs(hose, reg); | ||
506 | |||
507 | /* Configure inbound ranges PIMs */ | ||
508 | ppc4xx_configure_pcix_PIMs(hose, reg, &dma_window, big_pim, msi); | ||
509 | |||
510 | /* We don't need the registers anymore */ | ||
511 | iounmap(reg); | ||
512 | return; | ||
513 | |||
514 | fail: | ||
515 | if (hose) | ||
516 | pcibios_free_controller(hose); | ||
517 | if (reg) | ||
518 | iounmap(reg); | ||
519 | } | ||
520 | |||
521 | #ifdef CONFIG_PPC4xx_PCI_EXPRESS | ||
522 | |||
523 | /* | ||
524 | * 4xx PCI-Express part | ||
525 | * | ||
526 | * We support 3 parts currently based on the compatible property: | ||
527 | * | ||
528 | * ibm,plb-pciex-440spe | ||
529 | * ibm,plb-pciex-405ex | ||
530 | * | ||
531 | * Anything else will be rejected for now as they are all subtly | ||
532 | * different unfortunately. | ||
533 | * | ||
534 | */ | ||
535 | |||
536 | #define MAX_PCIE_BUS_MAPPED 0x40 | ||
537 | |||
538 | struct ppc4xx_pciex_port | ||
539 | { | ||
540 | struct pci_controller *hose; | ||
541 | struct device_node *node; | ||
542 | unsigned int index; | ||
543 | int endpoint; | ||
544 | int link; | ||
545 | int has_ibpre; | ||
546 | unsigned int sdr_base; | ||
547 | dcr_host_t dcrs; | ||
548 | struct resource cfg_space; | ||
549 | struct resource utl_regs; | ||
550 | void __iomem *utl_base; | ||
551 | }; | ||
552 | |||
553 | static struct ppc4xx_pciex_port *ppc4xx_pciex_ports; | ||
554 | static unsigned int ppc4xx_pciex_port_count; | ||
555 | |||
556 | struct ppc4xx_pciex_hwops | ||
557 | { | ||
558 | int (*core_init)(struct device_node *np); | ||
559 | int (*port_init_hw)(struct ppc4xx_pciex_port *port); | ||
560 | int (*setup_utl)(struct ppc4xx_pciex_port *port); | ||
561 | }; | ||
562 | |||
563 | static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops; | ||
564 | |||
565 | #ifdef CONFIG_44x | ||
566 | |||
567 | /* Check various reset bits of the 440SPe PCIe core */ | ||
568 | static int __init ppc440spe_pciex_check_reset(struct device_node *np) | ||
569 | { | ||
570 | u32 valPE0, valPE1, valPE2; | ||
571 | int err = 0; | ||
572 | |||
573 | /* SDR0_PEGPLLLCT1 reset */ | ||
574 | if (!(mfdcri(SDR0, PESDR0_PLLLCT1) & 0x01000000)) { | ||
575 | /* | ||
576 | * the PCIe core was probably already initialised | ||
577 | * by firmware - let's re-reset RCSSET regs | ||
578 | * | ||
579 | * -- Shouldn't we also re-reset the whole thing ? -- BenH | ||
580 | */ | ||
581 | pr_debug("PCIE: SDR0_PLLLCT1 already reset.\n"); | ||
582 | mtdcri(SDR0, PESDR0_440SPE_RCSSET, 0x01010000); | ||
583 | mtdcri(SDR0, PESDR1_440SPE_RCSSET, 0x01010000); | ||
584 | mtdcri(SDR0, PESDR2_440SPE_RCSSET, 0x01010000); | ||
585 | } | ||
586 | |||
587 | valPE0 = mfdcri(SDR0, PESDR0_440SPE_RCSSET); | ||
588 | valPE1 = mfdcri(SDR0, PESDR1_440SPE_RCSSET); | ||
589 | valPE2 = mfdcri(SDR0, PESDR2_440SPE_RCSSET); | ||
590 | |||
591 | /* SDR0_PExRCSSET rstgu */ | ||
592 | if (!(valPE0 & 0x01000000) || | ||
593 | !(valPE1 & 0x01000000) || | ||
594 | !(valPE2 & 0x01000000)) { | ||
595 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstgu error\n"); | ||
596 | err = -1; | ||
597 | } | ||
598 | |||
599 | /* SDR0_PExRCSSET rstdl */ | ||
600 | if (!(valPE0 & 0x00010000) || | ||
601 | !(valPE1 & 0x00010000) || | ||
602 | !(valPE2 & 0x00010000)) { | ||
603 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstdl error\n"); | ||
604 | err = -1; | ||
605 | } | ||
606 | |||
607 | /* SDR0_PExRCSSET rstpyn */ | ||
608 | if ((valPE0 & 0x00001000) || | ||
609 | (valPE1 & 0x00001000) || | ||
610 | (valPE2 & 0x00001000)) { | ||
611 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET rstpyn error\n"); | ||
612 | err = -1; | ||
613 | } | ||
614 | |||
615 | /* SDR0_PExRCSSET hldplb */ | ||
616 | if ((valPE0 & 0x10000000) || | ||
617 | (valPE1 & 0x10000000) || | ||
618 | (valPE2 & 0x10000000)) { | ||
619 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET hldplb error\n"); | ||
620 | err = -1; | ||
621 | } | ||
622 | |||
623 | /* SDR0_PExRCSSET rdy */ | ||
624 | if ((valPE0 & 0x00100000) || | ||
625 | (valPE1 & 0x00100000) || | ||
626 | (valPE2 & 0x00100000)) { | ||
627 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET rdy error\n"); | ||
628 | err = -1; | ||
629 | } | ||
630 | |||
631 | /* SDR0_PExRCSSET shutdown */ | ||
632 | if ((valPE0 & 0x00000100) || | ||
633 | (valPE1 & 0x00000100) || | ||
634 | (valPE2 & 0x00000100)) { | ||
635 | printk(KERN_INFO "PCIE: SDR0_PExRCSSET shutdown error\n"); | ||
636 | err = -1; | ||
637 | } | ||
638 | |||
639 | return err; | ||
640 | } | ||
641 | |||
642 | /* Global PCIe core initializations for 440SPe core */ | ||
643 | static int __init ppc440spe_pciex_core_init(struct device_node *np) | ||
644 | { | ||
645 | int time_out = 20; | ||
646 | |||
647 | /* Set PLL clock receiver to LVPECL */ | ||
648 | mtdcri(SDR0, PESDR0_PLLLCT1, mfdcri(SDR0, PESDR0_PLLLCT1) | 1 << 28); | ||
649 | |||
650 | /* Shouldn't we do all the calibration stuff etc... here ? */ | ||
651 | if (ppc440spe_pciex_check_reset(np)) | ||
652 | return -ENXIO; | ||
653 | |||
654 | if (!(mfdcri(SDR0, PESDR0_PLLLCT2) & 0x10000)) { | ||
655 | printk(KERN_INFO "PCIE: PESDR_PLLCT2 resistance calibration " | ||
656 | "failed (0x%08x)\n", | ||
657 | mfdcri(SDR0, PESDR0_PLLLCT2)); | ||
658 | return -1; | ||
659 | } | ||
660 | |||
661 | /* De-assert reset of PCIe PLL, wait for lock */ | ||
662 | mtdcri(SDR0, PESDR0_PLLLCT1, | ||
663 | mfdcri(SDR0, PESDR0_PLLLCT1) & ~(1 << 24)); | ||
664 | udelay(3); | ||
665 | |||
666 | while (time_out) { | ||
667 | if (!(mfdcri(SDR0, PESDR0_PLLLCT3) & 0x10000000)) { | ||
668 | time_out--; | ||
669 | udelay(1); | ||
670 | } else | ||
671 | break; | ||
672 | } | ||
673 | if (!time_out) { | ||
674 | printk(KERN_INFO "PCIE: VCO output not locked\n"); | ||
675 | return -1; | ||
676 | } | ||
677 | |||
678 | pr_debug("PCIE initialization OK\n"); | ||
679 | |||
680 | return 3; | ||
681 | } | ||
682 | |||
683 | static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | ||
684 | { | ||
685 | u32 val = 1 << 24; | ||
686 | |||
687 | if (port->endpoint) | ||
688 | val = PTYPE_LEGACY_ENDPOINT << 20; | ||
689 | else | ||
690 | val = PTYPE_ROOT_PORT << 20; | ||
691 | |||
692 | if (port->index == 0) | ||
693 | val |= LNKW_X8 << 12; | ||
694 | else | ||
695 | val |= LNKW_X4 << 12; | ||
696 | |||
697 | mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val); | ||
698 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x20222222); | ||
699 | if (ppc440spe_revA()) | ||
700 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x11000000); | ||
701 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL0SET1, 0x35000000); | ||
702 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL1SET1, 0x35000000); | ||
703 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL2SET1, 0x35000000); | ||
704 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL3SET1, 0x35000000); | ||
705 | if (port->index == 0) { | ||
706 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL4SET1, | ||
707 | 0x35000000); | ||
708 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL5SET1, | ||
709 | 0x35000000); | ||
710 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL6SET1, | ||
711 | 0x35000000); | ||
712 | mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL7SET1, | ||
713 | 0x35000000); | ||
714 | } | ||
715 | val = mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET); | ||
716 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | ||
717 | (val & ~(1 << 24 | 1 << 16)) | 1 << 12); | ||
718 | |||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | ||
723 | { | ||
724 | return ppc440spe_pciex_init_port_hw(port); | ||
725 | } | ||
726 | |||
727 | static int ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | ||
728 | { | ||
729 | int rc = ppc440spe_pciex_init_port_hw(port); | ||
730 | |||
731 | port->has_ibpre = 1; | ||
732 | |||
733 | return rc; | ||
734 | } | ||
735 | |||
736 | static int ppc440speA_pciex_init_utl(struct ppc4xx_pciex_port *port) | ||
737 | { | ||
738 | /* XXX Check what that value means... I hate magic */ | ||
739 | dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x68782800); | ||
740 | |||
741 | /* | ||
742 | * Set buffer allocations and then assert VRB and TXE. | ||
743 | */ | ||
744 | out_be32(port->utl_base + PEUTL_OUTTR, 0x08000000); | ||
745 | out_be32(port->utl_base + PEUTL_INTR, 0x02000000); | ||
746 | out_be32(port->utl_base + PEUTL_OPDBSZ, 0x10000000); | ||
747 | out_be32(port->utl_base + PEUTL_PBBSZ, 0x53000000); | ||
748 | out_be32(port->utl_base + PEUTL_IPHBSZ, 0x08000000); | ||
749 | out_be32(port->utl_base + PEUTL_IPDBSZ, 0x10000000); | ||
750 | out_be32(port->utl_base + PEUTL_RCIRQEN, 0x00f00000); | ||
751 | out_be32(port->utl_base + PEUTL_PCTL, 0x80800066); | ||
752 | |||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | static int ppc440speB_pciex_init_utl(struct ppc4xx_pciex_port *port) | ||
757 | { | ||
758 | /* Report CRS to the operating system */ | ||
759 | out_be32(port->utl_base + PEUTL_PBCTL, 0x08000000); | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | static struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata = | ||
765 | { | ||
766 | .core_init = ppc440spe_pciex_core_init, | ||
767 | .port_init_hw = ppc440speA_pciex_init_port_hw, | ||
768 | .setup_utl = ppc440speA_pciex_init_utl, | ||
769 | }; | ||
770 | |||
771 | static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = | ||
772 | { | ||
773 | .core_init = ppc440spe_pciex_core_init, | ||
774 | .port_init_hw = ppc440speB_pciex_init_port_hw, | ||
775 | .setup_utl = ppc440speB_pciex_init_utl, | ||
776 | }; | ||
777 | |||
778 | #endif /* CONFIG_44x */ | ||
779 | |||
780 | #ifdef CONFIG_40x | ||
781 | |||
782 | static int __init ppc405ex_pciex_core_init(struct device_node *np) | ||
783 | { | ||
784 | /* Nothing to do, return 2 ports */ | ||
785 | return 2; | ||
786 | } | ||
787 | |||
788 | static void ppc405ex_pcie_phy_reset(struct ppc4xx_pciex_port *port) | ||
789 | { | ||
790 | /* Assert the PE0_PHY reset */ | ||
791 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01010000); | ||
792 | msleep(1); | ||
793 | |||
794 | /* deassert the PE0_hotreset */ | ||
795 | if (port->endpoint) | ||
796 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01111000); | ||
797 | else | ||
798 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x01101000); | ||
799 | |||
800 | /* poll for phy !reset */ | ||
801 | /* XXX FIXME add timeout */ | ||
802 | while (!(mfdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSTA) & 0x00001000)) | ||
803 | ; | ||
804 | |||
805 | /* deassert the PE0_gpl_utl_reset */ | ||
806 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, 0x00101000); | ||
807 | } | ||
808 | |||
809 | static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | ||
810 | { | ||
811 | u32 val; | ||
812 | |||
813 | if (port->endpoint) | ||
814 | val = PTYPE_LEGACY_ENDPOINT; | ||
815 | else | ||
816 | val = PTYPE_ROOT_PORT; | ||
817 | |||
818 | mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, | ||
819 | 1 << 24 | val << 20 | LNKW_X1 << 12); | ||
820 | |||
821 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000); | ||
822 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000); | ||
823 | mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET1, 0x720F0000); | ||
824 | mtdcri(SDR0, port->sdr_base + PESDRn_405EX_PHYSET2, 0x70600003); | ||
825 | |||
826 | /* | ||
827 | * Only reset the PHY when no link is currently established. | ||
828 | * This is for the Atheros PCIe board which has problems to establish | ||
829 | * the link (again) after this PHY reset. All other currently tested | ||
830 | * PCIe boards don't show this problem. | ||
831 | * This has to be re-tested and fixed in a later release! | ||
832 | */ | ||
833 | #if 0 /* XXX FIXME: Not resetting the PHY will leave all resources | ||
834 | * configured as done previously by U-Boot. Then Linux will currently | ||
835 | * not reassign them. So the PHY reset is now done always. This will | ||
836 | * lead to problems with the Atheros PCIe board again. | ||
837 | */ | ||
838 | val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP); | ||
839 | if (!(val & 0x00001000)) | ||
840 | ppc405ex_pcie_phy_reset(port); | ||
841 | #else | ||
842 | ppc405ex_pcie_phy_reset(port); | ||
843 | #endif | ||
844 | |||
845 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, 0x10000000); /* guarded on */ | ||
846 | |||
847 | port->has_ibpre = 1; | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port) | ||
853 | { | ||
854 | dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0); | ||
855 | |||
856 | /* | ||
857 | * Set buffer allocations and then assert VRB and TXE. | ||
858 | */ | ||
859 | out_be32(port->utl_base + PEUTL_OUTTR, 0x02000000); | ||
860 | out_be32(port->utl_base + PEUTL_INTR, 0x02000000); | ||
861 | out_be32(port->utl_base + PEUTL_OPDBSZ, 0x04000000); | ||
862 | out_be32(port->utl_base + PEUTL_PBBSZ, 0x21000000); | ||
863 | out_be32(port->utl_base + PEUTL_IPHBSZ, 0x02000000); | ||
864 | out_be32(port->utl_base + PEUTL_IPDBSZ, 0x04000000); | ||
865 | out_be32(port->utl_base + PEUTL_RCIRQEN, 0x00f00000); | ||
866 | out_be32(port->utl_base + PEUTL_PCTL, 0x80800066); | ||
867 | |||
868 | out_be32(port->utl_base + PEUTL_PBCTL, 0x08000000); | ||
869 | |||
870 | return 0; | ||
871 | } | ||
872 | |||
873 | static struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata = | ||
874 | { | ||
875 | .core_init = ppc405ex_pciex_core_init, | ||
876 | .port_init_hw = ppc405ex_pciex_init_port_hw, | ||
877 | .setup_utl = ppc405ex_pciex_init_utl, | ||
878 | }; | ||
879 | |||
880 | #endif /* CONFIG_40x */ | ||
881 | |||
882 | |||
883 | /* Check that the core has been initied and if not, do it */ | ||
884 | static int __init ppc4xx_pciex_check_core_init(struct device_node *np) | ||
885 | { | ||
886 | static int core_init; | ||
887 | int count = -ENODEV; | ||
888 | |||
889 | if (core_init++) | ||
890 | return 0; | ||
891 | |||
892 | #ifdef CONFIG_44x | ||
893 | if (of_device_is_compatible(np, "ibm,plb-pciex-440spe")) { | ||
894 | if (ppc440spe_revA()) | ||
895 | ppc4xx_pciex_hwops = &ppc440speA_pcie_hwops; | ||
896 | else | ||
897 | ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops; | ||
898 | } | ||
899 | #endif /* CONFIG_44x */ | ||
900 | #ifdef CONFIG_40x | ||
901 | if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) | ||
902 | ppc4xx_pciex_hwops = &ppc405ex_pcie_hwops; | ||
903 | #endif | ||
904 | if (ppc4xx_pciex_hwops == NULL) { | ||
905 | printk(KERN_WARNING "PCIE: unknown host type %s\n", | ||
906 | np->full_name); | ||
907 | return -ENODEV; | ||
908 | } | ||
909 | |||
910 | count = ppc4xx_pciex_hwops->core_init(np); | ||
911 | if (count > 0) { | ||
912 | ppc4xx_pciex_ports = | ||
913 | kzalloc(count * sizeof(struct ppc4xx_pciex_port), | ||
914 | GFP_KERNEL); | ||
915 | if (ppc4xx_pciex_ports) { | ||
916 | ppc4xx_pciex_port_count = count; | ||
917 | return 0; | ||
918 | } | ||
919 | printk(KERN_WARNING "PCIE: failed to allocate ports array\n"); | ||
920 | return -ENOMEM; | ||
921 | } | ||
922 | return -ENODEV; | ||
923 | } | ||
924 | |||
925 | static void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port) | ||
926 | { | ||
927 | /* We map PCI Express configuration based on the reg property */ | ||
928 | dcr_write(port->dcrs, DCRO_PEGPL_CFGBAH, | ||
929 | RES_TO_U32_HIGH(port->cfg_space.start)); | ||
930 | dcr_write(port->dcrs, DCRO_PEGPL_CFGBAL, | ||
931 | RES_TO_U32_LOW(port->cfg_space.start)); | ||
932 | |||
933 | /* XXX FIXME: Use size from reg property. For now, map 512M */ | ||
934 | dcr_write(port->dcrs, DCRO_PEGPL_CFGMSK, 0xe0000001); | ||
935 | |||
936 | /* We map UTL registers based on the reg property */ | ||
937 | dcr_write(port->dcrs, DCRO_PEGPL_REGBAH, | ||
938 | RES_TO_U32_HIGH(port->utl_regs.start)); | ||
939 | dcr_write(port->dcrs, DCRO_PEGPL_REGBAL, | ||
940 | RES_TO_U32_LOW(port->utl_regs.start)); | ||
941 | |||
942 | /* XXX FIXME: Use size from reg property */ | ||
943 | dcr_write(port->dcrs, DCRO_PEGPL_REGMSK, 0x00007001); | ||
944 | |||
945 | /* Disable all other outbound windows */ | ||
946 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, 0); | ||
947 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, 0); | ||
948 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0); | ||
949 | dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0); | ||
950 | } | ||
951 | |||
952 | static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port, | ||
953 | unsigned int sdr_offset, | ||
954 | unsigned int mask, | ||
955 | unsigned int value, | ||
956 | int timeout_ms) | ||
957 | { | ||
958 | u32 val; | ||
959 | |||
960 | while(timeout_ms--) { | ||
961 | val = mfdcri(SDR0, port->sdr_base + sdr_offset); | ||
962 | if ((val & mask) == value) { | ||
963 | pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n", | ||
964 | port->index, sdr_offset, timeout_ms, val); | ||
965 | return 0; | ||
966 | } | ||
967 | msleep(1); | ||
968 | } | ||
969 | return -1; | ||
970 | } | ||
971 | |||
972 | static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) | ||
973 | { | ||
974 | int rc = 0; | ||
975 | |||
976 | /* Init HW */ | ||
977 | if (ppc4xx_pciex_hwops->port_init_hw) | ||
978 | rc = ppc4xx_pciex_hwops->port_init_hw(port); | ||
979 | if (rc != 0) | ||
980 | return rc; | ||
981 | |||
982 | printk(KERN_INFO "PCIE%d: Checking link...\n", | ||
983 | port->index); | ||
984 | |||
985 | /* Wait for reset to complete */ | ||
986 | if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) { | ||
987 | printk(KERN_WARNING "PCIE%d: PGRST failed\n", | ||
988 | port->index); | ||
989 | return -1; | ||
990 | } | ||
991 | |||
992 | /* Check for card presence detect if supported, if not, just wait for | ||
993 | * link unconditionally. | ||
994 | * | ||
995 | * note that we don't fail if there is no link, we just filter out | ||
996 | * config space accesses. That way, it will be easier to implement | ||
997 | * hotplug later on. | ||
998 | */ | ||
999 | if (!port->has_ibpre || | ||
1000 | !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, | ||
1001 | 1 << 28, 1 << 28, 100)) { | ||
1002 | printk(KERN_INFO | ||
1003 | "PCIE%d: Device detected, waiting for link...\n", | ||
1004 | port->index); | ||
1005 | if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, | ||
1006 | 0x1000, 0x1000, 2000)) | ||
1007 | printk(KERN_WARNING | ||
1008 | "PCIE%d: Link up failed\n", port->index); | ||
1009 | else { | ||
1010 | printk(KERN_INFO | ||
1011 | "PCIE%d: link is up !\n", port->index); | ||
1012 | port->link = 1; | ||
1013 | } | ||
1014 | } else | ||
1015 | printk(KERN_INFO "PCIE%d: No device detected.\n", port->index); | ||
1016 | |||
1017 | /* | ||
1018 | * Initialize mapping: disable all regions and configure | ||
1019 | * CFG and REG regions based on resources in the device tree | ||
1020 | */ | ||
1021 | ppc4xx_pciex_port_init_mapping(port); | ||
1022 | |||
1023 | /* | ||
1024 | * Map UTL | ||
1025 | */ | ||
1026 | port->utl_base = ioremap(port->utl_regs.start, 0x100); | ||
1027 | BUG_ON(port->utl_base == NULL); | ||
1028 | |||
1029 | /* | ||
1030 | * Setup UTL registers --BenH. | ||
1031 | */ | ||
1032 | if (ppc4xx_pciex_hwops->setup_utl) | ||
1033 | ppc4xx_pciex_hwops->setup_utl(port); | ||
1034 | |||
1035 | /* | ||
1036 | * Check for VC0 active and assert RDY. | ||
1037 | */ | ||
1038 | if (port->link && | ||
1039 | ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, | ||
1040 | 1 << 16, 1 << 16, 5000)) { | ||
1041 | printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); | ||
1042 | port->link = 0; | ||
1043 | } | ||
1044 | |||
1045 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | ||
1046 | mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | 1 << 20); | ||
1047 | msleep(100); | ||
1048 | |||
1049 | return 0; | ||
1050 | } | ||
1051 | |||
1052 | static int ppc4xx_pciex_validate_bdf(struct ppc4xx_pciex_port *port, | ||
1053 | struct pci_bus *bus, | ||
1054 | unsigned int devfn) | ||
1055 | { | ||
1056 | static int message; | ||
1057 | |||
1058 | /* Endpoint can not generate upstream(remote) config cycles */ | ||
1059 | if (port->endpoint && bus->number != port->hose->first_busno) | ||
1060 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1061 | |||
1062 | /* Check we are within the mapped range */ | ||
1063 | if (bus->number > port->hose->last_busno) { | ||
1064 | if (!message) { | ||
1065 | printk(KERN_WARNING "Warning! Probing bus %u" | ||
1066 | " out of range !\n", bus->number); | ||
1067 | message++; | ||
1068 | } | ||
1069 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1070 | } | ||
1071 | |||
1072 | /* The root complex has only one device / function */ | ||
1073 | if (bus->number == port->hose->first_busno && devfn != 0) | ||
1074 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1075 | |||
1076 | /* The other side of the RC has only one device as well */ | ||
1077 | if (bus->number == (port->hose->first_busno + 1) && | ||
1078 | PCI_SLOT(devfn) != 0) | ||
1079 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1080 | |||
1081 | /* Check if we have a link */ | ||
1082 | if ((bus->number != port->hose->first_busno) && !port->link) | ||
1083 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1084 | |||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | static void __iomem *ppc4xx_pciex_get_config_base(struct ppc4xx_pciex_port *port, | ||
1089 | struct pci_bus *bus, | ||
1090 | unsigned int devfn) | ||
1091 | { | ||
1092 | int relbus; | ||
1093 | |||
1094 | /* Remove the casts when we finally remove the stupid volatile | ||
1095 | * in struct pci_controller | ||
1096 | */ | ||
1097 | if (bus->number == port->hose->first_busno) | ||
1098 | return (void __iomem *)port->hose->cfg_addr; | ||
1099 | |||
1100 | relbus = bus->number - (port->hose->first_busno + 1); | ||
1101 | return (void __iomem *)port->hose->cfg_data + | ||
1102 | ((relbus << 20) | (devfn << 12)); | ||
1103 | } | ||
1104 | |||
1105 | static int ppc4xx_pciex_read_config(struct pci_bus *bus, unsigned int devfn, | ||
1106 | int offset, int len, u32 *val) | ||
1107 | { | ||
1108 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | ||
1109 | struct ppc4xx_pciex_port *port = | ||
1110 | &ppc4xx_pciex_ports[hose->indirect_type]; | ||
1111 | void __iomem *addr; | ||
1112 | u32 gpl_cfg; | ||
1113 | |||
1114 | BUG_ON(hose != port->hose); | ||
1115 | |||
1116 | if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) | ||
1117 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1118 | |||
1119 | addr = ppc4xx_pciex_get_config_base(port, bus, devfn); | ||
1120 | |||
1121 | /* | ||
1122 | * Reading from configuration space of non-existing device can | ||
1123 | * generate transaction errors. For the read duration we suppress | ||
1124 | * assertion of machine check exceptions to avoid those. | ||
1125 | */ | ||
1126 | gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG); | ||
1127 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA); | ||
1128 | |||
1129 | /* Make sure no CRS is recorded */ | ||
1130 | out_be32(port->utl_base + PEUTL_RCSTA, 0x00040000); | ||
1131 | |||
1132 | switch (len) { | ||
1133 | case 1: | ||
1134 | *val = in_8((u8 *)(addr + offset)); | ||
1135 | break; | ||
1136 | case 2: | ||
1137 | *val = in_le16((u16 *)(addr + offset)); | ||
1138 | break; | ||
1139 | default: | ||
1140 | *val = in_le32((u32 *)(addr + offset)); | ||
1141 | break; | ||
1142 | } | ||
1143 | |||
1144 | pr_debug("pcie-config-read: bus=%3d [%3d..%3d] devfn=0x%04x" | ||
1145 | " offset=0x%04x len=%d, addr=0x%p val=0x%08x\n", | ||
1146 | bus->number, hose->first_busno, hose->last_busno, | ||
1147 | devfn, offset, len, addr + offset, *val); | ||
1148 | |||
1149 | /* Check for CRS (440SPe rev B does that for us but heh ..) */ | ||
1150 | if (in_be32(port->utl_base + PEUTL_RCSTA) & 0x00040000) { | ||
1151 | pr_debug("Got CRS !\n"); | ||
1152 | if (len != 4 || offset != 0) | ||
1153 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1154 | *val = 0xffff0001; | ||
1155 | } | ||
1156 | |||
1157 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg); | ||
1158 | |||
1159 | return PCIBIOS_SUCCESSFUL; | ||
1160 | } | ||
1161 | |||
1162 | static int ppc4xx_pciex_write_config(struct pci_bus *bus, unsigned int devfn, | ||
1163 | int offset, int len, u32 val) | ||
1164 | { | ||
1165 | struct pci_controller *hose = (struct pci_controller *) bus->sysdata; | ||
1166 | struct ppc4xx_pciex_port *port = | ||
1167 | &ppc4xx_pciex_ports[hose->indirect_type]; | ||
1168 | void __iomem *addr; | ||
1169 | u32 gpl_cfg; | ||
1170 | |||
1171 | if (ppc4xx_pciex_validate_bdf(port, bus, devfn) != 0) | ||
1172 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
1173 | |||
1174 | addr = ppc4xx_pciex_get_config_base(port, bus, devfn); | ||
1175 | |||
1176 | /* | ||
1177 | * Reading from configuration space of non-existing device can | ||
1178 | * generate transaction errors. For the read duration we suppress | ||
1179 | * assertion of machine check exceptions to avoid those. | ||
1180 | */ | ||
1181 | gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG); | ||
1182 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA); | ||
1183 | |||
1184 | pr_debug("pcie-config-write: bus=%3d [%3d..%3d] devfn=0x%04x" | ||
1185 | " offset=0x%04x len=%d, addr=0x%p val=0x%08x\n", | ||
1186 | bus->number, hose->first_busno, hose->last_busno, | ||
1187 | devfn, offset, len, addr + offset, val); | ||
1188 | |||
1189 | switch (len) { | ||
1190 | case 1: | ||
1191 | out_8((u8 *)(addr + offset), val); | ||
1192 | break; | ||
1193 | case 2: | ||
1194 | out_le16((u16 *)(addr + offset), val); | ||
1195 | break; | ||
1196 | default: | ||
1197 | out_le32((u32 *)(addr + offset), val); | ||
1198 | break; | ||
1199 | } | ||
1200 | |||
1201 | dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg); | ||
1202 | |||
1203 | return PCIBIOS_SUCCESSFUL; | ||
1204 | } | ||
1205 | |||
1206 | static struct pci_ops ppc4xx_pciex_pci_ops = | ||
1207 | { | ||
1208 | .read = ppc4xx_pciex_read_config, | ||
1209 | .write = ppc4xx_pciex_write_config, | ||
1210 | }; | ||
1211 | |||
1212 | static void __init ppc4xx_configure_pciex_POMs(struct ppc4xx_pciex_port *port, | ||
1213 | struct pci_controller *hose, | ||
1214 | void __iomem *mbase) | ||
1215 | { | ||
1216 | u32 lah, lal, pciah, pcial, sa; | ||
1217 | int i, j; | ||
1218 | |||
1219 | /* Setup outbound memory windows */ | ||
1220 | for (i = j = 0; i < 3; i++) { | ||
1221 | struct resource *res = &hose->mem_resources[i]; | ||
1222 | |||
1223 | /* we only care about memory windows */ | ||
1224 | if (!(res->flags & IORESOURCE_MEM)) | ||
1225 | continue; | ||
1226 | if (j > 1) { | ||
1227 | printk(KERN_WARNING "%s: Too many ranges\n", | ||
1228 | port->node->full_name); | ||
1229 | break; | ||
1230 | } | ||
1231 | |||
1232 | /* Calculate register values */ | ||
1233 | lah = RES_TO_U32_HIGH(res->start); | ||
1234 | lal = RES_TO_U32_LOW(res->start); | ||
1235 | pciah = RES_TO_U32_HIGH(res->start - hose->pci_mem_offset); | ||
1236 | pcial = RES_TO_U32_LOW(res->start - hose->pci_mem_offset); | ||
1237 | sa = res->end + 1 - res->start; | ||
1238 | if (!is_power_of_2(sa) || sa < 0x100000 || | ||
1239 | sa > 0xffffffffu) { | ||
1240 | printk(KERN_WARNING "%s: Resource out of range\n", | ||
1241 | port->node->full_name); | ||
1242 | continue; | ||
1243 | } | ||
1244 | sa = (0xffffffffu << ilog2(sa)) | 0x1; | ||
1245 | |||
1246 | /* Program register values */ | ||
1247 | switch (j) { | ||
1248 | case 0: | ||
1249 | out_le32(mbase + PECFG_POM0LAH, pciah); | ||
1250 | out_le32(mbase + PECFG_POM0LAL, pcial); | ||
1251 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAH, lah); | ||
1252 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1BAL, lal); | ||
1253 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKH, 0x7fffffff); | ||
1254 | dcr_write(port->dcrs, DCRO_PEGPL_OMR1MSKL, sa | 3); | ||
1255 | break; | ||
1256 | case 1: | ||
1257 | out_le32(mbase + PECFG_POM1LAH, pciah); | ||
1258 | out_le32(mbase + PECFG_POM1LAL, pcial); | ||
1259 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAH, lah); | ||
1260 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2BAL, lal); | ||
1261 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKH, 0x7fffffff); | ||
1262 | dcr_write(port->dcrs, DCRO_PEGPL_OMR2MSKL, sa | 3); | ||
1263 | break; | ||
1264 | } | ||
1265 | j++; | ||
1266 | } | ||
1267 | |||
1268 | /* Configure IO, always 64K starting at 0 */ | ||
1269 | if (hose->io_resource.flags & IORESOURCE_IO) { | ||
1270 | lah = RES_TO_U32_HIGH(hose->io_base_phys); | ||
1271 | lal = RES_TO_U32_LOW(hose->io_base_phys); | ||
1272 | out_le32(mbase + PECFG_POM2LAH, 0); | ||
1273 | out_le32(mbase + PECFG_POM2LAL, 0); | ||
1274 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAH, lah); | ||
1275 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3BAL, lal); | ||
1276 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKH, 0x7fffffff); | ||
1277 | dcr_write(port->dcrs, DCRO_PEGPL_OMR3MSKL, 0xffff0000 | 3); | ||
1278 | } | ||
1279 | } | ||
1280 | |||
1281 | static void __init ppc4xx_configure_pciex_PIMs(struct ppc4xx_pciex_port *port, | ||
1282 | struct pci_controller *hose, | ||
1283 | void __iomem *mbase, | ||
1284 | struct resource *res) | ||
1285 | { | ||
1286 | resource_size_t size = res->end - res->start + 1; | ||
1287 | u64 sa; | ||
1288 | |||
1289 | /* Calculate window size */ | ||
1290 | sa = (0xffffffffffffffffull << ilog2(size));; | ||
1291 | if (res->flags & IORESOURCE_PREFETCH) | ||
1292 | sa |= 0x8; | ||
1293 | |||
1294 | out_le32(mbase + PECFG_BAR0HMPA, RES_TO_U32_HIGH(sa)); | ||
1295 | out_le32(mbase + PECFG_BAR0LMPA, RES_TO_U32_LOW(sa)); | ||
1296 | |||
1297 | /* The setup of the split looks weird to me ... let's see if it works */ | ||
1298 | out_le32(mbase + PECFG_PIM0LAL, 0x00000000); | ||
1299 | out_le32(mbase + PECFG_PIM0LAH, 0x00000000); | ||
1300 | out_le32(mbase + PECFG_PIM1LAL, 0x00000000); | ||
1301 | out_le32(mbase + PECFG_PIM1LAH, 0x00000000); | ||
1302 | out_le32(mbase + PECFG_PIM01SAH, 0xffff0000); | ||
1303 | out_le32(mbase + PECFG_PIM01SAL, 0x00000000); | ||
1304 | |||
1305 | /* Enable inbound mapping */ | ||
1306 | out_le32(mbase + PECFG_PIMEN, 0x1); | ||
1307 | |||
1308 | out_le32(mbase + PCI_BASE_ADDRESS_0, RES_TO_U32_LOW(res->start)); | ||
1309 | out_le32(mbase + PCI_BASE_ADDRESS_1, RES_TO_U32_HIGH(res->start)); | ||
1310 | |||
1311 | /* Enable I/O, Mem, and Busmaster cycles */ | ||
1312 | out_le16(mbase + PCI_COMMAND, | ||
1313 | in_le16(mbase + PCI_COMMAND) | | ||
1314 | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); | ||
1315 | } | ||
1316 | |||
1317 | static void __init ppc4xx_pciex_port_setup_hose(struct ppc4xx_pciex_port *port) | ||
1318 | { | ||
1319 | struct resource dma_window; | ||
1320 | struct pci_controller *hose = NULL; | ||
1321 | const int *bus_range; | ||
1322 | int primary = 0, busses; | ||
1323 | void __iomem *mbase = NULL, *cfg_data = NULL; | ||
1324 | |||
1325 | /* XXX FIXME: Handle endpoint mode properly */ | ||
1326 | if (port->endpoint) { | ||
1327 | printk(KERN_WARNING "PCIE%d: Port in endpoint mode !\n", | ||
1328 | port->index); | ||
1329 | return; | ||
1330 | } | ||
1331 | |||
1332 | /* Check if primary bridge */ | ||
1333 | if (of_get_property(port->node, "primary", NULL)) | ||
1334 | primary = 1; | ||
1335 | |||
1336 | /* Get bus range if any */ | ||
1337 | bus_range = of_get_property(port->node, "bus-range", NULL); | ||
1338 | |||
1339 | /* Allocate the host controller data structure */ | ||
1340 | hose = pcibios_alloc_controller(port->node); | ||
1341 | if (!hose) | ||
1342 | goto fail; | ||
1343 | |||
1344 | /* We stick the port number in "indirect_type" so the config space | ||
1345 | * ops can retrieve the port data structure easily | ||
1346 | */ | ||
1347 | hose->indirect_type = port->index; | ||
1348 | |||
1349 | /* Get bus range */ | ||
1350 | hose->first_busno = bus_range ? bus_range[0] : 0x0; | ||
1351 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
1352 | |||
1353 | /* Because of how big mapping the config space is (1M per bus), we | ||
1354 | * limit how many busses we support. In the long run, we could replace | ||
1355 | * that with something akin to kmap_atomic instead. We set aside 1 bus | ||
1356 | * for the host itself too. | ||
1357 | */ | ||
1358 | busses = hose->last_busno - hose->first_busno; /* This is off by 1 */ | ||
1359 | if (busses > MAX_PCIE_BUS_MAPPED) { | ||
1360 | busses = MAX_PCIE_BUS_MAPPED; | ||
1361 | hose->last_busno = hose->first_busno + busses; | ||
1362 | } | ||
1363 | |||
1364 | /* We map the external config space in cfg_data and the host config | ||
1365 | * space in cfg_addr. External space is 1M per bus, internal space | ||
1366 | * is 4K | ||
1367 | */ | ||
1368 | cfg_data = ioremap(port->cfg_space.start + | ||
1369 | (hose->first_busno + 1) * 0x100000, | ||
1370 | busses * 0x100000); | ||
1371 | mbase = ioremap(port->cfg_space.start + 0x10000000, 0x1000); | ||
1372 | if (cfg_data == NULL || mbase == NULL) { | ||
1373 | printk(KERN_ERR "%s: Can't map config space !", | ||
1374 | port->node->full_name); | ||
1375 | goto fail; | ||
1376 | } | ||
1377 | |||
1378 | hose->cfg_data = cfg_data; | ||
1379 | hose->cfg_addr = mbase; | ||
1380 | |||
1381 | pr_debug("PCIE %s, bus %d..%d\n", port->node->full_name, | ||
1382 | hose->first_busno, hose->last_busno); | ||
1383 | pr_debug(" config space mapped at: root @0x%p, other @0x%p\n", | ||
1384 | hose->cfg_addr, hose->cfg_data); | ||
1385 | |||
1386 | /* Setup config space */ | ||
1387 | hose->ops = &ppc4xx_pciex_pci_ops; | ||
1388 | port->hose = hose; | ||
1389 | mbase = (void __iomem *)hose->cfg_addr; | ||
1390 | |||
1391 | /* | ||
1392 | * Set bus numbers on our root port | ||
1393 | */ | ||
1394 | out_8(mbase + PCI_PRIMARY_BUS, hose->first_busno); | ||
1395 | out_8(mbase + PCI_SECONDARY_BUS, hose->first_busno + 1); | ||
1396 | out_8(mbase + PCI_SUBORDINATE_BUS, hose->last_busno); | ||
1397 | |||
1398 | /* | ||
1399 | * OMRs are already reset, also disable PIMs | ||
1400 | */ | ||
1401 | out_le32(mbase + PECFG_PIMEN, 0); | ||
1402 | |||
1403 | /* Parse outbound mapping resources */ | ||
1404 | pci_process_bridge_OF_ranges(hose, port->node, primary); | ||
1405 | |||
1406 | /* Parse inbound mapping resources */ | ||
1407 | if (ppc4xx_parse_dma_ranges(hose, mbase, &dma_window) != 0) | ||
1408 | goto fail; | ||
1409 | |||
1410 | /* Configure outbound ranges POMs */ | ||
1411 | ppc4xx_configure_pciex_POMs(port, hose, mbase); | ||
1412 | |||
1413 | /* Configure inbound ranges PIMs */ | ||
1414 | ppc4xx_configure_pciex_PIMs(port, hose, mbase, &dma_window); | ||
1415 | |||
1416 | /* The root complex doesn't show up if we don't set some vendor | ||
1417 | * and device IDs into it. Those are the same bogus one that the | ||
1418 | * initial code in arch/ppc add. We might want to change that. | ||
1419 | */ | ||
1420 | out_le16(mbase + 0x200, 0xaaa0 + port->index); | ||
1421 | out_le16(mbase + 0x202, 0xbed0 + port->index); | ||
1422 | |||
1423 | /* Set Class Code to PCI-PCI bridge and Revision Id to 1 */ | ||
1424 | out_le32(mbase + 0x208, 0x06040001); | ||
1425 | |||
1426 | printk(KERN_INFO "PCIE%d: successfully set as root-complex\n", | ||
1427 | port->index); | ||
1428 | return; | ||
1429 | fail: | ||
1430 | if (hose) | ||
1431 | pcibios_free_controller(hose); | ||
1432 | if (cfg_data) | ||
1433 | iounmap(cfg_data); | ||
1434 | if (mbase) | ||
1435 | iounmap(mbase); | ||
1436 | } | ||
1437 | |||
1438 | static void __init ppc4xx_probe_pciex_bridge(struct device_node *np) | ||
1439 | { | ||
1440 | struct ppc4xx_pciex_port *port; | ||
1441 | const u32 *pval; | ||
1442 | int portno; | ||
1443 | unsigned int dcrs; | ||
1444 | |||
1445 | /* First, proceed to core initialization as we assume there's | ||
1446 | * only one PCIe core in the system | ||
1447 | */ | ||
1448 | if (ppc4xx_pciex_check_core_init(np)) | ||
1449 | return; | ||
1450 | |||
1451 | /* Get the port number from the device-tree */ | ||
1452 | pval = of_get_property(np, "port", NULL); | ||
1453 | if (pval == NULL) { | ||
1454 | printk(KERN_ERR "PCIE: Can't find port number for %s\n", | ||
1455 | np->full_name); | ||
1456 | return; | ||
1457 | } | ||
1458 | portno = *pval; | ||
1459 | if (portno >= ppc4xx_pciex_port_count) { | ||
1460 | printk(KERN_ERR "PCIE: port number out of range for %s\n", | ||
1461 | np->full_name); | ||
1462 | return; | ||
1463 | } | ||
1464 | port = &ppc4xx_pciex_ports[portno]; | ||
1465 | port->index = portno; | ||
1466 | port->node = of_node_get(np); | ||
1467 | pval = of_get_property(np, "sdr-base", NULL); | ||
1468 | if (pval == NULL) { | ||
1469 | printk(KERN_ERR "PCIE: missing sdr-base for %s\n", | ||
1470 | np->full_name); | ||
1471 | return; | ||
1472 | } | ||
1473 | port->sdr_base = *pval; | ||
1474 | |||
1475 | /* XXX Currently, we only support root complex mode */ | ||
1476 | port->endpoint = 0; | ||
1477 | |||
1478 | /* Fetch config space registers address */ | ||
1479 | if (of_address_to_resource(np, 0, &port->cfg_space)) { | ||
1480 | printk(KERN_ERR "%s: Can't get PCI-E config space !", | ||
1481 | np->full_name); | ||
1482 | return; | ||
1483 | } | ||
1484 | /* Fetch host bridge internal registers address */ | ||
1485 | if (of_address_to_resource(np, 1, &port->utl_regs)) { | ||
1486 | printk(KERN_ERR "%s: Can't get UTL register base !", | ||
1487 | np->full_name); | ||
1488 | return; | ||
1489 | } | ||
1490 | |||
1491 | /* Map DCRs */ | ||
1492 | dcrs = dcr_resource_start(np, 0); | ||
1493 | if (dcrs == 0) { | ||
1494 | printk(KERN_ERR "%s: Can't get DCR register base !", | ||
1495 | np->full_name); | ||
1496 | return; | ||
1497 | } | ||
1498 | port->dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0)); | ||
1499 | |||
1500 | /* Initialize the port specific registers */ | ||
1501 | if (ppc4xx_pciex_port_init(port)) { | ||
1502 | printk(KERN_WARNING "PCIE%d: Port init failed\n", port->index); | ||
1503 | return; | ||
1504 | } | ||
1505 | |||
1506 | /* Setup the linux hose data structure */ | ||
1507 | ppc4xx_pciex_port_setup_hose(port); | ||
1508 | } | ||
1509 | |||
1510 | #endif /* CONFIG_PPC4xx_PCI_EXPRESS */ | ||
1511 | |||
1512 | static int __init ppc4xx_pci_find_bridges(void) | ||
1513 | { | ||
1514 | struct device_node *np; | ||
1515 | |||
1516 | #ifdef CONFIG_PPC4xx_PCI_EXPRESS | ||
1517 | for_each_compatible_node(np, NULL, "ibm,plb-pciex") | ||
1518 | ppc4xx_probe_pciex_bridge(np); | ||
1519 | #endif | ||
1520 | for_each_compatible_node(np, NULL, "ibm,plb-pcix") | ||
1521 | ppc4xx_probe_pcix_bridge(np); | ||
1522 | for_each_compatible_node(np, NULL, "ibm,plb-pci") | ||
1523 | ppc4xx_probe_pci_bridge(np); | ||
1524 | |||
1525 | return 0; | ||
1526 | } | ||
1527 | arch_initcall(ppc4xx_pci_find_bridges); | ||
1528 | |||
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.h b/arch/powerpc/sysdev/ppc4xx_pci.h new file mode 100644 index 000000000000..1c07908dc6ef --- /dev/null +++ b/arch/powerpc/sysdev/ppc4xx_pci.h | |||
@@ -0,0 +1,369 @@ | |||
1 | /* | ||
2 | * PCI / PCI-X / PCI-Express support for 4xx parts | ||
3 | * | ||
4 | * Copyright 2007 Ben. Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. | ||
5 | * | ||
6 | * Bits and pieces extracted from arch/ppc support by | ||
7 | * | ||
8 | * Matt Porter <mporter@kernel.crashing.org> | ||
9 | * | ||
10 | * Copyright 2002-2005 MontaVista Software Inc. | ||
11 | */ | ||
12 | #ifndef __PPC4XX_PCI_H__ | ||
13 | #define __PPC4XX_PCI_H__ | ||
14 | |||
15 | /* | ||
16 | * 4xx PCI-X bridge register definitions | ||
17 | */ | ||
18 | #define PCIX0_VENDID 0x000 | ||
19 | #define PCIX0_DEVID 0x002 | ||
20 | #define PCIX0_COMMAND 0x004 | ||
21 | #define PCIX0_STATUS 0x006 | ||
22 | #define PCIX0_REVID 0x008 | ||
23 | #define PCIX0_CLS 0x009 | ||
24 | #define PCIX0_CACHELS 0x00c | ||
25 | #define PCIX0_LATTIM 0x00d | ||
26 | #define PCIX0_HDTYPE 0x00e | ||
27 | #define PCIX0_BIST 0x00f | ||
28 | #define PCIX0_BAR0L 0x010 | ||
29 | #define PCIX0_BAR0H 0x014 | ||
30 | #define PCIX0_BAR1 0x018 | ||
31 | #define PCIX0_BAR2L 0x01c | ||
32 | #define PCIX0_BAR2H 0x020 | ||
33 | #define PCIX0_BAR3 0x024 | ||
34 | #define PCIX0_CISPTR 0x028 | ||
35 | #define PCIX0_SBSYSVID 0x02c | ||
36 | #define PCIX0_SBSYSID 0x02e | ||
37 | #define PCIX0_EROMBA 0x030 | ||
38 | #define PCIX0_CAP 0x034 | ||
39 | #define PCIX0_RES0 0x035 | ||
40 | #define PCIX0_RES1 0x036 | ||
41 | #define PCIX0_RES2 0x038 | ||
42 | #define PCIX0_INTLN 0x03c | ||
43 | #define PCIX0_INTPN 0x03d | ||
44 | #define PCIX0_MINGNT 0x03e | ||
45 | #define PCIX0_MAXLTNCY 0x03f | ||
46 | #define PCIX0_BRDGOPT1 0x040 | ||
47 | #define PCIX0_BRDGOPT2 0x044 | ||
48 | #define PCIX0_ERREN 0x050 | ||
49 | #define PCIX0_ERRSTS 0x054 | ||
50 | #define PCIX0_PLBBESR 0x058 | ||
51 | #define PCIX0_PLBBEARL 0x05c | ||
52 | #define PCIX0_PLBBEARH 0x060 | ||
53 | #define PCIX0_POM0LAL 0x068 | ||
54 | #define PCIX0_POM0LAH 0x06c | ||
55 | #define PCIX0_POM0SA 0x070 | ||
56 | #define PCIX0_POM0PCIAL 0x074 | ||
57 | #define PCIX0_POM0PCIAH 0x078 | ||
58 | #define PCIX0_POM1LAL 0x07c | ||
59 | #define PCIX0_POM1LAH 0x080 | ||
60 | #define PCIX0_POM1SA 0x084 | ||
61 | #define PCIX0_POM1PCIAL 0x088 | ||
62 | #define PCIX0_POM1PCIAH 0x08c | ||
63 | #define PCIX0_POM2SA 0x090 | ||
64 | #define PCIX0_PIM0SAL 0x098 | ||
65 | #define PCIX0_PIM0SA PCIX0_PIM0SAL | ||
66 | #define PCIX0_PIM0LAL 0x09c | ||
67 | #define PCIX0_PIM0LAH 0x0a0 | ||
68 | #define PCIX0_PIM1SA 0x0a4 | ||
69 | #define PCIX0_PIM1LAL 0x0a8 | ||
70 | #define PCIX0_PIM1LAH 0x0ac | ||
71 | #define PCIX0_PIM2SAL 0x0b0 | ||
72 | #define PCIX0_PIM2SA PCIX0_PIM2SAL | ||
73 | #define PCIX0_PIM2LAL 0x0b4 | ||
74 | #define PCIX0_PIM2LAH 0x0b8 | ||
75 | #define PCIX0_OMCAPID 0x0c0 | ||
76 | #define PCIX0_OMNIPTR 0x0c1 | ||
77 | #define PCIX0_OMMC 0x0c2 | ||
78 | #define PCIX0_OMMA 0x0c4 | ||
79 | #define PCIX0_OMMUA 0x0c8 | ||
80 | #define PCIX0_OMMDATA 0x0cc | ||
81 | #define PCIX0_OMMEOI 0x0ce | ||
82 | #define PCIX0_PMCAPID 0x0d0 | ||
83 | #define PCIX0_PMNIPTR 0x0d1 | ||
84 | #define PCIX0_PMC 0x0d2 | ||
85 | #define PCIX0_PMCSR 0x0d4 | ||
86 | #define PCIX0_PMCSRBSE 0x0d6 | ||
87 | #define PCIX0_PMDATA 0x0d7 | ||
88 | #define PCIX0_PMSCRR 0x0d8 | ||
89 | #define PCIX0_CAPID 0x0dc | ||
90 | #define PCIX0_NIPTR 0x0dd | ||
91 | #define PCIX0_CMD 0x0de | ||
92 | #define PCIX0_STS 0x0e0 | ||
93 | #define PCIX0_IDR 0x0e4 | ||
94 | #define PCIX0_CID 0x0e8 | ||
95 | #define PCIX0_RID 0x0ec | ||
96 | #define PCIX0_PIM0SAH 0x0f8 | ||
97 | #define PCIX0_PIM2SAH 0x0fc | ||
98 | #define PCIX0_MSGIL 0x100 | ||
99 | #define PCIX0_MSGIH 0x104 | ||
100 | #define PCIX0_MSGOL 0x108 | ||
101 | #define PCIX0_MSGOH 0x10c | ||
102 | #define PCIX0_IM 0x1f8 | ||
103 | |||
104 | /* | ||
105 | * 4xx PCI bridge register definitions | ||
106 | */ | ||
107 | #define PCIL0_PMM0LA 0x00 | ||
108 | #define PCIL0_PMM0MA 0x04 | ||
109 | #define PCIL0_PMM0PCILA 0x08 | ||
110 | #define PCIL0_PMM0PCIHA 0x0c | ||
111 | #define PCIL0_PMM1LA 0x10 | ||
112 | #define PCIL0_PMM1MA 0x14 | ||
113 | #define PCIL0_PMM1PCILA 0x18 | ||
114 | #define PCIL0_PMM1PCIHA 0x1c | ||
115 | #define PCIL0_PMM2LA 0x20 | ||
116 | #define PCIL0_PMM2MA 0x24 | ||
117 | #define PCIL0_PMM2PCILA 0x28 | ||
118 | #define PCIL0_PMM2PCIHA 0x2c | ||
119 | #define PCIL0_PTM1MS 0x30 | ||
120 | #define PCIL0_PTM1LA 0x34 | ||
121 | #define PCIL0_PTM2MS 0x38 | ||
122 | #define PCIL0_PTM2LA 0x3c | ||
123 | |||
124 | /* | ||
125 | * 4xx PCIe bridge register definitions | ||
126 | */ | ||
127 | |||
128 | /* DCR offsets */ | ||
129 | #define DCRO_PEGPL_CFGBAH 0x00 | ||
130 | #define DCRO_PEGPL_CFGBAL 0x01 | ||
131 | #define DCRO_PEGPL_CFGMSK 0x02 | ||
132 | #define DCRO_PEGPL_MSGBAH 0x03 | ||
133 | #define DCRO_PEGPL_MSGBAL 0x04 | ||
134 | #define DCRO_PEGPL_MSGMSK 0x05 | ||
135 | #define DCRO_PEGPL_OMR1BAH 0x06 | ||
136 | #define DCRO_PEGPL_OMR1BAL 0x07 | ||
137 | #define DCRO_PEGPL_OMR1MSKH 0x08 | ||
138 | #define DCRO_PEGPL_OMR1MSKL 0x09 | ||
139 | #define DCRO_PEGPL_OMR2BAH 0x0a | ||
140 | #define DCRO_PEGPL_OMR2BAL 0x0b | ||
141 | #define DCRO_PEGPL_OMR2MSKH 0x0c | ||
142 | #define DCRO_PEGPL_OMR2MSKL 0x0d | ||
143 | #define DCRO_PEGPL_OMR3BAH 0x0e | ||
144 | #define DCRO_PEGPL_OMR3BAL 0x0f | ||
145 | #define DCRO_PEGPL_OMR3MSKH 0x10 | ||
146 | #define DCRO_PEGPL_OMR3MSKL 0x11 | ||
147 | #define DCRO_PEGPL_REGBAH 0x12 | ||
148 | #define DCRO_PEGPL_REGBAL 0x13 | ||
149 | #define DCRO_PEGPL_REGMSK 0x14 | ||
150 | #define DCRO_PEGPL_SPECIAL 0x15 | ||
151 | #define DCRO_PEGPL_CFG 0x16 | ||
152 | #define DCRO_PEGPL_ESR 0x17 | ||
153 | #define DCRO_PEGPL_EARH 0x18 | ||
154 | #define DCRO_PEGPL_EARL 0x19 | ||
155 | #define DCRO_PEGPL_EATR 0x1a | ||
156 | |||
157 | /* DMER mask */ | ||
158 | #define GPL_DMER_MASK_DISA 0x02000000 | ||
159 | |||
160 | /* | ||
161 | * System DCRs (SDRs) | ||
162 | */ | ||
163 | #define PESDR0_PLLLCT1 0x03a0 | ||
164 | #define PESDR0_PLLLCT2 0x03a1 | ||
165 | #define PESDR0_PLLLCT3 0x03a2 | ||
166 | |||
167 | /* | ||
168 | * 440SPe additional DCRs | ||
169 | */ | ||
170 | #define PESDR0_440SPE_UTLSET1 0x0300 | ||
171 | #define PESDR0_440SPE_UTLSET2 0x0301 | ||
172 | #define PESDR0_440SPE_DLPSET 0x0302 | ||
173 | #define PESDR0_440SPE_LOOP 0x0303 | ||
174 | #define PESDR0_440SPE_RCSSET 0x0304 | ||
175 | #define PESDR0_440SPE_RCSSTS 0x0305 | ||
176 | #define PESDR0_440SPE_HSSL0SET1 0x0306 | ||
177 | #define PESDR0_440SPE_HSSL0SET2 0x0307 | ||
178 | #define PESDR0_440SPE_HSSL0STS 0x0308 | ||
179 | #define PESDR0_440SPE_HSSL1SET1 0x0309 | ||
180 | #define PESDR0_440SPE_HSSL1SET2 0x030a | ||
181 | #define PESDR0_440SPE_HSSL1STS 0x030b | ||
182 | #define PESDR0_440SPE_HSSL2SET1 0x030c | ||
183 | #define PESDR0_440SPE_HSSL2SET2 0x030d | ||
184 | #define PESDR0_440SPE_HSSL2STS 0x030e | ||
185 | #define PESDR0_440SPE_HSSL3SET1 0x030f | ||
186 | #define PESDR0_440SPE_HSSL3SET2 0x0310 | ||
187 | #define PESDR0_440SPE_HSSL3STS 0x0311 | ||
188 | #define PESDR0_440SPE_HSSL4SET1 0x0312 | ||
189 | #define PESDR0_440SPE_HSSL4SET2 0x0313 | ||
190 | #define PESDR0_440SPE_HSSL4STS 0x0314 | ||
191 | #define PESDR0_440SPE_HSSL5SET1 0x0315 | ||
192 | #define PESDR0_440SPE_HSSL5SET2 0x0316 | ||
193 | #define PESDR0_440SPE_HSSL5STS 0x0317 | ||
194 | #define PESDR0_440SPE_HSSL6SET1 0x0318 | ||
195 | #define PESDR0_440SPE_HSSL6SET2 0x0319 | ||
196 | #define PESDR0_440SPE_HSSL6STS 0x031a | ||
197 | #define PESDR0_440SPE_HSSL7SET1 0x031b | ||
198 | #define PESDR0_440SPE_HSSL7SET2 0x031c | ||
199 | #define PESDR0_440SPE_HSSL7STS 0x031d | ||
200 | #define PESDR0_440SPE_HSSCTLSET 0x031e | ||
201 | #define PESDR0_440SPE_LANE_ABCD 0x031f | ||
202 | #define PESDR0_440SPE_LANE_EFGH 0x0320 | ||
203 | |||
204 | #define PESDR1_440SPE_UTLSET1 0x0340 | ||
205 | #define PESDR1_440SPE_UTLSET2 0x0341 | ||
206 | #define PESDR1_440SPE_DLPSET 0x0342 | ||
207 | #define PESDR1_440SPE_LOOP 0x0343 | ||
208 | #define PESDR1_440SPE_RCSSET 0x0344 | ||
209 | #define PESDR1_440SPE_RCSSTS 0x0345 | ||
210 | #define PESDR1_440SPE_HSSL0SET1 0x0346 | ||
211 | #define PESDR1_440SPE_HSSL0SET2 0x0347 | ||
212 | #define PESDR1_440SPE_HSSL0STS 0x0348 | ||
213 | #define PESDR1_440SPE_HSSL1SET1 0x0349 | ||
214 | #define PESDR1_440SPE_HSSL1SET2 0x034a | ||
215 | #define PESDR1_440SPE_HSSL1STS 0x034b | ||
216 | #define PESDR1_440SPE_HSSL2SET1 0x034c | ||
217 | #define PESDR1_440SPE_HSSL2SET2 0x034d | ||
218 | #define PESDR1_440SPE_HSSL2STS 0x034e | ||
219 | #define PESDR1_440SPE_HSSL3SET1 0x034f | ||
220 | #define PESDR1_440SPE_HSSL3SET2 0x0350 | ||
221 | #define PESDR1_440SPE_HSSL3STS 0x0351 | ||
222 | #define PESDR1_440SPE_HSSCTLSET 0x0352 | ||
223 | #define PESDR1_440SPE_LANE_ABCD 0x0353 | ||
224 | |||
225 | #define PESDR2_440SPE_UTLSET1 0x0370 | ||
226 | #define PESDR2_440SPE_UTLSET2 0x0371 | ||
227 | #define PESDR2_440SPE_DLPSET 0x0372 | ||
228 | #define PESDR2_440SPE_LOOP 0x0373 | ||
229 | #define PESDR2_440SPE_RCSSET 0x0374 | ||
230 | #define PESDR2_440SPE_RCSSTS 0x0375 | ||
231 | #define PESDR2_440SPE_HSSL0SET1 0x0376 | ||
232 | #define PESDR2_440SPE_HSSL0SET2 0x0377 | ||
233 | #define PESDR2_440SPE_HSSL0STS 0x0378 | ||
234 | #define PESDR2_440SPE_HSSL1SET1 0x0379 | ||
235 | #define PESDR2_440SPE_HSSL1SET2 0x037a | ||
236 | #define PESDR2_440SPE_HSSL1STS 0x037b | ||
237 | #define PESDR2_440SPE_HSSL2SET1 0x037c | ||
238 | #define PESDR2_440SPE_HSSL2SET2 0x037d | ||
239 | #define PESDR2_440SPE_HSSL2STS 0x037e | ||
240 | #define PESDR2_440SPE_HSSL3SET1 0x037f | ||
241 | #define PESDR2_440SPE_HSSL3SET2 0x0380 | ||
242 | #define PESDR2_440SPE_HSSL3STS 0x0381 | ||
243 | #define PESDR2_440SPE_HSSCTLSET 0x0382 | ||
244 | #define PESDR2_440SPE_LANE_ABCD 0x0383 | ||
245 | |||
246 | /* | ||
247 | * 405EX additional DCRs | ||
248 | */ | ||
249 | #define PESDR0_405EX_UTLSET1 0x0400 | ||
250 | #define PESDR0_405EX_UTLSET2 0x0401 | ||
251 | #define PESDR0_405EX_DLPSET 0x0402 | ||
252 | #define PESDR0_405EX_LOOP 0x0403 | ||
253 | #define PESDR0_405EX_RCSSET 0x0404 | ||
254 | #define PESDR0_405EX_RCSSTS 0x0405 | ||
255 | #define PESDR0_405EX_PHYSET1 0x0406 | ||
256 | #define PESDR0_405EX_PHYSET2 0x0407 | ||
257 | #define PESDR0_405EX_BIST 0x0408 | ||
258 | #define PESDR0_405EX_LPB 0x040B | ||
259 | #define PESDR0_405EX_PHYSTA 0x040C | ||
260 | |||
261 | #define PESDR1_405EX_UTLSET1 0x0440 | ||
262 | #define PESDR1_405EX_UTLSET2 0x0441 | ||
263 | #define PESDR1_405EX_DLPSET 0x0442 | ||
264 | #define PESDR1_405EX_LOOP 0x0443 | ||
265 | #define PESDR1_405EX_RCSSET 0x0444 | ||
266 | #define PESDR1_405EX_RCSSTS 0x0445 | ||
267 | #define PESDR1_405EX_PHYSET1 0x0446 | ||
268 | #define PESDR1_405EX_PHYSET2 0x0447 | ||
269 | #define PESDR1_405EX_BIST 0x0448 | ||
270 | #define PESDR1_405EX_LPB 0x044B | ||
271 | #define PESDR1_405EX_PHYSTA 0x044C | ||
272 | |||
273 | /* | ||
274 | * Of the above, some are common offsets from the base | ||
275 | */ | ||
276 | #define PESDRn_UTLSET1 0x00 | ||
277 | #define PESDRn_UTLSET2 0x01 | ||
278 | #define PESDRn_DLPSET 0x02 | ||
279 | #define PESDRn_LOOP 0x03 | ||
280 | #define PESDRn_RCSSET 0x04 | ||
281 | #define PESDRn_RCSSTS 0x05 | ||
282 | |||
283 | /* 440spe only */ | ||
284 | #define PESDRn_440SPE_HSSL0SET1 0x06 | ||
285 | #define PESDRn_440SPE_HSSL0SET2 0x07 | ||
286 | #define PESDRn_440SPE_HSSL0STS 0x08 | ||
287 | #define PESDRn_440SPE_HSSL1SET1 0x09 | ||
288 | #define PESDRn_440SPE_HSSL1SET2 0x0a | ||
289 | #define PESDRn_440SPE_HSSL1STS 0x0b | ||
290 | #define PESDRn_440SPE_HSSL2SET1 0x0c | ||
291 | #define PESDRn_440SPE_HSSL2SET2 0x0d | ||
292 | #define PESDRn_440SPE_HSSL2STS 0x0e | ||
293 | #define PESDRn_440SPE_HSSL3SET1 0x0f | ||
294 | #define PESDRn_440SPE_HSSL3SET2 0x10 | ||
295 | #define PESDRn_440SPE_HSSL3STS 0x11 | ||
296 | |||
297 | /* 440spe port 0 only */ | ||
298 | #define PESDRn_440SPE_HSSL4SET1 0x12 | ||
299 | #define PESDRn_440SPE_HSSL4SET2 0x13 | ||
300 | #define PESDRn_440SPE_HSSL4STS 0x14 | ||
301 | #define PESDRn_440SPE_HSSL5SET1 0x15 | ||
302 | #define PESDRn_440SPE_HSSL5SET2 0x16 | ||
303 | #define PESDRn_440SPE_HSSL5STS 0x17 | ||
304 | #define PESDRn_440SPE_HSSL6SET1 0x18 | ||
305 | #define PESDRn_440SPE_HSSL6SET2 0x19 | ||
306 | #define PESDRn_440SPE_HSSL6STS 0x1a | ||
307 | #define PESDRn_440SPE_HSSL7SET1 0x1b | ||
308 | #define PESDRn_440SPE_HSSL7SET2 0x1c | ||
309 | #define PESDRn_440SPE_HSSL7STS 0x1d | ||
310 | |||
311 | /* 405ex only */ | ||
312 | #define PESDRn_405EX_PHYSET1 0x06 | ||
313 | #define PESDRn_405EX_PHYSET2 0x07 | ||
314 | #define PESDRn_405EX_PHYSTA 0x0c | ||
315 | |||
316 | /* | ||
317 | * UTL register offsets | ||
318 | */ | ||
319 | #define PEUTL_PBCTL 0x00 | ||
320 | #define PEUTL_PBBSZ 0x20 | ||
321 | #define PEUTL_OPDBSZ 0x68 | ||
322 | #define PEUTL_IPHBSZ 0x70 | ||
323 | #define PEUTL_IPDBSZ 0x78 | ||
324 | #define PEUTL_OUTTR 0x90 | ||
325 | #define PEUTL_INTR 0x98 | ||
326 | #define PEUTL_PCTL 0xa0 | ||
327 | #define PEUTL_RCSTA 0xB0 | ||
328 | #define PEUTL_RCIRQEN 0xb8 | ||
329 | |||
330 | /* | ||
331 | * Config space register offsets | ||
332 | */ | ||
333 | #define PECFG_ECRTCTL 0x074 | ||
334 | |||
335 | #define PECFG_BAR0LMPA 0x210 | ||
336 | #define PECFG_BAR0HMPA 0x214 | ||
337 | #define PECFG_BAR1MPA 0x218 | ||
338 | #define PECFG_BAR2LMPA 0x220 | ||
339 | #define PECFG_BAR2HMPA 0x224 | ||
340 | |||
341 | #define PECFG_PIMEN 0x33c | ||
342 | #define PECFG_PIM0LAL 0x340 | ||
343 | #define PECFG_PIM0LAH 0x344 | ||
344 | #define PECFG_PIM1LAL 0x348 | ||
345 | #define PECFG_PIM1LAH 0x34c | ||
346 | #define PECFG_PIM01SAL 0x350 | ||
347 | #define PECFG_PIM01SAH 0x354 | ||
348 | |||
349 | #define PECFG_POM0LAL 0x380 | ||
350 | #define PECFG_POM0LAH 0x384 | ||
351 | #define PECFG_POM1LAL 0x388 | ||
352 | #define PECFG_POM1LAH 0x38c | ||
353 | #define PECFG_POM2LAL 0x390 | ||
354 | #define PECFG_POM2LAH 0x394 | ||
355 | |||
356 | |||
357 | enum | ||
358 | { | ||
359 | PTYPE_ENDPOINT = 0x0, | ||
360 | PTYPE_LEGACY_ENDPOINT = 0x1, | ||
361 | PTYPE_ROOT_PORT = 0x4, | ||
362 | |||
363 | LNKW_X1 = 0x1, | ||
364 | LNKW_X4 = 0x4, | ||
365 | LNKW_X8 = 0x8 | ||
366 | }; | ||
367 | |||
368 | |||
369 | #endif /* __PPC4XX_PCI_H__ */ | ||
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig index f611d344a126..adc66212a419 100644 --- a/arch/powerpc/sysdev/qe_lib/Kconfig +++ b/arch/powerpc/sysdev/qe_lib/Kconfig | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | config UCC_SLOW | 5 | config UCC_SLOW |
6 | bool | 6 | bool |
7 | default n | 7 | default y if SERIAL_QE |
8 | help | 8 | help |
9 | This option provides qe_lib support to UCC slow | 9 | This option provides qe_lib support to UCC slow |
10 | protocols: UART, BISYNC, QMC | 10 | protocols: UART, BISYNC, QMC |
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 3d57d3835b04..5ef844da9355 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/ioport.h> | 27 | #include <linux/ioport.h> |
28 | #include <linux/crc32.h> | ||
28 | #include <asm/irq.h> | 29 | #include <asm/irq.h> |
29 | #include <asm/page.h> | 30 | #include <asm/page.h> |
30 | #include <asm/pgtable.h> | 31 | #include <asm/pgtable.h> |
@@ -64,17 +65,22 @@ static phys_addr_t qebase = -1; | |||
64 | phys_addr_t get_qe_base(void) | 65 | phys_addr_t get_qe_base(void) |
65 | { | 66 | { |
66 | struct device_node *qe; | 67 | struct device_node *qe; |
68 | unsigned int size; | ||
69 | const void *prop; | ||
67 | 70 | ||
68 | if (qebase != -1) | 71 | if (qebase != -1) |
69 | return qebase; | 72 | return qebase; |
70 | 73 | ||
71 | qe = of_find_node_by_type(NULL, "qe"); | 74 | qe = of_find_compatible_node(NULL, NULL, "fsl,qe"); |
72 | if (qe) { | 75 | if (!qe) { |
73 | unsigned int size; | 76 | qe = of_find_node_by_type(NULL, "qe"); |
74 | const void *prop = of_get_property(qe, "reg", &size); | 77 | if (!qe) |
75 | qebase = of_translate_address(qe, prop); | 78 | return qebase; |
76 | of_node_put(qe); | 79 | } |
77 | }; | 80 | |
81 | prop = of_get_property(qe, "reg", &size); | ||
82 | qebase = of_translate_address(qe, prop); | ||
83 | of_node_put(qe); | ||
78 | 84 | ||
79 | return qebase; | 85 | return qebase; |
80 | } | 86 | } |
@@ -152,34 +158,45 @@ static unsigned int brg_clk = 0; | |||
152 | unsigned int get_brg_clk(void) | 158 | unsigned int get_brg_clk(void) |
153 | { | 159 | { |
154 | struct device_node *qe; | 160 | struct device_node *qe; |
161 | unsigned int size; | ||
162 | const u32 *prop; | ||
163 | |||
155 | if (brg_clk) | 164 | if (brg_clk) |
156 | return brg_clk; | 165 | return brg_clk; |
157 | 166 | ||
158 | qe = of_find_node_by_type(NULL, "qe"); | 167 | qe = of_find_compatible_node(NULL, NULL, "fsl,qe"); |
159 | if (qe) { | 168 | if (!qe) { |
160 | unsigned int size; | 169 | qe = of_find_node_by_type(NULL, "qe"); |
161 | const u32 *prop = of_get_property(qe, "brg-frequency", &size); | 170 | if (!qe) |
162 | brg_clk = *prop; | 171 | return brg_clk; |
163 | of_node_put(qe); | 172 | } |
164 | }; | 173 | |
174 | prop = of_get_property(qe, "brg-frequency", &size); | ||
175 | if (!prop || size != sizeof(*prop)) | ||
176 | return brg_clk; | ||
177 | |||
178 | brg_clk = *prop; | ||
179 | of_node_put(qe); | ||
180 | |||
165 | return brg_clk; | 181 | return brg_clk; |
166 | } | 182 | } |
167 | 183 | ||
168 | /* Program the BRG to the given sampling rate and multiplier | 184 | /* Program the BRG to the given sampling rate and multiplier |
169 | * | 185 | * |
170 | * @brg: the BRG, 1-16 | 186 | * @brg: the BRG, QE_BRG1 - QE_BRG16 |
171 | * @rate: the desired sampling rate | 187 | * @rate: the desired sampling rate |
172 | * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or | 188 | * @multiplier: corresponds to the value programmed in GUMR_L[RDCR] or |
173 | * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01, | 189 | * GUMR_L[TDCR]. E.g., if this BRG is the RX clock, and GUMR_L[RDCR]=01, |
174 | * then 'multiplier' should be 8. | 190 | * then 'multiplier' should be 8. |
175 | * | ||
176 | * Also note that the value programmed into the BRGC register must be even. | ||
177 | */ | 191 | */ |
178 | void qe_setbrg(unsigned int brg, unsigned int rate, unsigned int multiplier) | 192 | int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier) |
179 | { | 193 | { |
180 | u32 divisor, tempval; | 194 | u32 divisor, tempval; |
181 | u32 div16 = 0; | 195 | u32 div16 = 0; |
182 | 196 | ||
197 | if ((brg < QE_BRG1) || (brg > QE_BRG16)) | ||
198 | return -EINVAL; | ||
199 | |||
183 | divisor = get_brg_clk() / (rate * multiplier); | 200 | divisor = get_brg_clk() / (rate * multiplier); |
184 | 201 | ||
185 | if (divisor > QE_BRGC_DIVISOR_MAX + 1) { | 202 | if (divisor > QE_BRGC_DIVISOR_MAX + 1) { |
@@ -196,8 +213,43 @@ void qe_setbrg(unsigned int brg, unsigned int rate, unsigned int multiplier) | |||
196 | tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | | 213 | tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | |
197 | QE_BRGC_ENABLE | div16; | 214 | QE_BRGC_ENABLE | div16; |
198 | 215 | ||
199 | out_be32(&qe_immr->brg.brgc[brg - 1], tempval); | 216 | out_be32(&qe_immr->brg.brgc[brg - QE_BRG1], tempval); |
217 | |||
218 | return 0; | ||
219 | } | ||
220 | EXPORT_SYMBOL(qe_setbrg); | ||
221 | |||
222 | /* Convert a string to a QE clock source enum | ||
223 | * | ||
224 | * This function takes a string, typically from a property in the device | ||
225 | * tree, and returns the corresponding "enum qe_clock" value. | ||
226 | */ | ||
227 | enum qe_clock qe_clock_source(const char *source) | ||
228 | { | ||
229 | unsigned int i; | ||
230 | |||
231 | if (strcasecmp(source, "none") == 0) | ||
232 | return QE_CLK_NONE; | ||
233 | |||
234 | if (strncasecmp(source, "brg", 3) == 0) { | ||
235 | i = simple_strtoul(source + 3, NULL, 10); | ||
236 | if ((i >= 1) && (i <= 16)) | ||
237 | return (QE_BRG1 - 1) + i; | ||
238 | else | ||
239 | return QE_CLK_DUMMY; | ||
240 | } | ||
241 | |||
242 | if (strncasecmp(source, "clk", 3) == 0) { | ||
243 | i = simple_strtoul(source + 3, NULL, 10); | ||
244 | if ((i >= 1) && (i <= 24)) | ||
245 | return (QE_CLK1 - 1) + i; | ||
246 | else | ||
247 | return QE_CLK_DUMMY; | ||
248 | } | ||
249 | |||
250 | return QE_CLK_DUMMY; | ||
200 | } | 251 | } |
252 | EXPORT_SYMBOL(qe_clock_source); | ||
201 | 253 | ||
202 | /* Initialize SNUMs (thread serial numbers) according to | 254 | /* Initialize SNUMs (thread serial numbers) according to |
203 | * QE Module Control chapter, SNUM table | 255 | * QE Module Control chapter, SNUM table |
@@ -285,7 +337,7 @@ static rh_info_t qe_muram_info; | |||
285 | static void qe_muram_init(void) | 337 | static void qe_muram_init(void) |
286 | { | 338 | { |
287 | struct device_node *np; | 339 | struct device_node *np; |
288 | u32 address; | 340 | const u32 *address; |
289 | u64 size; | 341 | u64 size; |
290 | unsigned int flags; | 342 | unsigned int flags; |
291 | 343 | ||
@@ -298,11 +350,21 @@ static void qe_muram_init(void) | |||
298 | /* XXX: This is a subset of the available muram. It | 350 | /* XXX: This is a subset of the available muram. It |
299 | * varies with the processor and the microcode patches activated. | 351 | * varies with the processor and the microcode patches activated. |
300 | */ | 352 | */ |
301 | if ((np = of_find_node_by_name(NULL, "data-only")) != NULL) { | 353 | np = of_find_compatible_node(NULL, NULL, "fsl,qe-muram-data"); |
302 | address = *of_get_address(np, 0, &size, &flags); | 354 | if (!np) { |
303 | of_node_put(np); | 355 | np = of_find_node_by_name(NULL, "data-only"); |
304 | rh_attach_region(&qe_muram_info, address, (int) size); | 356 | if (!np) { |
357 | WARN_ON(1); | ||
358 | return; | ||
359 | } | ||
305 | } | 360 | } |
361 | |||
362 | address = of_get_address(np, 0, &size, &flags); | ||
363 | WARN_ON(!address); | ||
364 | |||
365 | of_node_put(np); | ||
366 | if (address) | ||
367 | rh_attach_region(&qe_muram_info, *address, (int)size); | ||
306 | } | 368 | } |
307 | 369 | ||
308 | /* This function returns an index into the MURAM area. | 370 | /* This function returns an index into the MURAM area. |
@@ -358,3 +420,249 @@ void *qe_muram_addr(unsigned long offset) | |||
358 | return (void *)&qe_immr->muram[offset]; | 420 | return (void *)&qe_immr->muram[offset]; |
359 | } | 421 | } |
360 | EXPORT_SYMBOL(qe_muram_addr); | 422 | EXPORT_SYMBOL(qe_muram_addr); |
423 | |||
424 | /* The maximum number of RISCs we support */ | ||
425 | #define MAX_QE_RISC 2 | ||
426 | |||
427 | /* Firmware information stored here for qe_get_firmware_info() */ | ||
428 | static struct qe_firmware_info qe_firmware_info; | ||
429 | |||
430 | /* | ||
431 | * Set to 1 if QE firmware has been uploaded, and therefore | ||
432 | * qe_firmware_info contains valid data. | ||
433 | */ | ||
434 | static int qe_firmware_uploaded; | ||
435 | |||
436 | /* | ||
437 | * Upload a QE microcode | ||
438 | * | ||
439 | * This function is a worker function for qe_upload_firmware(). It does | ||
440 | * the actual uploading of the microcode. | ||
441 | */ | ||
442 | static void qe_upload_microcode(const void *base, | ||
443 | const struct qe_microcode *ucode) | ||
444 | { | ||
445 | const __be32 *code = base + be32_to_cpu(ucode->code_offset); | ||
446 | unsigned int i; | ||
447 | |||
448 | if (ucode->major || ucode->minor || ucode->revision) | ||
449 | printk(KERN_INFO "qe-firmware: " | ||
450 | "uploading microcode '%s' version %u.%u.%u\n", | ||
451 | ucode->id, ucode->major, ucode->minor, ucode->revision); | ||
452 | else | ||
453 | printk(KERN_INFO "qe-firmware: " | ||
454 | "uploading microcode '%s'\n", ucode->id); | ||
455 | |||
456 | /* Use auto-increment */ | ||
457 | out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) | | ||
458 | QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR); | ||
459 | |||
460 | for (i = 0; i < be32_to_cpu(ucode->count); i++) | ||
461 | out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i])); | ||
462 | } | ||
463 | |||
464 | /* | ||
465 | * Upload a microcode to the I-RAM at a specific address. | ||
466 | * | ||
467 | * See Documentation/powerpc/qe-firmware.txt for information on QE microcode | ||
468 | * uploading. | ||
469 | * | ||
470 | * Currently, only version 1 is supported, so the 'version' field must be | ||
471 | * set to 1. | ||
472 | * | ||
473 | * The SOC model and revision are not validated, they are only displayed for | ||
474 | * informational purposes. | ||
475 | * | ||
476 | * 'calc_size' is the calculated size, in bytes, of the firmware structure and | ||
477 | * all of the microcode structures, minus the CRC. | ||
478 | * | ||
479 | * 'length' is the size that the structure says it is, including the CRC. | ||
480 | */ | ||
481 | int qe_upload_firmware(const struct qe_firmware *firmware) | ||
482 | { | ||
483 | unsigned int i; | ||
484 | unsigned int j; | ||
485 | u32 crc; | ||
486 | size_t calc_size = sizeof(struct qe_firmware); | ||
487 | size_t length; | ||
488 | const struct qe_header *hdr; | ||
489 | |||
490 | if (!firmware) { | ||
491 | printk(KERN_ERR "qe-firmware: invalid pointer\n"); | ||
492 | return -EINVAL; | ||
493 | } | ||
494 | |||
495 | hdr = &firmware->header; | ||
496 | length = be32_to_cpu(hdr->length); | ||
497 | |||
498 | /* Check the magic */ | ||
499 | if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') || | ||
500 | (hdr->magic[2] != 'F')) { | ||
501 | printk(KERN_ERR "qe-firmware: not a microcode\n"); | ||
502 | return -EPERM; | ||
503 | } | ||
504 | |||
505 | /* Check the version */ | ||
506 | if (hdr->version != 1) { | ||
507 | printk(KERN_ERR "qe-firmware: unsupported version\n"); | ||
508 | return -EPERM; | ||
509 | } | ||
510 | |||
511 | /* Validate some of the fields */ | ||
512 | if ((firmware->count < 1) || (firmware->count >= MAX_QE_RISC)) { | ||
513 | printk(KERN_ERR "qe-firmware: invalid data\n"); | ||
514 | return -EINVAL; | ||
515 | } | ||
516 | |||
517 | /* Validate the length and check if there's a CRC */ | ||
518 | calc_size += (firmware->count - 1) * sizeof(struct qe_microcode); | ||
519 | |||
520 | for (i = 0; i < firmware->count; i++) | ||
521 | /* | ||
522 | * For situations where the second RISC uses the same microcode | ||
523 | * as the first, the 'code_offset' and 'count' fields will be | ||
524 | * zero, so it's okay to add those. | ||
525 | */ | ||
526 | calc_size += sizeof(__be32) * | ||
527 | be32_to_cpu(firmware->microcode[i].count); | ||
528 | |||
529 | /* Validate the length */ | ||
530 | if (length != calc_size + sizeof(__be32)) { | ||
531 | printk(KERN_ERR "qe-firmware: invalid length\n"); | ||
532 | return -EPERM; | ||
533 | } | ||
534 | |||
535 | /* Validate the CRC */ | ||
536 | crc = be32_to_cpu(*(__be32 *)((void *)firmware + calc_size)); | ||
537 | if (crc != crc32(0, firmware, calc_size)) { | ||
538 | printk(KERN_ERR "qe-firmware: firmware CRC is invalid\n"); | ||
539 | return -EIO; | ||
540 | } | ||
541 | |||
542 | /* | ||
543 | * If the microcode calls for it, split the I-RAM. | ||
544 | */ | ||
545 | if (!firmware->split) | ||
546 | setbits16(&qe_immr->cp.cercr, QE_CP_CERCR_CIR); | ||
547 | |||
548 | if (firmware->soc.model) | ||
549 | printk(KERN_INFO | ||
550 | "qe-firmware: firmware '%s' for %u V%u.%u\n", | ||
551 | firmware->id, be16_to_cpu(firmware->soc.model), | ||
552 | firmware->soc.major, firmware->soc.minor); | ||
553 | else | ||
554 | printk(KERN_INFO "qe-firmware: firmware '%s'\n", | ||
555 | firmware->id); | ||
556 | |||
557 | /* | ||
558 | * The QE only supports one microcode per RISC, so clear out all the | ||
559 | * saved microcode information and put in the new. | ||
560 | */ | ||
561 | memset(&qe_firmware_info, 0, sizeof(qe_firmware_info)); | ||
562 | strcpy(qe_firmware_info.id, firmware->id); | ||
563 | qe_firmware_info.extended_modes = firmware->extended_modes; | ||
564 | memcpy(qe_firmware_info.vtraps, firmware->vtraps, | ||
565 | sizeof(firmware->vtraps)); | ||
566 | |||
567 | /* Loop through each microcode. */ | ||
568 | for (i = 0; i < firmware->count; i++) { | ||
569 | const struct qe_microcode *ucode = &firmware->microcode[i]; | ||
570 | |||
571 | /* Upload a microcode if it's present */ | ||
572 | if (ucode->code_offset) | ||
573 | qe_upload_microcode(firmware, ucode); | ||
574 | |||
575 | /* Program the traps for this processor */ | ||
576 | for (j = 0; j < 16; j++) { | ||
577 | u32 trap = be32_to_cpu(ucode->traps[j]); | ||
578 | |||
579 | if (trap) | ||
580 | out_be32(&qe_immr->rsp[i].tibcr[j], trap); | ||
581 | } | ||
582 | |||
583 | /* Enable traps */ | ||
584 | out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr)); | ||
585 | } | ||
586 | |||
587 | qe_firmware_uploaded = 1; | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | EXPORT_SYMBOL(qe_upload_firmware); | ||
592 | |||
593 | /* | ||
594 | * Get info on the currently-loaded firmware | ||
595 | * | ||
596 | * This function also checks the device tree to see if the boot loader has | ||
597 | * uploaded a firmware already. | ||
598 | */ | ||
599 | struct qe_firmware_info *qe_get_firmware_info(void) | ||
600 | { | ||
601 | static int initialized; | ||
602 | struct property *prop; | ||
603 | struct device_node *qe; | ||
604 | struct device_node *fw = NULL; | ||
605 | const char *sprop; | ||
606 | unsigned int i; | ||
607 | |||
608 | /* | ||
609 | * If we haven't checked yet, and a driver hasn't uploaded a firmware | ||
610 | * yet, then check the device tree for information. | ||
611 | */ | ||
612 | if (initialized || qe_firmware_uploaded) | ||
613 | return NULL; | ||
614 | |||
615 | initialized = 1; | ||
616 | |||
617 | /* | ||
618 | * Newer device trees have an "fsl,qe" compatible property for the QE | ||
619 | * node, but we still need to support older device trees. | ||
620 | */ | ||
621 | qe = of_find_compatible_node(NULL, NULL, "fsl,qe"); | ||
622 | if (!qe) { | ||
623 | qe = of_find_node_by_type(NULL, "qe"); | ||
624 | if (!qe) | ||
625 | return NULL; | ||
626 | } | ||
627 | |||
628 | /* Find the 'firmware' child node */ | ||
629 | for_each_child_of_node(qe, fw) { | ||
630 | if (strcmp(fw->name, "firmware") == 0) | ||
631 | break; | ||
632 | } | ||
633 | |||
634 | of_node_put(qe); | ||
635 | |||
636 | /* Did we find the 'firmware' node? */ | ||
637 | if (!fw) | ||
638 | return NULL; | ||
639 | |||
640 | qe_firmware_uploaded = 1; | ||
641 | |||
642 | /* Copy the data into qe_firmware_info*/ | ||
643 | sprop = of_get_property(fw, "id", NULL); | ||
644 | if (sprop) | ||
645 | strncpy(qe_firmware_info.id, sprop, | ||
646 | sizeof(qe_firmware_info.id) - 1); | ||
647 | |||
648 | prop = of_find_property(fw, "extended-modes", NULL); | ||
649 | if (prop && (prop->length == sizeof(u64))) { | ||
650 | const u64 *iprop = prop->value; | ||
651 | |||
652 | qe_firmware_info.extended_modes = *iprop; | ||
653 | } | ||
654 | |||
655 | prop = of_find_property(fw, "virtual-traps", NULL); | ||
656 | if (prop && (prop->length == 32)) { | ||
657 | const u32 *iprop = prop->value; | ||
658 | |||
659 | for (i = 0; i < ARRAY_SIZE(qe_firmware_info.vtraps); i++) | ||
660 | qe_firmware_info.vtraps[i] = iprop[i]; | ||
661 | } | ||
662 | |||
663 | of_node_put(fw); | ||
664 | |||
665 | return &qe_firmware_info; | ||
666 | } | ||
667 | EXPORT_SYMBOL(qe_get_firmware_info); | ||
668 | |||
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c index 0174b3aeef8f..b2870b208ddb 100644 --- a/arch/powerpc/sysdev/qe_lib/ucc_slow.c +++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/stddef.h> | 19 | #include <linux/stddef.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/module.h> | ||
22 | 23 | ||
23 | #include <asm/io.h> | 24 | #include <asm/io.h> |
24 | #include <asm/immap_qe.h> | 25 | #include <asm/immap_qe.h> |
@@ -41,6 +42,7 @@ u32 ucc_slow_get_qe_cr_subblock(int uccs_num) | |||
41 | default: return QE_CR_SUBBLOCK_INVALID; | 42 | default: return QE_CR_SUBBLOCK_INVALID; |
42 | } | 43 | } |
43 | } | 44 | } |
45 | EXPORT_SYMBOL(ucc_slow_get_qe_cr_subblock); | ||
44 | 46 | ||
45 | void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs) | 47 | void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs) |
46 | { | 48 | { |
@@ -56,6 +58,7 @@ void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs) | |||
56 | qe_issue_cmd(QE_GRACEFUL_STOP_TX, id, | 58 | qe_issue_cmd(QE_GRACEFUL_STOP_TX, id, |
57 | QE_CR_PROTOCOL_UNSPECIFIED, 0); | 59 | QE_CR_PROTOCOL_UNSPECIFIED, 0); |
58 | } | 60 | } |
61 | EXPORT_SYMBOL(ucc_slow_graceful_stop_tx); | ||
59 | 62 | ||
60 | void ucc_slow_stop_tx(struct ucc_slow_private * uccs) | 63 | void ucc_slow_stop_tx(struct ucc_slow_private * uccs) |
61 | { | 64 | { |
@@ -65,6 +68,7 @@ void ucc_slow_stop_tx(struct ucc_slow_private * uccs) | |||
65 | id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); | 68 | id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); |
66 | qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); | 69 | qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); |
67 | } | 70 | } |
71 | EXPORT_SYMBOL(ucc_slow_stop_tx); | ||
68 | 72 | ||
69 | void ucc_slow_restart_tx(struct ucc_slow_private * uccs) | 73 | void ucc_slow_restart_tx(struct ucc_slow_private * uccs) |
70 | { | 74 | { |
@@ -74,6 +78,7 @@ void ucc_slow_restart_tx(struct ucc_slow_private * uccs) | |||
74 | id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); | 78 | id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num); |
75 | qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); | 79 | qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0); |
76 | } | 80 | } |
81 | EXPORT_SYMBOL(ucc_slow_restart_tx); | ||
77 | 82 | ||
78 | void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) | 83 | void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) |
79 | { | 84 | { |
@@ -94,6 +99,7 @@ void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode) | |||
94 | } | 99 | } |
95 | out_be32(&us_regs->gumr_l, gumr_l); | 100 | out_be32(&us_regs->gumr_l, gumr_l); |
96 | } | 101 | } |
102 | EXPORT_SYMBOL(ucc_slow_enable); | ||
97 | 103 | ||
98 | void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) | 104 | void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) |
99 | { | 105 | { |
@@ -114,6 +120,7 @@ void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode) | |||
114 | } | 120 | } |
115 | out_be32(&us_regs->gumr_l, gumr_l); | 121 | out_be32(&us_regs->gumr_l, gumr_l); |
116 | } | 122 | } |
123 | EXPORT_SYMBOL(ucc_slow_disable); | ||
117 | 124 | ||
118 | /* Initialize the UCC for Slow operations | 125 | /* Initialize the UCC for Slow operations |
119 | * | 126 | * |
@@ -347,6 +354,7 @@ int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** ucc | |||
347 | *uccs_ret = uccs; | 354 | *uccs_ret = uccs; |
348 | return 0; | 355 | return 0; |
349 | } | 356 | } |
357 | EXPORT_SYMBOL(ucc_slow_init); | ||
350 | 358 | ||
351 | void ucc_slow_free(struct ucc_slow_private * uccs) | 359 | void ucc_slow_free(struct ucc_slow_private * uccs) |
352 | { | 360 | { |
@@ -366,5 +374,5 @@ void ucc_slow_free(struct ucc_slow_private * uccs) | |||
366 | 374 | ||
367 | kfree(uccs); | 375 | kfree(uccs); |
368 | } | 376 | } |
369 | 377 | EXPORT_SYMBOL(ucc_slow_free); | |
370 | 378 | ||
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c index a113d800cbf0..be2808a292f7 100644 --- a/arch/powerpc/sysdev/tsi108_dev.c +++ b/arch/powerpc/sysdev/tsi108_dev.c | |||
@@ -66,14 +66,12 @@ EXPORT_SYMBOL(get_vir_csrbase); | |||
66 | static int __init tsi108_eth_of_init(void) | 66 | static int __init tsi108_eth_of_init(void) |
67 | { | 67 | { |
68 | struct device_node *np; | 68 | struct device_node *np; |
69 | unsigned int i; | 69 | unsigned int i = 0; |
70 | struct platform_device *tsi_eth_dev; | 70 | struct platform_device *tsi_eth_dev; |
71 | struct resource res; | 71 | struct resource res; |
72 | int ret; | 72 | int ret; |
73 | 73 | ||
74 | for (np = NULL, i = 0; | 74 | for_each_compatible_node(np, "network", "tsi108-ethernet") { |
75 | (np = of_find_compatible_node(np, "network", "tsi108-ethernet")) != NULL; | ||
76 | i++) { | ||
77 | struct resource r[2]; | 75 | struct resource r[2]; |
78 | struct device_node *phy, *mdio; | 76 | struct device_node *phy, *mdio; |
79 | hw_info tsi_eth_data; | 77 | hw_info tsi_eth_data; |
@@ -98,7 +96,7 @@ static int __init tsi108_eth_of_init(void) | |||
98 | __FUNCTION__,r[1].name, r[1].start, r[1].end); | 96 | __FUNCTION__,r[1].name, r[1].start, r[1].end); |
99 | 97 | ||
100 | tsi_eth_dev = | 98 | tsi_eth_dev = |
101 | platform_device_register_simple("tsi-ethernet", i, &r[0], | 99 | platform_device_register_simple("tsi-ethernet", i++, &r[0], |
102 | 1); | 100 | 1); |
103 | 101 | ||
104 | if (IS_ERR(tsi_eth_dev)) { | 102 | if (IS_ERR(tsi_eth_dev)) { |
@@ -154,6 +152,7 @@ static int __init tsi108_eth_of_init(void) | |||
154 | unreg: | 152 | unreg: |
155 | platform_device_unregister(tsi_eth_dev); | 153 | platform_device_unregister(tsi_eth_dev); |
156 | err: | 154 | err: |
155 | of_node_put(np); | ||
157 | return ret; | 156 | return ret; |
158 | } | 157 | } |
159 | 158 | ||
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 847a5496b869..625b275c3795 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c | |||
@@ -53,21 +53,23 @@ struct uic { | |||
53 | 53 | ||
54 | /* The remapper for this UIC */ | 54 | /* The remapper for this UIC */ |
55 | struct irq_host *irqhost; | 55 | struct irq_host *irqhost; |
56 | |||
57 | /* For secondary UICs, the cascade interrupt's irqaction */ | ||
58 | struct irqaction cascade; | ||
59 | }; | 56 | }; |
60 | 57 | ||
61 | static void uic_unmask_irq(unsigned int virq) | 58 | static void uic_unmask_irq(unsigned int virq) |
62 | { | 59 | { |
60 | struct irq_desc *desc = get_irq_desc(virq); | ||
63 | struct uic *uic = get_irq_chip_data(virq); | 61 | struct uic *uic = get_irq_chip_data(virq); |
64 | unsigned int src = uic_irq_to_hw(virq); | 62 | unsigned int src = uic_irq_to_hw(virq); |
65 | unsigned long flags; | 63 | unsigned long flags; |
66 | u32 er; | 64 | u32 er, sr; |
67 | 65 | ||
66 | sr = 1 << (31-src); | ||
68 | spin_lock_irqsave(&uic->lock, flags); | 67 | spin_lock_irqsave(&uic->lock, flags); |
68 | /* ack level-triggered interrupts here */ | ||
69 | if (desc->status & IRQ_LEVEL) | ||
70 | mtdcr(uic->dcrbase + UIC_SR, sr); | ||
69 | er = mfdcr(uic->dcrbase + UIC_ER); | 71 | er = mfdcr(uic->dcrbase + UIC_ER); |
70 | er |= 1 << (31 - src); | 72 | er |= sr; |
71 | mtdcr(uic->dcrbase + UIC_ER, er); | 73 | mtdcr(uic->dcrbase + UIC_ER, er); |
72 | spin_unlock_irqrestore(&uic->lock, flags); | 74 | spin_unlock_irqrestore(&uic->lock, flags); |
73 | } | 75 | } |
@@ -99,6 +101,7 @@ static void uic_ack_irq(unsigned int virq) | |||
99 | 101 | ||
100 | static void uic_mask_ack_irq(unsigned int virq) | 102 | static void uic_mask_ack_irq(unsigned int virq) |
101 | { | 103 | { |
104 | struct irq_desc *desc = get_irq_desc(virq); | ||
102 | struct uic *uic = get_irq_chip_data(virq); | 105 | struct uic *uic = get_irq_chip_data(virq); |
103 | unsigned int src = uic_irq_to_hw(virq); | 106 | unsigned int src = uic_irq_to_hw(virq); |
104 | unsigned long flags; | 107 | unsigned long flags; |
@@ -109,7 +112,16 @@ static void uic_mask_ack_irq(unsigned int virq) | |||
109 | er = mfdcr(uic->dcrbase + UIC_ER); | 112 | er = mfdcr(uic->dcrbase + UIC_ER); |
110 | er &= ~sr; | 113 | er &= ~sr; |
111 | mtdcr(uic->dcrbase + UIC_ER, er); | 114 | mtdcr(uic->dcrbase + UIC_ER, er); |
112 | mtdcr(uic->dcrbase + UIC_SR, sr); | 115 | /* On the UIC, acking (i.e. clearing the SR bit) |
116 | * a level irq will have no effect if the interrupt | ||
117 | * is still asserted by the device, even if | ||
118 | * the interrupt is already masked. Therefore | ||
119 | * we only ack the egde interrupts here, while | ||
120 | * level interrupts are ack'ed after the actual | ||
121 | * isr call in the uic_unmask_irq() | ||
122 | */ | ||
123 | if (!(desc->status & IRQ_LEVEL)) | ||
124 | mtdcr(uic->dcrbase + UIC_SR, sr); | ||
113 | spin_unlock_irqrestore(&uic->lock, flags); | 125 | spin_unlock_irqrestore(&uic->lock, flags); |
114 | } | 126 | } |
115 | 127 | ||
@@ -173,64 +185,6 @@ static struct irq_chip uic_irq_chip = { | |||
173 | .set_type = uic_set_irq_type, | 185 | .set_type = uic_set_irq_type, |
174 | }; | 186 | }; |
175 | 187 | ||
176 | /** | ||
177 | * handle_uic_irq - irq flow handler for UIC | ||
178 | * @irq: the interrupt number | ||
179 | * @desc: the interrupt description structure for this irq | ||
180 | * | ||
181 | * This is modified version of the generic handle_level_irq() suitable | ||
182 | * for the UIC. On the UIC, acking (i.e. clearing the SR bit) a level | ||
183 | * irq will have no effect if the interrupt is still asserted by the | ||
184 | * device, even if the interrupt is already masked. Therefore, unlike | ||
185 | * the standard handle_level_irq(), we must ack the interrupt *after* | ||
186 | * invoking the ISR (which should have de-asserted the interrupt in | ||
187 | * the external source). For edge interrupts we ack at the beginning | ||
188 | * instead of the end, to keep the window in which we can miss an | ||
189 | * interrupt as small as possible. | ||
190 | */ | ||
191 | void fastcall handle_uic_irq(unsigned int irq, struct irq_desc *desc) | ||
192 | { | ||
193 | unsigned int cpu = smp_processor_id(); | ||
194 | struct irqaction *action; | ||
195 | irqreturn_t action_ret; | ||
196 | |||
197 | spin_lock(&desc->lock); | ||
198 | if (desc->status & IRQ_LEVEL) | ||
199 | desc->chip->mask(irq); | ||
200 | else | ||
201 | desc->chip->mask_ack(irq); | ||
202 | |||
203 | if (unlikely(desc->status & IRQ_INPROGRESS)) | ||
204 | goto out_unlock; | ||
205 | desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); | ||
206 | kstat_cpu(cpu).irqs[irq]++; | ||
207 | |||
208 | /* | ||
209 | * If its disabled or no action available | ||
210 | * keep it masked and get out of here | ||
211 | */ | ||
212 | action = desc->action; | ||
213 | if (unlikely(!action || (desc->status & IRQ_DISABLED))) { | ||
214 | desc->status |= IRQ_PENDING; | ||
215 | goto out_unlock; | ||
216 | } | ||
217 | |||
218 | desc->status |= IRQ_INPROGRESS; | ||
219 | desc->status &= ~IRQ_PENDING; | ||
220 | spin_unlock(&desc->lock); | ||
221 | |||
222 | action_ret = handle_IRQ_event(irq, action); | ||
223 | |||
224 | spin_lock(&desc->lock); | ||
225 | desc->status &= ~IRQ_INPROGRESS; | ||
226 | if (desc->status & IRQ_LEVEL) | ||
227 | desc->chip->ack(irq); | ||
228 | if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | ||
229 | desc->chip->unmask(irq); | ||
230 | out_unlock: | ||
231 | spin_unlock(&desc->lock); | ||
232 | } | ||
233 | |||
234 | static int uic_host_map(struct irq_host *h, unsigned int virq, | 188 | static int uic_host_map(struct irq_host *h, unsigned int virq, |
235 | irq_hw_number_t hw) | 189 | irq_hw_number_t hw) |
236 | { | 190 | { |
@@ -239,7 +193,7 @@ static int uic_host_map(struct irq_host *h, unsigned int virq, | |||
239 | set_irq_chip_data(virq, uic); | 193 | set_irq_chip_data(virq, uic); |
240 | /* Despite the name, handle_level_irq() works for both level | 194 | /* Despite the name, handle_level_irq() works for both level |
241 | * and edge irqs on UIC. FIXME: check this is correct */ | 195 | * and edge irqs on UIC. FIXME: check this is correct */ |
242 | set_irq_chip_and_handler(virq, &uic_irq_chip, handle_uic_irq); | 196 | set_irq_chip_and_handler(virq, &uic_irq_chip, handle_level_irq); |
243 | 197 | ||
244 | /* Set default irq type */ | 198 | /* Set default irq type */ |
245 | set_irq_type(virq, IRQ_TYPE_NONE); | 199 | set_irq_type(virq, IRQ_TYPE_NONE); |
@@ -264,23 +218,36 @@ static struct irq_host_ops uic_host_ops = { | |||
264 | .xlate = uic_host_xlate, | 218 | .xlate = uic_host_xlate, |
265 | }; | 219 | }; |
266 | 220 | ||
267 | irqreturn_t uic_cascade(int virq, void *data) | 221 | void uic_irq_cascade(unsigned int virq, struct irq_desc *desc) |
268 | { | 222 | { |
269 | struct uic *uic = data; | 223 | struct uic *uic = get_irq_data(virq); |
270 | u32 msr; | 224 | u32 msr; |
271 | int src; | 225 | int src; |
272 | int subvirq; | 226 | int subvirq; |
273 | 227 | ||
228 | spin_lock(&desc->lock); | ||
229 | if (desc->status & IRQ_LEVEL) | ||
230 | desc->chip->mask(virq); | ||
231 | else | ||
232 | desc->chip->mask_ack(virq); | ||
233 | spin_unlock(&desc->lock); | ||
234 | |||
274 | msr = mfdcr(uic->dcrbase + UIC_MSR); | 235 | msr = mfdcr(uic->dcrbase + UIC_MSR); |
275 | if (!msr) /* spurious interrupt */ | 236 | if (!msr) /* spurious interrupt */ |
276 | return IRQ_HANDLED; | 237 | goto uic_irq_ret; |
277 | 238 | ||
278 | src = 32 - ffs(msr); | 239 | src = 32 - ffs(msr); |
279 | 240 | ||
280 | subvirq = irq_linear_revmap(uic->irqhost, src); | 241 | subvirq = irq_linear_revmap(uic->irqhost, src); |
281 | generic_handle_irq(subvirq); | 242 | generic_handle_irq(subvirq); |
282 | 243 | ||
283 | return IRQ_HANDLED; | 244 | uic_irq_ret: |
245 | spin_lock(&desc->lock); | ||
246 | if (desc->status & IRQ_LEVEL) | ||
247 | desc->chip->ack(virq); | ||
248 | if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) | ||
249 | desc->chip->unmask(virq); | ||
250 | spin_unlock(&desc->lock); | ||
284 | } | 251 | } |
285 | 252 | ||
286 | static struct uic * __init uic_init_one(struct device_node *node) | 253 | static struct uic * __init uic_init_one(struct device_node *node) |
@@ -342,33 +309,27 @@ void __init uic_init_tree(void) | |||
342 | const u32 *interrupts; | 309 | const u32 *interrupts; |
343 | 310 | ||
344 | /* First locate and initialize the top-level UIC */ | 311 | /* First locate and initialize the top-level UIC */ |
345 | 312 | for_each_compatible_node(np, NULL, "ibm,uic") { | |
346 | np = of_find_compatible_node(NULL, NULL, "ibm,uic"); | ||
347 | while (np) { | ||
348 | interrupts = of_get_property(np, "interrupts", NULL); | 313 | interrupts = of_get_property(np, "interrupts", NULL); |
349 | if (! interrupts) | 314 | if (!interrupts) |
350 | break; | 315 | break; |
351 | |||
352 | np = of_find_compatible_node(np, NULL, "ibm,uic"); | ||
353 | } | 316 | } |
354 | 317 | ||
355 | BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the | 318 | BUG_ON(!np); /* uic_init_tree() assumes there's a UIC as the |
356 | * top-level interrupt controller */ | 319 | * top-level interrupt controller */ |
357 | primary_uic = uic_init_one(np); | 320 | primary_uic = uic_init_one(np); |
358 | if (! primary_uic) | 321 | if (!primary_uic) |
359 | panic("Unable to initialize primary UIC %s\n", np->full_name); | 322 | panic("Unable to initialize primary UIC %s\n", np->full_name); |
360 | 323 | ||
361 | irq_set_default_host(primary_uic->irqhost); | 324 | irq_set_default_host(primary_uic->irqhost); |
362 | of_node_put(np); | 325 | of_node_put(np); |
363 | 326 | ||
364 | /* The scan again for cascaded UICs */ | 327 | /* The scan again for cascaded UICs */ |
365 | np = of_find_compatible_node(NULL, NULL, "ibm,uic"); | 328 | for_each_compatible_node(np, NULL, "ibm,uic") { |
366 | while (np) { | ||
367 | interrupts = of_get_property(np, "interrupts", NULL); | 329 | interrupts = of_get_property(np, "interrupts", NULL); |
368 | if (interrupts) { | 330 | if (interrupts) { |
369 | /* Secondary UIC */ | 331 | /* Secondary UIC */ |
370 | int cascade_virq; | 332 | int cascade_virq; |
371 | int ret; | ||
372 | 333 | ||
373 | uic = uic_init_one(np); | 334 | uic = uic_init_one(np); |
374 | if (! uic) | 335 | if (! uic) |
@@ -377,20 +338,11 @@ void __init uic_init_tree(void) | |||
377 | 338 | ||
378 | cascade_virq = irq_of_parse_and_map(np, 0); | 339 | cascade_virq = irq_of_parse_and_map(np, 0); |
379 | 340 | ||
380 | uic->cascade.handler = uic_cascade; | 341 | set_irq_data(cascade_virq, uic); |
381 | uic->cascade.name = "UIC cascade"; | 342 | set_irq_chained_handler(cascade_virq, uic_irq_cascade); |
382 | uic->cascade.dev_id = uic; | ||
383 | |||
384 | ret = setup_irq(cascade_virq, &uic->cascade); | ||
385 | if (ret) | ||
386 | printk(KERN_ERR "Failed to setup_irq(%d) for " | ||
387 | "UIC%d cascade\n", cascade_virq, | ||
388 | uic->index); | ||
389 | 343 | ||
390 | /* FIXME: setup critical cascade?? */ | 344 | /* FIXME: setup critical cascade?? */ |
391 | } | 345 | } |
392 | |||
393 | np = of_find_compatible_node(np, NULL, "ibm,uic"); | ||
394 | } | 346 | } |
395 | } | 347 | } |
396 | 348 | ||
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index c2f17cc43dfa..ba8eea2bcce0 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c | |||
@@ -135,10 +135,16 @@ void __init xilinx_intc_init_tree(void) | |||
135 | struct device_node *np; | 135 | struct device_node *np; |
136 | 136 | ||
137 | /* find top level interrupt controller */ | 137 | /* find top level interrupt controller */ |
138 | for_each_compatible_node(np, NULL, "xilinx,intc") { | 138 | for_each_compatible_node(np, NULL, "xlnx,opb-intc-1.00.c") { |
139 | if (!of_get_property(np, "interrupts", NULL)) | 139 | if (!of_get_property(np, "interrupts", NULL)) |
140 | break; | 140 | break; |
141 | } | 141 | } |
142 | if (!np) { | ||
143 | for_each_compatible_node(np, NULL, "xlnx,xps-intc-1.00.a") { | ||
144 | if (!of_get_property(np, "interrupts", NULL)) | ||
145 | break; | ||
146 | } | ||
147 | } | ||
142 | 148 | ||
143 | /* xilinx interrupt controller needs to be top level */ | 149 | /* xilinx interrupt controller needs to be top level */ |
144 | BUG_ON(!np); | 150 | BUG_ON(!np); |