Merge branch "preempt" in "trunk".
[bertos.git] / bertos / cpu / arm / drv / ser_at91.c
index bc1555c25c75434dd638cef0e2430f52c996f974..0ddeee5ae8b6aca2b10b9890edc027a727c51b67 100644 (file)
  * the GNU General Public License.
  *
  * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
- * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
+ * Copyright 2000 Bernie Innocenti <bernie@codewiz.org>
  *
  * -->
  *
  * \brief ARM UART and SPI I/O driver
  *
  *
- * \version $Id: ser_at91.c 20881 2008-03-04 14:07:02Z batt $
+ * \version $Id$
  * \author Daniele Basile <asterix@develer.com>
  */
 
-#include "hw_ser.h"  /* Required for bus macros overrides */
-#include "hw_cpu.h"  /* CLOCK_FREQ */
+#include "hw/hw_ser.h"  /* Required for bus macros overrides */
+#include <hw/hw_cpufreq.h>  /* CPU_FREQ */
 
+#include "cfg/cfg_ser.h"
 #include <cfg/debug.h>
 
-#include <appconfig.h>
 
 #include <io/arm.h>
 
@@ -52,7 +52,7 @@
 #include <drv/ser.h>
 #include <drv/ser_p.h>
 
-#include <mware/fifobuf.h>
+#include <struct/fifobuf.h>
 
 
 #define SERIRQ_PRIORITY 4 ///< default priority for serial irqs.
@@ -84,7 +84,7 @@
         *
         * - Disable GPIO on USART0 tx/rx pins
         */
-       #if !CPU_ARM_AT91SAM7S256 && !CPU_ARM_AT91SAM7X256 && !CPU_ARM_AT91SAM7X128
+       #if !CPU_ARM_SAM7S_LARGE && !CPU_ARM_SAM7X
                #warning Check USART0 pins!
        #endif
        #define SER_UART0_BUS_TXINIT do { \
         *
         * - Disable GPIO on USART1 tx/rx pins
         */
-       #if !CPU_ARM_AT91SAM7S256 && !CPU_ARM_AT91SAM7X256 && !CPU_ARM_AT91SAM7X128
+       #if !CPU_ARM_SAM7S_LARGE && !CPU_ARM_SAM7X
                #warning Check USART1 pins!
        #endif
        #define SER_UART1_BUS_TXINIT do { \
        #define SER_SPI0_BUS_TXCLOSE
 #endif
 
-#if CPU_ARM_AT91SAM7X128 || CPU_ARM_AT91SAM7X256
+#if CPU_ARM_SAM7X
 
        #ifndef SER_SPI1_BUS_TXINIT
                /**
 /*\}*/
 
 
-/**
- * \def CONFIG_SER_STROBE
- *
- * This is a debug facility that can be used to
- * monitor SER interrupt activity on an external pin.
- *
- * To use strobes, redefine the macros SER_STROBE_ON,
- * SER_STROBE_OFF and SER_STROBE_INIT and set
- * CONFIG_SER_STROBE to 1.
- */
-#if !defined(CONFIG_SER_STROBE) || !CONFIG_SER_STROBE
-       #define SER_STROBE_ON    do {/*nop*/} while(0)
-       #define SER_STROBE_OFF   do {/*nop*/} while(0)
-       #define SER_STROBE_INIT  do {/*nop*/} while(0)
-#endif
 
 
 /* From the high-level serial driver */
-extern struct Serial ser_handles[SER_CNT];
+extern struct Serial *ser_handles[SER_CNT];
 
 /* TX and RX buffers */
 static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
@@ -231,7 +216,7 @@ static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
 
 static unsigned char spi0_txbuffer[CONFIG_SPI0_TXBUFSIZE];
 static unsigned char spi0_rxbuffer[CONFIG_SPI0_RXBUFSIZE];
