/* * This file is subject to the terms and conditions of the * Open Software License. * See http://www.opensource.org/licenses/osl-2.0.php for more details. * * Copyright (C) 2003 gluk * Copyright (C) 2004-2010 Samium Gromoff <_deepfire@feelingofgreen.ru> * Copyright (C) 2003-2011 Elvees, Inc. */ #include #include #include #include #include #include //#include #include #include #include #include #include static void multicore_ack_irq(struct irq_data *data) { int qstr_irq = data->irq - QSTR_IRQ_BASE; unsigned qstr_reg; if (qstr_irq < 0) return; #if defined(CONFIG_MCT04) qstr_reg = 0; while (qstr_irq >= 32) { qstr_reg++; qstr_irq -= 32; } switch (qstr_reg) { case 0: MC_MASKR00 &= ~(1 << qstr_irq); //MC_MASKR10 &= ~(1 << qstr_irq); TODO break; case 1: MC_MASKR01 &= ~(1 << qstr_irq); //MC_MASKR11 &= ~(1 << qstr_irq); TODO break; case 2: MC_MASKR02 &= ~(1 << qstr_irq); //MC_MASKR12 &= ~(1 << qstr_irq); TODO break; case 3: MC_MASKR03 &= ~(1 << qstr_irq); //MC_MASKR13 &= ~(1 << qstr_irq); TODO break; case 4: MC_MASKR04 &= ~(1 << qstr_irq); //MC_MASKR14 &= ~(1 << qstr_irq); TODO break; default: BUG(); } #else #if defined (CONFIG_MC24) MC_MASKR &= ~(1 << qstr_irq); #else // defined(CONFIG_NVCOM01) || defined(CONFIG_NVCOM02) || defined(CONFIG_MC24M) || defined(CONFIG_MC24R2) || defined(CONFIG_MCT02R) || defined(CONFIG_MCT06) qstr_reg = 0; while (qstr_irq >= 32) { qstr_reg++; qstr_irq -= 32; } switch (qstr_reg) { case 0: MC_MASKR0 &= ~(1 << qstr_irq); break; case 1: MC_MASKR1 &= ~(1 << qstr_irq); break; case 2: MC_MASKR2 &= ~(1 << qstr_irq); break; #if defined(CONFIG_MCT02R) || defined(CONFIG_MCT03P) || defined(CONFIG_MC30SF6) || defined(CONFIG_MCT06) case 3: MC_MASKR3 &= ~(1 << qstr_irq); break; #endif #if defined(CONFIG_MCT02R) || defined(CONFIG_MCT03P) || defined(CONFIG_MCT06) case 4: MC_MASKR4 &= ~(1 << qstr_irq); break; #endif default: BUG(); } #endif #endif } static void multicore_mask_irq(struct irq_data *data) { multicore_ack_irq(data); } static void multicore_unmask_irq(struct irq_data *data) { int qstr_irq = data->irq - QSTR_IRQ_BASE; unsigned qstr_reg; if (qstr_irq < 0) return; #if defined(CONFIG_MCT04) qstr_reg = 0; while (qstr_irq >= 32) { qstr_reg++; qstr_irq -= 32; } switch (qstr_reg) { case 0: MC_MASKR00 |= (1 << qstr_irq); //MC_MASKR10 |= (1 << qstr_irq); TODO ? break; case 1: MC_MASKR01 |= (1 << qstr_irq); //MC_MASKR11 |= (1 << qstr_irq); TODO ? break; case 2: MC_MASKR02 |= (1 << qstr_irq); //MC_MASKR12 |= (1 << qstr_irq); TODO ? break; case 3: MC_MASKR03 |= (1 << qstr_irq); //MC_MASKR13 |= (1 << qstr_irq); TODO ? break; case 4: MC_MASKR04 |= (1 << qstr_irq); //MC_MASKR14 |= (1 << qstr_irq); TODO ? break; default: BUG(); } #else #if defined(CONFIG_MC24) MC_MASKR |= (1 << qstr_irq); #else // defined(CONFIG_NVCOM01) || defined(CONFIG_NVCOM02)|| defined(CONFIG_MC24M) || defined(CONFIG_MC24R2) || defined(CONFIG_MCT02R) || defined(CONFIG_MCT06) qstr_reg = 0; while (qstr_irq >= 32) { qstr_reg++; qstr_irq -= 32; } switch (qstr_reg) { case 0: MC_MASKR0 |= (1 << qstr_irq); break; case 1: MC_MASKR1 |= (1 << qstr_irq); break; case 2: MC_MASKR2 |= (1 << qstr_irq); break; #if defined(CONFIG_MCT02R) || defined(CONFIG_MCT03P) || defined(CONFIG_MC30SF6) || defined(CONFIG_MCT06) case 3: MC_MASKR3 |= (1 << qstr_irq); break; #endif #if defined(CONFIG_MCT02R) || defined(CONFIG_MCT03P) || defined(CONFIG_MCT06) case 4: MC_MASKR4 |= (1 << qstr_irq); break; #endif default: BUG(); } #endif #endif } static struct irq_chip multicore_irq_type = { .name = "Multicore", .irq_unmask = multicore_unmask_irq, .irq_mask = multicore_mask_irq, .irq_mask_ack = multicore_ack_irq }; static struct irqaction multicore_cascade_action = { .handler = no_action, .name = "Multicore QSTR cascade interrupt" }; static void __init multicore_irq_init(int base) { int i; #if defined(CONFIG_MCT04) MC_MASKR00 = 0; //MC_MASKR10 = 0; TODO MC_MASKR01 = 0; //MC_MASKR11 = 0; TODO MC_MASKR02 = 0; //MC_MASKR12 = 0; TODO MC_MASKR03 = 0; //MC_MASKR13 = 0; TODO MC_MASKR04 = 0; //MC_MASKR14 = 0; TODO #else #if defined(CONFIG_MC24) MC_MASKR = 0; #else // defined(CONFIG_NVCOM01) || defined(CONFIG_NVCOM02) || defined(CONFIG_MC24R2) || defined (CONFIG_MC24R2) || defined(CONFIG_MCT02R) || defined(CONFIG_MCT06) MC_MASKR0 = 0; MC_MASKR1 = 0; MC_MASKR2 = 0; #if defined(CONFIG_MCT02R) || defined(CONFIG_MCT03P) || defined(CONFIG_MC30SF6) || defined(CONFIG_MCT06) MC_MASKR3 = 0; #endif #if defined(CONFIG_MCT02R) || defined(CONFIG_MCT03P) || defined(CONFIG_MCT06) MC_MASKR4 = 0; #endif #endif #endif for (i = 0; i < QSTR_NR_IRQS; i++) irq_set_chip_and_handler(base + i, &multicore_irq_type, handle_level_irq); for (i = IRQ_QSTR; i < IRQ_COMPARE; ++i) { if (i != IRQ_DSP) setup_irq(i, &multicore_cascade_action); set_c0_status(mips_irqmask(i)); } } void __init arch_init_irq(void) { mips_cpu_irq_init(); multicore_irq_init(QSTR_IRQ_BASE); } static void multicore_cascade(void) { #if defined(CONFIG_MCT04) unsigned qstr = MC_QSTR00 & MC_MASKR00; if (qstr) { do_IRQ(QSTR_IRQ_BASE + ilog2(qstr)); } else { qstr = MC_QSTR01 & MC_MASKR01; if (qstr) { do_IRQ(QSTR_IRQ_BASE + 32 + ilog2(qstr)); } else { qstr = MC_QSTR02 & MC_MASKR02; if (qstr) { do_IRQ(QSTR_IRQ_BASE + 64 + ilog2(qstr)); } else { qstr = MC_QSTR03 & MC_MASKR03; if (qstr) { do_IRQ(QSTR_IRQ_BASE + 96 + ilog2(qstr)); } else { qstr = MC_QSTR04 & MC_MASKR04; if (qstr) { do_IRQ(QSTR_IRQ_BASE + 128 + ilog2(qstr)); } else { spurious_interrupt(); } } } } } #else #if defined(CONFIG_MC24) unsigned qstr = MC_QSTR & MC_MASKR; if (qstr) { do_IRQ(QSTR_IRQ_BASE + ilog2(qstr)); } else { spurious_interrupt(); } #else //defined(CONFIG_NVCOM01) || defined(CONFIG_NVCOM02) || defined(CONFIG_MC24R2) || defined(CONFIG_MC24R2) || defined(CONFIG_MCT02R) || defined(CONFIG_MCT06) unsigned qstr = MC_QSTR0 & MC_MASKR0; if (qstr) { do_IRQ(QSTR_IRQ_BASE + ilog2(qstr)); } else { qstr = MC_QSTR1 & MC_MASKR1; if (qstr) { do_IRQ(QSTR_IRQ_BASE + 32 + ilog2(qstr)); } else { qstr = MC_QSTR2 & MC_MASKR2; if (qstr) { do_IRQ(QSTR_IRQ_BASE + 64 + ilog2(qstr)); } else { #if defined(CONFIG_MCT02R) || defined(CONFIG_MCT03P) || defined(CONFIG_MCT06) qstr = MC_QSTR3 & MC_MASKR3; if (qstr) { do_IRQ(QSTR_IRQ_BASE + 96 + ilog2(qstr)); } else { qstr = MC_QSTR4 & MC_MASKR4; if (qstr) { do_IRQ(QSTR_IRQ_BASE + 128 + ilog2(qstr)); } else { spurious_interrupt(); } } #else spurious_interrupt(); #endif #if defined(CONFIG_MC30SF6) qstr = MC_QSTR3 & MC_MASKR3; if (qstr) { do_IRQ(QSTR_IRQ_BASE + 96 + ilog2(qstr)); } else { spurious_interrupt(); } #else spurious_interrupt(); #endif } } } #endif #endif } asmlinkage void plat_irq_dispatch(void) { unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM; if (pending & STATUS_MASK_COMPARE) /* cpu timer */ do_IRQ(IRQ_COMPARE); else multicore_cascade(); }