]> git.kernelconcepts.de Git - karo-tx-redboot.git/blobdiff - packages/hal/arm/at91/var/v2_0/src/at91_misc.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / hal / arm / at91 / var / v2_0 / src / at91_misc.c
index 946438d66333fd2cb1d78043b9ddf4da989fc67e..c244270da8287c0002b460e3785ec74d500b3827 100644 (file)
 #include <cyg/hal/var_io.h>             // platform registers
 
 // -------------------------------------------------------------------------
-// Clock support
-
-static cyg_uint32 _period;
-
-void hal_clock_initialize(cyg_uint32 period)
-{
-    CYG_ADDRESS timer = AT91_TC+AT91_TC_TC0;
-
-    CYG_ASSERT(period < 0x10000, "Invalid clock period");
-
-    // Disable counter
-    HAL_WRITE_UINT32(timer+AT91_TC_CCR, AT91_TC_CCR_CLKDIS);
-
-    // Set registers
-    HAL_WRITE_UINT32(timer+AT91_TC_CMR, AT91_TC_CMR_CPCTRG |        // Reset counter on CPC
-                                        AT91_TC_CMR_CLKS_MCK32);    // 1 MHz
-    HAL_WRITE_UINT32(timer+AT91_TC_RC, period);
-
-    // Start timer
-    HAL_WRITE_UINT32(timer+AT91_TC_CCR, AT91_TC_CCR_TRIG | AT91_TC_CCR_CLKEN);
-
-    // Enable timer 0 interrupt    
-    HAL_WRITE_UINT32(timer+AT91_TC_IER, AT91_TC_IER_CPC);
-}
+// Hardware init
 
-void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
+void hal_hardware_init(void)
 {
-    CYG_ADDRESS timer = AT91_TC+AT91_TC_TC0;
-    cyg_uint32 sr;
-
-    CYG_ASSERT(period < 0x10000, "Invalid clock period");
-
-    HAL_READ_UINT32(timer+AT91_TC_SR, sr);  // Clear interrupt
+    unsigned i;
 
-    if (period != _period) {
-        hal_clock_initialize(period);
-    }
-    _period = period;
+    // Reset all interrupts
+    HAL_WRITE_UINT32(AT91_AIC+AT91_AIC_IDCR, 0xFFFFFFFF);
 
-}
+    // Flush internal priority level stack
+    for (i = 0; i < 8; ++i)
+        HAL_WRITE_UINT32(AT91_AIC+AT91_AIC_EOI, 0xFFFFFFFF);
 
-void hal_clock_read(cyg_uint32 *pvalue)
-{
-    CYG_ADDRESS timer = AT91_TC+AT91_TC_TC0;
-    cyg_uint32 val;
+#ifdef HAL_PLF_HARDWARE_INIT
+    // Perform any platform specific initializations
+    HAL_PLF_HARDWARE_INIT();
+#endif
 
-    HAL_READ_UINT32(timer+AT91_TC_CV, val);
-    *pvalue = val;
+    // Set up eCos/ROM interfaces
+    hal_if_init();
 }
 
-// -------------------------------------------------------------------------
-//
-// Delay for some number of micro-seconds
-//   Use timer #2 in MCLOCK/32 mode.
-//
-void hal_delay_us(cyg_int32 usecs)
+#if CYGINT_HAL_ARM_AT91_SYS_INTERRUPT
+// Decode a system interrupt. Not all systems have all interrupts. So
+// code will only be generated for those interrupts which have a
+// defined value.
+static int sys_irq_handler(void)
 {
-    cyg_uint32 stat;
-    cyg_uint64 ticks;
-#if defined(CYGHWR_HAL_ARM_AT91_JTST)
-    // TC2 is reserved for AD/DA. Use TC1 instead. 
-    CYG_ADDRESS timer = AT91_TC+AT91_TC_TC1;
-#else
-    CYG_ADDRESS timer = AT91_TC+AT91_TC_TC2;
+  cyg_uint32 sr, mr;
+
+#ifdef CYGNUM_HAL_INTERRUPT_PITC
+  // Periodic Interrupt Timer Controller
+  HAL_READ_UINT32((AT91_PITC+AT91_PITC_PISR), sr);
+  if (sr & AT91_PITC_PISR_PITS) {
+    return CYGNUM_HAL_INTERRUPT_PITC;
+  }
 #endif
-    // Calculate how many timer ticks the required number of
-    // microseconds equate to. We do this calculation in 64 bit
-    // arithmetic to avoid overflow.
-    ticks = (((cyg_uint64)usecs) * ((cyg_uint64)CYGNUM_HAL_ARM_AT91_CLOCK_SPEED))/32000000LL;
-    
-    // Disable counter
-    HAL_WRITE_UINT32(timer+AT91_TC_CCR, AT91_TC_CCR_CLKDIS);
-
-    // Set registers
-    HAL_WRITE_UINT32(timer+AT91_TC_CMR, AT91_TC_CMR_CLKS_MCK32);  // 1MHz
-    HAL_WRITE_UINT32(timer+AT91_TC_RA, 0);
-    HAL_WRITE_UINT32(timer+AT91_TC_RC, ticks);
 
-       // Clear status flags
-    HAL_READ_UINT32(timer+AT91_TC_SR, stat);
-
-    // Start timer
-    HAL_WRITE_UINT32(timer+AT91_TC_CCR, AT91_TC_CCR_TRIG | AT91_TC_CCR_CLKEN);
-
-    // Wait for the compare
-    do {
-        HAL_READ_UINT32(timer+AT91_TC_SR, stat);
-    } while ((stat & AT91_TC_SR_CPC) == 0);
-}
+#ifdef CYGNUM_HAL_INTERRUPT_DBG
+  // Debug Unit
+  HAL_READ_UINT32((AT91_DBG + AT91_DBG_CSR), sr);
+  HAL_READ_UINT32((AT91_DBG + AT91_DBG_IMR), mr);
+  if (sr & mr) {
+    return CYGNUM_HAL_INTERRUPT_DBG;
+  }
+#endif
 