-#if CPU_ARM_AT91SAM7X128 || CPU_ARM_AT91SAM7X256
+#if CPU_ARM_SAM7X
 static unsigned char spi1_txbuffer[CONFIG_SPI1_TXBUFSIZE];
 static unsigned char spi1_rxbuffer[CONFIG_SPI1_RXBUFSIZE];
 #endif
@@ -258,27 +243,11 @@ struct ArmSerial
        volatile bool sending;
 };
 
-
-/*
- * These are to trick GCC into *not* using absolute addressing mode
- * when accessing ser_handles, which is very expensive.
- *
- * Accessing through these pointers generates much shorter
- * (and hopefully faster) code.
- */
-struct Serial *ser_uart0 = &ser_handles[SER_UART0];
-struct Serial *ser_uart1 = &ser_handles[SER_UART1];
-
-struct Serial *ser_spi0 = &ser_handles[SER_SPI0];
-#if CPU_ARM_AT91SAM7X128 || CPU_ARM_AT91SAM7X256
-struct Serial *ser_spi1 = &ser_handles[SER_SPI1];
-#endif
-
-static void uart0_irq_dispatcher(void);
-static void uart1_irq_dispatcher(void);
-static void spi0_irq_handler(void);
-#if CPU_ARM_AT91SAM7X128 || CPU_ARM_AT91SAM7X256
-static void spi1_irq_handler(void);
+static ISR_PROTO(uart0_irq_dispatcher);
+static ISR_PROTO(uart1_irq_dispatcher);
+static ISR_PROTO(spi0_irq_handler);
+#if CPU_ARM_SAM7X
+static ISR_PROTO(spi1_irq_handler);
 #endif
 /*
  * Callbacks for USART0
@@ -342,7 +311,7 @@ static void uart0_enabletxirq(struct SerialHardware *_hw)
 static void uart0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
 {
        /* Compute baud-rate period */
-       US0_BRGR = CLOCK_FREQ / (16 * rate);
+       US0_BRGR = CPU_FREQ / (16 * rate);
        //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
 }
 
@@ -437,7 +406,7 @@ static void uart1_enabletxirq(struct SerialHardware *_hw)
 static void uart1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
 {
        /* Compute baud-rate period */
-       US1_BRGR = CLOCK_FREQ / (16 * rate);
+       US1_BRGR = CPU_FREQ / (16 * rate);
        //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
 }
 
@@ -533,14 +502,14 @@ static void spi0_starttx(struct SerialHardware *_hw)
 {
        struct ArmSerial *hw = (struct ArmSerial *)_hw;
 
-       cpuflags_t flags;
+       cpu_flags_t flags;
        IRQ_SAVE_DISABLE(flags);
 
        /* Send data only if the SPI is not already transmitting */
-       if (!hw->sending && !fifo_isempty(&ser_spi0->txfifo))
+       if (!hw->sending && !fifo_isempty(&ser_handles[SER_SPI0]->txfifo))
        {
                hw->sending = true;
-               SPI0_TDR = fifo_pop(&ser_spi0->txfifo);
+               SPI0_TDR = fifo_pop(&ser_handles[SER_SPI0]->txfifo);
        }
 
        IRQ_RESTORE(flags);
@@ -550,21 +519,24 @@ static void spi0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned
 {
        SPI0_CSR0 &= ~SPI_SCBR;
 
-       ASSERT((uint8_t)DIV_ROUND(CLOCK_FREQ, rate));
-       SPI0_CSR0 |= DIV_ROUND(CLOCK_FREQ, rate) << SPI_SCBR_SHIFT;
+       ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
+       SPI0_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
 }
 
-#if CPU_ARM_AT91SAM7X128 || CPU_ARM_AT91SAM7X256
+#if CPU_ARM_SAM7X
 /* SPI driver */
 static void spi1_init(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(struct Serial *, ser))
 {
        /* Disable PIO on SPI pins */
        PIOA_PDR = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO);
 
+       /* SPI1 pins are on B peripheral function! */
+       PIOA_BSR = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO);
+
        /* Reset device */
        SPI1_CR = BV(SPI_SWRST);
 
