diff options
| -rw-r--r-- | arch/powerpc/platforms/512x/Kconfig | 1 | ||||
| -rw-r--r-- | arch/powerpc/platforms/512x/Makefile | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads.c | 11 | ||||
| -rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads.h | 16 | ||||
| -rw-r--r-- | arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | 204 |
5 files changed, 233 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig index 5d72dc3435af..c62f893ede19 100644 --- a/arch/powerpc/platforms/512x/Kconfig +++ b/arch/powerpc/platforms/512x/Kconfig | |||
| @@ -13,6 +13,7 @@ config MPC5121_ADS | |||
| 13 | depends on PPC_MULTIPLATFORM && PPC32 | 13 | depends on PPC_MULTIPLATFORM && PPC32 |
| 14 | select DEFAULT_UIMAGE | 14 | select DEFAULT_UIMAGE |
| 15 | select PPC_MPC5121 | 15 | select PPC_MPC5121 |
| 16 | select MPC5121_ADS_CPLD | ||
| 16 | help | 17 | help |
| 17 | This option enables support for the MPC5121E ADS board. | 18 | This option enables support for the MPC5121E ADS board. |
| 18 | 19 | ||
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile index 8090e222a2dd..90be2f5717e6 100644 --- a/arch/powerpc/platforms/512x/Makefile +++ b/arch/powerpc/platforms/512x/Makefile | |||
| @@ -2,5 +2,5 @@ | |||
| 2 | # Makefile for the Freescale PowerPC 512x linux kernel. | 2 | # Makefile for the Freescale PowerPC 512x linux kernel. |
| 3 | # | 3 | # |
| 4 | obj-y += clock.o mpc512x_shared.o | 4 | obj-y += clock.o mpc512x_shared.o |
| 5 | obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o | 5 | obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o mpc5121_ads_cpld.o |
| 6 | obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o | 6 | obj-$(CONFIG_MPC5121_GENERIC) += mpc5121_generic.o |
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c index 3ec9ca34d8e8..5ebf6939a697 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c | |||
| @@ -23,10 +23,21 @@ | |||
| 23 | #include <asm/time.h> | 23 | #include <asm/time.h> |
| 24 | 24 | ||
| 25 | #include "mpc512x.h" | 25 | #include "mpc512x.h" |
| 26 | #include "mpc5121_ads.h" | ||
| 27 | |||
| 28 | static void __init mpc5121_ads_setup_arch(void) | ||
| 29 | { | ||
| 30 | printk(KERN_INFO "MPC5121 ADS board from Freescale Semiconductor\n"); | ||
| 31 | /* | ||
| 32 | * cpld regs are needed early | ||
| 33 | */ | ||
| 34 | mpc5121_ads_cpld_map(); | ||
| 35 | } | ||
| 26 | 36 | ||
| 27 | static void __init mpc5121_ads_init_IRQ(void) | 37 | static void __init mpc5121_ads_init_IRQ(void) |
| 28 | { | 38 | { |
| 29 | mpc512x_init_IRQ(); | 39 | mpc512x_init_IRQ(); |
| 40 | mpc5121_ads_cpld_pic_init(); | ||
| 30 | } | 41 | } |
| 31 | 42 | ||
| 32 | /* | 43 | /* |
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.h b/arch/powerpc/platforms/512x/mpc5121_ads.h new file mode 100644 index 000000000000..662076cfee2f --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms of the GNU General Public License as published by the | ||
| 6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 7 | * option) any later version. | ||
| 8 | * | ||
| 9 | * Prototypes for ADS5121 specific code | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef __MPC512ADS_H__ | ||
| 13 | #define __MPC512ADS_H__ | ||
| 14 | extern void __init mpc5121_ads_cpld_map(void); | ||
| 15 | extern void __init mpc5121_ads_cpld_pic_init(void); | ||
| 16 | #endif /* __MPC512ADS_H__ */ | ||
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c new file mode 100644 index 000000000000..a6ce80566625 --- /dev/null +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | |||
| @@ -0,0 +1,204 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
| 3 | * | ||
| 4 | * Author: John Rigby, <jrigby@freescale.com> | ||
| 5 | * | ||
| 6 | * Description: | ||
| 7 | * MPC5121ADS CPLD irq handling | ||
| 8 | * | ||
| 9 | * This is free software; you can redistribute it and/or modify it | ||
| 10 | * under the terms of the GNU General Public License as published by | ||
| 11 | * the Free Software Foundation; either version 2 of the License, or | ||
| 12 | * (at your option) any later version. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #undef DEBUG | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/interrupt.h> | ||
| 19 | #include <linux/irq.h> | ||
| 20 | #include <linux/io.h> | ||
| 21 | #include <asm/prom.h> | ||
| 22 | |||
| 23 | static struct device_node *cpld_pic_node; | ||
| 24 | static struct irq_host *cpld_pic_host; | ||
| 25 | |||
| 26 | /* | ||
| 27 | * Bits to ignore in the misc_status register | ||
| 28 | * 0x10 touch screen pendown is hard routed to irq1 | ||
| 29 | * 0x02 pci status is read from pci status register | ||
| 30 | */ | ||
| 31 | #define MISC_IGNORE 0x12 | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Nothing to ignore in pci status register | ||
| 35 | */ | ||
| 36 | #define PCI_IGNORE 0x00 | ||
| 37 | |||
| 38 | struct cpld_pic { | ||
| 39 | u8 pci_mask; | ||
| 40 | u8 pci_status; | ||
| 41 | u8 route; | ||
| 42 | u8 misc_mask; | ||
| 43 | u8 misc_status; | ||
| 44 | u8 misc_control; | ||
| 45 | }; | ||
| 46 | |||
| 47 | static struct cpld_pic __iomem *cpld_regs; | ||
| 48 | |||
| 49 | static void __iomem * | ||
| 50 | irq_to_pic_mask(unsigned int irq) | ||
| 51 | { | ||
| 52 | return irq <= 7 ? &cpld_regs->pci_mask : &cpld_regs->misc_mask; | ||
| 53 | } | ||
| 54 | |||
| 55 | static unsigned int | ||
| 56 | irq_to_pic_bit(unsigned int irq) | ||
| 57 | { | ||
| 58 | return 1 << (irq & 0x7); | ||
| 59 | } | ||
| 60 | |||
| 61 | static void | ||
| 62 | cpld_mask_irq(unsigned int irq) | ||
| 63 | { | ||
| 64 | unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; | ||
| 65 | void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); | ||
| 66 | |||
| 67 | out_8(pic_mask, | ||
| 68 | in_8(pic_mask) | irq_to_pic_bit(cpld_irq)); | ||
| 69 | } | ||
| 70 | |||
| 71 | static void | ||
| 72 | cpld_unmask_irq(unsigned int irq) | ||
| 73 | { | ||
| 74 | unsigned int cpld_irq = (unsigned int)irq_map[irq].hwirq; | ||
| 75 | void __iomem *pic_mask = irq_to_pic_mask(cpld_irq); | ||
| 76 | |||
| 77 | out_8(pic_mask, | ||
| 78 | in_8(pic_mask) & ~irq_to_pic_bit(cpld_irq)); | ||
| 79 | } | ||
| 80 | |||
| 81 | static struct irq_chip cpld_pic = { | ||
| 82 | .typename = " CPLD PIC ", | ||
| 83 | .mask = cpld_mask_irq, | ||
| 84 | .ack = cpld_mask_irq, | ||
| 85 | .unmask = cpld_unmask_irq, | ||
| 86 | }; | ||
| 87 | |||
| 88 | static int | ||
| 89 | cpld_pic_get_irq(int offset, u8 ignore, u8 __iomem *statusp, | ||
| 90 | u8 __iomem *maskp) | ||
| 91 | { | ||
| 92 | int cpld_irq; | ||
| 93 | u8 status = in_8(statusp); | ||
| 94 | u8 mask = in_8(maskp); | ||
| 95 | |||
| 96 | /* ignore don't cares and masked irqs */ | ||
| 97 | status |= (ignore | mask); | ||
| 98 | |||
| 99 | if (status == 0xff) | ||
| 100 | return NO_IRQ_IGNORE; | ||
| 101 | |||
| 102 | cpld_irq = ffz(status) + offset; | ||
| 103 | |||
| 104 | return irq_linear_revmap(cpld_pic_host, cpld_irq); | ||
| 105 | } | ||
| 106 | |||
| 107 | static void | ||
| 108 | cpld_pic_cascade(unsigned int irq, struct irq_desc *desc) | ||
| 109 | { | ||
| 110 | irq = cpld_pic_get_irq(0, PCI_IGNORE, &cpld_regs->pci_status, | ||
| 111 | &cpld_regs->pci_mask); | ||
| 112 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { | ||
| 113 | generic_handle_irq(irq); | ||
| 114 | return; | ||
| 115 | } | ||
| 116 | |||
| 117 | irq = cpld_pic_get_irq(8, MISC_IGNORE, &cpld_regs->misc_status, | ||
| 118 | &cpld_regs->misc_mask); | ||
| 119 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) { | ||
| 120 | generic_handle_irq(irq); | ||
| 121 | return; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | static int | ||
| 126 | cpld_pic_host_match(struct irq_host *h, struct device_node *node) | ||
| 127 | { | ||
| 128 | return cpld_pic_node == node; | ||
| 129 | } | ||
| 130 | |||
| 131 | static int | ||
| 132 | cpld_pic_host_map(struct irq_host *h, unsigned int virq, | ||
| 133 | irq_hw_number_t hw) | ||
| 134 | { | ||
| 135 | get_irq_desc(virq)->status |= IRQ_LEVEL; | ||
| 136 | set_irq_chip_and_handler(virq, &cpld_pic, handle_level_irq); | ||
| 137 | return 0; | ||
| 138 | } | ||
| 139 | |||
| 140 | static struct | ||
| 141 | irq_host_ops cpld_pic_host_ops = { | ||
| 142 | .match = cpld_pic_host_match, | ||
| 143 | .map = cpld_pic_host_map, | ||
| 144 | }; | ||
| 145 | |||
| 146 | void __init | ||
| 147 | mpc5121_ads_cpld_map(void) | ||
| 148 | { | ||
| 149 | struct device_node *np = NULL; | ||
| 150 | |||
| 151 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic"); | ||
| 152 | if (!np) { | ||
| 153 | printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n"); | ||
| 154 | return; | ||
| 155 | } | ||
| 156 | |||
| 157 | cpld_regs = of_iomap(np, 0); | ||
| 158 | of_node_put(np); | ||
| 159 | } | ||
| 160 | |||
| 161 | void __init | ||
| 162 | mpc5121_ads_cpld_pic_init(void) | ||
| 163 | { | ||
| 164 | unsigned int cascade_irq; | ||
| 165 | struct device_node *np = NULL; | ||
| 166 | |||
| 167 | pr_debug("cpld_ic_init\n"); | ||
| 168 | |||
| 169 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld-pic"); | ||
| 170 | if (!np) { | ||
| 171 | printk(KERN_ERR "CPLD PIC init: can not find cpld-pic node\n"); | ||
| 172 | return; | ||
| 173 | } | ||
| 174 | |||
| 175 | if (!cpld_regs) | ||
| 176 | goto end; | ||
| 177 | |||
| 178 | cascade_irq = irq_of_parse_and_map(np, 0); | ||
| 179 | if (cascade_irq == NO_IRQ) | ||
| 180 | goto end; | ||
| 181 | |||
| 182 | /* | ||
| 183 | * statically route touch screen pendown through 1 | ||
| 184 | * and ignore it here | ||
| 185 | * route all others through our cascade irq | ||
| 186 | */ | ||
| 187 | out_8(&cpld_regs->route, 0xfd); | ||
| 188 | out_8(&cpld_regs->pci_mask, 0xff); | ||
| 189 | /* unmask pci ints in misc mask */ | ||
| 190 | out_8(&cpld_regs->misc_mask, ~(MISC_IGNORE)); | ||
| 191 | |||
| 192 | cpld_pic_node = of_node_get(np); | ||
| 193 | |||
| 194 | cpld_pic_host = | ||
| 195 | irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, 16, &cpld_pic_host_ops, 16); | ||
| 196 | if (!cpld_pic_host) { | ||
| 197 | printk(KERN_ERR "CPLD PIC: failed to allocate irq host!\n"); | ||
| 198 | goto end; | ||
| 199 | } | ||
| 200 | |||
| 201 | set_irq_chained_handler(cascade_irq, cpld_pic_cascade); | ||
| 202 | end: | ||
| 203 | of_node_put(np); | ||
| 204 | } | ||
