--- linux-org/linux-2.2.5-embedded/arch/ppc/8xx_io/commproc.c Fri Apr 9 06:46:08 1999 +++ linux-york/arch/ppc/8xx_io/commproc.c Thu Feb 10 13:25:35 2000 @@ -3,6 +3,7 @@ * General Purpose functions for the global management of the * Communication Processor Module. * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) + * Copyright (c) 1999 Honeywell INUcontrol (bjorn.lundberg@inu.se) * * In addition to the individual control of the communication * channels, there are a few functions that globally affect the @@ -20,6 +21,9 @@ * memory that can never be used for microcode. If there are * applications that require more DP ram, we can expand the boundaries * but then we have to be careful of any downloaded microcode. + * + * Added support for RISC-timer IRQ and more DP ram (microcode alert). + * bjorn.lundberg@inu.se */ #include #include @@ -49,6 +53,7 @@ void *dev_id; }; static struct cpm_action cpm_vecs[CPMVEC_NR]; +static struct cpm_action cpm_risctimer_vecs[16]; static void cpm_interrupt(int irq, void * dev, struct pt_regs * regs); static void cpm_error_interrupt(void *); @@ -104,12 +109,16 @@ cpmp = (cpm8xx_t *)commproc; } +static void cpm_risctimer_interrupt(void *dev); + /* This is called during init_IRQ. We used to do it above, but this * was too early since init_IRQ was not yet called. */ void -cpm_interrupt_init() +cpm_interrupt_init(void) { + cprtt_t *rtt_pramp = (cprtt_t *)(&cpmp->cp_dparam[PROFF_RISCTT]); + /* Initialize the CPM interrupt controller. */ ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cicr = @@ -122,6 +131,19 @@ if (request_8xxirq(CPM_INTERRUPT, cpm_interrupt, 0, "cpm", NULL) != 0) panic("Could not allocate CPM IRQ!"); + /* Install our own timer handler. + */ + ((volatile immap_t *)IMAP_ADDR)->im_cpm.cp_rccr &= 0x00ff; /* stop, clear TIMEP */ + cpm_install_handler(CPMVEC_RISCTIMER, cpm_risctimer_interrupt, NULL); + rtt_pramp->tm_base = m8xx_cpm_dpalloc(4*16); + + /* want timer period = 0.1ms -> timep = 4800/1024 = 4.69 + * timep = 4 -> 4096 = 0.08533 ms -> 11719Hz + */ +#define RISCTIMER_FREQ 11719 + ((volatile immap_t *)IMAP_ADDR)->im_cpm.cp_rccr |= (4 << 8); + ((volatile immap_t *)IMAP_ADDR)->im_cpm.cp_rccr |= (0x8000); /* enable */ + /* Install our own error handler. */ cpm_install_handler(CPMVEC_ERROR, cpm_error_interrupt, NULL); @@ -144,8 +166,10 @@ if (cpm_vecs[vec].handler != 0) (*cpm_vecs[vec].handler)(cpm_vecs[vec].dev_id); - else + else { + printk("CPM : No handler for irq %x.\n", vec); ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr &= ~(1 << vec); + } /* After servicing the interrupt, we have to remove the status * indicator. @@ -164,6 +188,35 @@ { } +/* The CPM RISC timer interrupt handler. + */ +static void +cpm_risctimer_interrupt(void *dev) +{ + uint i, rter; + + /* first save then clear eventregister + */ + rter = ((volatile immap_t *)IMAP_ADDR)->im_cpm.cp_rter; + ((volatile immap_t *)IMAP_ADDR)->im_cpm.cp_rter = 0xffff; + +/* printk("CPM : RISC-irq rtmr = %x rter = %x.\n", ((immap_t *)IMAP_ADDR)->im_cpm.cp_rtmr, rter); */ + for (i=0; i<16; i++) { + if (rter & 0x0001) { +/* printk("CPM : cpm_risctimer_vecs[%d].handler=%x.\n", i, cpm_risctimer_vecs[i].handler); */ + if (cpm_risctimer_vecs[i].handler != 0) { + /* printk("CPM : calling %x.\n", cpm_risctimer_vecs[i].handler); */ + (*cpm_risctimer_vecs[i].handler)(cpm_risctimer_vecs[i].dev_id); + /* printk("CPM : called %x.\n", cpm_risctimer_vecs[i].handler); */ + } else { + printk("CPM : No handler for RISC timer %x.\n", i); + ((immap_t *)IMAP_ADDR)->im_cpm.cp_rtmr &= ~(1 << i); + } + } + rter >>= 1; + } +} + /* Install a CPM interrupt handler. */ void @@ -177,17 +230,46 @@ ((immap_t *)IMAP_ADDR)->im_cpic.cpic_cimr |= (1 << vec); } -/* Allocate some memory from the dual ported ram. We may want to - * enforce alignment restrictions, but right now everyone is a good - * citizen. +/* Install a CPM RISC timer interrupt handler. +*/ +void +cpm_install_risctimer_handler(int timer, int n_ms, void (*handler)(void *), void *dev_id) +{ + volatile cpm8xx_t *cp = cpmp; /* Get pointer to Communication Processor */ + volatile cprtt_t *rtt_pramp = (cprtt_t *)(&cpmp->cp_dparam[PROFF_RISCTT]); + + if (cpm_risctimer_vecs[timer].handler != 0) + printk("CPM RISC timer interrupt %x replacing %x\n", + (uint)handler, (uint)cpm_risctimer_vecs[timer].handler); + printk("CPM RISC timer interrupt %x\n", (uint)handler); + cpm_risctimer_vecs[timer].handler = handler; + cpm_risctimer_vecs[timer].dev_id = dev_id; + rtt_pramp->tm_cmd = (0xC0000000 | (timer<<16) | n_ms*RISCTIMER_FREQ/1000); + while (cp->cp_cpcr & CPM_CR_FLG); + cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_SET_TIMER) | CPM_CR_FLG; + while (cp->cp_cpcr & CPM_CR_FLG); + ((immap_t *)IMAP_ADDR)->im_cpm.cp_rtmr |= (1 << timer); +} + +/* Allocate some memory from the dual ported ram. + * We enforce 32 byte alignment restrictions. */ uint -m8xx_cpm_dpalloc(uint size) +m8xx_cpm_dpalloc(uint size_non_align) { uint retloc; + uint size = (((size_non_align - 1) / 32) + 1) * 32; - if ((dp_alloc_base + size) >= dp_alloc_top) + if ((dp_alloc_base + size) >= dp_alloc_top) { + if(dp_alloc_base == CPM_DATAONLY_BASE && + size < CPM_DATA2_SIZE) { + printk("Switching to DPRAM DATA2\n"); + dp_alloc_base = CPM_DATA2_BASE; + dp_alloc_top = dp_alloc_base + CPM_DATA2_SIZE; + } + else return(CPM_DP_NOSPACE); + } retloc = dp_alloc_base; dp_alloc_base += size;