-// -------------------------------------------------------------------------
-// Hardware init
+#ifdef CYGNUM_HAL_INTERRUPT_RTTC
+  /* Real Time Timer. Check the interrupt is enabled, not that just
+     the status indicates there is an interrupt. It takes a while for
+     the status bit to clear. */
+  HAL_READ_UINT32((AT91_RTTC+AT91_RTTC_RTSR), sr);
+  HAL_READ_UINT32((AT91_RTTC+AT91_RTTC_RTMR), mr);
+  if (((mr & AT91_RTTC_RTMR_ALMIEN) &&
+       (sr & AT91_RTTC_RTSR_ALMS)) ||
+      ((mr & AT91_RTTC_RTMR_RTTINCIEN) &&
+       (sr & AT91_RTTC_RTSR_RTTINC))) {
+    return CYGNUM_HAL_INTERRUPT_RTTC;
+  }
+#endif
 
-void hal_hardware_init(void)
-{
-    unsigned i;
+#ifdef CYGNUM_HAL_INTERRUPT_PMC
+  // Power Management Controller
+  HAL_READ_UINT32((AT91_PMC+AT91_PMC_IMR), mr);
+  HAL_READ_UINT32((AT91_PMC+AT91_PMC_SR), sr);
+  if ((sr & mr) & 
+      (AT91_PMC_SR_MOSCS   |
+       AT91_PMC_SR_LOCK    |
+       AT91_PMC_SR_MCKRDY  |
+       AT91_PMC_SR_PCK0RDY |
+       AT91_PMC_SR_PCK1RDY |
+       AT91_PMC_SR_PCK2RDY |
+       AT91_PMC_SR_PCK3RDY)) {
+    return CYGNUM_HAL_INTERRUPT_PMC;
+  }
+#endif
 
-    // Reset all interrupts
-    HAL_WRITE_UINT32(AT91_AIC+AT91_AIC_IDCR, 0xFFFFFFFF);
+#ifdef CYGNUM_HAL_INTERRUPT_MC
+  // Memory controller
+  HAL_READ_UINT32((AT91_MC+AT91_MC_FMR), mr);
+  HAL_READ_UINT32((AT91_MC+AT91_MC_FSR), sr);
+  if ((sr & mr) & 
+      (AT91_MC_FSR_FRDY  |
+       AT91_MC_FSR_LOCKE |
+       AT91_MC_FSR_PROGE)) {
+    return CYGNUM_HAL_INTERRUPT_MC;
+  }
+#endif
 
-    // Flush internal priority level stack
-    for (i = 0; i < 8; ++i)
-        HAL_WRITE_UINT32(AT91_AIC+AT91_AIC_EOI, 0xFFFFFFFF);
-    
-    // Set up eCos/ROM interfaces
-    hal_if_init();
+#ifdef CYGNUM_HAL_INTERRUPT_WDTC
+  // Watchdog Timer Controller
+  HAL_READ_UINT32((AT91_WDTC+AT91_WDTC_WDSR), sr);
+  HAL_READ_UINT32((AT91_WDTC+AT91_WDTC_WDMR), mr);
+  if ((mr & AT91_WDTC_WDMR_FIEN) &&
+      sr & (AT91_WDTC_WDSR_UNDER |
+            AT91_WDTC_WDSR_ERROR)) {
+    return CYGNUM_HAL_INTERRUPT_WDTC;
+  }
+#endif
 
+#ifdef CYGNUM_HAL_INTERRUPT_RSTC
+  // Reset Controller
+  HAL_READ_UINT32((AT91_RST + AT91_RST_RSR), sr);
+  HAL_READ_UINT32((AT91_RST + AT91_RST_RMR), mr);
+  if (((mr & AT91_RST_RMR_URSTIEN) && (sr & AT91_RST_RSR_USER)) ||  
+      ((mr & AT91_RST_RMR_BODIEN) && (sr & AT91_RST_RSR_BROWN)))
+    return CYGNUM_HAL_INTERRUPT_RSTC;
+#endif
+  
+  return CYGNUM_HAL_INTERRUPT_NONE;
 }