-/*
+       /*
         * Set SPI to master mode, fixed peripheral select, chip select directly connected to a peripheral device,
         * SPI clock set to MCK, mode fault detection disabled, loopback disable, NPCS0 active, Delay between CS = 0
         */
@@ -617,14 +589,14 @@ static void spi1_starttx(struct SerialHardware *_hw)
 {
        struct ArmSerial *hw = (struct ArmSerial *)_hw;
 
-       cpuflags_t flags;
+       cpu_flags_t flags;
        IRQ_SAVE_DISABLE(flags);
 
        /* Send data only if the SPI is not already transmitting */
-       if (!hw->sending && !fifo_isempty(&ser_spi1->txfifo))
+       if (!hw->sending && !fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
        {
                hw->sending = true;
-               SPI1_TDR = fifo_pop(&ser_spi1->txfifo);
+               SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
        }
 
        IRQ_RESTORE(flags);
@@ -634,8 +606,8 @@ static void spi1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned
 {
        SPI1_CSR0 &= ~SPI_SCBR;
 
-       ASSERT((uint8_t)DIV_ROUND(CLOCK_FREQ, rate));
-       SPI1_CSR0 |= DIV_ROUND(CLOCK_FREQ, rate) << SPI_SCBR_SHIFT;
+       ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
+       SPI1_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
 }
 #endif
 
@@ -693,7 +665,7 @@ static const struct SerialHardwareVT SPI0_VT =
        C99INIT(txStart, spi0_starttx),
        C99INIT(txSending, tx_sending),
 };
-#if CPU_ARM_AT91SAM7X128 || CPU_ARM_AT91SAM7X256
+#if CPU_ARM_SAM7X
 static const struct SerialHardwareVT SPI1_VT =
 {
        C99INIT(init, spi1_init),
@@ -738,7 +710,7 @@ static struct ArmSerial UARTDescs[SER_CNT] =
                },
                C99INIT(sending, false),
        },
