initial commit of lk (little kernel) project
diff --git a/platform/at91sam7/README b/platform/at91sam7/README
new file mode 100644
index 0000000..41ce561
--- /dev/null
+++ b/platform/at91sam7/README
@@ -0,0 +1,15 @@
+
+Platform support for the ATMEL AT91SAM7[XS] ARM7 microcontrollers.
+
+This is a base platform -- it needs to be specialized for a particular
+board (see sam7ex256 as an example of this) to be useful.  In particular
+it does not provide the platform/board.h (which must include the 
+correct at91sam7*h file and mux config).
+
+TODO:
+- support clock rates other than (and above) 18MHz
+- compute uart divisor, PIT interval, etc from MCK
+- timer hook should honor the requested interval
+- current_time() should return a meaningful value
+- actually pass argument to interrupt handlers?
+
diff --git a/platform/at91sam7/at91sam7s.pins b/platform/at91sam7/at91sam7s.pins
new file mode 100644
index 0000000..e9c4474
--- /dev/null
+++ b/platform/at91sam7/at91sam7s.pins
@@ -0,0 +1,32 @@
+PA0    PWM0   TIOA0
+PA1    PWM1   TIOB0
+PA2    PWM2   SCK0
+PA3    TWD    NPCS3
+PA4    TWCK   TCLK0
+PA5    RXD0   NPCS3
+PA6    TXD0   PCK0
+PA7    RTS0   PWM3
+PA8    CTS0   ADTRG
+PA9    DRXD   NPCS1
+PA10   DTXD   NPCS2
+PA11   NPCS0  PWM0
+PA12   MISO   PWM1
+PA13   MOSI   PWM2
+PA14   SPCK   PWM3
+PA15   TF     TIOA1
+PA16   TK     TIOB1
+PA17   TD     PCK1
+PA18   RD     PCK2
+PA19   RK     FIQ
+PA20   RF     IRQ0
+PA21   RXD1   PCK1
+PA22   TXD1   NPCS3
+PA23   SCK1   PWM0
+PA24   RTS1   PWM1
+PA25   CTS1   PWM2
+PA26   DCD1   TIOA2
+PA27   DTR1   TIOB2
+PA28   DSR1   TCLK1
+PA29   RI1    TCLK2
+PA30   IRQ1   NPCS2
+PA31   NPCS1  PCK2
\ No newline at end of file
diff --git a/platform/at91sam7/at91sam7x.pins b/platform/at91sam7/at91sam7x.pins
new file mode 100644
index 0000000..f026fb6
--- /dev/null
+++ b/platform/at91sam7/at91sam7x.pins
@@ -0,0 +1,31 @@
+PA0   RXD0        NC
+PA1   TXD0        NC
+PA2   SCK0        SPI1_NPCS1
+PA3   RTS0        SPI1_NPCS2
+PA4   CTS0        SPI1_NPCS3
+PA5   RXD1        NC
+PA6   TXD1        NC
+PA7   SCK1        SPI0_NPCS1
+PA8   RTS1        SPI0_NPCS2
+PA9   CTS1        SPI0_NPCS3
+PA10  TWD         NC
+PA11  TWCK        NC
+PA12  SPI0_NPCS0  NC
+PA13  SPI0_NPCS1  PCK1
+PA14  SPI0_NPCS2  IRQ1
+PA15  SPI0_NPCS3  TCLK2
+PA16  SPI0_MISO   NC
+PA17  SPI0_MOSI   NC
+PA18  SPI0_SPCK   NC
+PA19  CANRX       NC
+PA20  CANTX       NC
+PA21  TF          SPI1_NPCS0
+PA22  TK          SPI1_SPCK
+PA23  TD          SPI1_MOSI
+PA24  RD          SPI1_MISO
+PA25  RK          SPI1_NPCS1
+PA26  RF          SPI1_NPCS2
+PA27  DRXD        PCK3
+PA28  DTXD        NC
+PA29  FIQ         SPI1_NPCS3
+PA30  IRQ0        PCK2
diff --git a/platform/at91sam7/debug.c b/platform/at91sam7/debug.c
new file mode 100644
index 0000000..2cca7b3
--- /dev/null
+++ b/platform/at91sam7/debug.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <debug.h>
+#include <printf.h>
+#include <platform/at91sam7.h>
+#include <kernel/thread.h>
+#include <stdarg.h>
+
+void ser_init(void)
+{
+    AT91DBGU *dbgu = AT91DBGU_ADDR;
+
+//    AT91PIO *pio = AT91PIO_ADDR;
+//    pio->select_a = PIN_DRXD | PIN_DTXD;
+//    pio->pio_disable = PIN_DRXD | PIN_DTXD;
+    
+    dbgu->MR = DBGU_PAR_NONE | DBGU_MODE_NORMAL;
+    // dbgu->BRGR = 10; //MCK_IN_MHZ / 115200 / 16; 
+    dbgu->BRGR = AT91_MCK_MHZ / 115200 / 16;
+    dbgu->CR = DBGU_RXEN | DBGU_TXEN;
+}
+
+void ser_putc(unsigned c)
+{
+    AT91DBGU *dbgu = AT91DBGU_ADDR;
+    if(c == 10) {
+        while(!(dbgu->SR & DBGU_TXRDY));
+        dbgu->THR = 13;
+    }
+    while(!(dbgu->SR & DBGU_TXRDY));
+    dbgu->THR = c;
+}
+
+void ser_puts(const char *s)
+{
+    AT91DBGU *dbgu = AT91DBGU_ADDR;
+    while(*s) {
+        if(*s == 10) {
+            while(!(dbgu->SR & DBGU_TXRDY));
+            dbgu->THR = 13;
+        }
+        while(!(dbgu->SR & DBGU_TXRDY));
+        dbgu->THR = *s++;
+    }
+}
+
+void dputc(char c)
+{
+	ser_putc(c);
+}
+
+void debug_halt()
+{
+	arch_disable_ints();
+    for(;;);
+}
+
+uint32_t debug_cycle_count()
+{
+	PANIC_UNIMPLEMENTED;
+}
diff --git a/platform/at91sam7/emac_dev.c b/platform/at91sam7/emac_dev.c
new file mode 100644
index 0000000..d042ef6
--- /dev/null
+++ b/platform/at91sam7/emac_dev.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <kernel/thread.h>
+#include <kernel/mutex.h>
+#include <platform/at91sam7.h>
+#include <platform/debug.h>
+
+#include <dev/ethernet.h>
+
+#include <malloc.h>
+#include <string.h>
+
+#include <hw/mii.h>
+
+void emac_init_send(void);
+
+#define PHYA 31
+
+static unsigned mi_rd(AT91EMAC *emac, unsigned addr)
+{
+    addr &= 0x1f;
+
+    thread_sleep(20);
+    
+    emac->MAN =
+        (1 << 30) |    /* sof:  01 */
+        (2 << 28) |    /* rw:   10 = read */
+        (PHYA << 23) | /* phya: PHYA */
+        (addr << 18) | /* rega: addr */
+        (2 << 16);     /* code: 10 */
+
+    while(!(emac->NSR & NSR_IDLE)) ;
+
+    thread_sleep(20);
+    return emac->MAN & 0xffff;
+}
+
+static void mi_wr(AT91EMAC *emac, unsigned addr, unsigned val)
+{
+    addr &= 0x1f;
+    val &= 0xffff;
+    
+    emac->MAN =
+        (1 << 30) |    /* sof:  01 */
+        (1 << 28) |    /* rw:   01 = read */
+        (PHYA << 23) | /* phya: PHYA */
+        (addr << 18) | /* rega: addr */
+        (2 << 16) |    /* code: 10 */
+        val;           /* data: val */
+
+    while(!(emac->NSR & NSR_IDLE)) ;
+}
+
+#define PIN_EMAC_ALL   0x3ffff
+#define PIN_PHY_PD     (1 << 18)
+#define PIN_PHY_IRQ    (1 << 26)
+
+#define PIN_PHYAD0     (1 << 26)
+#define PIN_PHYAD1     (1 << 14)
+#define PIN_PHYAD2     (1 << 13)
+#define PIN_PHYAD3     (1 << 6)
+#define PIN_PHYAD4     (1 << 5)
+#define PIN_LPBK       (1 << 15)
+#define PIN_ISOLATE    (1 << 7)
+#define PIN_RMII_MODE  (1 << 16)
+#define PIN_RMII_BTB   (1 << 4)
+
+/* select RMII w/ BTB, 100mbps duplex autonegotiate 
+** disable ISOLATE and LPBK 
+** phya=00001b
+*/
+#define PIN_RESET_LOW  (PIN_LPBK)
+
+int emac_init(void)
+{
+    AT91EMAC *emac = AT91EMAC_ADDR;
+    AT91PIO *piob = AT91PIOB_ADDR;
+    AT91PMC *pmc = AT91PMC_ADDR;
+    AT91RSTC *rstc = AT91RSTC_ADDR;
+
+    dprintf("emac_init()\n");
+    
+        /* enable clock to EMAC */
+    pmc->PCER = (1 << PID_EMAC);
+
+    thread_sleep(10);
+    
+        /* for reset, all lines are gpio inputs and pullups are
+           enabled or disabled per strapping mode defined above */
+    piob->pio_enable = PIN_EMAC_ALL | PIN_PHY_PD | PIN_PHY_IRQ;
+    piob->select_a = PIN_EMAC_ALL;
+    piob->pullup_enable = PIN_EMAC_ALL | PIN_PHY_IRQ;
+    piob->pullup_disable = PIN_LPBK | PIN_ISOLATE | PIN_RMII_MODE;
+    piob->output_disable = PIN_EMAC_ALL;
+
+        /* PHY PD becomes output and high (no powerdown mode */
+    piob->data_set = PIN_PHY_PD;
+    piob->output_enable = PIN_PHY_PD;
+
+    thread_sleep(30);
+    
+    dprintf("emac_init() - reset phy\n");
+
+        /* assert the RST line and wait until the it deasserts */
+    rstc->CR = RSTC_KEY | RSTC_EXTRST;
+    while(rstc->SR & RSTC_NRSTL) ;
+
+    thread_sleep(30);
+    
+        /* after reset all the gpios are assigned to the EMAC,
+           except for PHY_PD (which remains output and high) */
+    piob->pio_disable = PIN_EMAC_ALL;
+
+    emac->USRIO = USRIO_CLKEN;
+    
+    thread_sleep(1000);
+    
+    dprintf("emac_init() - read state\n");
+    
+    emac->NCR = NCR_MPE;
+    emac->NCFG = NCFG_CLK_d64;
+
+    dprintf("bcr = %x\n", mi_rd(emac, MII_REG_BCR));
+    dprintf("id1 = %x\n", mi_rd(emac, MII_REG_PHY_ID1));
+    dprintf("id2 = %x\n", mi_rd(emac, MII_REG_PHY_ID2));
+
+#if 0
+    unsigned state, last;
+    last = 0xff;
+    
+    for(;;) {
+        state = mi_rd(emac, MII_REG_100TX_PHY) & MII_100TX_MODE_MASK;
+        if(last != state) {
+            last = state;
+            char *name;
+            switch(state) {
+            case MII_100TX_MODE_AUTO:
+                name = "auto negotiate";
+                break;
+            case MII_100TX_MODE_10T_H:
+                name = "10-T half duplex";
+                break;
+            case MII_100TX_MODE_10T_F:
+                name = "10-T full duplex";
+                break;
+            case MII_100TX_MODE_100TX_H:
+                name = "100-TX half duplex";
+                break;
+            case MII_100TX_MODE_100TX_F:
+                name = "100-TX full duplex";
+                break;
+            case MII_100TX_MODE_ISOLATE:
+                name = "isolate";
+                break;
+            default:
+                name = "unknown";
+            }
+            dprintf("link state: %s\n", name);
+        }
+        thread_sleep(100);
+    } 
+#endif
+
+    emac_init_send();
+    
+    return 0;
+}
+
+#define XMIT_ENTRY_COUNT 32
+static emac_xmit_entry xmit_list[XMIT_ENTRY_COUNT];
+static unsigned xmit_next = 0;
+static mutex_t xmit_lock;
+
+void emac_init_send(void)
+{
+    AT91EMAC *emac = AT91EMAC_ADDR;
+    int i;
+
+    for(i = 0; i < XMIT_ENTRY_COUNT; i++) {
+        xmit_list[i].info = XMIT_USED;
+        xmit_list[i].addr = 0;
+    }
+    xmit_list[i-1].info |= XMIT_LAST;
+
+    emac->NCFG = NCFG_CLK_d64 | NCFG_SPD | NCFG_FD;
+    emac->NCR = NCR_TE | NCR_MPE;
+    emac->TBQP = (unsigned) xmit_list;
+
+    mutex_init(&xmit_lock);
+}
+
+int ethernet_send(void *data, unsigned len)
+{
+    AT91EMAC *emac = AT91EMAC_ADDR;
+
+    emac_xmit_entry *xe;
+    int waited = 0;
+
+    mutex_acquire(&xmit_lock);
+    
+    xe = xmit_list + xmit_next;
+
+    while(!(xe->info & XMIT_USED)) {
+        thread_yield();
+        waited++;
+    }
+
+    if(waited) dprintf("W%d\n",waited);
+    
+    if(xe->addr != 0) {
+        free((void*) xe->addr);
+    }
+
+    xe->addr = (unsigned) data;
+    if(xmit_next == (XMIT_ENTRY_COUNT - 1)) {
+        xe->info = XMIT_LENGTH(len) | XMIT_LAST | XMIT_WRAP;
+        xmit_next = 0;
+    } else {
+        xe->info = XMIT_LENGTH(len) | XMIT_LAST;
+        xmit_next++;
+    }
+
+    emac->NCR |= NCR_TSTART;
+
+    mutex_release(&xmit_lock);
+
+    return 0;
+}
+
diff --git a/platform/at91sam7/include/platform/at91sam7.h b/platform/at91sam7/include/platform/at91sam7.h
new file mode 100644
index 0000000..cd5a50f
--- /dev/null
+++ b/platform/at91sam7/include/platform/at91sam7.h
@@ -0,0 +1,794 @@
+/* at91sam7s.h -- AT91SAM7S hardware definitions
+**
+** Copyright 2006, Brian Swetland.  All rights reserved.
+** See provided LICENSE file or http://frotz.net/LICENSE for details.
+*/
+
+#ifndef __PLATFORM_AT91SAM7_H__ 
+#define __PLATFORM_AT91SAM7_H__
+
+#if !defined(AT91_SAM7X) && !defined(AT91_SAM7S)
+#error Unspecified Architecture - AT91SAM7S or AT91SAM7X must be defined
+#endif
+
+/* peripheral ids */
+#define PID_AIC_FIQ    0
+#define PID_SYSIRQ     1
+#define PID_PIOA       2
+#define PID_USART0     6
+#define PID_USART1     7
+#define PID_SSC        8
+#define PID_TWI        9
+#define PID_PWMC       10
+#define PID_UDP        11
+#define PID_TC0        12
+#define PID_TC1        13
+#define PID_TC2        14
+#if AT91_SAM7X
+#define PID_PIOB       3
+#define PID_SPI0       4
+#define PID_SPI1       5
+#define PID_CAN        15
+#define PID_EMAC       16
+#define PID_ADC        17
+#define PID_AIC_IRQ0   30
+#define PID_AIC_IRQ1   31
+#else
+#define PID_ADC        4
+#define PID_SPI0       5
+#define PID_AIC_IRQ    30
+#endif
+
+#define BASE_FLASH     0x00100000
+#define BASE_SRAM      0x00200000
+#define BASE_TC        0xFFFA0000
+#define BASE_UDP       0xFFFB0000
+#define BASE_TWI       0xFFFB8000
+#define BASE_USART0    0xFFFC0000
+#define BASE_USART1    0xFFFC4000
+#define BASE_PWMC      0xFFFCC000
+#define BASE_SSC       0xFFFD4000
+#define BASE_ADC       0xFFFD8000
+#define BASE_SPI0      0xFFFE0000
+
+#define BASE_AIC       0xFFFFF000
+#define BASE_DBGU      0xFFFFF200
+#define BASE_PIOA      0xFFFFF400
+#define BASE_PMC       0xFFFFFC00
+#define BASE_RSTC      0xFFFFFD00
+#define BASE_RTT       0xFFFFFD20
+#define BASE_PIT       0xFFFFFD30
+#define BASE_WDT       0xFFFFFD40
+#define BASE_VREG      0xFFFFFD60
+#define BASE_MC        0xFFFFFF00
+
+#if AT91_SAM7X
+#define BASE_CAN       0xFFFD0000
+#define BASE_EMAC      0xFFFDC000
+#define BASE_SPI1      0xFFFE4000
+#define BASE_PIOB      0xFFFFF600
+#endif
+
+
+typedef volatile unsigned int vu4;
+
+typedef struct
+{
+    vu4 MR;
+    vu4 SR;
+    vu4 PIVR;
+    vu4 PIIR;
+} AT91PIT;
+
+/* MR */
+#define PIT_PITEN     (1 << 24)
+#define PIT_PITIEN    (1 << 25)
+
+/* SR */
+#define PIT_PITS      (1)
+
+/* PIxR */
+#define PIT_PICNT(x)   (x >> 20)
+#define PIT_CPIV(x)    (x & 0x000fffff)
+
+#define AT91PIT_ADDR ((AT91PIT*) BASE_PIT)
+
+typedef struct
+{
+    vu4 CR;
+    vu4 MR;
+    vu4 IER;
+    vu4 IDR;
+    vu4 IMR;
+    vu4 SR;
+    vu4 RHR;
+    vu4 THR;
+    vu4 BRGR;
+    vu4 __0[7];
+    vu4 CIDR;
+    vu4 EXID;
+    vu4 FNR;
+} AT91DBGU;
+
+/* CR bits */
+#define DBGU_RSTRX       0x00000004
+#define DBGU_RSTTX       0x00000008
+#define DBGU_RXEN        0x00000010
+#define DBGU_RXDIS       0x00000020
+#define DBGU_TXEN        0x00000040
+#define DBGU_TXDIS       0x00000080
+#define DBGU_RSTSTA      0x00000100
+
+/* MR bits */
+#define DBGU_PAR_EVEN    0x00000000
+#define DBGU_PAR_ODD     0x00000200
+#define DBGU_PAR_SPACE   0x00000400
+#define DBGU_PAR_MARK    0x00000600
+#define DBGU_PAR_NONE    0x00000800
+
+#define DBGU_MODE_NORMAL 0x00000000
+#define DBGU_MODE_ECHO   0x0000C000
+#define DBGU_MODE_LLOOP  0x00008000
+#define DBGU_MODE_RLOOP  0x00004000
+
+/* IER, IDR, IMR, and SR bits */
+#define DBGU_RXRDY       0x00000001
+#define DBGU_TXRDY       0x00000002
+#define DBGU_ENDRX       0x00000008
+#define DBGU_ENDTX       0x00000010
+#define DBGU_OVRE        0x00000020
+#define DBGU_FRAME       0x00000040
+#define DBGU_PARE        0x00000080
+#define DBGU_TXEMPTY     0x00000200
+#define DBGU_TXBUFE      0x00000800
+#define DBGU_RXBUFF      0x00001000
+#define DBGU_COMMTX      0x40000000
+#define DBGU_COMMRX      0x80000000
+
+#define AT91DBGU_ADDR ((AT91DBGU*) BASE_DBGU)
+    
+typedef struct 
+{
+    vu4 pio_enable;
+    vu4 pio_disable;
+    vu4 pio_status;
+    vu4 __0;
+    vu4 output_enable;
+    vu4 output_disable;
+    vu4 output_status;
+    vu4 __1;
+    vu4 filter_enable;
+    vu4 filter_disable;
+    vu4 filter_status;
+    vu4 __2;
+    vu4 data_set;
+    vu4 data_clear;
+    vu4 data_status;
+    vu4 pin_status;
+    vu4 irq_enable;
+    vu4 irq_disable;
+    vu4 irq_mask;
+    vu4 irq_status;
+    vu4 multidriver_enable;
+    vu4 multidriver_disable;
+    vu4 multidriver_status;
+    vu4 __3;
+    vu4 pullup_disable;
+    vu4 pullup_enable;
+    vu4 pullup_status;
+    vu4 __4;
+    vu4 select_a;
+    vu4 select_b;
+    vu4 select_status;
+    vu4 __5[9];
+    vu4 write_enable;
+    vu4 write_disable;
+    vu4 write_status;
+} AT91PIO;    
+
+#define AT91PIOA_ADDR ((AT91PIO*) BASE_PIOA)
+#if AT91_SAM7X
+#define AT91PIOB_ADDR ((AT91PIO*) BASE_PIOB)
+#endif
+
+typedef struct 
+{
+    vu4 SCER;
+    vu4 SCDR;
+    vu4 SCSR;
+    vu4 __0;
+    vu4 PCER;
+    vu4 PCDR;
+    vu4 PCSR;
+    vu4 __1;
+    vu4 MOR;
+    vu4 MCFR;
+    vu4 __2;
+    vu4 PLLR;
+    vu4 MCKR;
+    vu4 __3[2];
+    vu4 PCK0;
+    vu4 PCK1;
+    vu4 PCK2;
+} AT91PMC;
+
+#define AT91PMC_ADDR ((AT91PMC*) BASE_PMC)
+
+/* PMC_SCER/SCDR */
+#define PMC_PCK      0x00000001
+#define PMC_UDP      0x00000080
+#define PMC_PCK0     0x00000100
+#define PMC_PCK1     0x00000200
+#define PMC_PCK2     0x00000400
+
+typedef struct 
+{
+    vu4 CR;
+    vu4 MR;
+    vu4 RDR;
+    vu4 TDR;
+    vu4 SR;
+    vu4 IER;
+    vu4 IDR;
+    vu4 IMR;
+    vu4 __0[4];
+    vu4 CSR0;
+    vu4 CSR1;
+    vu4 CSR2;
+    vu4 CSR3;
+} AT91SPI;
+
+#define AT91SPI0_ADDR ((AT91SPI*) BASE_SPI0)
+#if AT91_SAM7X
+#define AT91SPI1_ADDR ((AT91SPI*) BASE_SPI0)
+#endif
+
+/* CR bits */
+#define SPI_SPIEN         0x00000001
+#define SPI_SPIDIS        0x00000002
+#define SPI_SWRST         0x00000080
+#define SPI_LASTXFER      0x01000000
+
+/* MR bits */
+#define SPI_MSTR          0x00000001
+#define SPI_PS            0x00000002
+#define SPI_PCSDEC        0x00000004
+#define SPI_MODFDIS       0x00000010
+#define SPI_LLB           0x00000080
+#define SPI_DLYBCS(n)     (((n) & 0xff) << 24)
+#define SPI_PCS0          0x000e0000
+#define SPI_PCS1          0x000d0000
+#define SPI_PCS2          0x000b0000
+#define SPI_PCS3          0x00070000
+
+/* SR bits */
+#define SPI_RDRF          0x00000001 /* recv data reg full */
+#define SPI_TDRE          0x00000002 /* xmit data reg empty */
+#define SPI_MODF          0x00000004 /* mode fault error */
+#define SPI_OVRES         0x00000008 /* overrun error */
+#define SPI_ENDRX         0x00000010 /* end of rx buffer */
+#define SPI_ENDTX         0x00000020 /* end of tx buffer */
+#define SPI_RXBUFF        0x00000040 /* rx buffer full */
+#define SPI_TXBUFE        0x00000080 /* tx buffer empty */
+#define SPI_NSSR          0x00000100 /* rising edge on NSS */
+#define SPI_TXEMPTY       0x00000200 /* transmission regs empty */
+#define SPI_SPIENS        0x00010000
+
+typedef struct 
+{
+    vu4 FRM_NUM;
+    vu4 GLB_STAT;
+    vu4 FADDR;
+    vu4 __0;
+    vu4 IER;
+    vu4 IDR;
+    vu4 IMR;
+    vu4 ISR;
+    vu4 ICR;
+    vu4 __1;
+    vu4 RST_EP;
+    vu4 __2;
+    vu4 CSR0;
+    vu4 CSR1;
+    vu4 CSR2;
+    vu4 CSR3;
+    vu4 __3[4];
+    vu4 FDR0;
+    vu4 FDR1;
+    vu4 FDR2;
+    vu4 FDR3;
+    vu4 __4[5];
+    vu4 TXVC;
+} AT91UDP;
+
+#define AT91UDP_ADDR ((AT91UDP*) BASE_UDP)
+
+// GLB_STAT bits
+#define UDP_FADDEN    0x00000001
+#define UDP_CONFG     0x00000002
+#define UDP_ESR       0x00000004
+#define UDP_RSMINPR   0x00000008
+#define UDP_RMWUPE    0x00000010
+
+// FADDR bits
+#define UDP_FEN       0x00000100
+
+// interrupt bits
+#define UDP_EP0INT    0x00000001
+#define UDP_EP1INT    0x00000002
+#define UDP_EP2INT    0x00000004
+#define UDP_EP3INT    0x00000008
+#define UDP_RXSUSP    0x00000100
+#define UDP_RXRSM     0x00000200
+#define UDP_EXTRSM    0x00000400
+#define UDP_SOFINT    0x00000800
+#define UDP_ENDBUSRES 0x00001000
+#define UDP_WAKEUP    0x00002000
+
+// RST_EP bits
+#define UDP_EP0       0x00000001
+#define UDP_EP1       0x00000002
+#define UDP_EP2       0x00000004
+#define UDP_EP3       0x00000008
+
+// CSR bits
+#define UDP_TXCOMP         0x00000001
+#define UDP_RX_DATA_BK0    0x00000002
+#define UDP_RXSETUP        0x00000004
+#define UDP_STALLSENT      0x00000008
+#define UDP_ISOERROR       0x00000008
+#define UDP_TXPKTRDY       0x00000010
+#define UDP_FORCESTALL     0x00000020
+#define UDP_RX_DATA_BK1    0x00000040
+#define UDP_DIR            0x00000080
+
+#define UDP_DTGL           0x00000800
+#define UDP_EPEDS          0x00008000
+
+#define UDP_TYPE_CONTROL     0x00000000
+#define UDP_TYPE_ISOCH_OUT   0x00000100
+#define UDP_TYPE_BULK_OUT    0x00000200
+#define UDP_TYPE_INT_OUT     0x00000300
+#define UDP_TYPE_ISOCH_IN    0x00000500
+#define UDP_TYPE_BULK_IN     0x00000600
+#define UDP_TYPE_INT_IN      0x00000700
+
+typedef struct 
+{
+    vu4 SMR[32];
+    vu4 SVR[32];
+    vu4 IVR;
+    vu4 FVR;
+    vu4 ISR;
+    vu4 IPR;
+    vu4 IMR;
+    vu4 CISR;
+    vu4 __0[2];
+    vu4 IECR;
+    vu4 IDCR;
+    vu4 ICCR;
+    vu4 ISCR;
+    vu4 EOICR;
+    vu4 SPU;
+    vu4 DCR;
+    vu4 __1;
+    vu4 FFER;
+    vu4 FFDR;
+    vu4 FFSR;
+} AT91AIC;
+
+#define AT91AIC_ADDR ((AT91AIC*) BASE_AIC)
+
+
+typedef struct 
+{
+    vu4 CR;
+    vu4 MR;
+    vu4 IER;
+    vu4 IDR;
+    vu4 IMD;
+    vu4 CSR;
+    vu4 RHR;
+    vu4 THR;
+    vu4 BRGR;
+    vu4 RTOR;
+    vu4 TTGR;
+    vu4 __0[5];
+    vu4 FIDI;
+    vu4 NER;
+    vu4 __1;
+    vu4 IF;
+    vu4 MAN;
+} AT91USART;
+
+#define AT91USART0_ADDR ((AT91USART*) 0xFFFC0000)
+#define AT91USART1_ADDR ((AT91USART*) 0xFFFC4000)
+
+/* CR */
+#define USART_RSTRX            0x00000004
+#define USART_RSTTX            0x00000008
+#define USART_RXEN             0x00000010
+#define USART_RXDIS            0x00000020
+#define USART_TXEN             0x00000040
+#define USART_TXDIS            0x00000080
+#define USART_RSTSTA           0x00000100
+#define USART_STTBRK           0x00000200
+#define USART_STPBRK           0x00000400
+#define USART_STTTO            0x00000800
+#define USART_SENDA            0x00001000
+#define USART_RSTIT            0x00002000
+#define USART_RSTNACK          0x00004000
+#define USART_RETTO            0x00008000
+#define USART_DTREN            0x00010000
+#define USART_DTRDIS           0x00020000
+#define USART_RTSEN            0x00040000
+#define USART_RTSDIS           0x00080000
+
+/* MR */
+#define USART_MODE_NORMAL      0x00000000
+#define USART_MODE_RS485       0x00000001
+#define USART_MODE_HWHS        0x00000002
+#define USART_MODE_MODEM       0x00000003
+#define USART_MODE_ISO7816T0   0x00000004
+#define USART_MODE_ISO7816T1   0x00000006
+#define USART_MODE_IRDA        0x00000008
+
+#define USART_CLK_MCK          0x00000000
+#define USART_CLK_MCK_DIV      0x00000010
+#define USART_CLK_SCK          0x00000030
+
+#define USART_CHRL_5BITS       0x00000000
+#define USART_CHRL_6BITS       0x00000040
+#define USART_CHRL_7BITS       0x00000080
+#define USART_CHRL_8BITS       0x000000C0
+
+#define USART_SYNCHRONOUS      0x00000100
+
+#define USART_PARITY_EVEN      0x00000000
+#define USART_PARITY_ODD       0x00000200
+#define USART_PARITY_SPACE     0x00000400
+#define USART_PARITY_MARK      0x00000600
+#define USART_PARITY_NONE      0x00000800
+#define USART_PARITY_MULTIDROP 0x00000C00
+
+#define USART_1STOP            0x00000000
+#define USART_1X5STOP          0x00001000
+#define USART_2STOP            0x00002000
+
+#define USART_CHMODE_NORMAL    0x00000000
+#define USART_CHMODE_ECHO      0x00004000
+#define USART_CHMODE_LLOOP     0x00008000
+#define USART_CHMODE_RLOOP     0x0000C000
+
+#define USART_MSBF             0x00010000
+#define USART_MODE9            0x00020000
+#define USART_CLKO             0x00040000
+#define USART_OVER             0x00080000
+#define USART_INACK            0x00100000
+#define USART_DSNACK           0x00200000
+#define USART_VAR_SYNC         0x00400000
+
+#define USART_FILTER           0x10000000
+#define USART_MAN              0x20000000
+#define USART_ONEBIT           0x80000000
+
+/* CSR */
+#define USART_RXRDY            0x00000001
+#define USART_TXRDY            0x00000002
+#define USART_RXBRK            0x00000004
+#define USART_ENDRX            0x00000008
+#define USART_ENDTX            0x00000010
+#define USART_OVRE             0x00000020
+#define USART_FRAME            0x00000040
+#define USART_PARE             0x00000080
+#define USART_TIMEOUT          0x00000100
+#define USART_TXEMPTY          0x00000200
+#define USART_ITERATION        0x00000400
+#define USART_TXBUFE           0x00000800
+#define USART_RXBUFF           0x00001000
+#define USART_NACK             0x00002000
+
+
+typedef struct 
+{
+    vu4 CR;
+    vu4 SR;
+    vu4 MR;
+} AT91RSTC;
+
+#define RSTC_KEY               0xA5000000
+
+/* cr */
+#define RSTC_PROCRST           0x00000001
+#define RSTC_PERRST            0x00000004
+#define RSTC_EXTRST            0x00000008
+
+/* sr */
+#define RSTC_URSTS             0x00000001
+#define RSTC_BODSTS            0x00000002
+#define RSTC_RSTTYP_MASK       0x00000070
+#define RSTC_RSTTYP_COLD       0x00000000
+#define RSTC_RSTTYP_WATCHDOG   0x00000020
+#define RSTC_RSTTYP_SOFTWARE   0x00000030
+#define RSTC_RSTTYP_NRST_PIN   0x00000040
+#define RSTC_RSTTYP_BROWNOUT   0x00000060
+#define RSTC_NRSTL             0x00010000
+#define RSTC_SRCMP             0x00020000
+
+/* mr */
+#define RSTC_URSTEN            0x00000001
+#define RSTC_URSTIEN           0x00000010
+#define RSTC_ERSTL(n)          (((n) & 0xf) << 8)
+#define RSTC_BODIEN            0x00010000
+
+#define AT91RSTC_ADDR ((AT91RSTC*) BASE_RSTC)
+    
+#if AT91_SAM7X
+
+typedef struct
+{
+    vu4 NCR;
+    vu4 NCFG;
+    vu4 NSR;
+    vu4 __0;
+    
+    vu4 __1;
+    vu4 TSR;
+    vu4 RBQP;
+    vu4 TBQP;
+    
+    vu4 RSR;
+    vu4 ISR;
+    vu4 IER;
+    vu4 IDR;
+    
+    vu4 IMR;
+    vu4 MAN;
+    vu4 PTR;
+    vu4 PFR;
+    
+    vu4 FTO;
+    vu4 SCF;
+    vu4 MCF;
+    vu4 FRO;
+    
+    vu4 FCSE;
+    vu4 ALE;
+    vu4 DTF;
+    vu4 LCOL;
+    
+    vu4 ECOL;
+    vu4 TUND;
+    vu4 CSE;
+    vu4 RRE;
+    
+    vu4 ROV;
+    vu4 RSE;
+    vu4 ELE;
+    vu4 RJA;
+    
+    vu4 USF;
+    vu4 STE;
+    vu4 RLE;
+    vu4 __2;
+    
+    vu4 HRB;
+    vu4 HRT;
+    vu4 SA1B;
+    vu4 SA1T;
+    
+    vu4 SA2B;
+    vu4 SA2T;
+    vu4 SA3B;
+    vu4 SA3T;
+    
+    vu4 SA4B;
+    vu4 SA5T;
+    vu4 TID;
+    vu4 __3;
+    
+    vu4 USRIO;
+} AT91EMAC;
+
+
+#define NCR_LB        0x00000001
+#define NCR_LLB       0x00000002
+#define NCR_RE        0x00000004
+#define NCR_TE        0x00000008
+#define NCR_MPE       0x00000010
+#define NCR_CLRSTAT   0x00000020
+#define NCR_INCSTAT   0x00000040
+#define NCR_WESTAT    0x00000080
+#define NCR_BP        0x00000100
+#define NCR_TSTART    0x00000200
+#define NCR_THALT     0x00000400
+
+#define NCFG_SPD      0x00000001
+#define NCFG_FD       0x00000002
+#define NCFG_JFRAME   0x00000008
+#define NCFG_CAF      0x00000010
+#define NCFG_NBC      0x00000020
+#define NCFG_MTI      0x00000040
+#define NCFG_UNI      0x00000080
+#define NCFG_BIG      0x00000100
+#define NCFG_CLK_d8   0x00000000
+#define NCFG_CLK_d16  0x00000400
+#define NCFG_CLK_d32  0x00000800
+#define NCFG_CLK_d64  0x00000C00
+#define NCFG_RTY      0x00001000
+#define NCFG_PAE      0x00002000
+#define NCFG_RBOF_0   0x00000000
+#define NCFG_RBOF_1   0x00004000
+#define NCFG_RBOF_2   0x00008000
+#define NCFG_RBOF_3   0x0000C000
+#define NCFG_RLCE     0x00010000
+#define NCFG_DRFCS    0x00020000
+#define NCFG_EFRHD    0x00040000
+#define NCFG_IRXFCS   0x00080000
+
+#define NSR_MDIO      0x00000002
+#define NSR_IDLE      0x00000004
+
+#define TSR_UBR       0x00000001
+#define TSR_COL       0x00000002
+#define TSR_RLE       0x00000004
+#define TSR_TGO       0x00000008
+#define TSR_BEX       0x00000010
+#define TSR_COMP      0x00000020
+#define TSR_UND       0x00000040
+
+#define RSR_BNA       0x00000001
+#define RSR_REC       0x00000002
+#define RSR_OVR       0x00000004
+
+#define ISR_MFD       0x00000001
+#define ISR_RCOMP     0x00000002
+#define ISR_RXUBR     0x00000004
+#define ISR_TXUBR     0x00000008
+#define ISR_TUND      0x00000010
+#define ISR_RLE       0x00000020
+#define ISR_TXERR     0x00000040
+#define ISR_TCOMP     0x00000080
+#define ISR_ROVR      0x00000400
+#define ISR_HRESP     0x00000800
+#define ISR_PFR       0x00001000
+#define ISR_PTZ       0x00002000
+
+#define USRIO_RMII    0x00000001
+#define USRIO_CLKEN   0x00000002
+
+#define AT91EMAC_ADDR ((AT91EMAC*) BASE_EMAC)
+
+
+typedef struct 
+{
+    vu4 addr;
+    vu4 info;
+} emac_xmit_entry;
+
+#define XMIT_USED           0x80000000
+#define XMIT_WRAP           0x40000000
+#define XMIT_ERR_RETRY      0x20000000
+#define XMIT_ERR_UNDERRUN   0x10000000
+#define XMIT_ERR_EXHAUSTED  0x08000000
+#define XMIT_NO_CRC         0x00010000
+#define XMIT_LAST           0x00008000
+#define XMIT_LENGTH(n)      ((n) & 0x3FF)
+
+
+/* CAN Registers */
+
+
+typedef struct
+{
+    vu4 MMR;		/* Mailbox Mode Register */
+    vu4 MAM;		/* Mailbox Acceptance Mask Register */
+    vu4 MID;		/* Mailbox ID Register */
+    vu4 MFID;		/* Mailbox Family ID Register */
+    vu4 MSR;		/* Mailbox Status Register */
+    vu4 MDL;		/* Mailbox Data Low Register */
+    vu4 MDH;		/* Mailbox Data High Register */
+    vu4 MCR;		/* Mailbox Control Register */
+}  AT91CAN_MAILBOX;
+
+typedef struct
+{
+    vu4 MR;		/* Mode Register */
+    vu4 IER;		/* Interrupt Enable Register */
+    vu4 IDR;		/* Interrupt Disable Register */
+    vu4 IMR;		/* Interrupt Mask Register */
+    vu4 SR;		/* Status Register */
+    vu4 BR;		/* Baudrate Register */
+    vu4 TIM;		/* Timer Register */
+    vu4 TIMESTP;	/* Timestamp Register */
+    vu4 ECR;		/* Error Counter Register */
+    vu4 TCR;		/* Transfer Command Register */
+    vu4 ACR;		/* Abort Command Register */
+    	
+    vu4 __0[53];	/* 0x002c - 0x0100 is undefined */
+    vu4 __1[63];	/* 0x0200 - 0x01fc is reserved */
+    AT91CAN_MAILBOX Mailbox[8];
+} AT91CAN;
+
+#define CAN_CANEN      0x00000001      /* CAN Controller Enable */
+#define CAN_LPM        0x00000002      /* Enable Low Power Mode */
+#define CAN_ABM        0x00000004      /* Enable Autoband/Listen Mode */
+#define CAN_OVL        0x00000008      /* Enable Overload Frame */
+#define CAN_TEOF       0x00000010      /* Timestamp Messages at each Frame */
+#define CAN_TTM        0x00000020      /* Enable Time Trigger Mode */
+#define CAN_TIMFRZ     0x00000040      /* Enable Timer Freeze */
+#define CAN_DRPT       0x00000080      /* Disable Repeat */
+
+#define CAN_MB(x)    (0x00000001 << x) /* Enable Interrupt Enable */
+#define CAN_ERRA      0x00010000      /* Enable Error Active Mode Interrupt */
+#define CAN_WARN      0x00020000      /* Enable Warning Limit Interrupt */
+#define CAN_ERRP      0x00040000      /* Enable Passive mode interrupt */
+#define CAN_BOFF      0x00080000      /* Enable Bus-off mode interrupt */
+#define CAN_SLEEP     0x00100000      /* Enable Sleep Interrupt */
+#define CAN_WAKEUP    0x00200000      /* Enable Wakeup Interrupt */
+#define CAN_TOVF      0x00400000      /* Enable Timer Overflow Interrupt */
+#define CAN_TSTP      0x00800000      /* Enable TimeStamp Interrupt */
+#define CAN_CERR      0x01000000      /* Enable CRC Error Interrupt */
+#define CAN_SERR      0x02000000      /* Enable Stuffing Error Interrupt */
+#define CAN_AERR      0x04000000      /* Enable Acknowledgement Error Int */
+#define CAN_FERR      0x08000000      /* Enable Form Error Interrupt */
+#define CAN_BERR      0x10000000      /* Enable Bit Error Interrupt */
+
+#define CAN_RBSY      0x20000000      /* Receiver Busy */
+#define CAN_TBSY      0x40000000      /* Transmitter Busy */
+#define CAN_OVLSY     0x80000000      /* Overload Busy */
+
+/* Can Baudrate Regiister */
+
+#define CAN_PHASE2(x)	(x)
+#define CAN_PHASE2_MASK	0x07
+#define CAN_PHASE1(x)	(x<<4)
+#define CAN_PHASE1_MASK	(0x07 << 4)
+#define CAN_PROPAG(x)	(x<<8)
+#define CAN_PROPAG_MASK	(0x07 << 8)
+#define CAN_SJW(x)	(x<<12)
+#define CAN_SJW_MASK(x)	(0x03 << 12)
+#define CAN_BRP(x)	(x<<16)
+#define CAN_BRP_MASK	(0x7f << 16)
+#define CAN_SMP	     0x01000000	     /* Sampling Mode */
+
+/* CAN Transfer Command Register */
+
+#define TCR_TIMRST   0x80000000	     /* Timer Reset */
+
+/* CAN Message Mode Register */
+
+#define CAN_MTIMEMARK(x)   (0x0000001 << x)
+#define CAN_PRIOR(x)	(x << 16)
+#define CAN_MOT(x)	(x << 24)
+
+#define CAN_MIDVB(x)	(x)
+#define CAN_MIDVA(x)	(x << 18)
+#define CAN_MIDE	0x20000000
+
+
+/* CAN MSRx */
+
+/* These are receive, so pass in the value of the register... */
+
+#define CAN_MTIMESTAMP(x)  (x & 0x0000ffff)
+#define CAN_MDLC(x)	   ( (x >> 16) & 0x0f)  /* Mailbox code length */
+#define CAN_MRTR	0x00100000              /* Mailbox Remote Trx Request*/
+#define CAN_MABT	0x00400000              /* Mailbox Message Abort  */
+#define CAN_MRDY	0x00800000              /* Mailbox Ready */
+#define CAN_MMI 	0x01000000              /* Mailbox Message Ignored */
+
+/* Message Control Register */
+
+//#define CAN_MDLC(x)	(x<<16)	        /* Mailbox Data Length Code */
+#define CAN_MACR	(0x01 << 22)	/* Abort Request */
+#define CAN_MTCR	(0x01 << 23)	/* Mailbox Transfer Command */
+
+
+#define AT91CAN_ADDR ((AT91CAN*) BASE_CAN)
+
+
+
+#endif
+
+#endif
diff --git a/platform/at91sam7/init_clock.S b/platform/at91sam7/init_clock.S
new file mode 100644
index 0000000..2de137f
--- /dev/null
+++ b/platform/at91sam7/init_clock.S
@@ -0,0 +1,101 @@
+/* init_clock.S -- AT91SAM7 clock coldstart code
+**
+** Copyright 2006, Brian Swetland.  All rights reserved.     
+** See provided LICENSE file or http://frotz.net/LICENSE for details.
+*/
+
+.globl init_clock
+
+init_clock:
+/* init flash controller timing for 18.432MHz */
+	mov r1, #0xffffff00
+	ldr r0, =0x00340100
+	str r0, [r1, #0x60]
+
+#define PMC_MOR    0x20
+#define PMC_MCFR   0x24
+#define PMC_PLLR   0x2c
+#define PMC_MCKR   0x30
+#define PMC_SR     0x68
+		
+/* PMC_MOR */
+#define PMC_MOSCEN     0x01
+#define PMC_OSCBYPASS  0x02
+
+/* PMC_MCFR */
+#define PMC_MAINRDY	   0x00010000
+
+/* PMC_SR */
+#define PMC_MOSCS      0x01
+#define PMC_LOCK       0x04
+#define PMC_MCKRDY     0x08
+
+/* PMC_MCKR */
+#define PMC_CSS_SLOW   0x00
+#define PMC_CSS_MAIN   0x01
+#define PMC_CSS_PLL    0x03
+#define PMC_PRES_NONE  0x00
+#define PMC_PRES_DIV2  0x04
+#define PMC_PRES_DIV4  0x08
+
+/* Oscillator Init Sequence based on the Atmel sample code
+** in cstartup_boot_SAM7S32_64.s  
+**
+** I cleaned it up a bit -- why they use a temporary register,
+** AND and then CMP instead of just TSTing against an immediate
+** boggles my mind.  I think this could be a bit simpler yet, 
+** but debugging it is a pain, so Good Enough wins for now.
+*/
+	ldr r1, =0xfffffc00
+
+/* bypass main oscillator */
+	mov r0, #PMC_OSCBYPASS
+	str r0, [r1, #PMC_MOR]
+
+/* compensate MAINRDY rising flag (45 SCLK) */
+	mov r0, #45
+1:	subs r0, r0, #1
+	bhi 1b
+
+/* if MAINRDY is set, we have an external oscillator */
+	ldr r0, [r1, #PMC_MCFR]
+	tst r0, #PMC_MAINRDY
+	bne ext_osc_found
+
+/* reset MOSCS flag */
+	mov r0, #0
+	str r0, [r1, #PMC_MOR]
+
+/* enable main oscillator */
+	ldr r0, =((0x40 << 8) | PMC_MOSCEN)
+	str r0, [r1, #PMC_MOR]
+
+/* wait for main oscillator to come online */
+1:	ldr r0, [r1, #PMC_SR]
+	tst r0, #PMC_MOSCS
+	beq 1b
+
+ext_osc_found:
+/* select main oscillator, no prescaler for MCK */
+	mov r0, #(PMC_CSS_MAIN | PMC_PRES_NONE)
+	str r0, [r1, #PMC_MCKR]
+
+/* wait until MCK settles to continue */
+1:	ldr r0, [r1, #PMC_SR]
+	tst r0, #PMC_MCKRDY
+	beq 1b
+
+/* this is a bit of voodoo for selecting a 96.109MHz PLL
+** freq (MUL=72, DIV=14, OUT=0, USBDIV=/1) from the 18.432MHz
+** main clock.
+*/
+	ldr r0, =0x10483f0e
+	str r0, [r1, #PMC_PLLR]
+
+/* let the PLL lock before we continue */
+1:	ldr r0, [r1, #PMC_SR]
+	tst r0, #PMC_LOCK
+	beq 1b
+
+	mov pc, lr
+
diff --git a/platform/at91sam7/init_clock_48mhz.S b/platform/at91sam7/init_clock_48mhz.S
new file mode 100644
index 0000000..a5bf961
--- /dev/null
+++ b/platform/at91sam7/init_clock_48mhz.S
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+.globl init_48mhz_clock
+
+#define PMC_MCKR   0x30
+#define PMC_SR     0x68
+
+#define PMC_MCKRDY     0x08
+#define PMC_PRES_DIV2  0x04
+#define PMC_CSS_PLL    0x03
+
+/* BUG?
+**
+** If I try to exit by bx lr, lr is corrupted somewhere in here.
+** No clue why.  FIQ USB wedge not playing nice?  Am I cheating
+** with my CPSR calls?
+*/
+init_48mhz_clock:
+	ldr r1, =0xfffffc00
+	mov r2, lr
+		
+	// turn on /2 prescaler
+	mov r0, #PMC_PRES_DIV2
+	str r0, [r1, #PMC_MCKR]
+wait_for_clock1:
+	ldr r0, [r1, #PMC_SR]
+	tst r0, #PMC_MCKRDY
+	beq wait_for_clock1
+
+	// switch to pll clock
+	mov r0, #(PMC_PRES_DIV2 | PMC_CSS_PLL)
+	str r0, [r1, #PMC_MCKR]
+wait_for_clock2:
+	ldr r0, [r1, #PMC_SR]
+	tst r0, #PMC_MCKRDY
+	beq wait_for_clock2
+
+	bx r2
diff --git a/platform/at91sam7/interrupts.c b/platform/at91sam7/interrupts.c
new file mode 100644
index 0000000..6c08ef9
--- /dev/null
+++ b/platform/at91sam7/interrupts.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <err.h>
+#include <sys/types.h>
+#include <kernel/thread.h>
+#include <platform.h>
+#include <platform/interrupts.h>
+#include <platform/at91sam7.h>
+#include <arch/arm.h>
+
+static int do_nothing()
+{
+    return INT_NO_RESCHEDULE;
+}
+
+void platform_init_interrupts(void)
+{
+    AT91AIC *aic = AT91AIC_ADDR;
+    int n;
+
+    for(n = 0; n < 31; n++) {
+        aic->SVR[n] = (unsigned) do_nothing;
+    }
+    aic->SPU = (unsigned) do_nothing;
+}
+
+
+status_t mask_interrupt(unsigned int vector, bool *oldstate)
+{
+    AT91AIC *aic = AT91AIC_ADDR;
+    
+    if(vector > 31) return ERR_INVALID_ARGS;
+    
+    if(oldstate) {
+        enter_critical_section();
+        *oldstate = aic->IMR & (1 << vector) ? 1 : 0;
+        aic->IDCR = (1 << vector);
+        exit_critical_section();
+    } else {
+        aic->IDCR = (1 << vector);
+    }
+    
+    return NO_ERROR;
+}
+
+status_t unmask_interrupt(unsigned int vector, bool *oldstate)
+{
+    AT91AIC *aic = AT91AIC_ADDR;
+    if(vector > 31) return ERR_INVALID_ARGS;
+
+    if(oldstate) {
+        enter_critical_section();
+        *oldstate = aic->IMR & (1 << vector) ? 1 : 0;
+        aic->IECR = (1 << vector);
+        exit_critical_section();
+    } else {
+        aic->IECR = (1 << vector);
+    }
+    
+    return NO_ERROR;
+}
+
+void platform_irq(struct arm_iframe *frame)
+{
+    AT91AIC *aic = AT91AIC_ADDR;
+    int_handler func;
+    enum handler_return ret;
+    
+    inc_critical_section();
+
+    func = (int_handler) aic->IVR;
+//    dprintf("platform_irq() -> %p\n", func);
+
+    ret = func(0);
+    
+    aic->EOICR = (unsigned) aic;
+
+    if(ret == INT_RESCHEDULE) {
+        thread_preempt();
+    }
+
+    dec_critical_section();
+}
+
+void platform_fiq(struct arm_iframe *frame)
+{
+}
+
+void register_int_handler(unsigned int vector, int_handler handler, void *arg)
+{
+    AT91AIC *aic = AT91AIC_ADDR;
+    if(vector > 31) return;
+    aic->SVR[vector] = (unsigned) handler;
+}
diff --git a/platform/at91sam7/mkboard.py b/platform/at91sam7/mkboard.py
new file mode 100755
index 0000000..62ce696
--- /dev/null
+++ b/platform/at91sam7/mkboard.py
@@ -0,0 +1,178 @@
+#!/usr/bin/python
+
+## mkboard.py -- atmel pio mux utility
+##
+## Copyright 2006, Brian Swetland.  All rights reserved.
+## See provided LICENSE file or http://frotz.net/LICENSE for details.
+##
+
+import os, sys, string
+
+# pindef -> num, out, pull, pio, sela, selb
+
+reg_output_disable = 0
+reg_output_enable = 0
+reg_pullup_disable = 0
+reg_pullup_enable = 0
+reg_pio_disable = 0
+reg_pio_enable = 0
+reg_select_a = 0
+reg_select_b = 0
+
+def setup_registers(pindef):
+    global reg_output_disable
+    global reg_output_enable
+    global reg_pullup_disable
+    global reg_pullup_enable
+    global reg_pio_disable
+    global reg_pio_enable
+    global reg_select_a
+    global reg_select_b
+    
+    (num, out, pull, pio, sela, selb) = pindef
+
+    bit = 1 << num
+    
+    if out:
+        reg_output_enable |= bit
+        reg_output_disable &= (~bit)
+    else:
+        reg_output_enable &= (~bit)
+        reg_output_disable |= bit
+
+    if pull:
+        reg_pullup_enable |= bit
+        reg_pullup_disable &= (~bit)
+    else:
+        reg_pullup_enable &= (~bit)
+        reg_pullup_disable |= bit
+
+    if pio:
+        reg_pio_enable |= bit
+        reg_pio_disable &= (~bit)
+    else:
+        reg_pio_enable &= (~bit)
+        reg_pio_disable |= bit
+
+    if sela:
+        reg_select_a |= bit
+    if selb:
+        reg_select_b |= bit
+
+def import_pindef(fn):
+    pass
+
+def read_pins_def(fn, table):
+    output = ""
+    fd = open(fn,'r')
+    for line in fd.xreadlines():
+        line = line.split('#')[0].strip()
+        if not line: continue
+
+        (gpio,pa,pb) = line.split()
+        num = int(gpio[2:])
+
+        table[gpio+"_IN"] = (num, 0, 0, 1, 0, 0)
+        table[gpio+"_IN_PULLUP"] = (num, 0, 1, 1, 0, 0)
+        table[gpio+"_OUT"] = (num, 1, 0, 1, 0, 0)
+        table[gpio+"_"+pa] = (num, 0, 0, 0, 1, 0)
+        table[gpio+"_"+pb] = (num, 0, 0, 0, 0, 1)
+
+    return output
+    
+def read_board_def(fn, table):
+    pins = {}
+    output = ""
+    for n in range(0,32):
+        pins[n] = ''
+        
+    fd = open(fn,'r')
+    for line in fd.xreadlines():
+        line = line.split('#')[0].strip()
+        if not line: continue
+
+        if len(line.split('=')) == 2:
+            (line,func) = line.split('=')
+            line = line.strip()
+            func = func.strip()
+        else:
+            func = ''
+            
+        parts = line.split()
+        if len(parts) < 2:
+            print "ERROR: invalid definition '%s'" % line
+            sys.exit(1)
+
+        if not func:
+            if (parts[1] == 'IN') or (parts[1] == 'OUT'):
+                func = parts[0]
+            else:
+                func = parts[1]
+            
+        pin = string.join(parts,"_")
+        
+        if not table.has_key(pin):
+            print "ERROR: pin '%s' does not exist" % pin
+            sys.exit(1)
+
+        pindef = table[pin]
+        num = pindef[0]
+        if pins[num]:
+            print "ERROR: pin '%s' conflicts with pin '%s'" % (pin, pins[num])
+            sys.exit(1)
+        pins[num] = pin
+
+        setup_registers(pindef)
+        output += "#define PIN_%-12s (1 << %d)\n" % (func, num)
+
+    return output
+
+table = {}
+output = ""
+    
+for fn in sys.argv[1:]:
+    if fn.endswith('.pins'):
+        if table:
+            print "ERROR: only one pin definition file allowed"
+            sys.exit(1)
+        output = read_pins_def(fn, table)
+        continue
+    
+    if fn.endswith('.def'):
+        if not table:
+            print "ERROR: must specify a pin definition file first"
+            sys.exit(1)
+
+        reg_output_disable = 0xffffffffL
+        reg_output_enable =  0L
+        reg_pullup_disable = 0L
+        reg_pullup_enable =  0xffffffffL
+        reg_pio_disable =    0L
+        reg_pio_enable =     0xffffffffL
+        reg_select_a =       0L
+        reg_select_b =       0L
+            
+        output = read_board_def(fn, table)
+        fd = open(fn[:-4] + ".h", 'w')
+        fd.write("/* DO NOT EDIT -- AUTOGENERATED FROM '%s' */\n\n" % fn)
+        fd.write("#ifndef __BOARD_DEFINITION_FILE__\n")
+        fd.write("#define __BOARD_DEFINITION_FILE__\n\n")
+        fd.write(output)
+        fd.write("\n")
+        fd.write("#define BOARD_OUTPUT_DISABLE 0x%08x\n" % reg_output_disable)
+        fd.write("#define BOARD_OUTPUT_ENABLE  0x%08x\n" % reg_output_enable)
+        fd.write("#define BOARD_PULLUP_DISABLE 0x%08x\n" % reg_pullup_disable)
+        fd.write("#define BOARD_PULLUP_ENABLE  0x%08x\n" % reg_pullup_enable)
+        fd.write("#define BOARD_PIO_DISABLE    0x%08x\n" % reg_pio_disable)
+        fd.write("#define BOARD_PIO_ENABLE     0x%08x\n" % reg_pio_enable)
+        fd.write("#define BOARD_SELECT_A       0x%08x\n" % reg_select_a)
+        fd.write("#define BOARD_SELECT_B       0x%08x\n" % reg_select_b)
+        fd.write("\n#endif\n")
+        fd.close()
+        continue
+
+    print "ERROR: what is '%s'?" % fn
+    sys.exit(1)
+    
+    
+
diff --git a/platform/at91sam7/mux.c b/platform/at91sam7/mux.c
new file mode 100644
index 0000000..7c9d9a6
--- /dev/null
+++ b/platform/at91sam7/mux.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <platform/at91sam7.h>
+#include <platform/mux.h>
+
+void mux_init(void)
+{
+	AT91PIO *pio = AT91PIOA_ADDR;
+
+	pio->output_disable = BOARD_OUTPUT_DISABLE;
+	pio->output_enable = BOARD_OUTPUT_ENABLE;
+	pio->pullup_disable = BOARD_PULLUP_DISABLE;
+	pio->pullup_enable = BOARD_PULLUP_ENABLE;
+	pio->pio_disable = BOARD_PIO_DISABLE;
+	pio->pio_enable = BOARD_PIO_ENABLE;
+	pio->select_a = BOARD_SELECT_A;
+	pio->select_b = BOARD_SELECT_B;
+}
+
diff --git a/platform/at91sam7/platform.c b/platform/at91sam7/platform.c
new file mode 100644
index 0000000..378c06d
--- /dev/null
+++ b/platform/at91sam7/platform.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+void emac_init();
+
+void platform_init(void)
+{
+#if AT91_SAM7X
+    emac_init();
+#endif
+}
diff --git a/platform/at91sam7/platform_early.S b/platform/at91sam7/platform_early.S
new file mode 100644
index 0000000..e78e271
--- /dev/null
+++ b/platform/at91sam7/platform_early.S
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+.globl platform_early_init
+platform_early_init:
+	stmdb sp!, {lr}
+		
+/* enable the NRST reset pin */
+	ldr r1, =0xfffffd08
+	ldr r0, =0xa5000401
+	str r0, [r1]
+		
+/* disable watchdog */
+	ldr r1, =0xfffffd44
+	ldr r0, =0x3fff8fff
+	str r0, [r1]
+
+	bl init_clock
+	bl init_48mhz_clock
+
+/* copy the .data section from ROM to RAM */
+	ldr     r0, =__rodata_end
+	ldr     r1, =__data_start
+	ldr     r2, =__bss_start
+__data_loop:
+	cmp     r1, r2
+	ldrlt   r3, [r0], #4
+	strlt   r3, [r1], #4
+	blt     __data_loop
+
+	bl mux_init		
+	bl ser_init
+	bl platform_init_interrupts
+		
+	ldmia sp!, {lr}
+	bx lr
diff --git a/platform/at91sam7/rules.mk b/platform/at91sam7/rules.mk
new file mode 100644
index 0000000..9186ef8
--- /dev/null
+++ b/platform/at91sam7/rules.mk
@@ -0,0 +1,70 @@
+#
+# The TARGET is expected to indicate which *specific* AT91SAM7 chip
+# is being used, since features and memory vary from chip to chip
+#
+#             chip       ram   rom    EMAC  CAN  
+# AT91CHIP := sam7s64    16k   64k    N     N    
+# AT91CHIP := sam7s256   64k   256k   N     N
+# AT91CHIP := sam7x256   64k   256k   Y     Y
+#
+
+# ROMBASE, MEMBASE, and MEMSIZE are required for the linker script
+ROMBASE := 0x0
+MEMBASE := 0x200000
+
+TMP_CFG := bad
+ifeq ($(AT91CHIP), sam7x256)
+DEFINES += AT91_SAM7X=1 
+DEFINES += AT91_RAMSIZE=65536
+DEFINES += AT91_ROMSIZE=262144
+MEMSIZE := 65536
+TMP_CFG := ok
+endif
+ifeq ($(AT91CHIP), sam7s256)
+DEFINES += AT91_SAM7S=1 
+DEFINES += AT91_RAMSIZE=65536
+DEFINES += AT91_ROMSIZE=262144
+MEMSIZE := 65536
+TMP_CFG := ok
+endif
+ifeq ($(AT91CHIP), sam7s64)
+DEFINES += AT91_SAM7S=1 
+DEFINES += AT91_RAMSIZE=16384
+DEFINES += AT91_ROMSIZE=65536
+MEMSIZE := 16384
+TMP_CFG := ok
+endif
+
+ifeq ($(TMP_CFG), bad)
+$(error The AT91SAM7 platform requires AT91CHIP be set by the target)
+endif
+
+LOCAL_DIR := $(GET_LOCAL_DIR)
+
+ARCH := arm
+ARM_CPU := arm7tdmi
+
+DEFINES += AT91_MCK_MHZ=48000000
+
+INCLUDES += \
+	-I$(LOCAL_DIR)/include
+
+OBJS += \
+	$(LOCAL_DIR)/debug.o \
+	$(LOCAL_DIR)/interrupts.o \
+	$(LOCAL_DIR)/platform_early.o \
+	$(LOCAL_DIR)/platform.o \
+	$(LOCAL_DIR)/timer.o \
+	$(LOCAL_DIR)/init_clock.o \
+	$(LOCAL_DIR)/init_clock_48mhz.o \
+	$(LOCAL_DIR)/mux.o \
+	$(LOCAL_DIR)/emac_dev.o
+
+# use a two segment memory layout, where all of the read-only sections 
+# of the binary reside in rom, and the read/write are in memory. The 
+# ROMBASE, MEMBASE, and MEMSIZE make variables are required to be set 
+# for the linker script to be generated properly.
+#
+LINKER_SCRIPT += \
+	$(BUILDDIR)/system-twosegment.ld
+
diff --git a/platform/at91sam7/timer.c b/platform/at91sam7/timer.c
new file mode 100644
index 0000000..e4b6596
--- /dev/null
+++ b/platform/at91sam7/timer.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2008 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <err.h>
+#include <sys/types.h>
+
+#include <kernel/thread.h>
+#include <platform/timer.h>
+#include <platform/interrupts.h>
+#include <platform/debug.h>
+#include <platform/at91sam7.h>
+
+#define FIXED_1KHZ_TIMER 0
+
+static platform_timer_callback timer_func;
+
+static volatile time_t ticks = 0;
+
+#if FIXED_1KHZ_TIMER
+static volatile int timer_interval;
+static volatile int timer_downcount;
+#else
+static int timer_ms_per_tick;
+#endif
+
+time_t current_time(void)
+{
+	return ticks;
+}
+
+static enum handler_return pit_irq_handler(void *arg)
+{
+    AT91PIT *pit = AT91PIT_ADDR;
+    unsigned n = PIT_PICNT(pit->PIVR);
+
+#if FIXED_1KHZ_TIMER
+    ticks += n;
+    timer_downcount -= n;
+
+    if(timer_downcount <= 0) {
+        timer_downcount = timer_interval;
+        return timer_func(0, ticks);
+    } else {
+        return INT_NO_RESCHEDULE;
+    }
+#else
+    ticks += (n * timer_ms_per_tick);
+    return timer_func(0, ticks);
+#endif
+}
+
+status_t platform_set_periodic_timer(platform_timer_callback callback,
+                                     void *arg, time_t interval)
+{
+    unsigned n;
+    
+    AT91PIT *pit = AT91PIT_ADDR;
+
+    n = AT91_MCK_MHZ / 16 / 1000;
+    dprintf("timer: MCK=%dKHz, n=%d\n", AT91_MCK_MHZ / 1000, n);
+
+    enter_critical_section();
+    
+    timer_func = callback;
+
+#if FIXED_1KHZ_TIMER
+    timer_interval = interval;
+    timer_downcount = interval;
+#else
+    timer_ms_per_tick = interval;
+    n *= interval;
+#endif
+    
+    pit->MR = PIT_PITEN | PIT_PITIEN | (n & 0xfffff);
+    
+    register_int_handler(PID_SYSIRQ, pit_irq_handler, 0);
+    unmask_interrupt(PID_SYSIRQ, 0);
+
+    exit_critical_section();
+    
+    return NO_ERROR;
+}
+