+#endif
 
 // -------------------------------------------------------------------------
 // This routine is called to respond to a hardware interrupt (IRQ).  It
@@ -204,7 +208,13 @@ int hal_IRQ_handler(void)
 
     HAL_READ_UINT32(AT91_AIC+AT91_AIC_ISR, irq_num);
 
-    // An invalid interrrupt source is treated as a spurious interrupt    
+#if CYGINT_HAL_ARM_AT91_SYS_INTERRUPT
+    if (irq_num == CYGNUM_HAL_INTERRUPT_SYS) {
+      // determine the source of the system interrupt
+      irq_num = sys_irq_handler();
+    }
+#endif
+    // An invalid interrupt source is treated as a spurious interrupt    
     if (irq_num < CYGNUM_HAL_ISR_MIN || irq_num > CYGNUM_HAL_ISR_MAX)
       irq_num = CYGNUM_HAL_INTERRUPT_NONE;
     
@@ -220,6 +230,13 @@ void hal_interrupt_mask(int vector)
     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
 
+#if CYGINT_HAL_ARM_AT91_SYS_INTERRUPT
+    if (vector >= 32) {
+      HAL_WRITE_UINT32(AT91_AIC+AT91_AIC_IDCR, 
+                       (1 << CYGINT_HAL_ARM_AT91_SYS_INTERRUPT));
+      return;
+    }
+#endif
     HAL_WRITE_UINT32(AT91_AIC+AT91_AIC_IDCR, (1<<vector));
 }
 
@@ -228,6 +245,14 @@ void hal_interrupt_unmask(int vector)
     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
 
+#if CYGINT_HAL_ARM_AT91_SYS_INTERRUPT
+    if (vector >= 32) {
+      hal_interrupt_configure(CYGINT_HAL_ARM_AT91_SYS_INTERRUPT, true, true);
+      HAL_WRITE_UINT32(AT91_AIC+AT91_AIC_IECR, 
+                       (1 <<CYGINT_HAL_ARM_AT91_SYS_INTERRUPT));
+      return;
+    }
+#endif
     HAL_WRITE_UINT32(AT91_AIC+AT91_AIC_IECR, (1<<vector));
 }
 
@@ -245,6 +270,10 @@ void hal_interrupt_configure(int vector, int level, int up)
     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
 
+#if CYGINT_HAL_ARM_AT91_SYS_INTERRUPT
+    if (vector >= 32) 
+      return;
+#endif
     if (level) {
         if (up) {
             mode = AT91_AIC_SMR_LEVEL_HI;
@@ -270,6 +299,11 @@ void hal_interrupt_set_level(int vector, int level)
                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
     CYG_ASSERT(level >= 0 && level <= 7, "Invalid level");
 
+#if CYGINT_HAL_ARM_AT91_SYS_INTERRUPT
+    if (vector >= 32) 
+      return;
+#endif
+
     HAL_READ_UINT32(AT91_AIC+(AT91_AIC_SMR0+(vector*4)), mode);
     mode = (mode & ~AT91_AIC_SMR_PRIORITY) | level;
     HAL_WRITE_UINT32(AT91_AIC+(AT91_AIC_SMR0+(vector*4)), mode);
@@ -281,15 +315,31 @@ void hal_show_IRQ(int vector, int data, int handler)
 }
 
 
+#ifndef AT91_RST
 /* Use the watchdog to generate a reset */
 void hal_at91_reset_cpu(void)
 {
     HAL_WRITE_UINT32(AT91_WD + AT91_WD_OMR, AT91_WD_OMR_OKEY);
     HAL_WRITE_UINT32(AT91_WD + AT91_WD_CMR, AT91_WD_CMR_CKEY);
     HAL_WRITE_UINT32(AT91_WD + AT91_WD_CR, AT91_WD_CR_RSTKEY);
-    HAL_WRITE_UINT32(AT91_WD + AT91_WD_OMR, AT91_WD_OMR_OKEY | AT91_WD_OMR_RSTEN | AT91_WD_OMR_WDEN);
+    HAL_WRITE_UINT32(AT91_WD + AT91_WD_OMR, 
+                     (AT91_WD_OMR_OKEY | 
+                      AT91_WD_OMR_RSTEN |
+                      AT91_WD_OMR_EXTEN | // also reset external circuitry
+                      AT91_WD_OMR_WDEN));
     while(1) CYG_EMPTY_STATEMENT;
 }
-
+#else
+/* Use the Reset Controller to generate a reset */
+void hal_at91_reset_cpu(void)
+{
+  HAL_WRITE_UINT32(AT91_RST + AT91_RST_RCR,
+                   AT91_RST_RCR_PROCRST |                   
+                   AT91_RST_RCR_ICERST  |
+                   AT91_RST_RCR_PERRST  |
+                   AT91_RST_RCR_KEY);
+  while(1) CYG_EMPTY_STATEMENT;
+}
+#endif
 //--------------------------------------------------------------------------
 // EOF at91_misc.c