-       #if CPU_ARM_AT91SAM7X128 || CPU_ARM_AT91SAM7X256
+       #if CPU_ARM_SAM7X
        {
                C99INIT(hw, /**/) {
                        C99INIT(table, &SPI1_VT),
@@ -766,7 +738,7 @@ static void uart0_irq_tx(void)
 {
        SER_STROBE_ON;
 
-       struct FIFOBuffer * const txfifo = &ser_uart0->txfifo;
+       struct FIFOBuffer * const txfifo = &ser_handles[SER_UART0]->txfifo;
 
        if (fifo_isempty(txfifo))
        {
@@ -794,14 +766,14 @@ static void uart0_irq_rx(void)
        SER_STROBE_ON;
 
        /* Should be read before US_CRS */
-       ser_uart0->status |= US0_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
+       ser_handles[SER_UART0]->status |= US0_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
        US0_CR = BV(US_RSTSTA);
 
        char c = US0_RHR;
-       struct FIFOBuffer * const rxfifo = &ser_uart0->rxfifo;
+       struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART0]->rxfifo;
 
        if (fifo_isfull(rxfifo))
-               ser_uart0->status |= SERRF_RXFIFOOVERRUN;
+               ser_handles[SER_UART0]->status |= SERRF_RXFIFOOVERRUN;
        else
                fifo_push(rxfifo, c);
 
@@ -811,8 +783,7 @@ static void uart0_irq_rx(void)
 /**
  * Serial IRQ dispatcher for USART0.
  */
-static void uart0_irq_dispatcher(void) __attribute__ ((interrupt));
-static void uart0_irq_dispatcher(void)
+static DECLARE_ISR(uart0_irq_dispatcher)
 {
        if (US0_CSR & BV(US_RXRDY))
                uart0_irq_rx();
@@ -831,7 +802,7 @@ static void uart1_irq_tx(void)
 {
        SER_STROBE_ON;
 
-       struct FIFOBuffer * const txfifo = &ser_uart1->txfifo;
+       struct FIFOBuffer * const txfifo = &ser_handles[SER_UART1]->txfifo;
 
        if (fifo_isempty(txfifo))
        {
@@ -859,14 +830,14 @@ static void uart1_irq_rx(void)
        SER_STROBE_ON;
 
        /* Should be read before US_CRS */
-       ser_uart1->status |= US1_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
+       ser_handles[SER_UART1]->status |= US1_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
        US1_CR = BV(US_RSTSTA);
 
        char c = US1_RHR;
-       struct FIFOBuffer * const rxfifo = &ser_uart1->rxfifo;
+       struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART1]->rxfifo;
 
        if (fifo_isfull(rxfifo))
-               ser_uart1->status |= SERRF_RXFIFOOVERRUN;
+               ser_handles[SER_UART1]->status |= SERRF_RXFIFOOVERRUN;
        else
                fifo_push(rxfifo, c);
 
@@ -876,8 +847,7 @@ static void uart1_irq_rx(void)
 /**
  * Serial IRQ dispatcher for USART1.
  */
-static void uart1_irq_dispatcher(void) __attribute__ ((interrupt));
-static void uart1_irq_dispatcher(void)
+static DECLARE_ISR(uart1_irq_dispatcher)
 {
        if (US1_CSR & BV(US_RXRDY))
                uart1_irq_rx();
@@ -892,24 +862,23 @@ static void uart1_irq_dispatcher(void)
 /**
  * SPI0 interrupt handler
  */
-static void spi0_irq_handler(void) __attribute__ ((interrupt));
-static void spi0_irq_handler(void)
+static DECLARE_ISR(spi0_irq_handler)
 {
        SER_STROBE_ON;
 
        char c = SPI0_RDR;
        /* Read incoming byte. */
-       if (!fifo_isfull(&ser_spi0->rxfifo))
-               fifo_push(&ser_spi0->rxfifo, c);
+       if (!fifo_isfull(&ser_handles[SER_SPI0]->rxfifo))
+               fifo_push(&ser_handles[SER_SPI0]->rxfifo, c);
        /*
         * FIXME
        else
-               ser_spi0->status |= SERRF_RXFIFOOVERRUN;
+               ser_handles[SER_SPI0]->status |= SERRF_RXFIFOOVERRUN;
        */
 
        /* Send */
-       if (!fifo_isempty(&ser_spi0->txfifo))
-               SPI0_TDR = fifo_pop(&ser_spi0->txfifo);
+       if (!fifo_isempty(&ser_handles[SER_SPI0]->txfifo))
+               SPI0_TDR = fifo_pop(&ser_handles[SER_SPI0]->txfifo);
        else
                UARTDescs[SER_SPI0].sending = false;
 
@@ -919,28 +888,27 @@ static void spi0_irq_handler(void)
 }
 
 
-#if CPU_ARM_AT91SAM7X128 || CPU_ARM_AT91SAM7X256
+#if CPU_ARM_SAM7X
 /**
  * SPI1 interrupt handler
  */
-static void spi1_irq_handler(void) __attribute__ ((interrupt));
-static void spi1_irq_handler(void)
+static DECLARE_ISR(spi1_irq_handler)
 {
        SER_STROBE_ON;
 
        char c = SPI1_RDR;
        /* Read incoming byte. */
-       if (!fifo_isfull(&ser_spi1->rxfifo))
-               fifo_push(&ser_spi1->rxfifo, c);
+       if (!fifo_isfull(&ser_handles[SER_SPI1]->rxfifo))
+               fifo_push(&ser_handles[SER_SPI1]->rxfifo, c);
        /*
         * FIXME
        else
-               ser_spi1->status |= SERRF_RXFIFOOVERRUN;
+               ser_handles[SER_SPI1]->status |= SERRF_RXFIFOOVERRUN;
        */
 
        /* Send */
-       if (!fifo_isempty(&ser_spi1->txfifo))
-               SPI1_TDR = fifo_pop(&ser_spi1->txfifo);
+       if (!fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
+               SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
        else
                UARTDescs[SER_SPI1].sending = false;