123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646 |
- /*
- * include/asm-ppc/ipic.c
- *
- * IPIC routines implementations.
- *
- * Copyright 2005 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/errno.h>
- #include <linux/reboot.h>
- #include <linux/slab.h>
- #include <linux/stddef.h>
- #include <linux/sched.h>
- #include <linux/signal.h>
- #include <linux/sysdev.h>
- #include <asm/irq.h>
- #include <asm/io.h>
- #include <asm/ipic.h>
- #include <asm/mpc83xx.h>
- #include "ipic.h"
- static struct ipic p_ipic;
- static struct ipic * primary_ipic;
- static struct ipic_info ipic_info[] = {
- [9] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 24,
- .prio_mask = 0,
- },
- [10] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 25,
- .prio_mask = 1,
- },
- [11] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 26,
- .prio_mask = 2,
- },
- [14] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 29,
- .prio_mask = 5,
- },
- [15] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 30,
- .prio_mask = 6,
- },
- [16] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_D,
- .force = IPIC_SIFCR_H,
- .bit = 31,
- .prio_mask = 7,
- },
- [17] = {
- .pend = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SEFCR,
- .bit = 1,
- .prio_mask = 5,
- },
- [18] = {
- .pend = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SEFCR,
- .bit = 2,
- .prio_mask = 6,
- },
- [19] = {
- .pend = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SEFCR,
- .bit = 3,
- .prio_mask = 7,
- },
- [20] = {
- .pend = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SEFCR,
- .bit = 4,
- .prio_mask = 4,
- },
- [21] = {
- .pend = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SEFCR,
- .bit = 5,
- .prio_mask = 5,
- },
- [22] = {
- .pend = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SEFCR,
- .bit = 6,
- .prio_mask = 6,
- },
- [23] = {
- .pend = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SEFCR,
- .bit = 7,
- .prio_mask = 7,
- },
- [32] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 0,
- .prio_mask = 0,
- },
- [33] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 1,
- .prio_mask = 1,
- },
- [34] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 2,
- .prio_mask = 2,
- },
- [35] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 3,
- .prio_mask = 3,
- },
- [36] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 4,
- .prio_mask = 4,
- },
- [37] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 5,
- .prio_mask = 5,
- },
- [38] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 6,
- .prio_mask = 6,
- },
- [39] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_H,
- .prio = IPIC_SIPRR_A,
- .force = IPIC_SIFCR_H,
- .bit = 7,
- .prio_mask = 7,
- },
- [48] = {
- .pend = IPIC_SEPNR,
- .mask = IPIC_SEMSR,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SEFCR,
- .bit = 0,
- .prio_mask = 4,
- },
- [64] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SIFCR_L,
- .bit = 0,
- .prio_mask = 0,
- },
- [65] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SIFCR_L,
- .bit = 1,
- .prio_mask = 1,
- },
- [66] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SIFCR_L,
- .bit = 2,
- .prio_mask = 2,
- },
- [67] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_A,
- .force = IPIC_SIFCR_L,
- .bit = 3,
- .prio_mask = 3,
- },
- [68] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SIFCR_L,
- .bit = 4,
- .prio_mask = 0,
- },
- [69] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SIFCR_L,
- .bit = 5,
- .prio_mask = 1,
- },
- [70] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SIFCR_L,
- .bit = 6,
- .prio_mask = 2,
- },
- [71] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = IPIC_SMPRR_B,
- .force = IPIC_SIFCR_L,
- .bit = 7,
- .prio_mask = 3,
- },
- [72] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 8,
- },
- [73] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 9,
- },
- [74] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 10,
- },
- [75] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 11,
- },
- [76] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 12,
- },
- [77] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 13,
- },
- [78] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 14,
- },
- [79] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 15,
- },
- [80] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 16,
- },
- [84] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 20,
- },
- [85] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 21,
- },
- [90] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 26,
- },
- [91] = {
- .pend = IPIC_SIPNR_H,
- .mask = IPIC_SIMSR_L,
- .prio = 0,
- .force = IPIC_SIFCR_L,
- .bit = 27,
- },
- };
- static inline u32 ipic_read(volatile u32 __iomem *base, unsigned int reg)
- {
- return in_be32(base + (reg >> 2));
- }
- static inline void ipic_write(volatile u32 __iomem *base, unsigned int reg, u32 value)
- {
- out_be32(base + (reg >> 2), value);
- }
- static inline struct ipic * ipic_from_irq(unsigned int irq)
- {
- return primary_ipic;
- }
- static void ipic_enable_irq(unsigned int irq)
- {
- struct ipic *ipic = ipic_from_irq(irq);
- unsigned int src = irq - ipic->irq_offset;
- u32 temp;
- temp = ipic_read(ipic->regs, ipic_info[src].mask);
- temp |= (1 << (31 - ipic_info[src].bit));
- ipic_write(ipic->regs, ipic_info[src].mask, temp);
- }
- static void ipic_disable_irq(unsigned int irq)
- {
- struct ipic *ipic = ipic_from_irq(irq);
- unsigned int src = irq - ipic->irq_offset;
- u32 temp;
- temp = ipic_read(ipic->regs, ipic_info[src].mask);
- temp &= ~(1 << (31 - ipic_info[src].bit));
- ipic_write(ipic->regs, ipic_info[src].mask, temp);
- }
- static void ipic_disable_irq_and_ack(unsigned int irq)
- {
- struct ipic *ipic = ipic_from_irq(irq);
- unsigned int src = irq - ipic->irq_offset;
- u32 temp;
- ipic_disable_irq(irq);
- temp = ipic_read(ipic->regs, ipic_info[src].pend);
- temp |= (1 << (31 - ipic_info[src].bit));
- ipic_write(ipic->regs, ipic_info[src].pend, temp);
- }
- static void ipic_end_irq(unsigned int irq)
- {
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- ipic_enable_irq(irq);
- }
- struct hw_interrupt_type ipic = {
- .typename = " IPIC ",
- .enable = ipic_enable_irq,
- .disable = ipic_disable_irq,
- .ack = ipic_disable_irq_and_ack,
- .end = ipic_end_irq,
- };
- void __init ipic_init(phys_addr_t phys_addr,
- unsigned int flags,
- unsigned int irq_offset,
- unsigned char *senses,
- unsigned int senses_count)
- {
- u32 i, temp = 0;
- primary_ipic = &p_ipic;
- primary_ipic->regs = ioremap(phys_addr, MPC83xx_IPIC_SIZE);
- primary_ipic->irq_offset = irq_offset;
- ipic_write(primary_ipic->regs, IPIC_SICNR, 0x0);
- /* default priority scheme is grouped. If spread mode is required
- * configure SICFR accordingly */
- if (flags & IPIC_SPREADMODE_GRP_A)
- temp |= SICFR_IPSA;
- if (flags & IPIC_SPREADMODE_GRP_D)
- temp |= SICFR_IPSD;
- if (flags & IPIC_SPREADMODE_MIX_A)
- temp |= SICFR_MPSA;
- if (flags & IPIC_SPREADMODE_MIX_B)
- temp |= SICFR_MPSB;
- ipic_write(primary_ipic->regs, IPIC_SICNR, temp);
- /* handle MCP route */
- temp = 0;
- if (flags & IPIC_DISABLE_MCP_OUT)
- temp = SERCR_MCPR;
- ipic_write(primary_ipic->regs, IPIC_SERCR, temp);
- /* handle routing of IRQ0 to MCP */
- temp = ipic_read(primary_ipic->regs, IPIC_SEMSR);
- if (flags & IPIC_IRQ0_MCP)
- temp |= SEMSR_SIRQ0;
- else
- temp &= ~SEMSR_SIRQ0;
- ipic_write(primary_ipic->regs, IPIC_SEMSR, temp);
- for (i = 0 ; i < NR_IPIC_INTS ; i++) {
- irq_desc[i+irq_offset].handler = &ipic;
- irq_desc[i+irq_offset].status = IRQ_LEVEL;
- }
- temp = 0;
- for (i = 0 ; i < senses_count ; i++) {
- if ((senses[i] & IRQ_SENSE_MASK) == IRQ_SENSE_EDGE) {
- temp |= 1 << (15 - i);
- if (i != 0)
- irq_desc[i + irq_offset + MPC83xx_IRQ_EXT1 - 1].status = 0;
- else
- irq_desc[irq_offset + MPC83xx_IRQ_EXT0].status = 0;
- }
- }
- ipic_write(primary_ipic->regs, IPIC_SECNR, temp);
- printk ("IPIC (%d IRQ sources, %d External IRQs) at %p\n", NR_IPIC_INTS,
- senses_count, primary_ipic->regs);
- }
- int ipic_set_priority(unsigned int irq, unsigned int priority)
- {
- struct ipic *ipic = ipic_from_irq(irq);
- unsigned int src = irq - ipic->irq_offset;
- u32 temp;
- if (priority > 7)
- return -EINVAL;
- if (src > 127)
- return -EINVAL;
- if (ipic_info[src].prio == 0)
- return -EINVAL;
- temp = ipic_read(ipic->regs, ipic_info[src].prio);
- if (priority < 4) {
- temp &= ~(0x7 << (20 + (3 - priority) * 3));
- temp |= ipic_info[src].prio_mask << (20 + (3 - priority) * 3);
- } else {
- temp &= ~(0x7 << (4 + (7 - priority) * 3));
- temp |= ipic_info[src].prio_mask << (4 + (7 - priority) * 3);
- }
- ipic_write(ipic->regs, ipic_info[src].prio, temp);
- return 0;
- }
- void ipic_set_highest_priority(unsigned int irq)
- {
- struct ipic *ipic = ipic_from_irq(irq);
- unsigned int src = irq - ipic->irq_offset;
- u32 temp;
- temp = ipic_read(ipic->regs, IPIC_SICFR);
- /* clear and set HPI */
- temp &= 0x7f000000;
- temp |= (src & 0x7f) << 24;
- ipic_write(ipic->regs, IPIC_SICFR, temp);
- }
- void ipic_set_default_priority(void)
- {
- ipic_set_priority(MPC83xx_IRQ_TSEC1_TX, 0);
- ipic_set_priority(MPC83xx_IRQ_TSEC1_RX, 1);
- ipic_set_priority(MPC83xx_IRQ_TSEC1_ERROR, 2);
- ipic_set_priority(MPC83xx_IRQ_TSEC2_TX, 3);
- ipic_set_priority(MPC83xx_IRQ_TSEC2_RX, 4);
- ipic_set_priority(MPC83xx_IRQ_TSEC2_ERROR, 5);
- ipic_set_priority(MPC83xx_IRQ_USB2_DR, 6);
- ipic_set_priority(MPC83xx_IRQ_USB2_MPH, 7);
- ipic_set_priority(MPC83xx_IRQ_UART1, 0);
- ipic_set_priority(MPC83xx_IRQ_UART2, 1);
- ipic_set_priority(MPC83xx_IRQ_SEC2, 2);
- ipic_set_priority(MPC83xx_IRQ_IIC1, 5);
- ipic_set_priority(MPC83xx_IRQ_IIC2, 6);
- ipic_set_priority(MPC83xx_IRQ_SPI, 7);
- ipic_set_priority(MPC83xx_IRQ_RTC_SEC, 0);
- ipic_set_priority(MPC83xx_IRQ_PIT, 1);
- ipic_set_priority(MPC83xx_IRQ_PCI1, 2);
- ipic_set_priority(MPC83xx_IRQ_PCI2, 3);
- ipic_set_priority(MPC83xx_IRQ_EXT0, 4);
- ipic_set_priority(MPC83xx_IRQ_EXT1, 5);
- ipic_set_priority(MPC83xx_IRQ_EXT2, 6);
- ipic_set_priority(MPC83xx_IRQ_EXT3, 7);
- ipic_set_priority(MPC83xx_IRQ_RTC_ALR, 0);
- ipic_set_priority(MPC83xx_IRQ_MU, 1);
- ipic_set_priority(MPC83xx_IRQ_SBA, 2);
- ipic_set_priority(MPC83xx_IRQ_DMA, 3);
- ipic_set_priority(MPC83xx_IRQ_EXT4, 4);
- ipic_set_priority(MPC83xx_IRQ_EXT5, 5);
- ipic_set_priority(MPC83xx_IRQ_EXT6, 6);
- ipic_set_priority(MPC83xx_IRQ_EXT7, 7);
- }
- void ipic_enable_mcp(enum ipic_mcp_irq mcp_irq)
- {
- struct ipic *ipic = primary_ipic;
- u32 temp;
- temp = ipic_read(ipic->regs, IPIC_SERMR);
- temp |= (1 << (31 - mcp_irq));
- ipic_write(ipic->regs, IPIC_SERMR, temp);
- }
- void ipic_disable_mcp(enum ipic_mcp_irq mcp_irq)
- {
- struct ipic *ipic = primary_ipic;
- u32 temp;
- temp = ipic_read(ipic->regs, IPIC_SERMR);
- temp &= (1 << (31 - mcp_irq));
- ipic_write(ipic->regs, IPIC_SERMR, temp);
- }
- u32 ipic_get_mcp_status(void)
- {
- return ipic_read(primary_ipic->regs, IPIC_SERMR);
- }
- void ipic_clear_mcp_status(u32 mask)
- {
- ipic_write(primary_ipic->regs, IPIC_SERMR, mask);
- }
- /* Return an interrupt vector or -1 if no interrupt is pending. */
- int ipic_get_irq(struct pt_regs *regs)
- {
- int irq;
- irq = ipic_read(primary_ipic->regs, IPIC_SIVCR) & 0x7f;
- if (irq == 0) /* 0 --> no irq is pending */
- irq = -1;
- return irq;
- }
- static struct sysdev_class ipic_sysclass = {
- set_kset_name("ipic"),
- };
- static struct sys_device device_ipic = {
- .id = 0,
- .cls = &ipic_sysclass,
- };
- static int __init init_ipic_sysfs(void)
- {
- int rc;
- if (!primary_ipic->regs)
- return -ENODEV;
- printk(KERN_DEBUG "Registering ipic with sysfs...\n");
- rc = sysdev_class_register(&ipic_sysclass);
- if (rc) {
- printk(KERN_ERR "Failed registering ipic sys class\n");
- return -ENODEV;
- }
- rc = sysdev_register(&device_ipic);
- if (rc) {
- printk(KERN_ERR "Failed registering ipic sys device\n");
- return -ENODEV;
- }
- return 0;
- }
- subsys_initcall(init_ipic_sysfs);
|