start of pwm interrupt support
[my-code/arm.git] / betty / interrupts.c
index fa1fcc1..df99354 100644 (file)
  */
 
 #include "interrupts.h"
+#include "functions.h"
+
+// 'module global' interrupt variable
+static t_interrupt interrupt;
 
 /*
  * functions
  */
 
+// generaal interrupt handling
+
+void interrupt_init(void) {
+
+       interrupt.default_soft_callback=0;
+       VICSoftIntClr=0xffffffff;
+       VICIntEnClr=0xffffffff;
+       VICDefVectAddr=0;
+}
+
+void interrupt_set_default_callback(u32 callback_addr) {
+
+       VICDefVectAddr=callback_addr;
+}
+
+void interrupt_set_soft_callback(void (*callback)(void)) {
+
+       interrupt.default_soft_callback=callback;
+}
+
+void interrupt_set_fiq_callback(void (*callback)(void)) {
+
+       interrupt.fiq_callback=callback;
+}
+
+void interrupt_soft_clear(u8 src_number) {
+
+       VICSoftIntClr=(1<<src_number);
+}
+void interrupt_clear(u8 src_number) {
+
+       int cnt;
+       u32 *addr;
+       u32 *cntl;
+
+       VICIntEnClr=(1<<src_number);
+       VICIntSelect&=~(1<<src_number);
+
+       addr=(u32 *)&VICVectAddr0;
+       cntl=(u32 *)&VICVectCntl0;
+
+       for(cnt=0;cnt<INTERRUPT_MAX_VIC;cnt++) {
+               if((cntl[cnt]&0x1f)==src_number) {
+                       *((volatile u32 *)(addr+cnt))=0;
+                       *((volatile u32 *)(cntl+cnt))=0;
+               }
+       }
+}
+
+void interrupt_soft_enable(u8 src_number) {
+       
+       VICSoftInt=(1<<src_number);
+}
+
+int interrupt_enable(u8 src_number,u8 mode,u8 prio,u32 callback_addr) {
+
+       u32 *addr;
+       u32 *cntl;
+
+       addr=(u32 *)&VICVectAddr0;
+       cntl=(u32 *)&VICVectCntl0;
+
+       /* check whether this ir source is allready assigned */
+       if(VICIntEnable&(1<<src_number))
+               return INTERRUPT_USED;
+
+       /* prepare depending on mode */
+       switch(mode) {
+               case INTERRUPT_MODE_FIQ:
+                       VICIntSelect|=(1<<src_number);
+                       break;
+               case INTERRUPT_MODE_VIRQ:
+                       if(addr[prio]&0x3f)
+                               return INTERRUPT_PRIORITY_USED;
+                       *((volatile u32 *)(addr+prio))=callback_addr;
+                       *((volatile u32 *)(cntl+prio))=(src_number&0x1f)+0x20;
+               case INTERRUPT_MODE_IRQ:
+               default:
+                       break;
+       }
+
+       /* force interrupt */
+       VICIntEnable=(1<<src_number);
+
+       return INTERRUPT_SET;
+}
+
+int interrupt_change_callback(u8 src_number,u32 callback) {
+
+       int i;
+       u32 *addr,*cntl;
+
+       cntl=(u32 *)&VICVectCntl0;
+       addr=(u32 *)&VICVectAddr0;
+
+       i=0;
+       while(i<INTERRUPT_MAX_VIC) {
+               if((*cntl&0x1f)==src_number) {
+                       *(addr+i)=callback;
+                       return INTERRUPT_CALLBACK_CHANGED;
+               }
+               i++;
+       }
+
+       return INTERRUPT_SRC_NOT_USED;
+}
+
+void interrupt_ack(void) {
+
+       VICVectAddr=0;
+}
+
+// specific interrupt handling
+
+// external interrupts
+void interrupt_ext_ir_config(u8 eint,u8 wakeup,u8 mode,u8 polarity) {
+
+       if(eint>3)
+               return;
+
+       if(wakeup)
+               EXTWAKE=(EXTWAKE&0xf)|(1<<eint);
+
+       EXTMODE=(EXTMODE&0xf)|(mode<<eint);
+       EXTPOLAR=(EXTPOLAR&0xf)|(polarity<<eint);
+}
+
+void interrupt_ext_ir_set(u8 eint) {
+
+       if(eint>3)
+               return;
+
+       EXTINT=(1<<eint);
+}
+
+// timer counter interrupts
+void interrupt_tc_config(u8 tcnum,u8 mode,u8 cap,u32 psv) {
+
+       if(tcnum>1)
+               return;
+
+       if(tcnum==0) {
+               T0TCR=0x03;
+               T0CTCR=mode|(cap<<2);
+               T0PR=psv;
+       }
+       else {
+               T1TCR=0x03;
+               T1CTCR=mode|(cap<<2);
+               T1PR=psv;
+       }
+}
+
+void interrupt_tc_match_config(u8 tcnum,u8 mnum,u32 val,u8 mode) {
+
+       u32 *mraddr;
+
+       if(tcnum>1)
+               return;
+
+       if(mnum>3)
+               return;
+
+       if(tcnum==0) {
+               T0MCR=(T0MCR&0x0fff)|(mode<<(3*mnum));
+               mrddr=&T0MR0
+       }
+       else {
+               T1MCR=(T1MCR&0x0fff)|(mode<<(3*mnum));
+               mrddr=&T1MR0
+       }
+
+       mraddr[mnum]=val;
+}
+
+void interrupt_tc_capt_config(u8 tcnum,u8 cnum,u8 mode) {
+
+       if(tcnum>1)
+               return;
+
+       if(cnum>3)
+               return;
+
+       if(tcnum==0)
+               T0CCR=(T0CCR&0x0fff)|(mode<<(3*cnum));
+       else
+               T1CCR=(T1CCR&0x0fff)|(mode<<(3*cnum));
+}
+
+void interrupt_tc_ir_set(u8 tcnum,u8 tcmc) {
+
+       if(tcnum>1)
+               return;
+
+       if(tcnum==0) {
+               T0IR=tcmc;
+               T0TCR=0x01;
+       }
+       else {
+               T1IR=tcmc;
+               T1TCR=0x01;
+       }
+}
+
+// pwm interrupts
+void interrupt_pwm_set_rate(u32 rate) {
+
+       PWMMR0=rate;
+}
+
+void interrupt_pwm_match_config(u8 mnum,u8 op,u8 mode,u32 val1,u32 val2) {
+
+       u32 *addr=&PWMR0;
+
+       *((volatile u32 *)(addr+mnum))=mval;
+       PWMMCR=(PWMMCR&0x1fffff)|(mode<<(op*3));
+}
+
+void interrupt_pwm_enable(u8 mode,u32 ps_val) {
+
+       PWMPR=ps_val;
+       PWMTCR=0x0b;
+}
+
+void interrupt_pwm_ir_set(u8 pwm_channel) {
+
+       PWMIR=(pwm_channel&0x0f)|((pwm_channel&0x70)<<4);
+       PWMTCR=0x09;
+}
+
 /*
  * the actual exception handlers (as defined in startup.s)
  */
@@ -25,6 +259,9 @@ void interrupt_handler_undef_instruction(void) {
 
 // software interrupt
 void interrupt_handler_soft_ir(void) {
+       
+       if(interrupt.default_soft_callback)
+               interrupt.default_soft_callback();
 }
 
 // prefetch abort
@@ -35,11 +272,10 @@ void interrupt_handler_prefetch_abort(void) {
 void interrupt_handler_data_abort(void) {
 }
 
-// irq
-void interrupt_handler_irq(void) {
-}
-
 // fiq
 void interrupt_handler_fiq(void) {
+
+       if(interrupt.fiq_callback)
+               interrupt.fiq_callback();
 }