1907208c4SChristophe Leroy /* 2907208c4SChristophe Leroy * (C) Copyright 2000-2002 3907208c4SChristophe Leroy * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4907208c4SChristophe Leroy * 5907208c4SChristophe Leroy * SPDX-License-Identifier: GPL-2.0+ 6907208c4SChristophe Leroy */ 7907208c4SChristophe Leroy 8907208c4SChristophe Leroy #include <common.h> 9907208c4SChristophe Leroy #include <mpc8xx.h> 10907208c4SChristophe Leroy #include <mpc8xx_irq.h> 11907208c4SChristophe Leroy #include <asm/processor.h> 12ba3da734SChristophe Leroy #include <asm/io.h> 13907208c4SChristophe Leroy #include <commproc.h> 14907208c4SChristophe Leroy 15907208c4SChristophe Leroy /************************************************************************/ 16907208c4SChristophe Leroy 17907208c4SChristophe Leroy /* 18907208c4SChristophe Leroy * CPM interrupt vector functions. 19907208c4SChristophe Leroy */ 20907208c4SChristophe Leroy struct interrupt_action { 21907208c4SChristophe Leroy interrupt_handler_t *handler; 22907208c4SChristophe Leroy void *arg; 23907208c4SChristophe Leroy }; 24907208c4SChristophe Leroy 25907208c4SChristophe Leroy static struct interrupt_action cpm_vecs[CPMVEC_NR]; 26907208c4SChristophe Leroy static struct interrupt_action irq_vecs[NR_IRQS]; 27907208c4SChristophe Leroy 28907208c4SChristophe Leroy static void cpm_interrupt_init(void); 29907208c4SChristophe Leroy static void cpm_interrupt(void *regs); 30907208c4SChristophe Leroy 31907208c4SChristophe Leroy /************************************************************************/ 32907208c4SChristophe Leroy 33907208c4SChristophe Leroy int interrupt_init_cpu(unsigned *decrementer_count) 34907208c4SChristophe Leroy { 35ba3da734SChristophe Leroy immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 36907208c4SChristophe Leroy 37907208c4SChristophe Leroy *decrementer_count = get_tbclk() / CONFIG_SYS_HZ; 38907208c4SChristophe Leroy 39907208c4SChristophe Leroy /* disable all interrupts */ 40ba3da734SChristophe Leroy out_be32(&immr->im_siu_conf.sc_simask, 0); 41907208c4SChristophe Leroy 42907208c4SChristophe Leroy /* Configure CPM interrupts */ 43907208c4SChristophe Leroy cpm_interrupt_init(); 44907208c4SChristophe Leroy 45*70fd0710SChristophe Leroy return 0; 46907208c4SChristophe Leroy } 47907208c4SChristophe Leroy 48907208c4SChristophe Leroy /************************************************************************/ 49907208c4SChristophe Leroy 50907208c4SChristophe Leroy /* 51907208c4SChristophe Leroy * Handle external interrupts 52907208c4SChristophe Leroy */ 53907208c4SChristophe Leroy void external_interrupt(struct pt_regs *regs) 54907208c4SChristophe Leroy { 55ba3da734SChristophe Leroy immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 56907208c4SChristophe Leroy int irq; 57ba3da734SChristophe Leroy ulong simask; 58907208c4SChristophe Leroy ulong vec, v_bit; 59907208c4SChristophe Leroy 60907208c4SChristophe Leroy /* 61907208c4SChristophe Leroy * read the SIVEC register and shift the bits down 62907208c4SChristophe Leroy * to get the irq number 63907208c4SChristophe Leroy */ 64ba3da734SChristophe Leroy vec = in_be32(&immr->im_siu_conf.sc_sivec); 65907208c4SChristophe Leroy irq = vec >> 26; 66907208c4SChristophe Leroy v_bit = 0x80000000UL >> irq; 67907208c4SChristophe Leroy 68907208c4SChristophe Leroy /* 69907208c4SChristophe Leroy * Read Interrupt Mask Register and Mask Interrupts 70907208c4SChristophe Leroy */ 71ba3da734SChristophe Leroy simask = in_be32(&immr->im_siu_conf.sc_simask); 72ba3da734SChristophe Leroy clrbits_be32(&immr->im_siu_conf.sc_simask, 0xFFFF0000 >> irq); 73907208c4SChristophe Leroy 74907208c4SChristophe Leroy if (!(irq & 0x1)) { /* External Interrupt ? */ 75907208c4SChristophe Leroy ulong siel; 76907208c4SChristophe Leroy 77907208c4SChristophe Leroy /* 78907208c4SChristophe Leroy * Read Interrupt Edge/Level Register 79907208c4SChristophe Leroy */ 80ba3da734SChristophe Leroy siel = in_be32(&immr->im_siu_conf.sc_siel); 81907208c4SChristophe Leroy 82907208c4SChristophe Leroy if (siel & v_bit) { /* edge triggered interrupt ? */ 83907208c4SChristophe Leroy /* 84907208c4SChristophe Leroy * Rewrite SIPEND Register to clear interrupt 85907208c4SChristophe Leroy */ 86ba3da734SChristophe Leroy out_be32(&immr->im_siu_conf.sc_sipend, v_bit); 87907208c4SChristophe Leroy } 88907208c4SChristophe Leroy } 89907208c4SChristophe Leroy 90907208c4SChristophe Leroy if (irq_vecs[irq].handler != NULL) { 91907208c4SChristophe Leroy irq_vecs[irq].handler(irq_vecs[irq].arg); 92907208c4SChristophe Leroy } else { 93907208c4SChristophe Leroy printf("\nBogus External Interrupt IRQ %d Vector %ld\n", 94907208c4SChristophe Leroy irq, vec); 95907208c4SChristophe Leroy /* turn off the bogus interrupt to avoid it from now */ 96907208c4SChristophe Leroy simask &= ~v_bit; 97907208c4SChristophe Leroy } 98907208c4SChristophe Leroy /* 99907208c4SChristophe Leroy * Re-Enable old Interrupt Mask 100907208c4SChristophe Leroy */ 101ba3da734SChristophe Leroy out_be32(&immr->im_siu_conf.sc_simask, simask); 102907208c4SChristophe Leroy } 103907208c4SChristophe Leroy 104907208c4SChristophe Leroy /************************************************************************/ 105907208c4SChristophe Leroy 106907208c4SChristophe Leroy /* 107907208c4SChristophe Leroy * CPM interrupt handler 108907208c4SChristophe Leroy */ 109907208c4SChristophe Leroy static void cpm_interrupt(void *regs) 110907208c4SChristophe Leroy { 111ba3da734SChristophe Leroy immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 112907208c4SChristophe Leroy uint vec; 113907208c4SChristophe Leroy 114907208c4SChristophe Leroy /* 115907208c4SChristophe Leroy * Get the vector by setting the ACK bit 116907208c4SChristophe Leroy * and then reading the register. 117907208c4SChristophe Leroy */ 118ba3da734SChristophe Leroy out_be16(&immr->im_cpic.cpic_civr, 1); 119ba3da734SChristophe Leroy vec = in_be16(&immr->im_cpic.cpic_civr); 120907208c4SChristophe Leroy vec >>= 11; 121907208c4SChristophe Leroy 122907208c4SChristophe Leroy if (cpm_vecs[vec].handler != NULL) { 123907208c4SChristophe Leroy (*cpm_vecs[vec].handler) (cpm_vecs[vec].arg); 124907208c4SChristophe Leroy } else { 125ba3da734SChristophe Leroy clrbits_be32(&immr->im_cpic.cpic_cimr, 1 << vec); 126907208c4SChristophe Leroy printf("Masking bogus CPM interrupt vector 0x%x\n", vec); 127907208c4SChristophe Leroy } 128907208c4SChristophe Leroy /* 129907208c4SChristophe Leroy * After servicing the interrupt, 130907208c4SChristophe Leroy * we have to remove the status indicator. 131907208c4SChristophe Leroy */ 132ba3da734SChristophe Leroy setbits_be32(&immr->im_cpic.cpic_cisr, 1 << vec); 133907208c4SChristophe Leroy } 134907208c4SChristophe Leroy 135907208c4SChristophe Leroy /* 136907208c4SChristophe Leroy * The CPM can generate the error interrupt when there is a race 137907208c4SChristophe Leroy * condition between generating and masking interrupts. All we have 138907208c4SChristophe Leroy * to do is ACK it and return. This is a no-op function so we don't 139907208c4SChristophe Leroy * need any special tests in the interrupt handler. 140907208c4SChristophe Leroy */ 141907208c4SChristophe Leroy static void cpm_error_interrupt(void *dummy) 142907208c4SChristophe Leroy { 143907208c4SChristophe Leroy } 144907208c4SChristophe Leroy 145907208c4SChristophe Leroy /************************************************************************/ 146907208c4SChristophe Leroy /* 147907208c4SChristophe Leroy * Install and free an interrupt handler 148907208c4SChristophe Leroy */ 149*70fd0710SChristophe Leroy void irq_install_handler(int vec, interrupt_handler_t *handler, void *arg) 150907208c4SChristophe Leroy { 151ba3da734SChristophe Leroy immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 152907208c4SChristophe Leroy 153907208c4SChristophe Leroy if ((vec & CPMVEC_OFFSET) != 0) { 154907208c4SChristophe Leroy /* CPM interrupt */ 155907208c4SChristophe Leroy vec &= 0xffff; 156*70fd0710SChristophe Leroy if (cpm_vecs[vec].handler != NULL) 157907208c4SChristophe Leroy printf("CPM interrupt 0x%x replacing 0x%x\n", 158*70fd0710SChristophe Leroy (uint)handler, (uint)cpm_vecs[vec].handler); 159907208c4SChristophe Leroy cpm_vecs[vec].handler = handler; 160907208c4SChristophe Leroy cpm_vecs[vec].arg = arg; 161ba3da734SChristophe Leroy setbits_be32(&immr->im_cpic.cpic_cimr, 1 << vec); 162907208c4SChristophe Leroy } else { 163907208c4SChristophe Leroy /* SIU interrupt */ 164*70fd0710SChristophe Leroy if (irq_vecs[vec].handler != NULL) 165907208c4SChristophe Leroy printf("SIU interrupt %d 0x%x replacing 0x%x\n", 166*70fd0710SChristophe Leroy vec, (uint)handler, (uint)cpm_vecs[vec].handler); 167907208c4SChristophe Leroy irq_vecs[vec].handler = handler; 168907208c4SChristophe Leroy irq_vecs[vec].arg = arg; 169ba3da734SChristophe Leroy setbits_be32(&immr->im_siu_conf.sc_simask, 1 << (31 - vec)); 170907208c4SChristophe Leroy } 171907208c4SChristophe Leroy } 172907208c4SChristophe Leroy 173907208c4SChristophe Leroy void irq_free_handler(int vec) 174907208c4SChristophe Leroy { 175ba3da734SChristophe Leroy immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 176907208c4SChristophe Leroy 177907208c4SChristophe Leroy if ((vec & CPMVEC_OFFSET) != 0) { 178907208c4SChristophe Leroy /* CPM interrupt */ 179907208c4SChristophe Leroy vec &= 0xffff; 180ba3da734SChristophe Leroy clrbits_be32(&immr->im_cpic.cpic_cimr, 1 << vec); 181907208c4SChristophe Leroy cpm_vecs[vec].handler = NULL; 182907208c4SChristophe Leroy cpm_vecs[vec].arg = NULL; 183907208c4SChristophe Leroy } else { 184907208c4SChristophe Leroy /* SIU interrupt */ 185ba3da734SChristophe Leroy clrbits_be32(&immr->im_siu_conf.sc_simask, 1 << (31 - vec)); 186907208c4SChristophe Leroy irq_vecs[vec].handler = NULL; 187907208c4SChristophe Leroy irq_vecs[vec].arg = NULL; 188907208c4SChristophe Leroy } 189907208c4SChristophe Leroy } 190907208c4SChristophe Leroy 191907208c4SChristophe Leroy /************************************************************************/ 192907208c4SChristophe Leroy 193907208c4SChristophe Leroy static void cpm_interrupt_init(void) 194907208c4SChristophe Leroy { 195ba3da734SChristophe Leroy immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 196ba3da734SChristophe Leroy uint cicr; 197907208c4SChristophe Leroy 198907208c4SChristophe Leroy /* 199907208c4SChristophe Leroy * Initialize the CPM interrupt controller. 200907208c4SChristophe Leroy */ 201907208c4SChristophe Leroy 202ba3da734SChristophe Leroy cicr = CICR_SCD_SCC4 | CICR_SCC_SCC3 | CICR_SCB_SCC2 | CICR_SCA_SCC1 | 203ba3da734SChristophe Leroy ((CPM_INTERRUPT / 2) << 13) | CICR_HP_MASK; 204907208c4SChristophe Leroy 205ba3da734SChristophe Leroy out_be32(&immr->im_cpic.cpic_cicr, cicr); 206ba3da734SChristophe Leroy out_be32(&immr->im_cpic.cpic_cimr, 0); 207907208c4SChristophe Leroy 208907208c4SChristophe Leroy /* 209907208c4SChristophe Leroy * Install the error handler. 210907208c4SChristophe Leroy */ 211907208c4SChristophe Leroy irq_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); 212907208c4SChristophe Leroy 213ba3da734SChristophe Leroy setbits_be32(&immr->im_cpic.cpic_cicr, CICR_IEN); 214907208c4SChristophe Leroy 215907208c4SChristophe Leroy /* 216907208c4SChristophe Leroy * Install the cpm interrupt handler 217907208c4SChristophe Leroy */ 218907208c4SChristophe Leroy irq_install_handler(CPM_INTERRUPT, cpm_interrupt, NULL); 219907208c4SChristophe Leroy } 220907208c4SChristophe Leroy 221907208c4SChristophe Leroy /************************************************************************/ 222907208c4SChristophe Leroy 223907208c4SChristophe Leroy /* 224907208c4SChristophe Leroy * timer_interrupt - gets called when the decrementer overflows, 225907208c4SChristophe Leroy * with interrupts disabled. 226907208c4SChristophe Leroy * Trivial implementation - no need to be really accurate. 227907208c4SChristophe Leroy */ 228907208c4SChristophe Leroy void timer_interrupt_cpu(struct pt_regs *regs) 229907208c4SChristophe Leroy { 230ba3da734SChristophe Leroy immap_t __iomem *immr = (immap_t __iomem *)CONFIG_SYS_IMMR; 231907208c4SChristophe Leroy 232907208c4SChristophe Leroy /* Reset Timer Expired and Timers Interrupt Status */ 233ba3da734SChristophe Leroy out_be32(&immr->im_clkrstk.cark_plprcrk, KAPWR_KEY); 234907208c4SChristophe Leroy __asm__ ("nop"); 235907208c4SChristophe Leroy /* 236907208c4SChristophe Leroy Clear TEXPS (and TMIST on older chips). SPLSS (on older 237907208c4SChristophe Leroy chips) is cleared too. 238907208c4SChristophe Leroy 239907208c4SChristophe Leroy Bitwise OR is a read-modify-write operation so ALL bits 240907208c4SChristophe Leroy which are cleared by writing `1' would be cleared by 241907208c4SChristophe Leroy operations like 242907208c4SChristophe Leroy 243907208c4SChristophe Leroy immr->im_clkrst.car_plprcr |= PLPRCR_TEXPS; 244907208c4SChristophe Leroy 245907208c4SChristophe Leroy The same can be achieved by simple writing of the PLPRCR 246907208c4SChristophe Leroy to itself. If a bit value should be preserved, read the 247907208c4SChristophe Leroy register, ZERO the bit and write, not OR, the result back. 248907208c4SChristophe Leroy */ 249ba3da734SChristophe Leroy setbits_be32(&immr->im_clkrst.car_plprcr, 0); 250907208c4SChristophe Leroy } 251907208c4SChristophe Leroy 252907208c4SChristophe Leroy /************************************************************************/ 253