From 949166d6c0436afba8b78420e6ef64a9719b9fca Mon Sep 17 00:00:00 2001 From: Thomas Doerfler Date: Fri, 27 Feb 2009 12:12:08 +0000 Subject: added missing files --- c/src/lib/libbsp/arm/lpc24xx/network/network.c | 1176 ++++++++++++++++++++ c/src/lib/libbsp/arm/lpc24xx/startup/bspreset.c | 27 + .../libbsp/arm/lpc24xx/startup/linkcmds.lpc2478 | 14 + .../arm/lpc24xx/startup/linkcmds.lpc2478_ncs | 14 + .../arm/lpc24xx/startup/linkcmds.lpc2478_ncs_ram | 14 + c/src/lib/libbsp/arm/shared/startup/linkcmds.rom | 385 +++++++ make/custom/lpc2478_ncs.cfg | 14 + make/custom/lpc2478_ncs_ram.cfg | 14 + make/custom/lpc24xx.cfg | 18 + 9 files changed, 1676 insertions(+) create mode 100644 c/src/lib/libbsp/arm/lpc24xx/network/network.c create mode 100644 c/src/lib/libbsp/arm/lpc24xx/startup/bspreset.c create mode 100644 c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478 create mode 100644 c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478_ncs create mode 100644 c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478_ncs_ram create mode 100644 c/src/lib/libbsp/arm/shared/startup/linkcmds.rom create mode 100644 make/custom/lpc2478_ncs.cfg create mode 100644 make/custom/lpc2478_ncs_ram.cfg create mode 100644 make/custom/lpc24xx.cfg diff --git a/c/src/lib/libbsp/arm/lpc24xx/network/network.c b/c/src/lib/libbsp/arm/lpc24xx/network/network.c new file mode 100644 index 0000000000..ede668a3ce --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/network/network.c @@ -0,0 +1,1176 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * @brief Network driver. + */ + +/* + * Copyright (c) 2008 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be found in the file + * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#if MCLBYTES > (2 * 1024) + #error "MCLBYTES to large" +#endif + +#define LPC24XX_ETH_INTERFACE_NUMBER 1 + +/** + * @brief Start address of the Ethernet RAM. + */ +#define LPC24XX_ETH_RAM_START 0x7fe00000U + +/** + * @brief Size of the Ethernet RAM. + */ +#define LPC24XX_ETH_RAM_SIZE (16 * 1024) + +#define LPC24XX_ETH_RAM_END \ + (LPC24XX_ETH_RAM_START + LPC24XX_ETH_RAM_SIZE) + +#define LPC24XX_ETH_TRANSMIT_BUFFER_SIZE 1518 + +#define LPC24XX_ETH_RECEIVE_UNIT_SIZE \ + (ETH_TRANSFER_DESCRIPTOR_SIZE \ + + ETH_RECEIVE_INFO_SIZE \ + + 4) + +#define LPC24XX_ETH_TRANSMIT_UNIT_SIZE \ + (ETH_TRANSFER_DESCRIPTOR_SIZE \ + + ETH_TRANSMIT_STATUS_SIZE \ + + LPC24XX_ETH_TRANSMIT_BUFFER_SIZE) + +#define LPC24XX_ETH_RECEIVE_UNIT_NUMBER 54 + +#define LPC24XX_ETH_TRANSMIT_UNIT_NUMBER 10 + +#define LPC24XX_ETH_RECEIVE_DATA_SIZE \ + (LPC24XX_ETH_RECEIVE_UNIT_NUMBER \ + * LPC24XX_ETH_RECEIVE_UNIT_SIZE) + +#define LPC24XX_ETH_RECEIVE_DATA_START \ + LPC24XX_ETH_RAM_START + +#define LPC24XX_ETH_RECEIVE_DATA_END \ + (LPC24XX_ETH_RECEIVE_DATA_START \ + + LPC24XX_ETH_RECEIVE_DATA_SIZE) + +#define LPC24XX_ETH_TRANSMIT_DATA_SIZE \ + (LPC24XX_ETH_TRANSMIT_UNIT_NUMBER \ + * LPC24XX_ETH_TRANSMIT_UNIT_SIZE) + +#if 1 + +#define LPC24XX_ETH_TRANSMIT_DATA_START \ + LPC24XX_ETH_RECEIVE_DATA_END + +#else + +static char lpc24xx_eth_transmit_buffer [LPC24XX_ETH_TRANSMIT_DATA_SIZE]; + +#define LPC24XX_ETH_TRANSMIT_DATA_START \ + lpc24xx_eth_transmit_buffer + +#endif + +#define LPC24XX_ETH_TRANSMIT_DATA_END \ + (LPC24XX_ETH_TRANSMIT_DATA_START \ + + LPC24XX_ETH_TRANSMIT_DATA_SIZE) + +#if LPC24XX_ETH_TRANSMIT_DATA_END > LPC24XX_ETH_RAM_END && 0 + #error "Ethernet RAM overflow" +#endif + +#define LPC24XX_ETH_RECEIVE_DESC_START \ + LPC24XX_ETH_RECEIVE_DATA_START + +#define LPC24XX_ETH_RECEIVE_INFO_START \ + (LPC24XX_ETH_RECEIVE_DESC_START \ + + LPC24XX_ETH_RECEIVE_UNIT_NUMBER * ETH_TRANSFER_DESCRIPTOR_SIZE) + +#define LPC24XX_ETH_RECEIVE_MBUF_START \ + (LPC24XX_ETH_RECEIVE_INFO_START \ + + LPC24XX_ETH_RECEIVE_UNIT_NUMBER * ETH_RECEIVE_INFO_SIZE) + +#define LPC24XX_ETH_TRANSMIT_DESC_START \ + LPC24XX_ETH_TRANSMIT_DATA_START + +#define LPC24XX_ETH_TRANSMIT_STATUS_START \ + (LPC24XX_ETH_TRANSMIT_DATA_START \ + + LPC24XX_ETH_TRANSMIT_UNIT_NUMBER * ETH_TRANSFER_DESCRIPTOR_SIZE) + +#define LPC24XX_ETH_TRANSMIT_BUFFER_START \ + (LPC24XX_ETH_TRANSMIT_STATUS_START \ + + LPC24XX_ETH_TRANSMIT_UNIT_NUMBER * ETH_TRANSMIT_STATUS_SIZE) + +#define LPC24XX_ETH_EVENT_TRANSMIT RTEMS_EVENT_1 + +#define LPC24XX_ETH_EVENT_TRANSMIT_START RTEMS_EVENT_2 + +#define LPC24XX_ETH_EVENT_TRANSMIT_ERROR RTEMS_EVENT_3 + +#define LPC24XX_ETH_EVENT_RECEIVE RTEMS_EVENT_4 + +#define LPC24XX_ETH_EVENT_RECEIVE_ERROR RTEMS_EVENT_5 + +#define LPC24XX_ETH_TIMEOUT 10 + +#define LPC24XX_ETH_INTERRUPT_RECEIVE \ + (ETH_INT_RX_ERROR | ETH_INT_RX_FINISHED | ETH_INT_RX_DONE) + +#define LPC24XX_ETH_INTERRUPT_TRANSMIT (ETH_INT_TX_DONE | ETH_INT_TX_FINISHED | ETH_INT_TX_ERROR) + +#define LPC24XX_ETH_RX_STAT_ERRORS \ + (ETH_RX_STAT_CRC_ERROR \ + | ETH_RX_STAT_SYMBOL_ERROR \ + | ETH_RX_STAT_LENGTH_ERROR \ + | ETH_RX_STAT_ALIGNMENT_ERROR \ + | ETH_RX_STAT_OVERRUN \ + | ETH_RX_STAT_NO_DESCRIPTOR) + +#define LPC24XX_ETH_LAST_FRAGMENT_FLAGS \ + (ETH_TX_CTRL_OVERRIDE \ + | ETH_TX_CTRL_PAD \ + | ETH_TX_CTRL_CRC \ + | ETH_TX_CTRL_INTERRUPT \ + | ETH_TX_CTRL_LAST) + +#ifdef DEBUG + #define LPC24XX_ETH_PRINTF( ...) printf( __VA_ARGS__) + #define LPC24XX_ETH_PRINTK( ...) printk( __VA_ARGS__) +#else + #define LPC24XX_ETH_PRINTF( ...) + #define LPC24XX_ETH_PRINTK( ...) +#endif + +typedef enum { + LPC24XX_ETH_NOT_INITIALIZED, + LPC24XX_ETH_INITIALIZED, + LPC24XX_ETH_STARTED, + LPC24XX_ETH_RUNNING +} lpc24xx_eth_state; + +typedef struct { + struct arpcom arpcom; + struct rtems_mdio_info mdio_info; + lpc24xx_eth_state state; + rtems_id receive_task; + rtems_id transmit_task; + unsigned receive_unit_number; + unsigned transmit_unit_number; + unsigned received_frames; + unsigned receive_interrupts; + unsigned transmitted_frames; + unsigned transmit_interrupts; + unsigned receive_overrun_errors; + unsigned receive_fragment_errors; + unsigned receive_crc_errors; + unsigned receive_symbol_errors; + unsigned receive_length_errors; + unsigned receive_alignment_errors; + unsigned receive_no_descriptor_errors; + unsigned receive_fatal_errors; + unsigned transmit_underrun_errors; + unsigned transmit_late_collision_errors; + unsigned transmit_excessive_collision_errors; + unsigned transmit_excessive_defer_errors; + unsigned transmit_no_descriptor_errors; + unsigned transmit_overflow_errors; + unsigned transmit_fatal_errors; +} lpc24xx_eth_driver_entry; + +static lpc24xx_eth_driver_entry lpc24xx_eth_driver_data = { + .state = LPC24XX_ETH_NOT_INITIALIZED, + .receive_task = RTEMS_ID_NONE, + .transmit_task = RTEMS_ID_NONE +}; + +static inline uint32_t lpc24xx_eth_increment( + uint32_t value, + uint32_t cycle +) +{ + if (value < cycle) { + return ++value; + } else { + return 0; + } +} + +static void lpc24xx_eth_reset_filter( void) +{ + MAC_RXFILTERCTRL = 0; + MAC_RXFILTERWOLCLR = 0xcf; + MAC_HASHFILTERL = 0; + MAC_HASHFILTERH = 0; +} + +static void lpc24xx_eth_enable_promiscous_mode( bool enable) +{ + if (enable) { + MAC_RXFILTERCTRL = ETH_RX_FIL_CTRL_ACCEPT_PERFECT + | ETH_RX_FIL_CTRL_ACCEPT_UNICAST + | ETH_RX_FIL_CTRL_ACCEPT_MULTICAST + | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST; + } else { + MAC_RXFILTERCTRL = ETH_RX_FIL_CTRL_ACCEPT_PERFECT + | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST; + } +} + +static void lpc24xx_eth_interrupt_handler( + rtems_vector_number vector, + void *arg +) +{ + lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg; + rtems_event_set re = 0; + rtems_event_set te = 0; + uint32_t ie = 0; + + /* Get interrupt status */ + uint32_t im = MAC_INTENABLE; + uint32_t is = MAC_INTSTATUS & im; + + /* Check receive interrupts */ + if (IS_FLAG_SET( is, ETH_INT_RX_OVERRUN)) { + re = LPC24XX_ETH_EVENT_RECEIVE_ERROR; + ++e->receive_fatal_errors; + /* FIXME */ + printk( "%s: fatal receive error\n", __func__); + while (1); + } else if (IS_ANY_FLAG_SET( is, LPC24XX_ETH_INTERRUPT_RECEIVE)) { + re = LPC24XX_ETH_EVENT_RECEIVE; + ie = SET_FLAGS( ie, LPC24XX_ETH_INTERRUPT_RECEIVE); + } + + /* Send events to receive task */ + if (re != 0) { + ++e->receive_interrupts; + (void) rtems_event_send( e->receive_task, re); + } + + /* Check transmit interrupts */ + if (IS_FLAG_SET( is, ETH_INT_TX_UNDERRUN)) { + te = LPC24XX_ETH_EVENT_TRANSMIT_ERROR; + ++e->transmit_fatal_errors; + /* FIXME */ + printk( "%s: fatal transmit error\n", __func__); + while (1); + } else if (IS_ANY_FLAG_SET( is, LPC24XX_ETH_INTERRUPT_TRANSMIT)) { + te = LPC24XX_ETH_EVENT_TRANSMIT; + ie = SET_FLAGS( ie, LPC24XX_ETH_INTERRUPT_TRANSMIT); + } + + /* Send events to transmit task */ + if (te != 0) { + ++e->transmit_interrupts; + (void) rtems_event_send( e->transmit_task, te); + } + + LPC24XX_ETH_PRINTK( "interrupt: rx = 0x%08x, tx = 0x%08x\n", re, te); + + /* Update interrupt mask */ + MAC_INTENABLE = CLEAR_FLAGS( im, ie); + + /* Clear interrupts */ + MAC_INTCLEAR = is; +} + +static void lpc24xx_eth_enable_receive_interrupts( void) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + MAC_INTENABLE = SET_FLAGS( MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_RECEIVE); + rtems_interrupt_enable( level); +} + +static void lpc24xx_eth_disable_receive_interrupts( void) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + MAC_INTENABLE = CLEAR_FLAGS( MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_RECEIVE); + rtems_interrupt_enable( level); +} + +static void lpc24xx_eth_enable_transmit_interrupts( void) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + MAC_INTENABLE = SET_FLAGS( MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_TRANSMIT); + rtems_interrupt_enable( level); +} + +static void lpc24xx_eth_disable_transmit_interrupts( void) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + MAC_INTENABLE = CLEAR_FLAGS( MAC_INTENABLE, LPC24XX_ETH_INTERRUPT_TRANSMIT); + rtems_interrupt_enable( level); +} + +static struct mbuf *lpc24xx_eth_new_mbuf( struct ifnet *ifp, bool wait) +{ + struct mbuf *m = NULL; + int mw = wait ? M_WAIT : M_DONTWAIT; + + MGETHDR( m, mw, MT_DATA); + if (m != NULL) { + MCLGET( m, mw); + if (IS_FLAG_SET( m->m_flags, M_EXT)) { + /* Set receive interface */ + m->m_pkthdr.rcvif = ifp; + + /* Adjust by two bytes for proper IP header alignment */ + m->m_data = mtod( m, char *) + 2; + + return m; + } else { + m_free( m); + } + } + + return NULL; +} + +static bool lpc24xx_eth_add_new_mbuf( + struct ifnet *ifp, + volatile lpc24xx_eth_transfer_descriptor *desc, + struct mbuf **mbuf_table, + unsigned i, + bool wait +) +{ + /* New mbuf */ + struct mbuf *m = lpc24xx_eth_new_mbuf( ifp, wait); + + /* Check mbuf */ + if (m != NULL) { + /* Add mbuf to queue */ + desc [i].start = mtod( m, uint32_t); + desc [i].control = SET_ETH_RX_CTRL_SIZE( 0, MCLBYTES - 1) + | ETH_RX_CTRL_INTERRUPT; + + /* Add mbuf to table */ + mbuf_table [i] = m; + + return true; + } else { + return false; + } +} + +static void lpc24xx_eth_receive_task( void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_event_set events = 0; + lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg; + struct ifnet *ifp = &e->arpcom.ac_if; + volatile lpc24xx_eth_transfer_descriptor *const desc = + (volatile lpc24xx_eth_transfer_descriptor *) + LPC24XX_ETH_RECEIVE_DESC_START; + volatile lpc24xx_eth_receive_info *const info = + (volatile lpc24xx_eth_receive_info *) + LPC24XX_ETH_RECEIVE_INFO_START; + struct mbuf **const mbuf_table = + (struct mbuf **) LPC24XX_ETH_RECEIVE_MBUF_START; + uint32_t index_max = e->receive_unit_number - 1; + uint32_t produce_index = 0; + uint32_t consume_index = 0; + uint32_t receive_index = 0; + + LPC24XX_ETH_PRINTF( "%s\n", __func__); + + /* Disable receive interrupts */ + lpc24xx_eth_disable_receive_interrupts(); + + /* Disable receiver */ + MAC_COMMAND = CLEAR_FLAG( MAC_COMMAND, ETH_CMD_RX_ENABLE); + + /* Clear receive interrupts */ + MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_RECEIVE; + + /* Fill receive queue */ + for (produce_index = 0; produce_index <= index_max; ++produce_index) { + if ( + !lpc24xx_eth_add_new_mbuf( ifp, desc, mbuf_table, produce_index, false) + ) { + break; + } + } + + /* Check if the queue is full */ + if (produce_index == 0) { + RTEMS_DO_CLEANUP( + cleanup, + "no buffers to fill receive queue: terminate receive task\n" + ); + } else if (produce_index <= index_max) { + /* Reduce the queue size */ + index_max = produce_index - 1; + + RTEMS_SYSLOG_ERROR( "not enough buffers to fill receive queue"); + } + + /* Receive descriptor table */ + MAC_RXDESCRIPTORNUM = index_max; + MAC_RXDESCRIPTOR = (uint32_t) desc; + MAC_RXSTATUS = (uint32_t) info; + + /* Initialize indices */ + produce_index = MAC_RXPRODUCEINDEX; + consume_index = MAC_RXCONSUMEINDEX; + receive_index = consume_index; + + /* Enable receiver */ + MAC_COMMAND = SET_FLAG( MAC_COMMAND, ETH_CMD_RX_ENABLE); + + /* Enable receive interrupts */ + lpc24xx_eth_enable_receive_interrupts(); + + /* Main event loop */ + while (true) { + bool wait_for_mbuf = false; + + /* Wait for events */ + sc = rtems_bsdnet_event_receive( + LPC24XX_ETH_EVENT_RECEIVE, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + RTEMS_CLEANUP_SC( sc, cleanup, "wait for events"); + + LPC24XX_ETH_PRINTF( "rx: wake up: 0x%08" PRIx32 "\n", events); + + while (true) { + /* Clear receive interrupt status */ + MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_RECEIVE; + + /* Get current produce index */ + produce_index = MAC_RXPRODUCEINDEX; + + if (receive_index != produce_index) { + /* Fragment mbuf and status */ + struct mbuf *m = mbuf_table [receive_index]; + uint32_t stat = info [receive_index].status; + + if ( + IS_FLAG_SET( stat, ETH_RX_STAT_LAST_FLAG) + && ARE_FLAGS_CLEARED( stat, LPC24XX_ETH_RX_STAT_ERRORS) + ) { + /* Ethernet header */ + struct ether_header *eh = mtod( m, struct ether_header *); + + /* Discard Ethernet header and CRC */ + int sz = (int) GET_ETH_RX_STAT_RXSIZE( stat) + 1 + - ETHER_HDR_LEN - ETHER_CRC_LEN; + + /* Update mbuf */ + m->m_len = sz; + m->m_pkthdr.len = sz; + m->m_data = mtod( m, char *) + ETHER_HDR_LEN; + + LPC24XX_ETH_PRINTF( "rx: %02" PRIu32 ": %u\n", receive_index, sz); + + /* Hand over */ + ether_input( ifp, eh, m); + + /* Increment received frames counter */ + ++e->received_frames; + } else { + /* Release mbuf */ + m_free( m); + + /* Update error counters */ + if (IS_FLAG_SET( stat, ETH_RX_STAT_OVERRUN)) { + ++e->receive_overrun_errors; + } + if (IS_FLAG_CLEARED( stat, ETH_RX_STAT_LAST_FLAG)) { + ++e->receive_fragment_errors; + } + if (IS_FLAG_SET( stat, ETH_RX_STAT_CRC_ERROR)) { + ++e->receive_crc_errors; + } + if (IS_FLAG_SET( stat, ETH_RX_STAT_SYMBOL_ERROR)) { + ++e->receive_symbol_errors; + } + if (IS_FLAG_SET( stat, ETH_RX_STAT_LENGTH_ERROR)) { + ++e->receive_length_errors; + } + if (IS_FLAG_SET( stat, ETH_RX_STAT_ALIGNMENT_ERROR)) { + ++e->receive_alignment_errors; + } + if (IS_FLAG_SET( stat, ETH_RX_STAT_NO_DESCRIPTOR)) { + ++e->receive_no_descriptor_errors; + } + } + + /* Increment receive index */ + receive_index = lpc24xx_eth_increment( receive_index, index_max); + } else { + /* Nothing to do, enable receive interrupts */ + lpc24xx_eth_enable_receive_interrupts(); + break; + } + } + + /* Wait for mbuf? */ + wait_for_mbuf = + lpc24xx_eth_increment( produce_index, index_max) == consume_index; + + /* Fill queue with new mbufs */ + while (consume_index != produce_index) { + /* Add new mbuf to queue */ + if ( + !lpc24xx_eth_add_new_mbuf( + ifp, desc, mbuf_table, consume_index, wait_for_mbuf + ) + ) { + break; + } + + /* We wait for at most one mbuf */ + wait_for_mbuf = false; + + /* Increment consume index */ + consume_index = lpc24xx_eth_increment( consume_index, index_max); + + /* Update consume indices */ + MAC_RXCONSUMEINDEX = consume_index; + } + } + +cleanup: + + /* Release network semaphore */ + rtems_bsdnet_semaphore_release(); + + /* Terminate self */ + (void) rtems_task_delete( RTEMS_SELF); +} + +static struct mbuf *lpc24xx_eth_next_fragment( + struct ifnet *ifp, + struct mbuf *m, + uint32_t *ctrl +) +{ + struct mbuf *n = NULL; + int size = 0; + + while (true) { + if (m == NULL) { + /* Dequeue first fragment of the next frame */ + IF_DEQUEUE( &ifp->if_snd, m); + + /* Empty queue? */ + if (m == NULL) { + return m; + } + } + + /* Get fragment size */ + size = m->m_len; + + if (size > 0) { + /* Now we have a not empty fragment */ + break; + } else { + /* Discard empty fragments */ + m = m_free( m); + } + } + + /* Set fragment size */ + *ctrl = SET_ETH_TX_CTRL_SIZE( 0, size - 1); + + /* Discard empty successive fragments */ + n = m->m_next; + while (n != NULL && n->m_len <= 0) { + n = m_free( n); + } + m->m_next = n; + + /* Is our fragment the last in the frame? */ + if (n == NULL) { + *ctrl = SET_FLAGS( *ctrl, LPC24XX_ETH_LAST_FRAGMENT_FLAGS); + } + + return m; +} + +static void lpc24xx_eth_transmit_task( void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_event_set events = 0; + lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg; + struct ifnet *ifp = &e->arpcom.ac_if; + volatile lpc24xx_eth_transfer_descriptor *const desc = + (volatile lpc24xx_eth_transfer_descriptor *) + LPC24XX_ETH_TRANSMIT_DESC_START; + volatile uint32_t *const status = + (volatile uint32_t *) LPC24XX_ETH_TRANSMIT_STATUS_START; + volatile char *const buf = + (volatile char *) LPC24XX_ETH_TRANSMIT_BUFFER_START; + struct mbuf *m = NULL; + uint32_t index_max = e->transmit_unit_number - 1; + uint32_t produce_index = 0; + uint32_t consume_index = 0; + uint32_t ctrl = 0; + uint32_t frame_length = 0; + char *frame_buffer = NULL; + + LPC24XX_ETH_PRINTF( "%s\n", __func__); + + /* Disable transmit interrupts */ + lpc24xx_eth_disable_transmit_interrupts(); + + /* Disable transmitter */ + MAC_COMMAND = CLEAR_FLAG( MAC_COMMAND, ETH_CMD_TX_ENABLE); + + /* Clear transmit interrupts */ + MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_TRANSMIT; + + /* Initialize descriptor table */ + for (produce_index = 0; produce_index <= index_max; ++produce_index) { + desc [produce_index].start = + (uint32_t) (buf + produce_index * LPC24XX_ETH_TRANSMIT_BUFFER_SIZE); + desc [produce_index].control = 0; + } + + /* Transmit descriptors */ + MAC_TXDESCRIPTORNUM = index_max; + MAC_TXDESCRIPTOR = (uint32_t) desc; + MAC_TXSTATUS = (uint32_t) status; + + /* Initialize indices */ + produce_index = MAC_TXPRODUCEINDEX; + consume_index = MAC_TXCONSUMEINDEX; + + /* Frame buffer start */ + frame_buffer = (char *) desc [produce_index].start; + + /* Enable transmitter */ + MAC_COMMAND = SET_FLAG( MAC_COMMAND, ETH_CMD_TX_ENABLE); + + /* Main event loop */ + while (true) { + /* Wait for events */ + sc = rtems_bsdnet_event_receive( + LPC24XX_ETH_EVENT_TRANSMIT | LPC24XX_ETH_EVENT_TRANSMIT_START, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + RTEMS_CLEANUP_SC( sc, cleanup, "wait for events"); + + LPC24XX_ETH_PRINTF( "tx: wake up: 0x%08" PRIx32 "\n", events); + + /* Free consumed fragments */ + while (true) { + /* Save last known consume index */ + uint32_t c = consume_index; + + /* Clear transmit interrupt status */ + MAC_INTCLEAR = LPC24XX_ETH_INTERRUPT_TRANSMIT; + + /* Get new consume index */ + consume_index = MAC_TXCONSUMEINDEX; + + /* Nothing consumed in the meantime? */ + if (c == consume_index) { + break; + } + + while (c != consume_index) { + uint32_t s = status [c]; + + /* Update error counters */ + if ( + IS_ANY_FLAG_SET( s, ETH_TX_STAT_ERROR | ETH_TX_STAT_NO_DESCRIPTOR) + ) { + if (IS_FLAG_SET( s, ETH_TX_STAT_UNDERRUN)) { + ++e->transmit_underrun_errors; + } + if (IS_FLAG_SET( s, ETH_TX_STAT_LATE_COLLISION)) { + ++e->transmit_late_collision_errors; + } + if (IS_FLAG_SET( s, ETH_TX_STAT_EXCESSIVE_COLLISION)) { + ++e->transmit_excessive_collision_errors; + } + if (IS_FLAG_SET( s, ETH_TX_STAT_EXCESSIVE_DEFER)) { + ++e->transmit_excessive_defer_errors; + } + if (IS_FLAG_SET( s, ETH_TX_STAT_NO_DESCRIPTOR)) { + ++e->transmit_no_descriptor_errors; + } + } + + /* Reinitialize control field */ + desc [c].control = 0; + + /* Next consume index */ + c = lpc24xx_eth_increment( c, index_max); + } + } + + /* Transmit new fragments */ + while (true) { + /* Compute next produce index */ + uint32_t p = lpc24xx_eth_increment( produce_index, index_max); + + /* Queue full? */ + if (p == consume_index) { + /* The queue is full, wait for transmit interrupt */ + break; + } + + /* Get next fragment and control value */ + m = lpc24xx_eth_next_fragment( ifp, m, &ctrl); + + /* New fragment? */ + if (m != NULL) { + size_t fragment_length = (size_t) m->m_len; + void *fragment_start = mtod( m, void *); + uint32_t new_frame_length = frame_length + fragment_length; + + /* Check buffer size */ + if (new_frame_length > LPC24XX_ETH_TRANSMIT_BUFFER_SIZE) { + LPC24XX_ETH_PRINTF( "tx: overflow\n"); + + /* Discard overflow data */ + new_frame_length = LPC24XX_ETH_TRANSMIT_BUFFER_SIZE; + fragment_length = new_frame_length - frame_length; + + /* Finalize frame */ + ctrl = SET_FLAGS( ctrl, LPC24XX_ETH_LAST_FRAGMENT_FLAGS); + + /* Update error counter */ + ++e->transmit_overflow_errors; + } + + LPC24XX_ETH_PRINTF( + "tx: copy: %" PRIu32 "%s%s\n", + fragment_length, + IS_FLAG_SET( m->m_flags, M_EXT) ? ", E" : "", + IS_FLAG_SET( m->m_flags, M_PKTHDR) ? ", H" : "" + ); + + /* Copy fragment to buffer in Ethernet RAM */ + memcpy( frame_buffer, fragment_start, fragment_length); + + if (IS_FLAG_SET( ctrl, ETH_TX_CTRL_LAST)) { + /* Finalize descriptor */ + desc [produce_index].control = + SET_ETH_TX_CTRL_SIZE( ctrl, new_frame_length - 1); + + LPC24XX_ETH_PRINTF( "tx: %02" PRIu32 ": %" PRIu32 "\n", produce_index, new_frame_length); + + /* Next produce index */ + produce_index = p; + + /* Update the produce index */ + MAC_TXPRODUCEINDEX = produce_index; + + /* Reinitialize frame length and buffer start */ + frame_length = 0; + frame_buffer = (char *) desc [produce_index].start; + + /* Increment transmitted frames counter */ + ++e->transmitted_frames; + } else { + /* New frame length */ + frame_length = new_frame_length; + + /* Update current frame buffer start */ + frame_buffer += fragment_length; + } + + /* Free mbuf and get next */ + m = m_free( m); + } else { + /* Nothing to transmit */ + break; + } + } + + /* No more fragments? */ + if (m == NULL) { + /* Interface is now inactive */ + ifp->if_flags = CLEAR_FLAG( ifp->if_flags, IFF_OACTIVE); + } else { + /* Enable transmit interrupts */ + lpc24xx_eth_enable_transmit_interrupts(); + } + } + +cleanup: + + /* Release network semaphore */ + rtems_bsdnet_semaphore_release(); + + /* Terminate self */ + (void) rtems_task_delete( RTEMS_SELF); +} + +static void lpc24xx_eth_interface_init( void *arg) +{ + lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) arg; + struct ifnet *ifp = &e->arpcom.ac_if; + + LPC24XX_ETH_PRINTF( "%s\n", __func__); + + if (e->state == LPC24XX_ETH_INITIALIZED) { + #ifndef LPC24XX_HAS_UBOOT + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + + /* Enable power */ + PCONP = SET_FLAGS( PCONP, 0x40000000); + + /* Set PIN selects */ + #ifdef LPC24XX_ETHERNET_RMII + PINSEL2 = SET_FLAGS( PINSEL2, 0x55555555); + #else + PINSEL2 = SET_FLAGS( PINSEL2, 0x50150105); + #endif + PINSEL3 = SET_FLAGS( PINSEL3, 0x05); + + rtems_interrupt_enable( level); + + /* Soft reset */ + + /* Do soft reset */ + MAC_MAC1 = 0xcf00; + MAC_COMMAND = 0x38; + + /* Initialize PHY */ + /* TODO */ + + /* Reinitialize registers */ + MAC_MAC2 = 0x31; + MAC_IPGT = 0x15; + MAC_IPGR = 0x12; + MAC_CLRT = 0x370f; + MAC_MAXF = 0x0600; + MAC_SUPP = 0x0100; + MAC_TEST = 0; + #ifdef LPC24XX_ETHERNET_RMII + MAC_COMMAND = 0x0400; + #else + MAC_COMMAND = 0x0600; + #endif + MAC_INTENABLE = 0; + MAC_INTCLEAR = 0x30ff; + MAC_POWERDOWN = 0; + + /* MAC address */ + MAC_SA0 = ((uint32_t) e->arpcom.ac_enaddr [5] << 8) + | (uint32_t) e->arpcom.ac_enaddr [4]; + MAC_SA1 = ((uint32_t) e->arpcom.ac_enaddr [3] << 8) + | (uint32_t) e->arpcom.ac_enaddr [2]; + MAC_SA2 = ((uint32_t) e->arpcom.ac_enaddr [1] << 8) + | (uint32_t) e->arpcom.ac_enaddr [0]; + + /* Enable receiver */ + MAC_MAC1 = 0x03; + #else /* LPC24XX_HAS_UBOOT */ + uint32_t reg = 0; + + /* TODO */ + + /* MAC configuration */ + MAC_MAC1 = 0x3; + + /* Disable and reset receiver and transmitter */ + reg = MAC_COMMAND; + reg = CLEAR_FLAGS( reg, ETH_CMD_RX_ENABLE | ETH_CMD_TX_ENABLE); + reg = SET_FLAGS( reg, ETH_CMD_RX_RESET | ETH_CMD_TX_RESET); + MAC_COMMAND = reg; + #endif /* LPC24XX_HAS_UBOOT */ + + /* Start receive task */ + if (e->receive_task == RTEMS_ID_NONE) { + e->receive_task = rtems_bsdnet_newproc( + "ntrx", + 4096, + lpc24xx_eth_receive_task, + e + ); + } + + /* Start transmit task */ + if (e->transmit_task == RTEMS_ID_NONE) { + e->transmit_task = rtems_bsdnet_newproc( + "nttx", + 4096, + lpc24xx_eth_transmit_task, + e + ); + } + + /* Change state */ + if ( + e->receive_task != RTEMS_ID_NONE && e->transmit_task != RTEMS_ID_NONE + ) { + e->state = LPC24XX_ETH_STARTED; + } + } + + if (e->state == LPC24XX_ETH_STARTED) { + /* Enable fatal interrupts */ + MAC_INTENABLE = ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN; + + /* Enable promiscous mode */ + lpc24xx_eth_enable_promiscous_mode( + IS_FLAG_SET( ifp->if_flags, IFF_PROMISC) + ); + + /* Start watchdog timer */ + ifp->if_timer = 1; + + /* Set interface to running state */ + ifp->if_flags = SET_FLAG( ifp->if_flags, IFF_RUNNING); + + /* Change state */ + e->state = LPC24XX_ETH_RUNNING; + } +} + +static void lpc24xx_eth_interface_stats( const lpc24xx_eth_driver_entry *e) +{ + printf( "received frames: %u\n", e->received_frames); + printf( "receive interrupts: %u\n", e->receive_interrupts); + printf( "transmitted frames: %u\n", e->transmitted_frames); + printf( "transmit interrupts: %u\n", e->transmit_interrupts); + printf( "receive overrun errors: %u\n", e->receive_overrun_errors); + printf( "receive fragment errors: %u\n", e->receive_fragment_errors); + printf( "receive CRC errors: %u\n", e->receive_crc_errors); + printf( "receive symbol errors: %u\n", e->receive_symbol_errors); + printf( "receive length errors: %u\n", e->receive_length_errors); + printf( "receive alignment errors: %u\n", e->receive_alignment_errors); + printf( "receive no descriptor errors: %u\n", e->receive_no_descriptor_errors); + printf( "receive fatal errors: %u\n", e->receive_fatal_errors); + printf( "transmit underrun errors: %u\n", e->transmit_underrun_errors); + printf( "transmit late collision errors: %u\n", e->transmit_late_collision_errors); + printf( "transmit excessive collision errors: %u\n", e->transmit_excessive_collision_errors); + printf( "transmit excessive defer errors: %u\n", e->transmit_excessive_defer_errors); + printf( "transmit no descriptor errors: %u\n", e->transmit_no_descriptor_errors); + printf( "transmit overflow errors: %u\n", e->transmit_overflow_errors); + printf( "transmit fatal errors: %u\n", e->transmit_fatal_errors); +} + +static int lpc24xx_eth_interface_ioctl( + struct ifnet *ifp, + ioctl_command_t command, + caddr_t data +) +{ + lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc; + int rv = 0; + + LPC24XX_ETH_PRINTF( "%s\n", __func__); + + switch (command) { + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + rtems_mii_ioctl( &e->mdio_info, e, (int) command, (int *) data); + break; + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl( ifp, command, data); + break; + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_RUNNING) { + /* TODO: off */ + } + if (ifp->if_flags & IFF_UP) { + ifp->if_flags = SET_FLAG( ifp->if_flags, IFF_RUNNING); + /* TODO: init */ + } + break; + case SIO_RTEMS_SHOW_STATS: + lpc24xx_eth_interface_stats( e); + break; + default: + rv = EINVAL; + break; + } + + return rv; +} + +static void lpc24xx_eth_interface_start( struct ifnet *ifp) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc; + + ifp->if_flags = SET_FLAG( ifp->if_flags, IFF_OACTIVE); + + sc = rtems_event_send( e->transmit_task, LPC24XX_ETH_EVENT_TRANSMIT_START); + RTEMS_SYSLOG_ERROR_SC( sc, "send transmit start event"); +} + +static void lpc24xx_eth_interface_watchdog( struct ifnet *ifp) +{ + lpc24xx_eth_driver_entry *e = (lpc24xx_eth_driver_entry *) ifp->if_softc; + + LPC24XX_ETH_PRINTF( "%s\n", __func__); +} + +static int lpc24xx_eth_attach( struct rtems_bsdnet_ifconfig *config) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc24xx_eth_driver_entry *e = &lpc24xx_eth_driver_data; + struct ifnet *ifp = &e->arpcom.ac_if; + char *unit_name = NULL; + int unit_number = rtems_bsdnet_parse_driver_name( config, &unit_name); + uint32_t reg = 0; + + /* Check parameter */ + if (unit_number < 0) { + RTEMS_SYSLOG_ERROR( "parse error for interface name\n"); + return 0; + } + if (unit_number != 0) { + RTEMS_DO_CLEANUP( cleanup, "unexpected unit number"); + } + if (config->hardware_address == NULL) { + RTEMS_DO_CLEANUP( cleanup, "MAC address missing"); + } + if (e->state != LPC24XX_ETH_NOT_INITIALIZED) { + RTEMS_DO_CLEANUP( cleanup, "already attached"); + } + + /* Interrupt number */ + config->irno = LPC24XX_IRQ_ETHERNET; + + /* Device control */ + config->drv_ctrl = e; + + /* Receive unit number */ + if ( + config->rbuf_count <= 0 + || config->rbuf_count > LPC24XX_ETH_RECEIVE_UNIT_NUMBER + ) { + config->rbuf_count = LPC24XX_ETH_RECEIVE_UNIT_NUMBER; + } + e->receive_unit_number = (unsigned) config->rbuf_count; + + /* Transmit unit number */ + if ( + config->xbuf_count <= 0 + || config->xbuf_count > LPC24XX_ETH_TRANSMIT_UNIT_NUMBER + ) { + config->xbuf_count = LPC24XX_ETH_TRANSMIT_UNIT_NUMBER; + } + e->transmit_unit_number = (unsigned) config->xbuf_count; + + /* Disable interrupts */ + MAC_INTENABLE = 0; + + /* Install interrupt handler */ + sc = rtems_interrupt_handler_install( + config->irno, + "Ethernet", + RTEMS_INTERRUPT_UNIQUE, + lpc24xx_eth_interrupt_handler, + e + ); + RTEMS_CLEANUP_SC( sc, cleanup, "install interrupt handler"); + + /* Copy MAC address */ + memcpy( e->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); + + /* Clear Ethernet RAM */ + memset( (void *) LPC24XX_ETH_RAM_START, 0, (size_t) LPC24XX_ETH_RAM_SIZE); + + /* Set interface data */ + ifp->if_softc = e; + ifp->if_unit = (short) unit_number; + ifp->if_name = unit_name; + ifp->if_mtu = (config->mtu > 0) ? (u_long) config->mtu : ETHERMTU; + ifp->if_init = lpc24xx_eth_interface_init; + ifp->if_ioctl = lpc24xx_eth_interface_ioctl; + ifp->if_start = lpc24xx_eth_interface_start; + ifp->if_output = ether_output; + ifp->if_watchdog = lpc24xx_eth_interface_watchdog; + ifp->if_flags = config->ignore_broadcast ? 0 : IFF_BROADCAST; + ifp->if_snd.ifq_maxlen = ifqmaxlen; + ifp->if_timer = 0; + + /* Change status */ + e->state = LPC24XX_ETH_INITIALIZED; + + /* Attach the interface */ + if_attach( ifp); + ether_ifattach( ifp); + + return 1; + +cleanup: + + /* FIXME: Type */ + free( unit_name, (int) 0xdeadbeef); + + return 0; +} + +int lpc24xx_eth_attach_detach( + struct rtems_bsdnet_ifconfig *config, + int attaching +) +{ + /* FIXME: Return value */ + + if (attaching) { + return lpc24xx_eth_attach( config); + } else { + /* TODO */ + return 0; + } +} diff --git a/c/src/lib/libbsp/arm/lpc24xx/startup/bspreset.c b/c/src/lib/libbsp/arm/lpc24xx/startup/bspreset.c new file mode 100644 index 0000000000..1f2ef57b8d --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/startup/bspreset.c @@ -0,0 +1,27 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * @brief Reset code. + */ + +/* + * Copyright (c) 2008 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be found in the file + * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. + */ + +#include +#include + +void bsp_reset( void) +{ + start(); +} diff --git a/c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478 b/c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478 new file mode 100644 index 0000000000..2edc351fb0 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478 @@ -0,0 +1,14 @@ +/** + * @file + * + * LPC2478 (QVGA Base Board from Embedded Artists). + */ + +MEMORY { + RAM_INT (AIW) : ORIGIN = 0x40000000, LENGTH = 64k + RAM_EXT (AIW) : ORIGIN = 0xa0000000, LENGTH = 32M + ROM_INT (RX) : ORIGIN = 0x00000000, LENGTH = 512k - 8k + NIRVANA : ORIGIN = 0, LENGTH = 0 +} + +INCLUDE linkcmds.base diff --git a/c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478_ncs b/c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478_ncs new file mode 100644 index 0000000000..1ca2b6a3f4 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478_ncs @@ -0,0 +1,14 @@ +/** + * @file + * + * LPC2478 (NCS). + */ + +MEMORY { + RAM_INT (AIW) : ORIGIN = 0x40000000, LENGTH = 64k + RAM_EXT (AIW) : ORIGIN = 0xa0400000, LENGTH = 4M + ROM_INT (RX) : ORIGIN = 0x00000000, LENGTH = 512k - 8k + NIRVANA : ORIGIN = 0, LENGTH = 0 +} + +INCLUDE linkcmds.rom diff --git a/c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478_ncs_ram b/c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478_ncs_ram new file mode 100644 index 0000000000..bd85ec9d66 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/startup/linkcmds.lpc2478_ncs_ram @@ -0,0 +1,14 @@ +/** + * @file + * + * LPC2478 (NCS, code and data in external RAM). + */ + +MEMORY { + RAM_INT (AIW) : ORIGIN = 0x40000000, LENGTH = 64k + RAM_EXT (AIW) : ORIGIN = 0xa0000000, LENGTH = 8M + ROM_INT (RX) : ORIGIN = 0x00000000, LENGTH = 512k - 8k + NIRVANA : ORIGIN = 0, LENGTH = 0 +} + +INCLUDE linkcmds.base diff --git a/c/src/lib/libbsp/arm/shared/startup/linkcmds.rom b/c/src/lib/libbsp/arm/shared/startup/linkcmds.rom new file mode 100644 index 0000000000..75f8b6e07d --- /dev/null +++ b/c/src/lib/libbsp/arm/shared/startup/linkcmds.rom @@ -0,0 +1,385 @@ +/** + * @file + * + * @brief Linker command base file for configuration with internal and external + * RAM and optional ROM load. + * + * You need to add a linker command file to your board support package that + * includes this file at the end and provides the following definitions. + * + * Compulsory are the memory regions RAM_INT, RAM_EXT and NIRVANA. + *
+ * MEMORY {
+ *   RAM_INT (AIW) : ORIGIN = 0x40000000, LENGTH = 64k
+ *   RAM_EXT (AIW) : ORIGIN = 0xa0000000, LENGTH = 32M
+ *   NIRVANA : ORIGIN = 0, LENGTH = 0
+ * }
+ * 
+ * + * You may optionally provide ROM start and size values. + *
+ * bsp_rom_start = 0x80000000;
+ * bsp_rom_size = 0x01000000;
+ * 
+ * + * Optionally you can enable the load to ROM. It is enabled then + * bsp_enable_rom_load is defined. The value is arbitrary. + *
+ * bsp_enable_rom_load = 1;
+ * 
+ * + * Include the linker command base file. This file has to be installed in the + * same directory than your linker command file. + *
+ * INCLUDE linkcmds.base
+ * 
+ * + * You may define optionally values for the following sizes: + * - bsp_ram_int_size + * - bsp_ram_ext_size + * - bsp_stack_abt_size + * - bsp_stack_fiq_size + * - bsp_stack_irq_size + * - bsp_stack_svc_size + * - bsp_stack_undef_size + */ + +/* + * Copyright (c) 2008 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be found in the file + * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. + */ + +OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") + +OUTPUT_ARCH (arm) + +ENTRY (start) + +/* + * BSP: Symbols that may be defined externally. The minimum alignment + * requirement for regions is bsp_section_align. + */ +bsp_ram_int_size = DEFINED (bsp_ram_int_size) ? bsp_ram_int_size : LENGTH (RAM_INT); + +bsp_ram_ext_size = DEFINED (bsp_ram_ext_size) ? bsp_ram_ext_size : LENGTH (RAM_EXT); + +bsp_rom_start = DEFINED (bsp_rom_start) ? bsp_rom_start : 0; + +bsp_rom_size = DEFINED (bsp_rom_size) ? bsp_rom_size : 0; + +bsp_ram_ext_load_start = DEFINED (bsp_enable_rom_load) ? bsp_rom_start : bsp_ram_ext_start; + +bsp_stack_abt_size = DEFINED (bsp_stack_abt_size) ? bsp_stack_abt_size : 128; + +bsp_stack_fiq_size = DEFINED (bsp_stack_fiq_size) ? bsp_stack_fiq_size : 128; + +bsp_stack_irq_size = DEFINED (bsp_stack_irq_size) ? bsp_stack_irq_size : 256; + +bsp_stack_svc_size = DEFINED (bsp_stack_svc_size) ? bsp_stack_svc_size : 256; + +bsp_stack_undef_size = DEFINED (bsp_stack_undef_size) ? bsp_stack_undef_size : 128; + +/* + * BSP: Global symbols + */ +bsp_ram_int_start = ORIGIN (RAM_INT); +bsp_ram_int_end = bsp_ram_int_start + bsp_ram_int_size; + +bsp_ram_ext_start = ORIGIN (RAM_EXT); +bsp_ram_ext_end = bsp_ram_ext_start + bsp_ram_ext_size; + +bsp_rom_end = bsp_rom_start + bsp_rom_size; + +bsp_section_align = 16; + +bsp_stack_align = 16; + +SECTIONS { + .vector : { + /* + * BSP: Start of vector section + */ + bsp_section_vector_start = .; + + /* + * BSP: Reserve space for the the exception vector table and + * the pointers to the default exceptions handlers. + */ + . = . + 64; + + . = ALIGN (bsp_section_align); + + /* + * BSP: End of vector section + */ + bsp_section_vector_end = .; + } > RAM_INT + + bsp_section_vector_size = bsp_section_vector_end - bsp_section_vector_start; + + .text : { + /* + * BSP: Start of text section + */ + bsp_section_text_start = .; + + /* + * BSP: System startup entry + */ + KEEP (*(.entry)) + + /* + * BSP: Moved into .text from .init + */ + KEEP (*(.init)) + + *(.text .stub .text.* .gnu.linkonce.t.*) + KEEP (*(.text.*personality*)) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(.gnu.warning) + + /* + * BSP: Magic ARM stuff + */ + *(.ARM.*) + *(.glue_7) + *(.glue_7t) + *(.vfp11_veneer) + + /* + * BSP: Special FreeBSD sysctl sections + */ + . = ALIGN (16); + __start_set_sysctl_set = .; + *(set_sysctl_*); + __stop_set_sysctl_set = ABSOLUTE(.); + *(set_domain_*); + *(set_pseudo_*); + + /* + * BSP: Moved into .text from .* + */ + *(.rodata .rodata.* .gnu.linkonce.r.*) + *(.rodata1) + *(.eh_frame_hdr) + + /* + * BSP: Required by cpukit/score/src/threadhandler.c + */ + PROVIDE (_fini = .); + + /* + * BSP: Moved into .text from .fini + */ + KEEP (*(.fini)) + + . = ALIGN (bsp_section_align); + + /* + * BSP: End of text section + */ + bsp_section_text_end = .; + } > ROM_INT + + bsp_section_text_size = bsp_section_text_end - bsp_section_text_start; + + .data : AT (bsp_section_text_end) { + /* + * BSP: Start of data section + */ + bsp_section_data_start = .; + + /* + * BSP: Moved into .data from .ctors + */ + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + + /* + * BSP: Moved into .data from .dtors + */ + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + + /* + * BSP: Moved into .data from .* + */ + *(.data1) + KEEP (*(.eh_frame)) + *(.gcc_except_table .gcc_except_table.*) + KEEP (*(.jcr)) + + *(.data .data.* .gnu.linkonce.d.*) + KEEP (*(.gnu.linkonce.d.*personality*)) + SORT(CONSTRUCTORS) + + . = ALIGN (bsp_section_align); + + /* + * BSP: End of data section + */ + bsp_section_data_end = .; + } > RAM_EXT + + bsp_section_data_size = bsp_section_data_end - bsp_section_data_start; + + .bss : { + /* + * BSP: Start of bss section + */ + bsp_section_bss_start = .; + + *(COMMON) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + + . = ALIGN (bsp_section_align); + + /* + * BSP: End of bss section + */ + bsp_section_bss_end = .; + } > RAM_EXT + + bsp_section_bss_size = bsp_section_bss_end - bsp_section_bss_start; + + .stack : { + /* + * BSP: Start of stack section + */ + bsp_section_stack_start = .; + + . = ALIGN (bsp_stack_align); + bsp_stack_abt_start = .; + . = . + bsp_stack_abt_size; + + . = ALIGN (bsp_stack_align); + bsp_stack_fiq_start = .; + . = . + bsp_stack_fiq_size; + + . = ALIGN (bsp_stack_align); + bsp_stack_irq_start = .; + . = . + bsp_stack_irq_size; + + . = ALIGN (bsp_stack_align); + bsp_stack_svc_start = .; + . = . + bsp_stack_svc_size; + + . = ALIGN (bsp_stack_align); + bsp_stack_undef_start = .; + . = . + bsp_stack_undef_size; + + . = ALIGN (bsp_section_align); + + /* + * BSP: End of stack section + */ + bsp_section_stack_end = .; + } > RAM_INT + + bsp_section_stack_size = bsp_section_stack_end - bsp_section_stack_start; + + .work_area : { + /* + * BSP: Start of work area. The work area will occupy the remaining + * RAM_EXT region and contains the RTEMS work space and heap. We cannot + * assign the region end directly since this leads to a region full + * warning. + */ + bsp_section_work_area_start = .; + + . = bsp_ram_ext_end - 4; + + . = ALIGN (bsp_section_align); + + /* + * BSP: End of work area + */ + bsp_section_work_area_end = .; + } > RAM_EXT + + bsp_section_work_area_size = bsp_section_work_area_end - bsp_section_work_area_start; + + /* + * BSP: External symbols (FIXME) + */ + RamBase = bsp_ram_ext_start; + RamSize = bsp_ram_ext_size; + WorkAreaBase = bsp_section_work_area_start; + HeapSize = 0; + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + + /DISCARD/ : { + *(.note.GNU-stack) *(.gnu_debuglink) + } + + /* + * BSP: Catch all unknown sections + */ + .nirvana : { + *(*) + } > NIRVANA +} diff --git a/make/custom/lpc2478_ncs.cfg b/make/custom/lpc2478_ncs.cfg new file mode 100644 index 0000000000..f826757f9e --- /dev/null +++ b/make/custom/lpc2478_ncs.cfg @@ -0,0 +1,14 @@ +# +# Config file for LPC2478 (NCS). +# +# $Id$ +# + +LPC24XX_LINKCMDS = linkcmds.lpc2478_ncs + +include $(RTEMS_ROOT)/make/custom/lpc24xx.cfg + +define bsp-post-link + $(OBJCOPY) -O ihex '$@' '$(basename $@).hex' + $(default-bsp-post-link) +endef diff --git a/make/custom/lpc2478_ncs_ram.cfg b/make/custom/lpc2478_ncs_ram.cfg new file mode 100644 index 0000000000..ae514d45cd --- /dev/null +++ b/make/custom/lpc2478_ncs_ram.cfg @@ -0,0 +1,14 @@ +# +# Config file for LPC2478 (NCS, code and data in external RAM). +# +# $Id$ +# + +LPC24XX_LINKCMDS = linkcmds.lpc2478_ncs_ram + +include $(RTEMS_ROOT)/make/custom/lpc24xx.cfg + +define bsp-post-link + $(OBJCOPY) -S '$@' '$(basename $@).elf' + $(default-bsp-post-link) +endef diff --git a/make/custom/lpc24xx.cfg b/make/custom/lpc24xx.cfg new file mode 100644 index 0000000000..41c40302a4 --- /dev/null +++ b/make/custom/lpc24xx.cfg @@ -0,0 +1,18 @@ +# +# Config file for LPC24XX. +# +# $Id$ +# + +include $(RTEMS_ROOT)/make/custom/default.cfg + +RTEMS_CPU = arm + +RTEMS_BSP_FAMILY = lpc24xx + +CPU_CFLAGS = -mcpu=arm7tdmi-s -mstructure-size-boundary=8 -mapcs-frame \ + -Wextra -Wno-unused -Wpointer-arith -Wcast-qual -Wconversion -Wmissing-prototypes -fno-inline + +CFLAGS_OPTIMIZE_V = -Os -g + +LDFLAGS += -qnolinkcmds -T $(LPC24XX_LINKCMDS) -- cgit v1.2.3