From 39c8fdb416327c5ec0c23807ae701798a5739cdf Mon Sep 17 00:00:00 2001 From: Thomas Doerfler Date: Tue, 12 Jan 2010 15:03:22 +0000 Subject: add support for lpc32xx --- c/src/lib/libbsp/arm/lpc24xx/ChangeLog | 7 + c/src/lib/libbsp/arm/lpc24xx/Makefile.am | 22 +- c/src/lib/libbsp/arm/lpc24xx/configure.ac | 2 +- c/src/lib/libbsp/arm/lpc24xx/include/bsp.h | 4 +- .../arm/lpc24xx/include/lpc-ethernet-config.h | 82 ++ c/src/lib/libbsp/arm/lpc24xx/include/lpc24xx.h | 230 +--- c/src/lib/libbsp/arm/lpc24xx/preinstall.am | 13 + c/src/lib/libbsp/arm/lpc32xx/ChangeLog | 8 + c/src/lib/libbsp/arm/lpc32xx/Makefile.am | 31 +- c/src/lib/libbsp/arm/lpc32xx/configure.ac | 3 + c/src/lib/libbsp/arm/lpc32xx/include/bsp.h | 4 +- c/src/lib/libbsp/arm/lpc32xx/include/bspopts.h.in | 3 + c/src/lib/libbsp/arm/lpc32xx/include/irq.h | 2 + .../arm/lpc32xx/include/lpc-ethernet-config.h | 81 ++ c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h | 1 + c/src/lib/libbsp/arm/lpc32xx/irq/irq.c | 53 +- c/src/lib/libbsp/arm/lpc32xx/preinstall.am | 27 +- c/src/lib/libbsp/arm/lpc32xx/rtc/rtc-config.c | 114 +- .../lib/libbsp/arm/lpc32xx/startup/bspstarthooks.c | 124 +- .../arm/lpc32xx/startup/linkcmds.lpc32xx_phycore | 5 +- c/src/lib/libbsp/arm/shared/abort/abort.c | 14 +- c/src/lib/libbsp/arm/shared/abort/simple_abort.c | 12 +- .../lib/libbsp/arm/shared/include/linker-symbols.h | 6 +- .../libbsp/arm/shared/lpc/network/lpc-ethernet.c | 1400 ++++++++++++++++++++ c/src/lib/libbsp/arm/shared/start/start.S | 54 +- c/src/lib/libbsp/arm/shared/startup/linkcmds.base | 52 +- c/src/lib/libcpu/arm/ChangeLog | 7 + c/src/lib/libcpu/arm/Makefile.am | 1 + c/src/lib/libcpu/arm/preinstall.am | 4 + c/src/lib/libcpu/arm/shared/arm920/mmu.c | 146 +- c/src/lib/libcpu/arm/shared/include/arm-cp15.h | 644 +++++++++ c/src/lib/libcpu/arm/shared/include/cache.h | 132 ++ c/src/lib/libcpu/arm/shared/include/cache_.h | 27 + cpukit/score/cpu/arm/ChangeLog | 9 + cpukit/score/cpu/arm/Makefile.am | 1 + cpukit/score/cpu/arm/arm_exc_abort.S | 123 ++ cpukit/score/cpu/arm/arm_exc_interrupt.S | 20 +- cpukit/score/cpu/arm/cpu.c | 28 +- cpukit/score/cpu/arm/rtems/asm.h | 16 + cpukit/score/cpu/arm/rtems/score/cpu.h | 169 ++- 40 files changed, 3098 insertions(+), 583 deletions(-) create mode 100644 c/src/lib/libbsp/arm/lpc24xx/include/lpc-ethernet-config.h create mode 100644 c/src/lib/libbsp/arm/lpc32xx/include/lpc-ethernet-config.h create mode 100644 c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c create mode 100644 c/src/lib/libcpu/arm/shared/include/arm-cp15.h create mode 100644 c/src/lib/libcpu/arm/shared/include/cache.h create mode 100644 c/src/lib/libcpu/arm/shared/include/cache_.h create mode 100644 cpukit/score/cpu/arm/arm_exc_abort.S diff --git a/c/src/lib/libbsp/arm/lpc24xx/ChangeLog b/c/src/lib/libbsp/arm/lpc24xx/ChangeLog index 399ebbb5e2..20d74c7726 100644 --- a/c/src/lib/libbsp/arm/lpc24xx/ChangeLog +++ b/c/src/lib/libbsp/arm/lpc24xx/ChangeLog @@ -1,3 +1,10 @@ +2010-01-12 Sebastian Huber + + * include/lpc-ethernet-config.h: New file. + * network/network.c: Removed file. + * Makefile.am, configure.ac, preinstall.am, include/bsp.h, + include/lpc24xx.h: Changes throughout. + 2009-12-15 Sebastian Huber * clock/clock-config.c: Removed file. diff --git a/c/src/lib/libbsp/arm/lpc24xx/Makefile.am b/c/src/lib/libbsp/arm/lpc24xx/Makefile.am index 765c2c1223..1ea711b82d 100644 --- a/c/src/lib/libbsp/arm/lpc24xx/Makefile.am +++ b/c/src/lib/libbsp/arm/lpc24xx/Makefile.am @@ -12,6 +12,7 @@ ACLOCAL_AMFLAGS = -I ../../../../aclocal include $(top_srcdir)/../../../../automake/compile.am include_bspdir = $(includedir)/bsp +include_libcpudir = $(includedir)/libcpu dist_project_lib_DATA = bsp_specs @@ -44,9 +45,12 @@ include_bsp_HEADERS += include/dma.h include_bsp_HEADERS += include/i2c.h include_bsp_HEADERS += include/io.h include_bsp_HEADERS += include/lpc-clock-config.h +include_bsp_HEADERS += include/lpc-ethernet-config.h include_HEADERS += ../../shared/include/tm27.h +include_libcpu_HEADERS = ../../../libcpu/arm/shared/include/cache.h + ############################################################################### # Data # ############################################################################### @@ -72,6 +76,8 @@ EXTRA_DIST += startup/linkcmds.lpc2362 noinst_LIBRARIES += libbsp.a libbsp_a_SOURCES = +libbsp_a_CPPFLAGS = +libbsp_a_LIBADD = # Shared libbsp_a_SOURCES += ../../shared/bootcard.c \ @@ -124,12 +130,18 @@ libbsp_a_SOURCES += ssp/ssp.c # I2C libbsp_a_SOURCES += i2c/i2c.c +# Cache +libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c \ + ../../../libcpu/arm/shared/cache/cache_.h +libbsp_a_CPPFLAGS += -I$(srcdir)/../../../libcpu/arm/shared/include + # Start hooks (FIXME: This is brittle.) libbsp_a_SOURCES += startup/bspstarthooks.c -bspstarthooks.o: startup/bspstarthooks.c - $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS:-mthumb=) \ - -MT bspstarthooks.o -MD -MP -MF $(DEPDIR)/bspstarthooks.Tpo -c -o bspstarthooks.o \ +libbsp_a-bspstarthooks.o: startup/bspstarthooks.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbsp_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS:-mthumb=) \ + -MT libbsp_a-bspstarthooks.o -MD -MP -MF $(DEPDIR)/libbsp_a-bspstarthooks.Tpo -c -o libbsp_a-bspstarthooks.o \ `test -f 'startup/bspstarthooks.c' || echo '$(srcdir)/'`startup/bspstarthooks.c + $(am__mv) $(DEPDIR)/libbsp_a-bspstarthooks.Tpo $(DEPDIR)/libbsp_a-bspstarthooks.Po ############################################################################### # Network # @@ -139,11 +151,11 @@ if HAS_NETWORKING noinst_PROGRAMS = network.rel -network_rel_SOURCES = network/network.c +network_rel_SOURCES = ../shared/lpc/network/lpc-ethernet.c network_rel_CPPFLAGS = $(AM_CPPFLAGS) -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ -D__BSD_VISIBLE network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) -libbsp_a_LIBADD = network.rel +libbsp_a_LIBADD += network.rel endif diff --git a/c/src/lib/libbsp/arm/lpc24xx/configure.ac b/c/src/lib/libbsp/arm/lpc24xx/configure.ac index e5724d7238..8a1f5daf4a 100644 --- a/c/src/lib/libbsp/arm/lpc24xx/configure.ac +++ b/c/src/lib/libbsp/arm/lpc24xx/configure.ac @@ -33,7 +33,7 @@ RTEMS_BSPOPTS_HELP([LPC24XX_CCLK],[CPU clock in Hz]) RTEMS_BSPOPTS_SET([LPC24XX_UART_BAUD],[*],[115200U]) RTEMS_BSPOPTS_HELP([LPC24XX_UART_BAUD],[baud for UARTs]) -RTEMS_BSPOPTS_SET([LPC24XX_ETHERNET_RMII],[lpc24xx_ncs_*],[1]) +RTEMS_BSPOPTS_SET([LPC24XX_ETHERNET_RMII],[*],[]) RTEMS_BSPOPTS_HELP([LPC24XX_ETHERNET_RMII],[enable RMII for Ethernet]) RTEMS_BSPOPTS_SET([LPC24XX_EMC_MICRON],[lpc24xx_ncs_rom_*],[1]) diff --git a/c/src/lib/libbsp/arm/lpc24xx/include/bsp.h b/c/src/lib/libbsp/arm/lpc24xx/include/bsp.h index a982305c95..9ab0ad629e 100644 --- a/c/src/lib/libbsp/arm/lpc24xx/include/bsp.h +++ b/c/src/lib/libbsp/arm/lpc24xx/include/bsp.h @@ -50,7 +50,7 @@ struct rtems_bsdnet_ifconfig; /** * @brief Network driver attach and detach function. */ -int lpc24xx_eth_attach_detach( +int lpc_eth_attach_detach( struct rtems_bsdnet_ifconfig *config, int attaching ); @@ -58,7 +58,7 @@ int lpc24xx_eth_attach_detach( /** * @brief Standard network driver attach and detach function. */ -#define RTEMS_BSP_NETWORK_DRIVER_ATTACH lpc24xx_eth_attach_detach +#define RTEMS_BSP_NETWORK_DRIVER_ATTACH lpc_eth_attach_detach /** * @brief Standard network driver name. diff --git a/c/src/lib/libbsp/arm/lpc24xx/include/lpc-ethernet-config.h b/c/src/lib/libbsp/arm/lpc24xx/include/lpc-ethernet-config.h new file mode 100644 index 0000000000..0bba1266e1 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc24xx/include/lpc-ethernet-config.h @@ -0,0 +1,82 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * @brief Ethernet driver configuration. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef LIBBSP_ARM_LPC24XX_LPC_ETHERNET_CONFIG_H +#define LIBBSP_ARM_LPC24XX_LPC_ETHERNET_CONFIG_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define LPC_ETH_CONFIG_INTERRUPT LPC24XX_IRQ_ETHERNET + +#define LPC_ETH_CONFIG_REG_BASE MAC_BASE_ADDR + +#define LPC_ETH_CONFIG_RX_UNIT_COUNT_DEFAULT 16 +#define LPC_ETH_CONFIG_RX_UNIT_COUNT_MAX 54 + +#define LPC_ETH_CONFIG_TX_UNIT_COUNT_DEFAULT 10 +#define LPC_ETH_CONFIG_TX_UNIT_COUNT_MAX 10 + +#define LPC_ETH_CONFIG_UNIT_MULTIPLE 1U + +#ifdef LPC24XX_ETHERNET_RMII + #define LPC_ETH_CONFIG_RMII + + static void lpc_eth_config_module_enable(void) + { + lpc24xx_module_enable(LPC24XX_MODULE_ETHERNET, LPC24XX_MODULE_PCLK_DEFAULT); + lpc24xx_io_config(LPC24XX_MODULE_ETHERNET, 0); + } +#else + static void lpc_eth_config_module_enable(void) + { + lpc24xx_module_enable(LPC24XX_MODULE_ETHERNET, LPC24XX_MODULE_PCLK_DEFAULT); + lpc24xx_io_config(LPC24XX_MODULE_ETHERNET, 1); + } +#endif + +#define LPC24XX_ETH_RAM_BEGIN 0x7fe00000U +#define LPC24XX_ETH_RAM_SIZE (16U * 1024U) + +static char *lpc_eth_config_alloc_table_area(size_t size) +{ + if (size < LPC24XX_ETH_RAM_SIZE) { + return (char *) LPC24XX_ETH_RAM_BEGIN; + } else { + return NULL; + } +} + +static void lpc_eth_config_free_table_area(char *table_area) +{ + /* Do nothing */ +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_ARM_LPC24XX_LPC_ETHERNET_CONFIG_H */ diff --git a/c/src/lib/libbsp/arm/lpc24xx/include/lpc24xx.h b/c/src/lib/libbsp/arm/lpc24xx/include/lpc24xx.h index daf198f372..2f296036d5 100644 --- a/c/src/lib/libbsp/arm/lpc24xx/include/lpc24xx.h +++ b/c/src/lib/libbsp/arm/lpc24xx/include/lpc24xx.h @@ -207,29 +207,29 @@ #define FIO4CLR (*(volatile uint32_t *) (FIO_BASE_ADDR + 0x9C)) /* FIOs can be accessed through WORD, HALF-WORD or BYTE. */ -#define FIO0DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x01)) -#define FIO1DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x21)) -#define FIO2DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x41)) -#define FIO3DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x61)) -#define FIO4DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x81)) - -#define FIO0DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x02)) -#define FIO1DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x22)) -#define FIO2DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x42)) -#define FIO3DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x62)) -#define FIO4DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x82)) - -#define FIO0DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x03)) -#define FIO1DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x23)) -#define FIO2DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x43)) -#define FIO3DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x63)) -#define FIO4DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x83)) - -#define FIO0DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x04)) -#define FIO1DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x24)) -#define FIO2DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x44)) -#define FIO3DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x64)) -#define FIO4DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x84)) +#define FIO0DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x00)) +#define FIO1DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x20)) +#define FIO2DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x40)) +#define FIO3DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x60)) +#define FIO4DIR0 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x80)) + +#define FIO0DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x01)) +#define FIO1DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x21)) +#define FIO2DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x41)) +#define FIO3DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x61)) +#define FIO4DIR1 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x81)) + +#define FIO0DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x02)) +#define FIO1DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x22)) +#define FIO2DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x42)) +#define FIO3DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x62)) +#define FIO4DIR2 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x82)) + +#define FIO0DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x03)) +#define FIO1DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x23)) +#define FIO2DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x43)) +#define FIO3DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x63)) +#define FIO4DIR3 (*(volatile uint8_t *) (FIO_BASE_ADDR + 0x83)) #define FIO0DIRL (*(volatile uint16_t *) (FIO_BASE_ADDR + 0x00)) #define FIO1DIRL (*(volatile uint16_t *) (FIO_BASE_ADDR + 0x20)) @@ -1837,190 +1837,6 @@ typedef struct { #define GPDMA_CH_CFG_HALT 0x00040000U -/* Ethernet (MAC) */ - -typedef struct { - uint32_t start; - uint32_t control; -} lpc24xx_eth_transfer_descriptor; - -typedef struct { - uint32_t status; - uint32_t hash_crc; -} lpc24xx_eth_receive_info; - -#define ETH_TRANSFER_DESCRIPTOR_SIZE 8 - -#define ETH_RECEIVE_INFO_SIZE 8 - -#define ETH_TRANSMIT_STATUS_SIZE 4 - -/* ETH_RX_CTRL */ - -#define ETH_RX_CTRL_SIZE_MASK 0x000007ffU - -#define GET_ETH_RX_CTRL_SIZE(reg) \ - GET_FIELD(reg, ETH_RX_CTRL_SIZE_MASK, 0) - -#define SET_ETH_RX_CTRL_SIZE(reg, val) \ - SET_FIELD(reg, val, ETH_RX_CTRL_SIZE_MASK, 0) - -#define ETH_RX_CTRL_INTERRUPT 0x80000000U - -/* ETH_RX_STAT */ - -#define ETH_RX_STAT_RXSIZE_MASK 0x000007ffU - -#define GET_ETH_RX_STAT_RXSIZE(reg) \ - GET_FIELD(reg, ETH_RX_STAT_RXSIZE_MASK, 0) - -#define SET_ETH_RX_STAT_RXSIZE(reg, val) \ - SET_FIELD(reg, val, ETH_RX_STAT_RXSIZE_MASK, 0) - -#define ETH_RX_STAT_BYTES 0x00000100U - -#define ETH_RX_STAT_CONTROL_FRAME 0x00040000U - -#define ETH_RX_STAT_VLAN 0x00080000U - -#define ETH_RX_STAT_FAIL_FILTER 0x00100000U - -#define ETH_RX_STAT_MULTICAST 0x00200000U - -#define ETH_RX_STAT_BROADCAST 0x00400000U - -#define ETH_RX_STAT_CRC_ERROR 0x00800000U - -#define ETH_RX_STAT_SYMBOL_ERROR 0x01000000U - -#define ETH_RX_STAT_LENGTH_ERROR 0x02000000U - -#define ETH_RX_STAT_RANGE_ERROR 0x04000000U - -#define ETH_RX_STAT_ALIGNMENT_ERROR 0x08000000U - -#define ETH_RX_STAT_OVERRUN 0x10000000U - -#define ETH_RX_STAT_NO_DESCRIPTOR 0x20000000U - -#define ETH_RX_STAT_LAST_FLAG 0x40000000U - -#define ETH_RX_STAT_ERROR 0x80000000U - -/* ETH_TX_CTRL */ - -#define ETH_TX_CTRL_SIZE_MASK 0x000007ffU - -#define GET_ETH_TX_CTRL_SIZE(reg) \ - GET_FIELD(reg, ETH_TX_CTRL_SIZE_MASK, 0) - -#define SET_ETH_TX_CTRL_SIZE(reg, val) \ - SET_FIELD(reg, val, ETH_TX_CTRL_SIZE_MASK, 0) - -#define ETH_TX_CTRL_OVERRIDE 0x04000000U - -#define ETH_TX_CTRL_HUGE 0x08000000U - -#define ETH_TX_CTRL_PAD 0x10000000U - -#define ETH_TX_CTRL_CRC 0x20000000U - -#define ETH_TX_CTRL_LAST 0x40000000U - -#define ETH_TX_CTRL_INTERRUPT 0x80000000U - -/* ETH_TX_STAT */ - -#define ETH_TX_STAT_COLLISION_COUNT_MASK 0x01e00000U - -#define GET_ETH_TX_STAT_COLLISION_COUNT(reg) \ - GET_FIELD(reg, ETH_TX_STAT_COLLISION_COUNT_MASK, 21) - -#define SET_ETH_TX_STAT_COLLISION_COUNT(reg, val) \ - SET_FIELD(reg, val, ETH_TX_STAT_COLLISION_COUNT_MASK, 21) - -#define ETH_TX_STAT_DEFER 0x02000000U - -#define ETH_TX_STAT_EXCESSIVE_DEFER 0x04000000U - -#define ETH_TX_STAT_EXCESSIVE_COLLISION 0x08000000U - -#define ETH_TX_STAT_LATE_COLLISION 0x10000000U - -#define ETH_TX_STAT_UNDERRUN 0x20000000U - -#define ETH_TX_STAT_NO_DESCRIPTOR 0x40000000U - -#define ETH_TX_STAT_ERROR 0x80000000U - -/* ETH_INT */ - -#define ETH_INT_RX_OVERRUN 0x00000001U - -#define ETH_INT_RX_ERROR 0x00000002U - -#define ETH_INT_RX_FINISHED 0x00000004U - -#define ETH_INT_RX_DONE 0x00000008U - -#define ETH_INT_TX_UNDERRUN 0x00000010U - -#define ETH_INT_TX_ERROR 0x00000020U - -#define ETH_INT_TX_FINISHED 0x00000040U - -#define ETH_INT_TX_DONE 0x00000080U - -#define ETH_INT_SOFT 0x00001000U - -#define ETH_INT_WAKEUP 0x00002000U - -/* ETH_RX_FIL_CTRL */ - -#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST 0x00000001U - -#define ETH_RX_FIL_CTRL_ACCEPT_BROADCAST 0x00000002U - -#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST 0x00000004U - -#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST_HASH 0x00000008U - -#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST_HASH 0x00000010U - -#define ETH_RX_FIL_CTRL_ACCEPT_PERFECT 0x00000020U - -#define ETH_RX_FIL_CTRL_MAGIC_PACKET_WOL 0x00001000U - -#define ETH_RX_FIL_CTRL_RX_FILTER_WOL 0x00002000U - -/* ETH_CMD */ - -#define ETH_CMD_RX_ENABLE 0x00000001U - -#define ETH_CMD_TX_ENABLE 0x00000002U - -#define ETH_CMD_REG_RESET 0x00000008U - -#define ETH_CMD_TX_RESET 0x00000010U - -#define ETH_CMD_RX_RESET 0x00000020U - -#define ETH_CMD_PASS_RUNT_FRAME 0x00000040U - -#define ETH_CMD_PASS_RX_FILTER 0X00000080U - -#define ETH_CMD_TX_FLOW_CONTROL 0x00000100U - -#define ETH_CMD_RMII 0x00000200U - -#define ETH_CMD_FULL_DUPLEX 0x00000400U - -/* ETH_STAT */ - -#define ETH_STAT_RX_ACTIVE 0x00000001U - -#define ETH_STAT_TX_ACTIVE 0x00000002U - /* AHBCFG */ #define AHBCFG_SCHEDULER_UNIFORM 0x00000001U diff --git a/c/src/lib/libbsp/arm/lpc24xx/preinstall.am b/c/src/lib/libbsp/arm/lpc24xx/preinstall.am index 3b145cd6a0..3618176b8e 100644 --- a/c/src/lib/libbsp/arm/lpc24xx/preinstall.am +++ b/c/src/lib/libbsp/arm/lpc24xx/preinstall.am @@ -33,6 +33,11 @@ $(PROJECT_INCLUDE)/bsp/$(dirstamp): @: > $(PROJECT_INCLUDE)/bsp/$(dirstamp) PREINSTALL_DIRS += $(PROJECT_INCLUDE)/bsp/$(dirstamp) +$(PROJECT_INCLUDE)/libcpu/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/libcpu + @: > $(PROJECT_INCLUDE)/libcpu/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/libcpu/$(dirstamp) + $(PROJECT_LIB)/bsp_specs: bsp_specs $(PROJECT_LIB)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_LIB)/bsp_specs PREINSTALL_FILES += $(PROJECT_LIB)/bsp_specs @@ -121,10 +126,18 @@ $(PROJECT_INCLUDE)/bsp/lpc-clock-config.h: include/lpc-clock-config.h $(PROJECT_ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/lpc-clock-config.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/lpc-clock-config.h +$(PROJECT_INCLUDE)/bsp/lpc-ethernet-config.h: include/lpc-ethernet-config.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/lpc-ethernet-config.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/lpc-ethernet-config.h + $(PROJECT_INCLUDE)/tm27.h: ../../shared/include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h +$(PROJECT_INCLUDE)/libcpu/cache.h: ../../../libcpu/arm/shared/include/cache.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/cache.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/cache.h + $(PROJECT_LIB)/start.$(OBJEXT): start.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_LIB)/start.$(OBJEXT) TMPINSTALL_FILES += $(PROJECT_LIB)/start.$(OBJEXT) diff --git a/c/src/lib/libbsp/arm/lpc32xx/ChangeLog b/c/src/lib/libbsp/arm/lpc32xx/ChangeLog index a89ffbd4d7..13500d9840 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/ChangeLog +++ b/c/src/lib/libbsp/arm/lpc32xx/ChangeLog @@ -1,3 +1,11 @@ +2010-01-12 Sebastian Huber + + * include/lpc-ethernet-config.h, include/mmu.h: New files. + * Makefile.am, configure.ac, preinstall.am, include/bsp.h, + include/bspopts.h.in, include/irq.h, include/lpc32xx.h, irq/irq.c, + rtc/rtc-config.c, startup/bspstarthooks.c, + startup/linkcmds.lpc32xx_phycore: Changes throughout. + 2009-12-17 Joel Sherrill * include/bspopts.h.in: Regenerated. diff --git a/c/src/lib/libbsp/arm/lpc32xx/Makefile.am b/c/src/lib/libbsp/arm/lpc32xx/Makefile.am index fd866bcdcd..fd33ab5a9c 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/Makefile.am +++ b/c/src/lib/libbsp/arm/lpc32xx/Makefile.am @@ -12,6 +12,7 @@ ACLOCAL_AMFLAGS = -I ../../../../aclocal include $(top_srcdir)/../../../../automake/compile.am include_bspdir = $(includedir)/bsp +include_libcpudir = $(includedir)/libcpu dist_project_lib_DATA = bsp_specs @@ -20,6 +21,7 @@ dist_project_lib_DATA = bsp_specs ############################################################################### include_HEADERS = include/bsp.h +include_HEADERS += ../../shared/include/tm27.h nodist_include_HEADERS = ../../shared/include/coverhd.h \ include/bspopts.h @@ -37,10 +39,13 @@ include_bsp_HEADERS += ../shared/include/start.h include_bsp_HEADERS += ../shared/lpc/include/lpc-timer.h include_bsp_HEADERS += include/irq-config.h include_bsp_HEADERS += include/irq.h +include_bsp_HEADERS += include/mmu.h include_bsp_HEADERS += include/lpc32xx.h include_bsp_HEADERS += include/lpc-clock-config.h +include_bsp_HEADERS += include/lpc-ethernet-config.h -include_HEADERS += ../../shared/include/tm27.h +include_libcpu_HEADERS = ../../../libcpu/arm/shared/include/cache.h \ + ../../../libcpu/arm/shared/include/arm-cp15.h ############################################################################### # Data # @@ -64,6 +69,8 @@ EXTRA_DIST = startup/linkcmds.lpc32xx_phycore noinst_LIBRARIES += libbsp.a libbsp_a_SOURCES = +libbsp_a_CPPFLAGS = +libbsp_a_LIBADD = # Shared libbsp_a_SOURCES += ../../shared/bootcard.c \ @@ -109,12 +116,18 @@ libbsp_a_SOURCES += misc/timer.c # I2C +# Cache +libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c \ + ../../../libcpu/arm/shared/cache/cache_.h +libbsp_a_CPPFLAGS += -I$(srcdir)/../../../libcpu/arm/shared/include + # Start hooks (FIXME: This is brittle.) libbsp_a_SOURCES += startup/bspstarthooks.c -bspstarthooks.o: startup/bspstarthooks.c - $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS:-mthumb=) \ - -MT bspstarthooks.o -MD -MP -MF $(DEPDIR)/bspstarthooks.Tpo -c -o bspstarthooks.o \ +libbsp_a-bspstarthooks.o: startup/bspstarthooks.c + $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbsp_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS:-mthumb=) \ + -MT libbsp_a-bspstarthooks.o -MD -MP -MF $(DEPDIR)/libbsp_a-bspstarthooks.Tpo -c -o libbsp_a-bspstarthooks.o \ `test -f 'startup/bspstarthooks.c' || echo '$(srcdir)/'`startup/bspstarthooks.c + $(am__mv) $(DEPDIR)/libbsp_a-bspstarthooks.Tpo $(DEPDIR)/libbsp_a-bspstarthooks.Po ############################################################################### # Network # @@ -122,13 +135,13 @@ bspstarthooks.o: startup/bspstarthooks.c if HAS_NETWORKING -# noinst_PROGRAMS = network.rel +noinst_PROGRAMS = network.rel -# network_rel_SOURCES = network/network.c -# network_rel_CPPFLAGS = $(AM_CPPFLAGS) -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ -D__BSD_VISIBLE -# network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) +network_rel_SOURCES = ../shared/lpc/network/lpc-ethernet.c +network_rel_CPPFLAGS = $(AM_CPPFLAGS) -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ -D__BSD_VISIBLE +network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) -# libbsp_a_LIBADD = network.rel +libbsp_a_LIBADD += network.rel endif diff --git a/c/src/lib/libbsp/arm/lpc32xx/configure.ac b/c/src/lib/libbsp/arm/lpc32xx/configure.ac index 6febd9d350..a3e90456c3 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/configure.ac +++ b/c/src/lib/libbsp/arm/lpc32xx/configure.ac @@ -33,6 +33,9 @@ RTEMS_BSPOPTS_HELP([LPC32XX_ARM_CLK],[ARM clock in Hz]) RTEMS_BSPOPTS_SET([LPC32XX_HCLK],[*],[104000000U]) RTEMS_BSPOPTS_HELP([LPC32XX_HCLK],[AHB bus clock in Hz]) +RTEMS_BSPOPTS_SET([LPC32XX_ETHERNET_RMII],[*],[1]) +RTEMS_BSPOPTS_HELP([LPC32XX_ETHERNET_RMII],[enable RMII for Ethernet]) + RTEMS_BSPOPTS_SET([LPC32XX_PERIPH_CLK],[*],[13000000U]) RTEMS_BSPOPTS_HELP([LPC32XX_PERIPH_CLK],[peripheral clock in Hz]) diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/bsp.h b/c/src/lib/libbsp/arm/lpc32xx/include/bsp.h index a42dd7b0be..c512ab28c2 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/include/bsp.h +++ b/c/src/lib/libbsp/arm/lpc32xx/include/bsp.h @@ -51,7 +51,7 @@ struct rtems_bsdnet_ifconfig; /** * @brief Network driver attach and detach function. */ -int lpc32xx_eth_attach_detach( +int lpc_eth_attach_detach( struct rtems_bsdnet_ifconfig *config, int attaching ); @@ -59,7 +59,7 @@ int lpc32xx_eth_attach_detach( /** * @brief Standard network driver attach and detach function. */ -#define RTEMS_BSP_NETWORK_DRIVER_ATTACH lpc32xx_eth_attach_detach +#define RTEMS_BSP_NETWORK_DRIVER_ATTACH lpc_eth_attach_detach /** * @brief Standard network driver name. diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/bspopts.h.in b/c/src/lib/libbsp/arm/lpc32xx/include/bspopts.h.in index f89ed3a90a..0de9964d9b 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/include/bspopts.h.in +++ b/c/src/lib/libbsp/arm/lpc32xx/include/bspopts.h.in @@ -33,6 +33,9 @@ /* clock mode configuration for UARTs */ #undef LPC32XX_CONFIG_UART_CLKMODE +/* enable RMII for Ethernet */ +#undef LPC32XX_ETHERNET_RMII + /* AHB bus clock in Hz */ #undef LPC32XX_HCLK diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/irq.h b/c/src/lib/libbsp/arm/lpc32xx/include/irq.h index 62d28fe7e0..2e047d27c1 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/include/irq.h +++ b/c/src/lib/libbsp/arm/lpc32xx/include/irq.h @@ -158,6 +158,8 @@ void lpc32xx_irq_set_activation_type(rtems_vector_number vector, lpc32xx_irq_act lpc32xx_irq_activation_type lpc32xx_irq_get_activation_type(rtems_vector_number vector); +void lpc32xx_set_exception_handler(Arm_symbolic_exception_name exception, void (*handler)(void)); + /** @} */ #endif /* ASM */ diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/lpc-ethernet-config.h b/c/src/lib/libbsp/arm/lpc32xx/include/lpc-ethernet-config.h new file mode 100644 index 0000000000..dd20823303 --- /dev/null +++ b/c/src/lib/libbsp/arm/lpc32xx/include/lpc-ethernet-config.h @@ -0,0 +1,81 @@ +/** + * @file + * + * @ingroup lpc32xx + * + * @brief Ethernet driver configuration. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef LIBBSP_ARM_LPC32XX_LPC_ETHERNET_CONFIG_H +#define LIBBSP_ARM_LPC32XX_LPC_ETHERNET_CONFIG_H + +#include +#include + +#include +#include + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define LPC_ETH_CONFIG_INTERRUPT LPC32XX_IRQ_ETHERNET + +#define LPC_ETH_CONFIG_REG_BASE LPC32XX_BASE_ETHERNET + +#define LPC_ETH_CONFIG_RX_UNIT_COUNT_DEFAULT 16 +#define LPC_ETH_CONFIG_RX_UNIT_COUNT_MAX INT_MAX + +#define LPC_ETH_CONFIG_TX_UNIT_COUNT_DEFAULT 32 +#define LPC_ETH_CONFIG_TX_UNIT_COUNT_MAX INT_MAX + +#define LPC_ETH_CONFIG_UNIT_MULTIPLE 8U + +#ifdef LPC32XX_ETHERNET_RMII + #define LPC_ETH_CONFIG_RMII + + static void lpc_eth_config_module_enable(void) + { + LPC32XX_MAC_CLK_CTRL = 0x1f; + } +#else + static void lpc_eth_config_module_enable(void) + { + LPC32XX_MAC_CLK_CTRL = 0x0f; + } +#endif + +#define LPC_ETH_CONFIG_USE_TRANSMIT_DMA + +static char *lpc_eth_config_alloc_table_area(size_t size) +{ + return rtems_heap_allocate_aligned_with_boundary(size, 32, 0); +} + +static void lpc_eth_config_free_table_area(char *table_area) +{ + /* FIXME: Type */ + free(table_area, (int) 0xdeadbeef); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_ARM_LPC32XX_LPC_ETHERNET_CONFIG_H */ diff --git a/c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h b/c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h index 2e82d34b80..d69e7db7f3 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h +++ b/c/src/lib/libbsp/arm/lpc32xx/include/lpc32xx.h @@ -90,5 +90,6 @@ #define LPC32XX_UART_CLKMODE (*(volatile uint32_t *) 0x40054004) #define LPC32XX_UART_LOOP (*(volatile uint32_t *) 0x40054008) #define LPC32XX_SW_INT (*(volatile uint32_t *) 0x400040a8) +#define LPC32XX_MAC_CLK_CTRL (*(volatile uint32_t *) 0x40004090) #endif /* LIBBSP_ARM_LPC32XX_LPC32XX_H */ diff --git a/c/src/lib/libbsp/arm/lpc32xx/irq/irq.c b/c/src/lib/libbsp/arm/lpc32xx/irq/irq.c index 187b4b310b..04eec9c921 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/irq/irq.c +++ b/c/src/lib/libbsp/arm/lpc32xx/irq/irq.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include /* * Mask out SIC 1 and 2 IRQ request. There is no need to mask out the FIQ, @@ -125,15 +127,15 @@ static inline void lpc32xx_irq_clear_bit_in_field(unsigned index, lpc32xx_irq_fi static inline unsigned lpc32xx_irq_get_index(uint32_t val) { - uint32_t reg; + ARM_SWITCH_REGISTERS; asm volatile ( - THUMB_TO_ARM - "clz %1, %1\n" - "rsb %1, %1, #31\n" - ARM_TO_THUMB - : "=&r" (reg), "=r" (val) - : "1" (val) + ARM_SWITCH_TO_ARM + "clz %[val], %[val]\n" + "rsb %[val], %[val], #31\n" + ARM_SWITCH_BACK + : [val] "=r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT + : "[val]" (val) ); return val; @@ -304,6 +306,21 @@ rtems_status_code bsp_interrupt_vector_disable(rtems_vector_number vector) return RTEMS_SUCCESSFUL; } +void lpc32xx_set_exception_handler( + Arm_symbolic_exception_name exception, + void (*handler)(void) +) +{ + if ((unsigned) exception < MAX_EXCEPTIONS) { + uint32_t *table = (uint32_t *) bsp_section_vector_begin + MAX_EXCEPTIONS; + + table [exception] = (uint32_t) handler; + + rtems_cache_flush_multiple_data_lines(NULL, 64); + rtems_cache_invalidate_multiple_data_lines(NULL, 64); + } +} + rtems_status_code bsp_interrupt_facility_initialize(void) { size_t i = 0; @@ -341,7 +358,7 @@ rtems_status_code bsp_interrupt_facility_initialize(void) lpc32xx_sic_1->atr = 0x26000; lpc32xx_sic_2->atr = 0x0; - _CPU_ISR_install_vector(ARM_EXCEPTION_IRQ, arm_exc_interrupt, NULL); + lpc32xx_set_exception_handler(ARM_EXCEPTION_IRQ, arm_exc_interrupt); return RTEMS_SUCCESSFUL; } @@ -350,23 +367,3 @@ void bsp_interrupt_handler_default(rtems_vector_number vector) { printk("spurious interrupt: %u\n", vector); } - -static void lpc32xx_irq_dump_controller(volatile lpc32xx_irq_controller *controller) -{ - printk( - "er %08x\nrsr %08x\nsr %08x\napr %08x\natr %08x\nitr %08x\n", - controller->er, - controller->rsr, - controller->sr, - controller->apr, - controller->atr, - controller->itr - ); -} - -void lpc32xx_irq_dump(void) -{ - lpc32xx_irq_dump_controller(lpc32xx_mic); - lpc32xx_irq_dump_controller(lpc32xx_sic_1); - lpc32xx_irq_dump_controller(lpc32xx_sic_2); -} diff --git a/c/src/lib/libbsp/arm/lpc32xx/preinstall.am b/c/src/lib/libbsp/arm/lpc32xx/preinstall.am index 3f2aa0c774..41a5255bd7 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/preinstall.am +++ b/c/src/lib/libbsp/arm/lpc32xx/preinstall.am @@ -33,6 +33,11 @@ $(PROJECT_INCLUDE)/bsp/$(dirstamp): @: > $(PROJECT_INCLUDE)/bsp/$(dirstamp) PREINSTALL_DIRS += $(PROJECT_INCLUDE)/bsp/$(dirstamp) +$(PROJECT_INCLUDE)/libcpu/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/libcpu + @: > $(PROJECT_INCLUDE)/libcpu/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/libcpu/$(dirstamp) + $(PROJECT_LIB)/bsp_specs: bsp_specs $(PROJECT_LIB)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_LIB)/bsp_specs PREINSTALL_FILES += $(PROJECT_LIB)/bsp_specs @@ -41,6 +46,10 @@ $(PROJECT_INCLUDE)/bsp.h: include/bsp.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp.h +$(PROJECT_INCLUDE)/tm27.h: ../../shared/include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h + $(PROJECT_INCLUDE)/coverhd.h: ../../shared/include/coverhd.h $(PROJECT_INCLUDE)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/coverhd.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/coverhd.h @@ -93,6 +102,10 @@ $(PROJECT_INCLUDE)/bsp/irq.h: include/irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq.h +$(PROJECT_INCLUDE)/bsp/mmu.h: include/mmu.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/mmu.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/mmu.h + $(PROJECT_INCLUDE)/bsp/lpc32xx.h: include/lpc32xx.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/lpc32xx.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/lpc32xx.h @@ -101,9 +114,17 @@ $(PROJECT_INCLUDE)/bsp/lpc-clock-config.h: include/lpc-clock-config.h $(PROJECT_ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/lpc-clock-config.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/lpc-clock-config.h -$(PROJECT_INCLUDE)/tm27.h: ../../shared/include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp) - $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h -PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h +$(PROJECT_INCLUDE)/bsp/lpc-ethernet-config.h: include/lpc-ethernet-config.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/lpc-ethernet-config.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/lpc-ethernet-config.h + +$(PROJECT_INCLUDE)/libcpu/cache.h: ../../../libcpu/arm/shared/include/cache.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/cache.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/cache.h + +$(PROJECT_INCLUDE)/libcpu/arm-cp15.h: ../../../libcpu/arm/shared/include/arm-cp15.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/arm-cp15.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/arm-cp15.h $(PROJECT_LIB)/start.$(OBJEXT): start.$(OBJEXT) $(PROJECT_LIB)/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_LIB)/start.$(OBJEXT) diff --git a/c/src/lib/libbsp/arm/lpc32xx/rtc/rtc-config.c b/c/src/lib/libbsp/arm/lpc32xx/rtc/rtc-config.c index 35a2c75be9..b518db3c1f 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/rtc/rtc-config.c +++ b/c/src/lib/libbsp/arm/lpc32xx/rtc/rtc-config.c @@ -21,44 +21,108 @@ #include +#include #include -#define LPC32XX_RTC_COUNT 1 +#define LPC32XX_RTC_COUNT 1U + +#define LPC32XX_RTC_COUNTER_DELTA 0xfffffffeU + +#define LPC32XX_RTC_KEY 0xb5c13f27U + +#define LPC32XX_RTC_CTRL_FORCE_ONSW (1U << 7) +#define LPC32XX_RTC_CTRL_STOP (1U << 6) +#define LPC32XX_RTC_CTRL_RESET (1U << 4) +#define LPC32XX_RTC_CTRL_MATCH_1_ONSW (1U << 3) +#define LPC32XX_RTC_CTRL_MATCH_0_ONSW (1U << 2) +#define LPC32XX_RTC_CTRL_MATCH_1_INTR (1U << 1) +#define LPC32XX_RTC_CTRL_MATCH_0_INTR (1U << 0) + +typedef struct { + uint32_t ucount; + uint32_t dcount; + uint32_t match0; + uint32_t match1; + uint32_t ctrl; + uint32_t intstat; + uint32_t key; + uint32_t sram [32]; +} lpc32xx_rtc_registers; + +static volatile lpc32xx_rtc_registers *const lpc32xx_rtc = + (volatile lpc32xx_rtc_registers *) LPC32XX_BASE_RTC; + +static void lpc32xx_rtc_set(uint32_t val) +{ + unsigned i = LPC32XX_ARM_CLK / LPC32XX_OSCILLATOR_RTC; + + lpc32xx_rtc->ctrl |= LPC32XX_RTC_CTRL_STOP; + lpc32xx_rtc->ucount = val; + lpc32xx_rtc->dcount = LPC32XX_RTC_COUNTER_DELTA - val; + lpc32xx_rtc->ctrl &= ~LPC32XX_RTC_CTRL_STOP; + + /* It needs some time before we can read the values back */ + while (i != 0) { + asm volatile ("nop"); + --i; + } +} + +static void lpc32xx_rtc_reset(void) +{ + lpc32xx_rtc->ctrl = LPC32XX_RTC_CTRL_RESET; + lpc32xx_rtc->ctrl = 0; + lpc32xx_rtc->key = LPC32XX_RTC_KEY; + lpc32xx_rtc_set(0); +} static void lpc32xx_rtc_initialize(int minor) { - /* TODO */ + uint32_t up_first = 0; + uint32_t up_second = 0; + uint32_t down_first = 0; + uint32_t down_second = 0; + + if (lpc32xx_rtc->key != LPC32XX_RTC_KEY) { + lpc32xx_rtc_reset(); + } + + do { + up_first = lpc32xx_rtc->ucount; + down_first = lpc32xx_rtc->dcount; + up_second = lpc32xx_rtc->ucount; + down_second = lpc32xx_rtc->dcount; + } while (up_first != up_second || down_first != down_second); + + if (up_first + down_first != LPC32XX_RTC_COUNTER_DELTA) { + lpc32xx_rtc_reset(); + } } static int lpc32xx_rtc_get_time(int minor, rtems_time_of_day *tod) { - /* TODO */ - -#if 0 - tod->ticks = 0; - tod->second = RTC_SEC; - tod->minute = RTC_MIN; - tod->hour = RTC_HOUR; - tod->day = RTC_DOM; - tod->month = RTC_MONTH; - tod->year = RTC_YEAR; -#endif - - return 0; + struct timeval now = { + .tv_sec = lpc32xx_rtc->ucount, + .tv_usec = 0 + }; + struct tm time; + + gmtime_r(&now.tv_sec, &time); + + tod->year = time.tm_year + 1900; + tod->month = time.tm_mon + 1; + tod->day = time.tm_mday; + tod->hour = time.tm_hour; + tod->minute = time.tm_min; + tod->second = time.tm_sec; + tod->ticks = 0; + + return RTEMS_SUCCESSFUL; } static int lpc32xx_rtc_set_time(int minor, const rtems_time_of_day *tod) { - /* TODO */ - -#if 0 - RTC_SEC = tod->second; - RTC_MIN = tod->minute; - RTC_HOUR = tod->hour; - RTC_DOM = tod->day; - RTC_MONTH = tod->month; - RTC_YEAR = tod->year; -#endif + lpc32xx_rtc_set(_TOD_To_seconds(tod)); return 0; } diff --git a/c/src/lib/libbsp/arm/lpc32xx/startup/bspstarthooks.c b/c/src/lib/libbsp/arm/lpc32xx/startup/bspstarthooks.c index 7f668f83c5..86164f518a 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/startup/bspstarthooks.c +++ b/c/src/lib/libbsp/arm/lpc32xx/startup/bspstarthooks.c @@ -24,9 +24,11 @@ #include #include #include +#include #include #define BSP_START_SECTION __attribute__((section(".bsp_start"))) +#define BSP_START_DATA_SECTION __attribute__((section(".bsp_start_data"))) static void BSP_START_SECTION lpc32xx_clear_bss(void) { @@ -40,9 +42,125 @@ static void BSP_START_SECTION lpc32xx_clear_bss(void) } } +typedef struct { + uint32_t begin; + uint32_t end; + uint32_t flags; +} lpc32xx_mmu_config; + +static const BSP_START_DATA_SECTION lpc32xx_mmu_config + lpc32xx_mmu_config_table [] = { + { + .begin = (uint32_t) bsp_section_start_begin, + .end = (uint32_t) bsp_section_start_end, + .flags = LPC32XX_MMU_READ_WRITE_CACHED + }, { + .begin = (uint32_t) bsp_section_vector_begin, + .end = (uint32_t) bsp_section_vector_end, + .flags = LPC32XX_MMU_READ_WRITE_CACHED + }, { + .begin = (uint32_t) bsp_section_text_begin, + .end = (uint32_t) bsp_section_text_end, + .flags = LPC32XX_MMU_READ_WRITE_CACHED + }, { + .begin = (uint32_t) bsp_section_rodata_begin, + .end = (uint32_t) bsp_section_rodata_end, + .flags = LPC32XX_MMU_READ_ONLY_CACHED + }, { + .begin = (uint32_t) bsp_section_data_begin, + .end = (uint32_t) bsp_section_data_end, + .flags = LPC32XX_MMU_READ_WRITE + }, { + .begin = (uint32_t) bsp_section_fast_begin, + .end = (uint32_t) bsp_section_fast_end, + .flags = LPC32XX_MMU_READ_ONLY_CACHED + }, { + .begin = (uint32_t) bsp_section_bss_begin, + .end = (uint32_t) bsp_section_bss_end, + .flags = LPC32XX_MMU_READ_WRITE + }, { + .begin = (uint32_t) bsp_section_work_begin, + .end = (uint32_t) bsp_section_work_end, + .flags = LPC32XX_MMU_READ_WRITE_CACHED + }, { + .begin = (uint32_t) bsp_section_stack_begin, + .end = (uint32_t) bsp_section_stack_end, + .flags = LPC32XX_MMU_READ_WRITE_CACHED + }, { + .begin = 0x0U, + .end = 0x100000U, + .flags = LPC32XX_MMU_READ_ONLY_CACHED + }, { + .begin = 0x20000000U, + .end = 0x200c0000U, + .flags = LPC32XX_MMU_READ_WRITE + }, { + .begin = 0x30000000U, + .end = 0x32000000U, + .flags = LPC32XX_MMU_READ_WRITE + }, { + .begin = 0x40000000U, + .end = 0x40100000U, + .flags = LPC32XX_MMU_READ_WRITE + } +}; + +static void BSP_START_SECTION lpc32xx_mmu_set_entries( + uint32_t *ttb, + const lpc32xx_mmu_config *config +) +{ + uint32_t i = ARM_MMU_SECT_GET_INDEX(config->begin); + uint32_t iend = ARM_MMU_SECT_GET_INDEX(ARM_MMU_SECT_MVA_ALIGN_UP(config->end)); + + if (config->begin != config->end) { + while (i < iend) { + ttb [i] = (i << ARM_MMU_SECT_BASE_SHIFT) | config->flags; + ++i; + } + } +} + +static void BSP_START_SECTION lpc32xx_mmu_and_cache_setup(void) +{ + uint32_t const dac = + ARM_CP15_DAC_DOMAIN(LPC32XX_MMU_CLIENT_DOMAIN, ARM_CP15_DAC_CLIENT); + uint32_t ctrl = 0; + uint32_t *const ttb = (uint32_t *) bsp_section_work_end; + size_t const config_entry_count = + sizeof(lpc32xx_mmu_config_table) / sizeof(lpc32xx_mmu_config_table [0]); + size_t i = 0; + + /* Disable MMU and cache, basic settings */ + ctrl = arm_cp15_get_control(); + ctrl &= ~(ARM_CP15_CTRL_I | ARM_CP15_CTRL_R | ARM_CP15_CTRL_C + | ARM_CP15_CTRL_V | ARM_CP15_CTRL_M); + ctrl |= ARM_CP15_CTRL_S | ARM_CP15_CTRL_A; + arm_cp15_set_control(ctrl); + + arm_cp15_cache_invalidate(); + arm_cp15_tlb_invalidate(); + + arm_cp15_set_domain_access_control(dac); + arm_cp15_set_translation_table_base(ttb); + + /* Initialize translation table with invalid entries */ + for (i = 0; i < ARM_MMU_TRANSLATION_TABLE_ENTRY_COUNT; ++i) { + ttb [i] = 0; + } + + for (i = 0; i < config_entry_count; ++i) { + lpc32xx_mmu_set_entries(ttb, &lpc32xx_mmu_config_table [i]); + } + + /* Enable MMU and cache */ + ctrl |= ARM_CP15_CTRL_I | ARM_CP15_CTRL_C | ARM_CP15_CTRL_M; + arm_cp15_set_control(ctrl); +} + void BSP_START_SECTION bsp_start_hook_0(void) { - /* TODO */ + lpc32xx_mmu_and_cache_setup(); } void BSP_START_SECTION bsp_start_hook_1(void) @@ -50,6 +168,7 @@ void BSP_START_SECTION bsp_start_hook_1(void) /* TODO */ /* Copy .text section */ + arm_cp15_instruction_cache_invalidate(); bsp_start_memcpy_arm( (int *) bsp_section_text_begin, (const int *) bsp_section_text_load_begin, @@ -57,6 +176,7 @@ void BSP_START_SECTION bsp_start_hook_1(void) ); /* Copy .rodata section */ + arm_cp15_instruction_cache_invalidate(); bsp_start_memcpy_arm( (int *) bsp_section_rodata_begin, (const int *) bsp_section_rodata_load_begin, @@ -64,6 +184,7 @@ void BSP_START_SECTION bsp_start_hook_1(void) ); /* Copy .data section */ + arm_cp15_instruction_cache_invalidate(); bsp_start_memcpy_arm( (int *) bsp_section_data_begin, (const int *) bsp_section_data_load_begin, @@ -71,6 +192,7 @@ void BSP_START_SECTION bsp_start_hook_1(void) ); /* Copy .fast section */ + arm_cp15_instruction_cache_invalidate(); bsp_start_memcpy_arm( (int *) bsp_section_fast_begin, (const int *) bsp_section_fast_load_begin, diff --git a/c/src/lib/libbsp/arm/lpc32xx/startup/linkcmds.lpc32xx_phycore b/c/src/lib/libbsp/arm/lpc32xx/startup/linkcmds.lpc32xx_phycore index 8003ecc996..2c2743caf0 100644 --- a/c/src/lib/libbsp/arm/lpc32xx/startup/linkcmds.lpc32xx_phycore +++ b/c/src/lib/libbsp/arm/lpc32xx/startup/linkcmds.lpc32xx_phycore @@ -36,7 +36,7 @@ MEMORY { RAM_INT (AIW) : ORIGIN = 0x08000000, LENGTH = 256k - RAM_EXT (AIW) : ORIGIN = 0x80000000, LENGTH = 64M /* SDRAM on DYCS0 */ + RAM_EXT (AIW) : ORIGIN = 0x80000000, LENGTH = 64M - 16k /* SDRAM on DYCS0 */ ROM_EXT (RX) : ORIGIN = 0xe0000000, LENGTH = 2M /* NOR flash on CS0 */ NIRVANA : ORIGIN = 0, LENGTH = 0 } @@ -56,5 +56,8 @@ REGION_ALIAS ("REGION_WORK", RAM_EXT); REGION_ALIAS ("REGION_STACK", RAM_INT); bsp_stack_irq_size = DEFINED (bsp_stack_irq_size) ? bsp_stack_irq_size : 4096; +bsp_stack_abt_size = DEFINED (bsp_stack_abt_size) ? bsp_stack_abt_size : 1024; + +bsp_section_robarrier_align = DEFINED (bsp_section_robarrier_align) ? bsp_section_robarrier_align : 1M; INCLUDE linkcmds.base diff --git a/c/src/lib/libbsp/arm/shared/abort/abort.c b/c/src/lib/libbsp/arm/shared/abort/abort.c index 3bd704c32e..123fda0f7e 100644 --- a/c/src/lib/libbsp/arm/shared/abort/abort.c +++ b/c/src/lib/libbsp/arm/shared/abort/abort.c @@ -63,7 +63,7 @@ char *_print_full_context_mode2txt[0x20]={ void _print_full_context(uint32_t spsr) { char *mode; - uint32_t prev_sp,prev_lr,cpsr,tmp; + uint32_t prev_sp,prev_lr,cpsr,arm_switch_reg; int i; printk("active thread thread 0x%08x\n", _Thread_Executing->Object.id); @@ -71,14 +71,16 @@ void _print_full_context(uint32_t spsr) mode=_print_full_context_mode2txt[spsr&0x1f]; if(!mode) mode="unknown"; - asm volatile (" MRS %[cpsr], cpsr \n" - " ORR %[tmp], %[spsr], #0xc0 \n" - " MSR cpsr_c, %[tmp] \n" + asm volatile (ARM_SWITCH_TO_ARM + " MRS %[cpsr], cpsr \n" + " ORR %[arm_switch_reg], %[spsr], #0xc0 \n" + " MSR cpsr_c, %[arm_switch_reg] \n" " MOV %[prev_sp], sp \n" " MOV %[prev_lr], lr \n" " MSR cpsr_c, %[cpsr] \n" - : [prev_sp] "=&r" (prev_sp), [prev_lr] "=&r" (prev_lr), - [cpsr] "=&r" (cpsr), [tmp] "=&r" (tmp) + ARM_SWITCH_BACK + : [arm_switch_reg] "=&r" (arm_switch_reg), [prev_sp] "=&r" (prev_sp), [prev_lr] "=&r" (prev_lr), + [cpsr] "=&r" (cpsr) : [spsr] "r" (spsr) : "cc"); diff --git a/c/src/lib/libbsp/arm/shared/abort/simple_abort.c b/c/src/lib/libbsp/arm/shared/abort/simple_abort.c index 25f6aee4e5..b77c425a5e 100644 --- a/c/src/lib/libbsp/arm/shared/abort/simple_abort.c +++ b/c/src/lib/libbsp/arm/shared/abort/simple_abort.c @@ -56,7 +56,7 @@ char *_print_full_context_mode2txt[0x10]={ void _print_full_context(uint32_t spsr) { char *mode; - uint32_t prev_sp,prev_lr,cpsr,tmp; + uint32_t prev_sp,prev_lr,cpsr,arm_switch_reg; int i, j; printk("active thread thread 0x%08x\n", _Thread_Executing->Object.id); @@ -65,16 +65,16 @@ void _print_full_context(uint32_t spsr) if(!mode) mode="unknown"; asm volatile ( - THUMB_TO_ARM + ARM_SWITCH_TO_ARM "mrs %[cpsr], cpsr\n" - "orr %[tmp], %[spsr], #0xc0\n" - "msr cpsr_c, %[tmp]\n" + "orr %[arm_switch_reg], %[spsr], #0xc0\n" + "msr cpsr_c, %[arm_switch_reg]\n" "mov %[prev_sp], sp\n" "mov %[prev_lr], lr\n" "msr cpsr_c, %[cpsr]\n" - ARM_TO_THUMB + ARM_SWITCH_BACK : [prev_sp] "=&r" (prev_sp), [prev_lr] "=&r" (prev_lr), - [cpsr] "=&r" (cpsr), [tmp] "=&r" (tmp) + [cpsr] "=&r" (cpsr), [arm_switch_reg] "=&r" (arm_switch_reg) : [spsr] "r" (spsr) : "cc" ); diff --git a/c/src/lib/libbsp/arm/shared/include/linker-symbols.h b/c/src/lib/libbsp/arm/shared/include/linker-symbols.h index 75f7d942e0..b8afed5c77 100644 --- a/c/src/lib/libbsp/arm/shared/include/linker-symbols.h +++ b/c/src/lib/libbsp/arm/shared/include/linker-symbols.h @@ -54,9 +54,9 @@ LINKER_SYMBOL(bsp_stack_abt_begin) LINKER_SYMBOL(bsp_stack_abt_end) LINKER_SYMBOL(bsp_stack_abt_size) -LINKER_SYMBOL(bsp_stack_undef_begin) -LINKER_SYMBOL(bsp_stack_undef_end) -LINKER_SYMBOL(bsp_stack_undef_size) +LINKER_SYMBOL(bsp_stack_und_begin) +LINKER_SYMBOL(bsp_stack_und_end) +LINKER_SYMBOL(bsp_stack_und_size) LINKER_SYMBOL(bsp_stack_svc_begin) LINKER_SYMBOL(bsp_stack_svc_end) diff --git a/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c b/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c new file mode 100644 index 0000000000..fe133c8955 --- /dev/null +++ b/c/src/lib/libbsp/arm/shared/lpc/network/lpc-ethernet.c @@ -0,0 +1,1400 @@ +/** + * @file + * + * @ingroup lpc + * + * @brief Ethernet driver. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * 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. + */ + +#define __INSIDE_RTEMS_BSD_TCPIP_STACK__ 1 +#define __BSD_VISIBLE 1 + +#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 + +#ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + #define LPC_ETH_CONFIG_TX_BUF_SIZE sizeof(struct mbuf *) +#else + #define LPC_ETH_CONFIG_TX_BUF_SIZE 1518U +#endif + +typedef struct { + uint32_t start; + uint32_t control; +} lpc_eth_transfer_descriptor; + +typedef struct { + uint32_t info; + uint32_t hash_crc; +} lpc_eth_receive_status; + +typedef struct { + uint32_t mac1; + uint32_t mac2; + uint32_t ipgt; + uint32_t ipgr; + uint32_t clrt; + uint32_t maxf; + uint32_t supp; + uint32_t test; + uint32_t mcfg; + uint32_t mcmd; + uint32_t madr; + uint32_t mwtd; + uint32_t mrdd; + uint32_t mind; + uint32_t reserved_0 [2]; + uint32_t sa0; + uint32_t sa1; + uint32_t sa2; + uint32_t reserved_1 [45]; + uint32_t command; + uint32_t status; + uint32_t rxdescriptor; + uint32_t rxstatus; + uint32_t rxdescriptornum; + uint32_t rxproduceindex; + uint32_t rxconsumeindex; + uint32_t txdescriptor; + uint32_t txstatus; + uint32_t txdescriptornum; + uint32_t txproduceindex; + uint32_t txconsumeindex; + uint32_t reserved_2 [10]; + uint32_t tsv0; + uint32_t tsv1; + uint32_t rsv; + uint32_t reserved_3 [3]; + uint32_t flowcontrolcnt; + uint32_t flowcontrolsts; + uint32_t reserved_4 [34]; + uint32_t rxfilterctrl; + uint32_t rxfilterwolsts; + uint32_t rxfilterwolclr; + uint32_t reserved_5 [1]; + uint32_t hashfilterl; + uint32_t hashfilterh; + uint32_t reserved_6 [882]; + uint32_t intstatus; + uint32_t intenable; + uint32_t intclear; + uint32_t intset; + uint32_t reserved_7 [1]; + uint32_t powerdown; +} lpc_eth_controller; + +static volatile lpc_eth_controller *const lpc_eth = + (volatile lpc_eth_controller *) LPC_ETH_CONFIG_REG_BASE; + +/* ETH_RX_CTRL */ + +#define ETH_RX_CTRL_SIZE_MASK 0x000007ffU +#define ETH_RX_CTRL_INTERRUPT 0x80000000U + +/* ETH_RX_STAT */ + +#define ETH_RX_STAT_RXSIZE_MASK 0x000007ffU +#define ETH_RX_STAT_BYTES 0x00000100U +#define ETH_RX_STAT_CONTROL_FRAME 0x00040000U +#define ETH_RX_STAT_VLAN 0x00080000U +#define ETH_RX_STAT_FAIL_FILTER 0x00100000U +#define ETH_RX_STAT_MULTICAST 0x00200000U +#define ETH_RX_STAT_BROADCAST 0x00400000U +#define ETH_RX_STAT_CRC_ERROR 0x00800000U +#define ETH_RX_STAT_SYMBOL_ERROR 0x01000000U +#define ETH_RX_STAT_LENGTH_ERROR 0x02000000U +#define ETH_RX_STAT_RANGE_ERROR 0x04000000U +#define ETH_RX_STAT_ALIGNMENT_ERROR 0x08000000U +#define ETH_RX_STAT_OVERRUN 0x10000000U +#define ETH_RX_STAT_NO_DESCRIPTOR 0x20000000U +#define ETH_RX_STAT_LAST_FLAG 0x40000000U +#define ETH_RX_STAT_ERROR 0x80000000U + +/* ETH_TX_CTRL */ + +#define ETH_TX_CTRL_SIZE_MASK 0x7ffU +#define ETH_TX_CTRL_SIZE_SHIFT 0 +#define ETH_TX_CTRL_OVERRIDE 0x04000000U +#define ETH_TX_CTRL_HUGE 0x08000000U +#define ETH_TX_CTRL_PAD 0x10000000U +#define ETH_TX_CTRL_CRC 0x20000000U +#define ETH_TX_CTRL_LAST 0x40000000U +#define ETH_TX_CTRL_INTERRUPT 0x80000000U + +/* ETH_TX_STAT */ + +#define ETH_TX_STAT_COLLISION_COUNT_MASK 0x01e00000U +#define ETH_TX_STAT_DEFER 0x02000000U +#define ETH_TX_STAT_EXCESSIVE_DEFER 0x04000000U +#define ETH_TX_STAT_EXCESSIVE_COLLISION 0x08000000U +#define ETH_TX_STAT_LATE_COLLISION 0x10000000U +#define ETH_TX_STAT_UNDERRUN 0x20000000U +#define ETH_TX_STAT_NO_DESCRIPTOR 0x40000000U +#define ETH_TX_STAT_ERROR 0x80000000U + +/* ETH_INT */ + +#define ETH_INT_RX_OVERRUN 0x00000001U +#define ETH_INT_RX_ERROR 0x00000002U +#define ETH_INT_RX_FINISHED 0x00000004U +#define ETH_INT_RX_DONE 0x00000008U +#define ETH_INT_TX_UNDERRUN 0x00000010U +#define ETH_INT_TX_ERROR 0x00000020U +#define ETH_INT_TX_FINISHED 0x00000040U +#define ETH_INT_TX_DONE 0x00000080U +#define ETH_INT_SOFT 0x00001000U +#define ETH_INT_WAKEUP 0x00002000U + +/* ETH_RX_FIL_CTRL */ + +#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST 0x00000001U +#define ETH_RX_FIL_CTRL_ACCEPT_BROADCAST 0x00000002U +#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST 0x00000004U +#define ETH_RX_FIL_CTRL_ACCEPT_UNICAST_HASH 0x00000008U +#define ETH_RX_FIL_CTRL_ACCEPT_MULTICAST_HASH 0x00000010U +#define ETH_RX_FIL_CTRL_ACCEPT_PERFECT 0x00000020U +#define ETH_RX_FIL_CTRL_MAGIC_PACKET_WOL 0x00001000U +#define ETH_RX_FIL_CTRL_RX_FILTER_WOL 0x00002000U + +/* ETH_CMD */ + +#define ETH_CMD_RX_ENABLE 0x00000001U +#define ETH_CMD_TX_ENABLE 0x00000002U +#define ETH_CMD_REG_RESET 0x00000008U +#define ETH_CMD_TX_RESET 0x00000010U +#define ETH_CMD_RX_RESET 0x00000020U +#define ETH_CMD_PASS_RUNT_FRAME 0x00000040U +#define ETH_CMD_PASS_RX_FILTER 0X00000080U +#define ETH_CMD_TX_FLOW_CONTROL 0x00000100U +#define ETH_CMD_RMII 0x00000200U +#define ETH_CMD_FULL_DUPLEX 0x00000400U + +/* ETH_STAT */ + +#define ETH_STAT_RX_ACTIVE 0x00000001U +#define ETH_STAT_TX_ACTIVE 0x00000002U + +/* Events */ + +#define LPC_ETH_EVENT_INITIALIZE RTEMS_EVENT_1 + +#define LPC_ETH_EVENT_START RTEMS_EVENT_2 + +#define LPC_ETH_EVENT_INTERRUPT RTEMS_EVENT_3 + +/* Status */ + +#define LPC_ETH_INTERRUPT_RECEIVE \ + (ETH_INT_RX_ERROR | ETH_INT_RX_FINISHED | ETH_INT_RX_DONE) + +#define LPC_ETH_INTERRUPT_TRANSMIT \ + (ETH_INT_TX_DONE | ETH_INT_TX_FINISHED | ETH_INT_TX_ERROR) + +#define LPC_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 LPC_ETH_LAST_FRAGMENT_FLAGS \ + (ETH_TX_CTRL_OVERRIDE \ + | ETH_TX_CTRL_PAD \ + | ETH_TX_CTRL_CRC \ + | ETH_TX_CTRL_INTERRUPT \ + | ETH_TX_CTRL_LAST) + +/* Debug */ + +#ifdef DEBUG + #define LPC_ETH_PRINTF(...) printf(__VA_ARGS__) + #define LPC_ETH_PRINTK(...) printk(__VA_ARGS__) +#else + #define LPC_ETH_PRINTF(...) + #define LPC_ETH_PRINTK(...) +#endif + +typedef enum { + LPC_ETH_NOT_INITIALIZED, + LPC_ETH_INITIALIZED, + LPC_ETH_STARTED, + LPC_ETH_RUNNING +} lpc_eth_state; + +typedef struct { + struct arpcom arpcom; + struct rtems_mdio_info mdio_info; + lpc_eth_state state; + rtems_id receive_task; + rtems_id transmit_task; + unsigned rx_unit_count; + unsigned tx_unit_count; + volatile lpc_eth_transfer_descriptor *rx_desc_table; + volatile lpc_eth_receive_status *rx_status_table; + struct mbuf **rx_mbuf_table; + volatile lpc_eth_transfer_descriptor *tx_desc_table; + volatile uint32_t *tx_status_table; + void *tx_buf_table; + 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; +} lpc_eth_driver_entry; + +static lpc_eth_driver_entry lpc_eth_driver_data = { + .state = LPC_ETH_NOT_INITIALIZED, + .receive_task = RTEMS_ID_NONE, + .transmit_task = RTEMS_ID_NONE +}; + +static inline uint32_t lpc_eth_increment( + uint32_t value, + uint32_t cycle +) +{ + if (value < cycle) { + return ++value; + } else { + return 0; + } +} + +static void lpc_eth_enable_promiscous_mode(bool enable) +{ + if (enable) { + lpc_eth->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 { + lpc_eth->rxfilterctrl = ETH_RX_FIL_CTRL_ACCEPT_PERFECT + | ETH_RX_FIL_CTRL_ACCEPT_BROADCAST; + } +} + +static void lpc_eth_interrupt_handler(void *arg) +{ + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg; + rtems_event_set re = 0; + rtems_event_set te = 0; + uint32_t ie = 0; + + /* Get interrupt status */ + uint32_t im = lpc_eth->intenable; + uint32_t is = lpc_eth->intstatus & im; + + /* Check receive interrupts */ + if ((is & ETH_INT_RX_OVERRUN) != 0) { + re = LPC_ETH_EVENT_INITIALIZE; + ++e->receive_fatal_errors; + } else if ((is & LPC_ETH_INTERRUPT_RECEIVE) != 0) { + re = LPC_ETH_EVENT_INTERRUPT; + ie |= LPC_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 & ETH_INT_TX_UNDERRUN) != 0) { + te = LPC_ETH_EVENT_INITIALIZE; + ++e->transmit_fatal_errors; + } else if ((is & LPC_ETH_INTERRUPT_TRANSMIT) != 0) { + te = LPC_ETH_EVENT_INTERRUPT; + ie |= LPC_ETH_INTERRUPT_TRANSMIT; + } + + /* Send events to transmit task */ + if (te != 0) { + ++e->transmit_interrupts; + (void) rtems_event_send(e->transmit_task, te); + } + + LPC_ETH_PRINTK("interrupt: rx = 0x%08x, tx = 0x%08x\n", re, te); + + /* Update interrupt mask */ + lpc_eth->intenable = im & ~ie; + + /* Clear interrupts */ + lpc_eth->intclear = is; +} + +static void lpc_eth_enable_receive_interrupts(void) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + lpc_eth->intenable |= LPC_ETH_INTERRUPT_RECEIVE; + rtems_interrupt_enable(level); +} + +static void lpc_eth_disable_receive_interrupts(void) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + lpc_eth->intenable &= ~LPC_ETH_INTERRUPT_RECEIVE; + rtems_interrupt_enable(level); +} + +static void lpc_eth_enable_transmit_interrupts(void) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + lpc_eth->intenable |= LPC_ETH_INTERRUPT_TRANSMIT; + rtems_interrupt_enable(level); +} + +static void lpc_eth_disable_transmit_interrupts(void) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + lpc_eth->intenable &= ~LPC_ETH_INTERRUPT_TRANSMIT; + rtems_interrupt_enable(level); +} + +#define LPC_ETH_RX_DATA_OFFSET 2 + +static struct mbuf *lpc_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 ((m->m_flags & M_EXT) != 0) { + /* Set receive interface */ + m->m_pkthdr.rcvif = ifp; + + /* Adjust by two bytes for proper IP header alignment */ + m->m_data = mtod(m, char *) + LPC_ETH_RX_DATA_OFFSET; + + return m; + } else { + m_free(m); + } + } + + return NULL; +} + +static bool lpc_eth_add_new_mbuf( + struct ifnet *ifp, + volatile lpc_eth_transfer_descriptor *desc, + struct mbuf **mbufs, + uint32_t i, + bool wait +) +{ + /* New mbuf */ + struct mbuf *m = lpc_eth_new_mbuf(ifp, wait); + + /* Check mbuf */ + if (m != NULL) { + /* Cache invalidate */ + rtems_cache_invalidate_multiple_data_lines( + mtod(m, void *), + MCLBYTES - LPC_ETH_RX_DATA_OFFSET + ); + + /* Add mbuf to queue */ + desc [i].start = mtod(m, uint32_t); + desc [i].control = (MCLBYTES - LPC_ETH_RX_DATA_OFFSET - 1) + | ETH_RX_CTRL_INTERRUPT; + + /* Cache flush of descriptor */ + rtems_cache_flush_multiple_data_lines(&desc [i], sizeof(desc [0])); + + /* Add mbuf to table */ + mbufs [i] = m; + + return true; + } else { + return false; + } +} + +static void lpc_eth_receive_task(void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_event_set events = 0; + lpc_eth_driver_entry *const e = (lpc_eth_driver_entry *) arg; + struct ifnet *const ifp = &e->arpcom.ac_if; + volatile lpc_eth_transfer_descriptor *const desc = e->rx_desc_table; + volatile lpc_eth_receive_status *const status = e->rx_status_table; + struct mbuf **const mbufs = e->rx_mbuf_table; + uint32_t const index_max = e->rx_unit_count - 1; + uint32_t produce_index = 0; + uint32_t consume_index = 0; + uint32_t receive_index = 0; + + LPC_ETH_PRINTF("%s\n", __func__); + + /* Main event loop */ + while (true) { + bool wait_for_mbuf = false; + + /* Wait for events */ + sc = rtems_bsdnet_event_receive( + LPC_ETH_EVENT_INITIALIZE | LPC_ETH_EVENT_INTERRUPT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + RTEMS_CLEANUP_SC(sc, cleanup, "wait for events"); + + LPC_ETH_PRINTF("rx: wake up: 0x%08" PRIx32 "\n", events); + + /* Initialize receiver? */ + if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) { + /* Disable receive interrupts */ + lpc_eth_disable_receive_interrupts(); + + /* Disable receiver */ + lpc_eth->command &= ~ETH_CMD_RX_ENABLE; + + /* Wait for inactive status */ + while ((lpc_eth->status & ETH_STAT_RX_ACTIVE) != 0) { + /* Wait */ + } + + /* Reset */ + lpc_eth->command |= ETH_CMD_RX_RESET; + + /* Clear receive interrupts */ + lpc_eth->intclear = LPC_ETH_INTERRUPT_RECEIVE; + + /* Move existing mbufs to the front */ + consume_index = 0; + for (produce_index = 0; produce_index <= index_max; ++produce_index) { + if (mbufs [produce_index] != NULL) { + mbufs [consume_index] = mbufs [produce_index]; + ++consume_index; + } + } + + /* Fill receive queue */ + for ( + produce_index = consume_index; + produce_index <= index_max; + ++produce_index + ) { + lpc_eth_add_new_mbuf(ifp, desc, mbufs, produce_index, true); + } + + /* Receive descriptor table */ + lpc_eth->rxdescriptornum = index_max; + lpc_eth->rxdescriptor = (uint32_t) desc; + lpc_eth->rxstatus = (uint32_t) status; + + /* Initialize indices */ + produce_index = lpc_eth->rxproduceindex; + consume_index = lpc_eth->rxconsumeindex; + receive_index = consume_index; + + /* Enable receiver */ + lpc_eth->command |= ETH_CMD_RX_ENABLE; + + /* Enable receive interrupts */ + lpc_eth_enable_receive_interrupts(); + + /* Wait for events */ + continue; + } + + while (true) { + /* Clear receive interrupt status */ + lpc_eth->intclear = LPC_ETH_INTERRUPT_RECEIVE; + + /* Get current produce index */ + produce_index = lpc_eth->rxproduceindex; + + if (receive_index != produce_index) { + uint32_t stat = 0; + + /* Fragment mbuf */ + struct mbuf *m = mbufs [receive_index]; + + /* Fragment status */ + rtems_cache_invalidate_multiple_data_lines( + &status [receive_index], + sizeof(status [0]) + ); + stat = status [receive_index].info; + + /* Remove mbuf from table */ + mbufs [receive_index] = NULL; + + if ( + (stat & ETH_RX_STAT_LAST_FLAG) != 0 + && (stat & LPC_ETH_RX_STAT_ERRORS) == 0 + ) { + /* Ethernet header */ + struct ether_header *eh = mtod(m, struct ether_header *); + + /* Discard Ethernet header and CRC */ + int sz = (int) (stat & ETH_RX_STAT_RXSIZE_MASK) + 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; + + LPC_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 ((stat & ETH_RX_STAT_OVERRUN) != 0) { + ++e->receive_overrun_errors; + } + if ((stat & ETH_RX_STAT_LAST_FLAG) == 0) { + ++e->receive_fragment_errors; + } + if ((stat & ETH_RX_STAT_CRC_ERROR) != 0) { + ++e->receive_crc_errors; + } + if ((stat & ETH_RX_STAT_SYMBOL_ERROR) != 0) { + ++e->receive_symbol_errors; + } + if ((stat & ETH_RX_STAT_LENGTH_ERROR) != 0) { + ++e->receive_length_errors; + } + if ((stat & ETH_RX_STAT_ALIGNMENT_ERROR) != 0) { + ++e->receive_alignment_errors; + } + if ((stat & ETH_RX_STAT_NO_DESCRIPTOR) != 0) { + ++e->receive_no_descriptor_errors; + } + } + + /* Increment receive index */ + receive_index = lpc_eth_increment(receive_index, index_max); + } else { + /* Nothing to do, enable receive interrupts */ + lpc_eth_enable_receive_interrupts(); + break; + } + } + + /* Wait for mbuf? */ + wait_for_mbuf = + lpc_eth_increment(produce_index, index_max) == consume_index; + + /* Fill queue with new mbufs */ + while (consume_index != produce_index) { + /* Add new mbuf to queue */ + if ( + !lpc_eth_add_new_mbuf(ifp, desc, mbufs, consume_index, wait_for_mbuf) + ) { + break; + } + + /* We wait for at most one mbuf */ + wait_for_mbuf = false; + + /* Increment consume index */ + consume_index = lpc_eth_increment(consume_index, index_max); + + /* Update consume indices */ + lpc_eth->rxconsumeindex = consume_index; + } + } + +cleanup: + + /* Clear task ID */ + e->receive_task = RTEMS_ID_NONE; + + /* Release network semaphore */ + rtems_bsdnet_semaphore_release(); + + /* Terminate self */ + (void) rtems_task_delete(RTEMS_SELF); +} + +static struct mbuf *lpc_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 = (uint32_t) (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 |= LPC_ETH_LAST_FRAGMENT_FLAGS; + } + + return m; +} + +static void lpc_eth_transmit_task(void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_event_set events = 0; + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg; + struct ifnet *ifp = &e->arpcom.ac_if; + volatile lpc_eth_transfer_descriptor *const desc = e->tx_desc_table; + volatile uint32_t *const status = e->tx_status_table; + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + struct mbuf **const mbufs = e->tx_buf_table; + #else + char *const buf = e->tx_buf_table; + #endif + struct mbuf *m = NULL; + uint32_t const index_max = e->tx_unit_count - 1; + uint32_t produce_index = 0; + uint32_t consume_index = 0; + uint32_t ctrl = 0; + #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + uint32_t frame_length = 0; + char *frame_buffer = NULL; + #endif + + LPC_ETH_PRINTF("%s\n", __func__); + + #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + /* Initialize descriptor table */ + for (produce_index = 0; produce_index <= index_max; ++produce_index) { + desc [produce_index].start = + (uint32_t) (buf + produce_index * LPC_ETH_CONFIG_TX_BUF_SIZE); + } + #endif + + /* Main event loop */ + while (true) { + /* Wait for events */ + sc = rtems_bsdnet_event_receive( + LPC_ETH_EVENT_INITIALIZE + | LPC_ETH_EVENT_START + | LPC_ETH_EVENT_INTERRUPT, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + RTEMS_CLEANUP_SC(sc, cleanup, "wait for events"); + + LPC_ETH_PRINTF("tx: wake up: 0x%08" PRIx32 "\n", events); + + /* Initialize transmitter? */ + if ((events & LPC_ETH_EVENT_INITIALIZE) != 0) { + /* Disable transmit interrupts */ + lpc_eth_disable_transmit_interrupts(); + + /* Disable transmitter */ + lpc_eth->command &= ~ETH_CMD_TX_ENABLE; + + /* Wait for inactive status */ + while ((lpc_eth->status & ETH_STAT_TX_ACTIVE) != 0) { + /* Wait */ + } + + /* Reset */ + lpc_eth->command |= ETH_CMD_TX_RESET; + + /* Clear transmit interrupts */ + lpc_eth->intclear = LPC_ETH_INTERRUPT_TRANSMIT; + + /* Transmit descriptors */ + lpc_eth->txdescriptornum = index_max; + lpc_eth->txdescriptor = (uint32_t) desc; + lpc_eth->txstatus = (uint32_t) status; + + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + /* Discard outstanding fragments (= data loss) */ + for (produce_index = 0; produce_index <= index_max; ++produce_index) { + struct mbuf *victim = mbufs [produce_index]; + + if (victim != NULL) { + m_free(victim); + mbufs [produce_index] = NULL; + } + } + #endif + + /* Initialize indices */ + produce_index = lpc_eth->txproduceindex; + consume_index = lpc_eth->txconsumeindex; + + #ifndef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + /* Fresh frame length and buffer start */ + frame_length = 0; + frame_buffer = (char *) desc [produce_index].start; + #endif + + /* Enable transmitter */ + lpc_eth->command |= ETH_CMD_TX_ENABLE; + } + + /* Free consumed fragments */ + while (true) { + /* Save last known consume index */ + uint32_t c = consume_index; + + /* Clear transmit interrupt status */ + lpc_eth->intclear = LPC_ETH_INTERRUPT_TRANSMIT; + + /* Get new consume index */ + consume_index = lpc_eth->txconsumeindex; + + /* Nothing consumed in the meantime? */ + if (c == consume_index) { + break; + } + + while (c != consume_index) { + uint32_t s = status [c]; + + /* Update error counters */ + if ((s & (ETH_TX_STAT_ERROR | ETH_TX_STAT_NO_DESCRIPTOR)) != 0) { + if ((s & ETH_TX_STAT_UNDERRUN) != 0) { + ++e->transmit_underrun_errors; + } + if ((s & ETH_TX_STAT_LATE_COLLISION) != 0) { + ++e->transmit_late_collision_errors; + } + if ((s & ETH_TX_STAT_EXCESSIVE_COLLISION) != 0) { + ++e->transmit_excessive_collision_errors; + } + if ((s & ETH_TX_STAT_EXCESSIVE_DEFER) != 0) { + ++e->transmit_excessive_defer_errors; + } + if ((s & ETH_TX_STAT_NO_DESCRIPTOR) != 0) { + ++e->transmit_no_descriptor_errors; + } + } + + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + /* Release mbuf */ + m_free(mbufs [c]); + mbufs [c] = NULL; + #endif + + /* Next consume index */ + c = lpc_eth_increment(c, index_max); + } + } + + /* Transmit new fragments */ + while (true) { + /* Compute next produce index */ + uint32_t p = lpc_eth_increment(produce_index, index_max); + + /* Get next fragment and control value */ + m = lpc_eth_next_fragment(ifp, m, &ctrl); + + /* Queue full? */ + if (p == consume_index) { + LPC_ETH_PRINTF("tx: full queue: 0x%08x\n", m); + + /* The queue is full, wait for transmit interrupt */ + break; + } + + /* New fragment? */ + if (m != NULL) { + #ifdef LPC_ETH_CONFIG_USE_TRANSMIT_DMA + /* Set the transfer data */ + rtems_cache_flush_multiple_data_lines( + mtod(m, const void *), + (size_t) m->m_len + ); + desc [produce_index].start = mtod(m, uint32_t); + desc [produce_index].control = ctrl; + rtems_cache_flush_multiple_data_lines( + &desc [produce_index], + sizeof(desc [0]) + ); + mbufs [produce_index] = m; + + LPC_ETH_PRINTF( + "tx: %02" PRIu32 ": %u %s\n", + produce_index, m->m_len, + (ctrl & ETH_TX_CTRL_LAST) != 0 ? "L" : "" + ); + + /* Next produce index */ + produce_index = p; + + /* Last fragment of a frame? */ + if ((ctrl & ETH_TX_CTRL_LAST) != 0) { + /* Update the produce index */ + lpc_eth->txproduceindex = produce_index; + + /* Increment transmitted frames counter */ + ++e->transmitted_frames; + } + + /* Next fragment of the frame */ + m = m->m_next; + #else + 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 > LPC_ETH_CONFIG_TX_BUF_SIZE) { + LPC_ETH_PRINTF("tx: overflow\n"); + + /* Discard overflow data */ + new_frame_length = LPC_ETH_CONFIG_TX_BUF_SIZE; + fragment_length = new_frame_length - frame_length; + + /* Finalize frame */ + ctrl |= LPC_ETH_LAST_FRAGMENT_FLAGS; + + /* Update error counter */ + ++e->transmit_overflow_errors; + } + + LPC_ETH_PRINTF( + "tx: copy: %" PRIu32 "%s%s\n", + fragment_length, + (m->m_flags & M_EXT) != 0 ? ", E" : "", + (m->m_flags & M_PKTHDR) != 0 ? ", H" : "" + ); + + /* Copy fragment to buffer in Ethernet RAM */ + memcpy(frame_buffer, fragment_start, fragment_length); + + if ((ctrl & ETH_TX_CTRL_LAST) != 0) { + /* Finalize descriptor */ + desc [produce_index].control = ctrl & ~ETH_TX_CTRL_SIZE_MASK + | (new_frame_length - 1); + + LPC_ETH_PRINTF( + "tx: %02" PRIu32 ": %" PRIu32 "\n", + produce_index, + new_frame_length + ); + + /* Cache flush of data */ + rtems_cache_flush_multiple_data_lines( + (const void *) desc [produce_index].start, + new_frame_length + ); + + /* Cache flush of descriptor */ + rtems_cache_flush_multiple_data_lines( + &desc [produce_index], + sizeof(desc [0]) + ); + + /* Next produce index */ + produce_index = p; + + /* Update the produce index */ + lpc_eth->txproduceindex = produce_index; + + /* Fresh 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); + #endif + } else { + /* Nothing to transmit */ + break; + } + } + + /* No more fragments? */ + if (m == NULL) { + /* Interface is now inactive */ + ifp->if_flags &= ~IFF_OACTIVE; + } else { + LPC_ETH_PRINTF("tx: enable interrupts\n"); + + /* Enable transmit interrupts */ + lpc_eth_enable_transmit_interrupts(); + } + } + +cleanup: + + /* Clear task ID */ + e->transmit_task = RTEMS_ID_NONE; + + /* Release network semaphore */ + rtems_bsdnet_semaphore_release(); + + /* Terminate self */ + (void) rtems_task_delete(RTEMS_SELF); +} + +static void lpc_eth_interface_init(void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) arg; + struct ifnet *ifp = &e->arpcom.ac_if; + + LPC_ETH_PRINTF("%s\n", __func__); + + if (e->state == LPC_ETH_INITIALIZED) { + lpc_eth_config_module_enable(); + + /* Soft reset */ + + /* Do soft reset */ + lpc_eth->command = 0x38; + lpc_eth->mac1 = 0xcf00; + lpc_eth->mac1 = 0x0; + + /* Initialize PHY */ + /* TODO */ + + /* Reinitialize registers */ + lpc_eth->mac2 = 0x31; + lpc_eth->ipgt = 0x15; + lpc_eth->ipgr = 0x12; + lpc_eth->clrt = 0x370f; + lpc_eth->maxf = 0x0600; + lpc_eth->supp = 0x0100; + lpc_eth->test = 0; + #ifdef LPC_ETH_CONFIG_RMII + lpc_eth->command = 0x0600; + #else + lpc_eth->command = 0x0400; + #endif + lpc_eth->intenable = 0; + lpc_eth->intclear = 0x30ff; + lpc_eth->powerdown = 0; + + /* MAC address */ + lpc_eth->sa0 = ((uint32_t) e->arpcom.ac_enaddr [5] << 8) + | (uint32_t) e->arpcom.ac_enaddr [4]; + lpc_eth->sa1 = ((uint32_t) e->arpcom.ac_enaddr [3] << 8) + | (uint32_t) e->arpcom.ac_enaddr [2]; + lpc_eth->sa2 = ((uint32_t) e->arpcom.ac_enaddr [1] << 8) + | (uint32_t) e->arpcom.ac_enaddr [0]; + + /* Enable receiver */ + lpc_eth->mac1 = 0x03; + + /* Start receive task */ + if (e->receive_task == RTEMS_ID_NONE) { + e->receive_task = rtems_bsdnet_newproc( + "ntrx", + 4096, + lpc_eth_receive_task, + e + ); + sc = rtems_event_send(e->receive_task, LPC_ETH_EVENT_INITIALIZE); + RTEMS_SYSLOG_ERROR_SC(sc, "send receive initialize event"); + } + + /* Start transmit task */ + if (e->transmit_task == RTEMS_ID_NONE) { + e->transmit_task = rtems_bsdnet_newproc( + "nttx", + 4096, + lpc_eth_transmit_task, + e + ); + sc = rtems_event_send(e->transmit_task, LPC_ETH_EVENT_INITIALIZE); + RTEMS_SYSLOG_ERROR_SC(sc, "send transmit initialize event"); + } + + /* Change state */ + if ( + e->receive_task != RTEMS_ID_NONE && e->transmit_task != RTEMS_ID_NONE + ) { + e->state = LPC_ETH_STARTED; + } + } + + if (e->state == LPC_ETH_STARTED) { + /* Enable fatal interrupts */ + lpc_eth->intenable = ETH_INT_RX_OVERRUN | ETH_INT_TX_UNDERRUN; + + /* Enable promiscous mode */ + lpc_eth_enable_promiscous_mode((ifp->if_flags & IFF_PROMISC) != 0); + + /* Start watchdog timer */ + ifp->if_timer = 1; + + /* Set interface to running state */ + ifp->if_flags |= IFF_RUNNING; + + /* Change state */ + e->state = LPC_ETH_RUNNING; + } +} + +static void lpc_eth_interface_stats(const lpc_eth_driver_entry *e) +{ + rtems_bsdnet_semaphore_release(); + + 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); + + rtems_bsdnet_semaphore_obtain(); +} + +static int lpc_eth_interface_ioctl( + struct ifnet *ifp, + ioctl_command_t command, + caddr_t data +) +{ + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc; + int rv = 0; + + LPC_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 |= IFF_RUNNING; + /* TODO: init */ + } + break; + case SIO_RTEMS_SHOW_STATS: + lpc_eth_interface_stats(e); + break; + default: + rv = EINVAL; + break; + } + + return rv; +} + +static void lpc_eth_interface_start(struct ifnet *ifp) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc_eth_driver_entry *e = (lpc_eth_driver_entry *) ifp->if_softc; + + ifp->if_flags |= IFF_OACTIVE; + + sc = rtems_event_send(e->transmit_task, LPC_ETH_EVENT_START); + RTEMS_SYSLOG_ERROR_SC(sc, "send transmit start event"); +} + +static void lpc_eth_interface_watchdog(struct ifnet *ifp __attribute__((unused))) +{ + LPC_ETH_PRINTF("%s\n", __func__); +} + +static unsigned lpc_eth_fixup_unit_count(int count, int default_value, int max) +{ + if (count <= 0) { + count = default_value; + } else if (count > max) { + count = max; + } + + return LPC_ETH_CONFIG_UNIT_MULTIPLE + + (((unsigned) count - 1U) & ~(LPC_ETH_CONFIG_UNIT_MULTIPLE - 1U)); +} + +static int lpc_eth_attach(struct rtems_bsdnet_ifconfig *config) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + lpc_eth_driver_entry *e = &lpc_eth_driver_data; + struct ifnet *ifp = &e->arpcom.ac_if; + char *unit_name = NULL; + int unit_index = rtems_bsdnet_parse_driver_name(config, &unit_name); + size_t table_area_size = 0; + char *table_area = NULL; + char *table_location = NULL; + + /* Check parameter */ + if (unit_index < 0) { + RTEMS_SYSLOG_ERROR("parse error for interface name\n"); + return 0; + } + if (unit_index != 0) { + RTEMS_DO_CLEANUP(cleanup, "unexpected unit number"); + } + if (config->hardware_address == NULL) { + RTEMS_DO_CLEANUP(cleanup, "MAC address missing"); + } + if (e->state != LPC_ETH_NOT_INITIALIZED) { + RTEMS_DO_CLEANUP(cleanup, "already attached"); + } + + /* Interrupt number */ + config->irno = LPC_ETH_CONFIG_INTERRUPT; + + /* Device control */ + config->drv_ctrl = e; + + /* Receive unit count */ + e->rx_unit_count = lpc_eth_fixup_unit_count( + config->rbuf_count, + LPC_ETH_CONFIG_RX_UNIT_COUNT_DEFAULT, + LPC_ETH_CONFIG_RX_UNIT_COUNT_MAX + ); + config->rbuf_count = (int) e->rx_unit_count; + + /* Transmit unit count */ + e->tx_unit_count = lpc_eth_fixup_unit_count( + config->xbuf_count, + LPC_ETH_CONFIG_TX_UNIT_COUNT_DEFAULT, + LPC_ETH_CONFIG_TX_UNIT_COUNT_MAX + ); + config->xbuf_count = (int) e->tx_unit_count; + + /* Disable interrupts */ + lpc_eth->intenable = 0; + + /* Install interrupt handler */ + sc = rtems_interrupt_handler_install( + config->irno, + "Ethernet", + RTEMS_INTERRUPT_UNIQUE, + lpc_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); + + /* Allocate and clear table area */ + table_area_size = + e->rx_unit_count + * (sizeof(lpc_eth_transfer_descriptor) + + sizeof(lpc_eth_receive_status) + + sizeof(struct mbuf *)) + + e->tx_unit_count + * (sizeof(lpc_eth_transfer_descriptor) + + sizeof(uint32_t) + + LPC_ETH_CONFIG_TX_BUF_SIZE); + table_area = lpc_eth_config_alloc_table_area(table_area_size); + if (table_area == NULL) { + RTEMS_DO_CLEANUP(cleanup, "no memory for table area"); + } + memset(table_area, 0, table_area_size); + + table_location = table_area; + + /* + * The receive status table must be the first one since it has the strictest + * alignment requirements. + */ + e->rx_status_table = (volatile lpc_eth_receive_status *) table_location; + table_location += e->rx_unit_count * sizeof(e->rx_status_table [0]); + + e->rx_desc_table = (volatile lpc_eth_transfer_descriptor *) table_location; + table_location += e->rx_unit_count * sizeof(e->rx_desc_table [0]); + + e->rx_mbuf_table = (struct mbuf **) table_location; + table_location += e->rx_unit_count * sizeof(e->rx_mbuf_table [0]); + + e->tx_desc_table = (volatile lpc_eth_transfer_descriptor *) table_location; + table_location += e->tx_unit_count * sizeof(e->tx_desc_table [0]); + + e->tx_status_table = (volatile uint32_t *) table_location; + table_location += e->tx_unit_count * sizeof(e->tx_status_table [0]); + + e->tx_buf_table = table_location; + + /* Set interface data */ + ifp->if_softc = e; + ifp->if_unit = (short) unit_index; + ifp->if_name = unit_name; + ifp->if_mtu = (config->mtu > 0) ? (u_long) config->mtu : ETHERMTU; + ifp->if_init = lpc_eth_interface_init; + ifp->if_ioctl = lpc_eth_interface_ioctl; + ifp->if_start = lpc_eth_interface_start; + ifp->if_output = ether_output; + ifp->if_watchdog = lpc_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 = LPC_ETH_INITIALIZED; + + /* Attach the interface */ + if_attach(ifp); + ether_ifattach(ifp); + + return 1; + +cleanup: + + lpc_eth_config_free_table_area(table_area); + + /* FIXME: Type */ + free(unit_name, (int) 0xdeadbeef); + + return 0; +} + +static int lpc_eth_detach( + struct rtems_bsdnet_ifconfig *config __attribute__((unused)) +) +{ + /* FIXME: Detach the interface from the upper layers? */ + + /* Module soft reset */ + lpc_eth->command = 0x38; + lpc_eth->mac1 = 0xcf00; + + /* FIXME: More cleanup */ + + return 0; +} + +int lpc_eth_attach_detach( + struct rtems_bsdnet_ifconfig *config, + int attaching +) +{ + /* FIXME: Return value */ + + if (attaching) { + return lpc_eth_attach(config); + } else { + return lpc_eth_detach(config); + } +} diff --git a/c/src/lib/libbsp/arm/shared/start/start.S b/c/src/lib/libbsp/arm/shared/start/start.S index 3b7c9fd5c2..d1843ce17f 100644 --- a/c/src/lib/libbsp/arm/shared/start/start.S +++ b/c/src/lib/libbsp/arm/shared/start/start.S @@ -17,6 +17,7 @@ */ #include +#include #include #include @@ -33,19 +34,6 @@ .globl start .globl bsp_start_memcpy -/* Program Status Register definitions */ - -.equ PSR_MODE_USR, 0x10 -.equ PSR_MODE_FIQ, 0x11 -.equ PSR_MODE_IRQ, 0x12 -.equ PSR_MODE_SVC, 0x13 -.equ PSR_MODE_ABT, 0x17 -.equ PSR_MODE_UNDEF, 0x1b -.equ PSR_MODE_SYS, 0x1f -.equ PSR_I, 0x80 -.equ PSR_F, 0x40 -.equ PSR_T, 0x20 - .section ".bsp_start", "ax" .arm @@ -117,33 +105,33 @@ start: /* * Set SVC mode, disable interrupts and enable ARM instructions. */ - mov r0, #(PSR_MODE_SVC | PSR_I | PSR_F) + mov r0, #(ARM_PSR_M_SVC | ARM_PSR_I | ARM_PSR_F) msr cpsr, r0 /* Initialize stack pointer registers for the various modes */ /* Enter IRQ mode and set up the IRQ stack pointer */ - mov r0, #(PSR_MODE_IRQ | PSR_I | PSR_F) + mov r0, #(ARM_PSR_M_IRQ | ARM_PSR_I | ARM_PSR_F) msr cpsr, r0 ldr sp, =bsp_stack_irq_end /* Enter FIQ mode and set up the FIQ stack pointer */ - mov r0, #(PSR_MODE_FIQ | PSR_I | PSR_F) + mov r0, #(ARM_PSR_M_FIQ | ARM_PSR_I | ARM_PSR_F) msr cpsr, r0 ldr sp, =bsp_stack_fiq_end /* Enter ABT mode and set up the ABT stack pointer */ - mov r0, #(PSR_MODE_ABT | PSR_I | PSR_F) + mov r0, #(ARM_PSR_M_ABT | ARM_PSR_I | ARM_PSR_F) msr cpsr, r0 ldr sp, =bsp_stack_abt_end - /* Enter UNDEF mode and set up the UNDEF stack pointer */ - mov r0, #(PSR_MODE_UNDEF | PSR_I | PSR_F) + /* Enter UND mode and set up the UND stack pointer */ + mov r0, #(ARM_PSR_M_UND | ARM_PSR_I | ARM_PSR_F) msr cpsr, r0 - ldr sp, =bsp_stack_undef_end + ldr sp, =bsp_stack_und_end /* Enter SVC mode and set up the SVC stack pointer */ - mov r0, #(PSR_MODE_SVC | PSR_I | PSR_F) + mov r0, #(ARM_PSR_M_SVC | ARM_PSR_I | ARM_PSR_F) msr cpsr, r0 ldr sp, =bsp_stack_svc_end @@ -178,32 +166,16 @@ bsp_start_hook_0_done: /* Branch to start hook 1 */ bl bsp_start_hook_1 + SWITCH_FROM_ARM_TO_THUMB r0 + /* Branch to boot card */ mov r0, #0 -#ifdef __thumb__ - ldr r3, =boot_card - mov lr, pc - bx r3 -.thumb - bx pc - nop -.arm -#else bl boot_card -#endif /* Branch to reset function */ -#ifdef __thumb__ - ldr r3, =bsp_reset - mov lr, pc - bx r3 -.thumb - bx pc - nop -.arm -#else bl bsp_reset -#endif + + SWITCH_FROM_THUMB_TO_ARM /* Spin forever */ diff --git a/c/src/lib/libbsp/arm/shared/startup/linkcmds.base b/c/src/lib/libbsp/arm/shared/startup/linkcmds.base index 0589169861..8e7764f5a3 100644 --- a/c/src/lib/libbsp/arm/shared/startup/linkcmds.base +++ b/c/src/lib/libbsp/arm/shared/startup/linkcmds.base @@ -25,16 +25,23 @@ OUTPUT_ARCH (arm) ENTRY (start) /* - * BSP: Global symbols + * BSP: Global symbols that may be defined externally */ -bsp_section_align = 32; +bsp_stack_align = DEFINED (bsp_stack_align) ? bsp_stack_align : 4; -bsp_stack_align = 4; +bsp_section_align = DEFINED (bsp_section_align) ? bsp_section_align : 32; -/* - * BSP: Symbols that may be defined externally - */ +bsp_section_start_end_align = DEFINED (bsp_section_start_end_align) ? bsp_section_start_end_align : bsp_section_align; +bsp_section_vector_end_align = DEFINED (bsp_section_vector_end_align) ? bsp_section_vector_end_align : bsp_section_align; +bsp_section_text_end_align = DEFINED (bsp_section_text_end_align) ? bsp_section_text_end_align : bsp_section_align; +bsp_section_rodata_end_align = DEFINED (bsp_section_rodata_end_align) ? bsp_section_rodata_end_align : bsp_section_align; +bsp_section_data_end_align = DEFINED (bsp_section_data_end_align) ? bsp_section_data_end_align : bsp_section_align; +bsp_section_fast_end_align = DEFINED (bsp_section_fast_end_align) ? bsp_section_fast_end_align : bsp_section_align; +bsp_section_bss_end_align = DEFINED (bsp_section_bss_end_align) ? bsp_section_bss_end_align : bsp_section_align; + +bsp_section_vbarrier_align = DEFINED (bsp_section_vbarrier_align) ? bsp_section_vbarrier_align : 1; +bsp_section_robarrier_align = DEFINED (bsp_section_robarrier_align) ? bsp_section_robarrier_align : 1; bsp_stack_abt_size = DEFINED (bsp_stack_abt_size) ? bsp_stack_abt_size : 128; bsp_stack_abt_size = ALIGN (bsp_stack_abt_size, bsp_stack_align); @@ -48,8 +55,8 @@ bsp_stack_irq_size = ALIGN (bsp_stack_irq_size, bsp_stack_align); bsp_stack_svc_size = DEFINED (bsp_stack_svc_size) ? bsp_stack_svc_size : 512; bsp_stack_svc_size = ALIGN (bsp_stack_svc_size, bsp_stack_align); -bsp_stack_undef_size = DEFINED (bsp_stack_undef_size) ? bsp_stack_undef_size : 128; -bsp_stack_undef_size = ALIGN (bsp_stack_undef_size, bsp_stack_align); +bsp_stack_und_size = DEFINED (bsp_stack_und_size) ? bsp_stack_und_size : 128; +bsp_stack_und_size = ALIGN (bsp_stack_und_size, bsp_stack_align); SECTIONS { .start : { @@ -62,8 +69,9 @@ SECTIONS { * BSP: System startup entry */ KEEP (*(.bsp_start)) + KEEP (*(.bsp_start_data)) - . = ALIGN (bsp_section_align); + . = ALIGN (bsp_section_start_end_align); /* * BSP: End of start section @@ -107,16 +115,16 @@ SECTIONS { . = . + bsp_stack_svc_size; bsp_stack_svc_end = .; - bsp_stack_undef_begin = .; - . = . + bsp_stack_undef_size; - bsp_stack_undef_end = .; + bsp_stack_und_begin = .; + . = . + bsp_stack_und_size; + bsp_stack_und_end = .; /* * BSP: Special vector data */ *(.bsp_vector) - . = ALIGN (bsp_section_align); + . = ALIGN (bsp_section_vector_end_align); /* * BSP: End of vector section @@ -126,6 +134,10 @@ SECTIONS { bsp_section_vector_size = bsp_section_vector_end - bsp_section_vector_begin; + .vbarrier : { + . = ALIGN (bsp_section_vbarrier_align); + } > REGION_VECTOR + .text : { /* * BSP: Begin of text section @@ -175,7 +187,7 @@ SECTIONS { */ KEEP (*(.fini)) - . = ALIGN (bsp_section_align); + . = ALIGN (bsp_section_text_end_align); /* * BSP: End of text section @@ -203,7 +215,7 @@ SECTIONS { *(.rodata .rodata.* .gnu.linkonce.r.*) *(.rodata1) - . = ALIGN (bsp_section_align); + . = ALIGN (bsp_section_rodata_end_align); /* * BSP: End of rodata section @@ -215,6 +227,10 @@ SECTIONS { bsp_section_rodata_load_begin = LOADADDR (.rodata); + .robarrier : { + . = ALIGN (bsp_section_robarrier_align); + } > REGION_RODATA + .data : { /* * BSP: Begin of data section @@ -264,7 +280,7 @@ SECTIONS { KEEP (*(.gnu.linkonce.d.*personality*)) SORT(CONSTRUCTORS) - . = ALIGN (bsp_section_align); + . = ALIGN (bsp_section_data_end_align); /* * BSP: End of data section @@ -281,7 +297,7 @@ SECTIONS { *(.bsp_fast) - . = ALIGN (bsp_section_align); + . = ALIGN (bsp_section_fast_end_align); bsp_section_fast_end = .; } > REGION_FAST AT > REGION_FAST_LOAD @@ -300,7 +316,7 @@ SECTIONS { *(.dynbss) *(.bss .bss.* .gnu.linkonce.b.*) - . = ALIGN (bsp_section_align); + . = ALIGN (bsp_section_bss_end_align); /* * BSP: End of bss section diff --git a/c/src/lib/libcpu/arm/ChangeLog b/c/src/lib/libcpu/arm/ChangeLog index 4c3a2707ba..cf99f1646a 100644 --- a/c/src/lib/libcpu/arm/ChangeLog +++ b/c/src/lib/libcpu/arm/ChangeLog @@ -1,3 +1,10 @@ +2010-01-12 Sebastian Huber + + * shared/include/arm-cp15.h, shared/include/cache.h, + shared/include/cache_.h: New files. + * Makefile.am, preinstall.am: Update for new files. + * shared/arm920/mmu.c: Include and use . + 2009-11-30 Fernando Nicodemos * at91rm9200/include/at91rm9200.h: Update to match development version. diff --git a/c/src/lib/libcpu/arm/Makefile.am b/c/src/lib/libcpu/arm/Makefile.am index 59d8ad1c6c..8ad15ed4b9 100644 --- a/c/src/lib/libcpu/arm/Makefile.am +++ b/c/src/lib/libcpu/arm/Makefile.am @@ -15,6 +15,7 @@ if shared include_libcpudir = $(includedir)/libcpu include_libcpu_HEADERS = shared/include/mmu.h +include_libcpu_HEADERS += shared/include/arm-cp15.h ## shared/arm920 noinst_PROGRAMS += shared/arm920.rel diff --git a/c/src/lib/libcpu/arm/preinstall.am b/c/src/lib/libcpu/arm/preinstall.am index 4ae225666a..a40ee5d945 100644 --- a/c/src/lib/libcpu/arm/preinstall.am +++ b/c/src/lib/libcpu/arm/preinstall.am @@ -27,6 +27,10 @@ PREINSTALL_DIRS += $(PROJECT_INCLUDE)/libcpu/$(dirstamp) $(PROJECT_INCLUDE)/libcpu/mmu.h: shared/include/mmu.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/mmu.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/mmu.h + +$(PROJECT_INCLUDE)/libcpu/arm-cp15.h: shared/include/arm-cp15.h $(PROJECT_INCLUDE)/libcpu/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/libcpu/arm-cp15.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/libcpu/arm-cp15.h endif if pxa255 $(PROJECT_INCLUDE)/pxa255.h: pxa255/include/pxa255.h $(PROJECT_INCLUDE)/$(dirstamp) diff --git a/c/src/lib/libcpu/arm/shared/arm920/mmu.c b/c/src/lib/libcpu/arm/shared/arm920/mmu.c index 752314723d..a9f90a8fa6 100644 --- a/c/src/lib/libcpu/arm/shared/arm920/mmu.c +++ b/c/src/lib/libcpu/arm/shared/arm920/mmu.c @@ -7,26 +7,12 @@ * $Id$ */ #include +#include typedef uint32_t mmu_lvl1_t; extern uint32_t _ttbl_base; -static inline uint32_t mmu_get_id(void); -static inline uint32_t mmu_get_ctrl(void); -static inline void mmu_set_ctrl(uint32_t val); -static inline uint32_t mmu_get_trans_tbl(void); -static inline void mmu_set_trans_tbl(uint32_t val); -static inline uint32_t mmu_get_domain_ctrl(void); -static inline void mmu_set_domain_ctrl(uint32_t val); -static inline uint32_t mmu_get_fault_stat(void); -static inline void mmu_set_fault_stat(uint32_t val); -static inline uint32_t mmu_get_fault_addr(void); -static inline void mmu_set_fault_addr(uint32_t val); -static inline void mmu_set_cache_inval(void); -static inline void mmu_set_tlb_inval(void); -static inline uint32_t mmu_get_proc_id(void); -static inline void mmu_set_proc_id(uint32_t val); static void mmu_set_map_inval(mmu_lvl1_t *base); #define MMU_CTRL_MMU_EN (1 << 0) @@ -54,25 +40,23 @@ static void mmu_set_map_inval(mmu_lvl1_t *base); #define MMU_SECT_AP_ALL (0x3 << 10) -#define NOP ( { asm volatile ("nop\n" ); } ) - void mmu_init(mmu_sect_map_t *map) { mmu_lvl1_t *lvl1_base; int i; /* flush the cache and TLB */ - mmu_set_cache_inval(); - mmu_set_tlb_inval(); + arm_cp15_cache_invalidate(); + arm_cp15_tlb_invalidate(); /* set manage mode access for all domains */ - mmu_set_domain_ctrl(0xffffffff); + arm_cp15_set_domain_access_control(0xffffffff); lvl1_base = (mmu_lvl1_t *)&_ttbl_base; /* set up the trans table */ mmu_set_map_inval(lvl1_base); - mmu_set_trans_tbl((uint32_t) lvl1_base); + arm_cp15_set_translation_table_base(lvl1_base); /* create a 1:1 mapping of the entire address space */ i = 0; @@ -120,118 +104,20 @@ void mmu_init(mmu_sect_map_t *map) } /* flush the cache and TLB */ - mmu_set_cache_inval(); - mmu_set_tlb_inval(); - - NOP; - NOP; + arm_cp15_cache_invalidate(); + arm_cp15_tlb_invalidate(); /* I & D caches turned on */ - mmu_set_ctrl(MMU_CTRL_DEFAULT | - MMU_CTRL_D_CACHE_EN | - MMU_CTRL_I_CACHE_EN | - MMU_CTRL_ALIGN_FAULT_EN | - MMU_CTRL_LITTLE_ENDIAN | - MMU_CTRL_MMU_EN); - - NOP; - NOP; + arm_cp15_set_control(MMU_CTRL_DEFAULT | + MMU_CTRL_D_CACHE_EN | + MMU_CTRL_I_CACHE_EN | + MMU_CTRL_ALIGN_FAULT_EN | + MMU_CTRL_LITTLE_ENDIAN | + MMU_CTRL_MMU_EN); return; } - -static inline uint32_t mmu_get_id(void) -{ - uint32_t val; - asm volatile ("msr 15, 0, %0, cr0, cr0\n" : "=r" (val)); - return val; -} - -static inline uint32_t mmu_get_ctrl(void) -{ - uint32_t val; - asm volatile ("mrc 15, 0, %0, cr1, cr0\n" : "=r" (val)); - return val; -} - -static inline void mmu_set_ctrl(uint32_t val) -{ - asm volatile ("mcr 15, 0, %0, cr1, cr0, 0\n" : :"r" (val)); -} - -static inline uint32_t mmu_get_trans_tbl(void) -{ - uint32_t val; - asm volatile ("msr 15, 0, %0, cr2, cr0\n" : "=r" (val)); - return val; -} - -static inline void mmu_set_trans_tbl(uint32_t val) -{ - asm volatile ("mcr 15, 0, %0, cr2, cr0, 0\n" : :"r" (val)); -} - -static inline uint32_t mmu_get_domain_ctrl(void) -{ - uint32_t val; - asm volatile ("msr 15, 0, %0, cr3, cr0\n" : "=r" (val)); - return val; -} - -static inline void mmu_set_domain_ctrl(uint32_t val) -{ - asm volatile ("mcr 15, 0, %0, cr3, cr0, 0\n" : :"r" (val)); -} - -static inline uint32_t mmu_get_fault_stat(void) -{ - uint32_t val; - asm volatile ("msr 15, 0, %0, cr5, cr0\n" : "=r" (val)); - return val; -} - -static inline void mmu_set_fault_stat(uint32_t val) -{ - asm volatile ("mcr 15, 0, %0, cr5, cr0, 0\n" : :"r" (val)); -} - -static inline uint32_t mmu_get_fault_addr(void) -{ - uint32_t val; - asm volatile ("msr 15, 0, %0, cr6, cr0\n" : "=r" (val)); - return val; -} - -static inline void mmu_set_fault_addr(uint32_t val) -{ - asm volatile ("mcr 15, 0, %0, cr6, cr0, 0\n" : :"r" (val)); -} - -static inline void mmu_set_cache_inval(void) -{ - uint32_t val = 0; - asm volatile ("mcr 15, 0, %0, cr7, cr7, 0\n" : :"r" (val)); -} - -static inline void mmu_set_tlb_inval(void) -{ - uint32_t val = 0; - asm volatile ("mcr 15, 0, %0, cr8, cr7, 0\n" : :"r" (val)); -} - -static inline uint32_t mmu_get_proc_id(void) -{ - uint32_t val; - asm volatile ("msr 15, 0, %0, cr13, cr0\n" : "=r" (val)); - return val; -} - -static inline void mmu_set_proc_id(uint32_t val) -{ - asm volatile ("mcr 15, 0, %0, cr13, cr0, 0\n" : :"r" (val)); -} - /* set all the level 1 entrys to be invalid descriptors */ static void mmu_set_map_inval(mmu_lvl1_t *base) { @@ -241,12 +127,10 @@ static void mmu_set_map_inval(mmu_lvl1_t *base) } } - void mmu_set_cpu_async_mode(void) { uint32_t reg; - reg = mmu_get_ctrl(); + reg = arm_cp15_get_control(); reg |= 0xc0000000; - mmu_set_ctrl(reg); + arm_cp15_set_control(reg); } - diff --git a/c/src/lib/libcpu/arm/shared/include/arm-cp15.h b/c/src/lib/libcpu/arm/shared/include/arm-cp15.h new file mode 100644 index 0000000000..3f0036f6c6 --- /dev/null +++ b/c/src/lib/libcpu/arm/shared/include/arm-cp15.h @@ -0,0 +1,644 @@ +/** + * @file + * + * @ingroup arm + * + * @brief ARM co-processor 15 (CP15) API. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef LIBCPU_SHARED_ARM_CP15_H +#define LIBCPU_SHARED_ARM_CP15_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define ARM_MMU_SECT_BASE_SHIFT 20 +#define ARM_MMU_SECT_BASE_MASK 0xfffU +#define ARM_MMU_SECT_DOMAIN_SHIFT 5 +#define ARM_MMU_SECT_DOMAIN_MASK 0xfU +#define ARM_MMU_SECT_AP_1 (1U << 11) +#define ARM_MMU_SECT_AP_0 (1U << 10) +#define ARM_MMU_SECT_AP_SHIFT 10 +#define ARM_MMU_SECT_AP_MASK 0x3U +#define ARM_MMU_SECT_C (1U << 3) +#define ARM_MMU_SECT_B (1U << 2) +#define ARM_MMU_SECT_DEFAULT 0x12U +#define ARM_MMU_SECT_GET_INDEX(mva) \ + (((uint32_t) (mva)) >> ARM_MMU_SECT_BASE_SHIFT) +#define ARM_MMU_SECT_MVA_ALIGN_UP(mva) \ + ((1U << ARM_MMU_SECT_BASE_SHIFT) \ + + ((((uint32_t) (mva) - 1U)) & ~((1U << ARM_MMU_SECT_BASE_SHIFT) - 1U))) + +#define ARM_MMU_TRANSLATION_TABLE_ENTRY_SIZE 4U +#define ARM_MMU_TRANSLATION_TABLE_ENTRY_COUNT 4096U + +static inline uint32_t arm_cp15_get_id_code(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t val; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mrc p15, 0, %[val], c0, c0, 0\n" + ARM_SWITCH_BACK + : [val] "=&r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT + ); + + return val; +} + +static inline uint32_t arm_cp15_get_cache_type(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t val; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mrc p15, 0, %[val], c0, c0, 1\n" + ARM_SWITCH_BACK + : [val] "=&r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT + ); + + return val; +} + +static inline uint32_t arm_cp15_get_tcm_status(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t val; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mrc p15, 0, %[val], c0, c0, 2\n" + ARM_SWITCH_BACK + : [val] "=&r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT + ); + + return val; +} + +#define ARM_CP15_CTRL_L4 (1U << 15) +#define ARM_CP15_CTRL_RR (1U << 14) +#define ARM_CP15_CTRL_V (1U << 13) +#define ARM_CP15_CTRL_I (1U << 12) +#define ARM_CP15_CTRL_R (1U << 9) +#define ARM_CP15_CTRL_S (1U << 8) +#define ARM_CP15_CTRL_B (1U << 7) +#define ARM_CP15_CTRL_C (1U << 2) +#define ARM_CP15_CTRL_A (1U << 1) +#define ARM_CP15_CTRL_M (1U << 0) + +static inline uint32_t arm_cp15_get_control(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t val; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mrc p15, 0, %[val], c1, c0, 0\n" + ARM_SWITCH_BACK + : [val] "=&r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT + ); + + return val; +} + +static inline void arm_cp15_set_control(uint32_t val) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[val], c1, c0, 0\n" + "nop\n" + "nop\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [val] "r" (val) + : "memory" + ); +} + +static inline uint32_t *arm_cp15_get_translation_table_base(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t *base; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mrc p15, 0, %[base], c2, c0, 0\n" + ARM_SWITCH_BACK + : [base] "=&r" (base) ARM_SWITCH_ADDITIONAL_OUTPUT + ); + + return base; +} + +static inline void arm_cp15_set_translation_table_base(uint32_t *base) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[base], c2, c0, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [base] "r" (base) + ); +} + +#define ARM_CP15_DAC_NO_ACCESS 0x0U +#define ARM_CP15_DAC_CLIENT 0x1U +#define ARM_CP15_DAC_MANAGER 0x3U +#define ARM_CP15_DAC_DOMAIN(index, val) ((val) << (2 * index)) + +static inline uint32_t arm_cp15_get_domain_access_control(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t val; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mrc p15, 0, %[val], c3, c0, 0\n" + ARM_SWITCH_BACK + : [val] "=&r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT + ); + + return val; +} + +static inline void arm_cp15_set_domain_access_control(uint32_t val) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[val], c3, c0, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [val] "r" (val) + ); +} + +static inline uint32_t arm_cp15_get_data_fault_status(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t val; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mrc p15, 0, %[val], c5, c0, 0\n" + ARM_SWITCH_BACK + : [val] "=&r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT + ); + + return val; +} + +static inline void arm_cp15_set_data_fault_status(uint32_t val) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[val], c5, c0, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [val] "r" (val) + ); +} + +static inline uint32_t arm_cp15_get_instruction_fault_status(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t val; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mrc p15, 0, %[val], c5, c0, 1\n" + ARM_SWITCH_BACK + : [val] "=&r" (val) ARM_SWITCH_ADDITIONAL_OUTPUT + ); + + return val; +} + +static inline void arm_cp15_set_instruction_fault_status(uint32_t val) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[val], c5, c0, 1\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [val] "r" (val) + ); +} + +static inline void *arm_cp15_get_fault_address(void) +{ + ARM_SWITCH_REGISTERS; + void *mva; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mrc p15, 0, %[mva], c6, c0, 0\n" + ARM_SWITCH_BACK + : [mva] "=&r" (mva) ARM_SWITCH_ADDITIONAL_OUTPUT + ); + + return mva; +} + +static inline void arm_cp15_set_fault_address(const void *mva) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[mva], c6, c0, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [mva] "r" (mva) + ); +} + +#define ARM_CP15_CACHE_PREPARE_MVA(mva) \ + ((const void *) (((uint32_t) (mva)) & ~0x1fU)) + +static inline void arm_cp15_cache_invalidate(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t sbz = 0; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[sbz], c7, c7, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [sbz] "r" (sbz) + : "memory" + ); +} + +static inline void arm_cp15_instruction_cache_invalidate(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t sbz = 0; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[sbz], c7, c5, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [sbz] "r" (sbz) + : "memory" + ); +} + +static inline void arm_cp15_instruction_cache_invalidate_line(const void *mva) +{ + ARM_SWITCH_REGISTERS; + + mva = ARM_CP15_CACHE_PREPARE_MVA(mva); + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[mva], c7, c5, 1\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [mva] "r" (mva) + : "memory" + ); +} + +static inline void arm_cp15_instruction_cache_invalidate_line_by_set_and_way(uint32_t set_and_way) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[set_and_way], c7, c5, 2\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [set_and_way] "r" (set_and_way) + : "memory" + ); +} + +static inline void arm_cp15_instruction_cache_prefetch_line(const void *mva) +{ + ARM_SWITCH_REGISTERS; + + mva = ARM_CP15_CACHE_PREPARE_MVA(mva); + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[mva], c7, c13, 1\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [mva] "r" (mva) + ); +} + +static inline void arm_cp15_data_cache_invalidate(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t sbz = 0; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[sbz], c7, c6, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [sbz] "r" (sbz) + : "memory" + ); +} + +static inline void arm_cp15_data_cache_invalidate_line(const void *mva) +{ + ARM_SWITCH_REGISTERS; + + mva = ARM_CP15_CACHE_PREPARE_MVA(mva); + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[mva], c7, c6, 1\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [mva] "r" (mva) + : "memory" + ); +} + +static inline void arm_cp15_data_cache_invalidate_line_by_set_and_way(uint32_t set_and_way) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[set_and_way], c7, c6, 2\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [set_and_way] "r" (set_and_way) + : "memory" + ); +} + +static inline void arm_cp15_data_cache_clean_line(const void *mva) +{ + ARM_SWITCH_REGISTERS; + + mva = ARM_CP15_CACHE_PREPARE_MVA(mva); + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[mva], c7, c10, 1\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [mva] "r" (mva) + : "memory" + ); +} + +static inline void arm_cp15_data_cache_clean_line_by_set_and_way(uint32_t set_and_way) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[set_and_way], c7, c10, 2\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [set_and_way] "r" (set_and_way) + : "memory" + ); +} + +static inline void arm_cp15_data_cache_test_and_clean(void) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "1:\n" + "mrc p15, 0, r15, c7, c10, 3\n" + "bne 1b\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : + : "memory" + ); +} + +static inline void arm_cp15_data_cache_clean_and_invalidate_line(const void *mva) +{ + ARM_SWITCH_REGISTERS; + + mva = ARM_CP15_CACHE_PREPARE_MVA(mva); + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[mva], c7, c14, 1\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [mva] "r" (mva) + : "memory" + ); +} + +static inline void arm_cp15_data_cache_clean_and_invalidate_line_by_set_and_way(uint32_t set_and_way) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[set_and_way], c7, c14, 2\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [set_and_way] "r" (set_and_way) + : "memory" + ); +} + +static inline void arm_cp15_data_cache_test_and_clean_and_invalidate(void) +{ + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "1:\n" + "mrc p15, 0, r15, c7, c14, 3\n" + "bne 1b\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : + : "memory" + ); +} + +static inline void arm_cp15_drain_write_buffer(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t sbz = 0; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[sbz], c7, c10, 4\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [sbz] "r" (sbz) + : "memory" + ); +} + +static inline void arm_cp15_wait_for_interrupt(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t sbz = 0; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[sbz], c7, c0, 4\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [sbz] "r" (sbz) + : "memory" + ); +} + +#define ARM_CP15_TLB_PREPARE_MVA(mva) \ + ((const void *) (((uint32_t) (mva)) & ~0x3fU)) + +static inline void arm_cp15_tlb_invalidate(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t sbz = 0; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[sbz], c8, c7, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [sbz] "r" (sbz) + ); +} + +static inline void arm_cp15_tlb_invalidate_entry(const void *mva) +{ + ARM_SWITCH_REGISTERS; + + mva = ARM_CP15_TLB_PREPARE_MVA(mva); + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[mva], c8, c7, 1\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [mva] "r" (mva) + ); +} + +static inline void arm_cp15_tlb_instruction_invalidate(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t sbz = 0; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[sbz], c8, c5, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [sbz] "r" (sbz) + ); +} + +static inline void arm_cp15_tlb_instruction_invalidate_entry(const void *mva) +{ + ARM_SWITCH_REGISTERS; + + mva = ARM_CP15_TLB_PREPARE_MVA(mva); + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[mva], c8, c5, 1\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [mva] "r" (mva) + ); +} + +static inline void arm_cp15_tlb_data_invalidate(void) +{ + ARM_SWITCH_REGISTERS; + uint32_t sbz = 0; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[sbz], c8, c6, 0\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [sbz] "r" (sbz) + ); +} + +static inline void arm_cp15_tlb_data_invalidate_entry(const void *mva) +{ + ARM_SWITCH_REGISTERS; + + mva = ARM_CP15_TLB_PREPARE_MVA(mva); + + asm volatile ( + ARM_SWITCH_TO_ARM + "mcr p15, 0, %[mva], c8, c6, 1\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [mva] "r" (mva) + ); +} + +static inline void arm_cp15_tlb_lockdown_entry(const void *mva) +{ + uint32_t arm_switch_reg; + + asm volatile ( + ARM_SWITCH_TO_ARM + "add %[arm_switch_reg], pc, #16\n" + "mcr p15, 0, %[arm_switch_reg], c7, c13, 1\n" + "mcr p15, 0, %[mva], c8, c7, 1\n" + "mrc p15, 0, %[arm_switch_reg], c10, c0, 0\n" + "orr %[arm_switch_reg], #0x1\n" + "mcr p15, 0, %[arm_switch_reg], c10, c0, 0\n" + "ldr %[mva], [%[mva]]\n" + "mrc p15, 0, %[arm_switch_reg], c10, c0, 0\n" + "bic %[arm_switch_reg], #0x1\n" + "mcr p15, 0, %[arm_switch_reg], c10, c0, 0\n" + ARM_SWITCH_BACK + : [mva] "=r" (mva), [arm_switch_reg] "=&r" (arm_switch_reg) + : "[mva]" (mva) + ); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBCPU_SHARED_ARM_CP15_H */ diff --git a/c/src/lib/libcpu/arm/shared/include/cache.h b/c/src/lib/libcpu/arm/shared/include/cache.h new file mode 100644 index 0000000000..3e6784f765 --- /dev/null +++ b/c/src/lib/libcpu/arm/shared/include/cache.h @@ -0,0 +1,132 @@ +/** + * @file + * + * @ingroup arm + * + * @brief ARM cache defines and implementation. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef LIBCPU_ARM_CACHE_H +#define LIBCPU_ARM_CACHE_H + +#ifdef __ARM_ARCH_5TEJ__ + #include + + #define CPU_DATA_CACHE_ALIGNMENT 32 + #define CPU_INSTRUCTION_CACHE_ALIGNMENT 32 + + static inline void _CPU_cache_flush_1_data_line(const void *d_addr) + { + arm_cp15_data_cache_clean_line(d_addr); + } + + static inline void _CPU_cache_invalidate_1_data_line(const void *d_addr) + { + arm_cp15_data_cache_invalidate_line(d_addr); + } + + static inline void _CPU_cache_freeze_data(void) + { + /* TODO */ + } + + static inline void _CPU_cache_unfreeze_data(void) + { + /* TODO */ + } + + static inline void _CPU_cache_invalidate_1_instruction_line(const void *d_addr) + { + arm_cp15_instruction_cache_invalidate_line(d_addr); + } + + static inline void _CPU_cache_freeze_instruction(void) + { + /* TODO */ + } + + static inline void _CPU_cache_unfreeze_instruction(void) + { + /* TODO */ + } + + static inline void _CPU_cache_flush_entire_data(void) + { + arm_cp15_data_cache_test_and_clean(); + } + + static inline void _CPU_cache_invalidate_entire_data(void) + { + arm_cp15_data_cache_invalidate(); + } + + static inline void _CPU_cache_enable_data(void) + { + rtems_interrupt_level level; + uint32_t ctrl; + + rtems_interrupt_disable(level); + ctrl = arm_cp15_get_control(); + ctrl |= ARM_CP15_CTRL_C; + arm_cp15_set_control(ctrl); + rtems_interrupt_enable(level); + } + + static inline void _CPU_cache_disable_data(void) + { + rtems_interrupt_level level; + uint32_t ctrl; + + rtems_interrupt_disable(level); + ctrl = arm_cp15_get_control(); + ctrl &= ~ARM_CP15_CTRL_C; + arm_cp15_set_control(ctrl); + rtems_interrupt_enable(level); + + arm_cp15_data_cache_test_and_clean_and_invalidate(); + } + + static inline void _CPU_cache_invalidate_entire_instruction(void) + { + arm_cp15_instruction_cache_invalidate(); + } + + static inline void _CPU_cache_enable_instruction(void) + { + rtems_interrupt_level level; + uint32_t ctrl; + + rtems_interrupt_disable(level); + ctrl = arm_cp15_get_control(); + ctrl |= ARM_CP15_CTRL_I; + arm_cp15_set_control(ctrl); + rtems_interrupt_enable(level); + } + + static inline void _CPU_cache_disable_instruction(void) + { + rtems_interrupt_level level; + uint32_t ctrl; + + rtems_interrupt_disable(level); + ctrl = arm_cp15_get_control(); + ctrl &= ~ARM_CP15_CTRL_I; + arm_cp15_set_control(ctrl); + rtems_interrupt_enable(level); + } +#endif + +#endif /* LIBCPU_ARM_CACHE_H */ diff --git a/c/src/lib/libcpu/arm/shared/include/cache_.h b/c/src/lib/libcpu/arm/shared/include/cache_.h new file mode 100644 index 0000000000..b617b65ace --- /dev/null +++ b/c/src/lib/libcpu/arm/shared/include/cache_.h @@ -0,0 +1,27 @@ +/** + * @file + * + * @ingroup arm + * + * @brief Empty file. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * 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. + */ + +#ifndef LIBCPU_ARM_CACHE__H +#define LIBCPU_ARM_CACHE__H + +/* Empty */ + +#endif /* LIBCPU_ARM_CACHE__H */ diff --git a/cpukit/score/cpu/arm/ChangeLog b/cpukit/score/cpu/arm/ChangeLog index 4c81e5cb1a..a47947170f 100644 --- a/cpukit/score/cpu/arm/ChangeLog +++ b/cpukit/score/cpu/arm/ChangeLog @@ -1,3 +1,12 @@ +2010-01-12 Sebastian Huber + + * arm_exc_abort.S: New file. + * Makefile.am: Update for new file. + * arm_exc_interrupt.S, cpu.c, rtems/asm.h, rtems/score/cpu.h: Changed + macros which switch from and to THUMB mode. Added a default prefetch + and data abort handler which reports the complete processor context. + Added PSR defines. + 2009-12-15 Sebastian Huber * rtems/score/arm.h: Recognize ARMv5TEJ. diff --git a/cpukit/score/cpu/arm/Makefile.am b/cpukit/score/cpu/arm/Makefile.am index 4cab7ddcd9..57f2b70642 100644 --- a/cpukit/score/cpu/arm/Makefile.am +++ b/cpukit/score/cpu/arm/Makefile.am @@ -13,6 +13,7 @@ noinst_LIBRARIES = libscorecpu.a libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS) libscorecpu_a_SOURCES = cpu.c \ cpu_asm.S \ + arm_exc_abort.S \ arm_exc_interrupt.S \ arm_exc_handler_low.S \ arm_exc_handler_high.c diff --git a/cpukit/score/cpu/arm/arm_exc_abort.S b/cpukit/score/cpu/arm/arm_exc_abort.S new file mode 100644 index 0000000000..906dcbb9f1 --- /dev/null +++ b/cpukit/score/cpu/arm/arm_exc_abort.S @@ -0,0 +1,123 @@ +/** + * @file + * + * @ingroup arm + * + * @brief ARM data and prefetch abort exception prologue and epilogue. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * 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 + +.extern rtems_fatal_error_occurred + +.globl arm_exc_data_abort_set_handler +.globl arm_exc_data_abort + +.globl arm_exc_prefetch_abort_set_handler +.globl arm_exc_prefetch_abort + +.section ".bss" + +data_abort_handler: +.long 0 + +prefetch_abort_handler: +.long 0 + +.section ".text" + +#ifdef __thumb__ + .thumb_func +#endif + +arm_exc_data_abort_set_handler: + ldr r1, =data_abort_handler + str r0, [r1] + bx lr + +#ifdef __thumb__ + .thumb_func +#endif + +arm_exc_prefetch_abort_set_handler: + ldr r1, =prefetch_abort_handler + str r0, [r1] + bx lr + +.arm + +arm_exc_prefetch_abort: + + /* Save context and load handler */ + sub sp, #16 + stmdb sp!, {r0-r12} + ldr r6, =prefetch_abort_handler + + b save_more_context + +arm_exc_data_abort: + + /* Save context and load handler */ + sub sp, #16 + stmdb sp!, {r0-r12} + ldr r6, =data_abort_handler + +save_more_context: + + /* Save more context */ + mov r2, lr + mrs r3, spsr + mrs r4, cpsr + orr r5, r3, #ARM_PSR_I + bic r5, #ARM_PSR_T + msr cpsr, r5 + mov r0, sp + mov r1, lr + msr cpsr, r4 + add r5, sp, #68 + stmdb r5!, {r0-r3} + + /* Call high level handler */ + ldr r2, [r6] + cmp r2, #0 + ldreq r2, =rtems_fatal_error_occurred + movne r0, sp + moveq r0, #0xaa +#ifndef __thumb__ + mov lr, pc + bx r2 +#else /* __thumb__ */ + SWITCH_FROM_ARM_TO_THUMB r1 + bl call_handler + SWITCH_FROM_THUMB_TO_ARM +#endif /* __thumb__ */ + + /* Restore context */ + ldmia r5!, {r0-r3} + mov lr, r2 + msr spsr, r3 + ldmia sp!, {r0-r12} + add sp, #16 + + /* Return from interrupt */ + subs pc, lr, #8 + +#ifdef __thumb__ +.thumb +call_handler: + bx r2 +#endif /* __thumb__ */ diff --git a/cpukit/score/cpu/arm/arm_exc_interrupt.S b/cpukit/score/cpu/arm/arm_exc_interrupt.S index 738c248141..a260d9dda1 100644 --- a/cpukit/score/cpu/arm/arm_exc_interrupt.S +++ b/cpukit/score/cpu/arm/arm_exc_interrupt.S @@ -1,6 +1,8 @@ /** * @file * + * @ingroup arm + * * @brief ARM interrupt exception prologue and epilogue. */ @@ -23,6 +25,8 @@ * The exchange area is only accessed if INT is disabled. */ +#include + #define EXCHANGE_LR r4 #define EXCHANGE_SPSR r5 #define EXCHANGE_CPSR r6 @@ -41,22 +45,6 @@ .extern bsp_interrupt_dispatch -.macro SWITCH_FROM_THUMB_TO_ARM -#ifdef __thumb__ -.align 2 - bx pc -.arm -#endif /* __thumb__ */ -.endm - -.macro SWITCH_FROM_ARM_TO_THUMB REG -#ifdef __thumb__ - add \REG, pc, #1 - bx \REG -.thumb -#endif /* __thumb__ */ -.endm - .arm .globl arm_exc_interrupt arm_exc_interrupt: diff --git a/cpukit/score/cpu/arm/cpu.c b/cpukit/score/cpu/arm/cpu.c index a44cff59bb..53b42c3748 100644 --- a/cpukit/score/cpu/arm/cpu.c +++ b/cpukit/score/cpu/arm/cpu.c @@ -56,31 +56,31 @@ void _CPU_Context_Initialize( void _CPU_ISR_Set_level( uint32_t level ) { - uint32_t reg; + uint32_t arm_switch_reg; asm volatile ( - THUMB_TO_ARM - "mrs %0, cpsr\n" - "bic %0, %0, #" _CPU_ISR_LEVEL_STRINGOF( CPU_MODES_INTERRUPT_MASK ) "\n" - "orr %0, %0, %1\n" + ARM_SWITCH_TO_ARM + "mrs %[arm_switch_reg], cpsr\n" + "bic %[arm_switch_reg], #" _CPU_ISR_LEVEL_STRINGOF( CPU_MODES_INTERRUPT_MASK ) "\n" + "orr %[arm_switch_reg], %[level]\n" "msr cpsr, %0\n" - ARM_TO_THUMB - : "=r" (reg) - : "r" (level) + ARM_SWITCH_BACK + : [arm_switch_reg] "=&r" (arm_switch_reg) + : [level] "r" (level) ); } uint32_t _CPU_ISR_Get_level( void ) { - uint32_t reg; + ARM_SWITCH_REGISTERS; uint32_t level; asm volatile ( - THUMB_TO_ARM - "mrs %0, cpsr\n" - "and %1, %0, #" _CPU_ISR_LEVEL_STRINGOF( CPU_MODES_INTERRUPT_MASK ) "\n" - ARM_TO_THUMB - : "=r" (reg), "=r" (level) + ARM_SWITCH_TO_ARM + "mrs %[level], cpsr\n" + "and %[level], #" _CPU_ISR_LEVEL_STRINGOF( CPU_MODES_INTERRUPT_MASK ) "\n" + ARM_SWITCH_BACK + : [level] "=&r" (level) ARM_SWITCH_ADDITIONAL_OUTPUT ); return level; diff --git a/cpukit/score/cpu/arm/rtems/asm.h b/cpukit/score/cpu/arm/rtems/asm.h index 04c5360790..f8b027cf1b 100644 --- a/cpukit/score/cpu/arm/rtems/asm.h +++ b/cpukit/score/cpu/arm/rtems/asm.h @@ -141,4 +141,20 @@ .globl name ; name: ; .globl name ## _arm ; name ## _arm: #endif +.macro SWITCH_FROM_THUMB_TO_ARM +#ifdef __thumb__ +.align 2 + bx pc +.arm +#endif /* __thumb__ */ +.endm + +.macro SWITCH_FROM_ARM_TO_THUMB REG +#ifdef __thumb__ + add \REG, pc, #1 + bx \REG +.thumb +#endif /* __thumb__ */ +.endm + #endif /* _RTEMS_ASM_H */ diff --git a/cpukit/score/cpu/arm/rtems/score/cpu.h b/cpukit/score/cpu/arm/rtems/score/cpu.h index d7eca1527c..de452e8cb4 100644 --- a/cpukit/score/cpu/arm/rtems/score/cpu.h +++ b/cpukit/score/cpu/arm/rtems/score/cpu.h @@ -8,6 +8,8 @@ * This include file contains information pertaining to the ARM * processor. * + * Copyright (c) 2009 embedded brains GmbH. + * * Copyright (c) 2007 Ray Xu * * Copyright (c) 2006 OAR Corporation @@ -44,13 +46,42 @@ #endif #ifdef __thumb__ - #define ARM_TO_THUMB "add %0, pc, #1\nbx %0\n.thumb\n" - #define THUMB_TO_ARM ".align 2\nbx pc\n.arm\n" + #define ARM_SWITCH_REGISTERS uint32_t arm_switch_reg + #define ARM_SWITCH_TO_ARM ".align 2\nbx pc\n.arm\n" + #define ARM_SWITCH_BACK "add %[arm_switch_reg], pc, #1\nbx %[arm_switch_reg]\n.thumb\n" + #define ARM_SWITCH_OUTPUT [arm_switch_reg] "=&r" (arm_switch_reg) + #define ARM_SWITCH_ADDITIONAL_OUTPUT , ARM_SWITCH_OUTPUT #else - #define ARM_TO_THUMB - #define THUMB_TO_ARM + #define ARM_SWITCH_REGISTERS + #define ARM_SWITCH_TO_ARM + #define ARM_SWITCH_BACK + #define ARM_SWITCH_OUTPUT + #define ARM_SWITCH_ADDITIONAL_OUTPUT #endif +#define ARM_PSR_N (1 << 31) +#define ARM_PSR_Z (1 << 30) +#define ARM_PSR_C (1 << 29) +#define ARM_PSR_V (1 << 28) +#define ARM_PSR_Q (1 << 27) +#define ARM_PSR_J (1 << 24) +#define ARM_PSR_GE_SHIFT 16 +#define ARM_PSR_GE_MASK (0xf << ARM_PSR_GE_SHIFT) +#define ARM_PSR_E (1 << 9) +#define ARM_PSR_A (1 << 8) +#define ARM_PSR_I (1 << 7) +#define ARM_PSR_F (1 << 6) +#define ARM_PSR_T (1 << 5) +#define ARM_PSR_M_SHIFT 0 +#define ARM_PSR_M_MASK (0x1f << ARM_PSR_M_SHIFT) +#define ARM_PSR_M_USR 0x10 +#define ARM_PSR_M_FIQ 0x11 +#define ARM_PSR_M_IRQ 0x12 +#define ARM_PSR_M_SVC 0x13 +#define ARM_PSR_M_ABT 0x17 +#define ARM_PSR_M_UND 0x1b +#define ARM_PSR_M_SYS 0x1f + /* If someone uses THUMB we assume she wants minimal code size */ #ifdef __thumb__ #define CPU_INLINE_ENABLE_DISPATCH FALSE @@ -205,16 +236,16 @@ SCORE_EXTERN Context_Control_fp _CPU_Null_fp_context; static inline uint32_t arm_interrupt_disable( void ) { - uint32_t reg; + uint32_t arm_switch_reg; uint32_t level; asm volatile ( - THUMB_TO_ARM - "mrs %1, cpsr\n" - "orr %0, %1, #0x80\n" - "msr cpsr, %0\n" - ARM_TO_THUMB - : "=r" (reg), "=r" (level) + ARM_SWITCH_TO_ARM + "mrs %[level], cpsr\n" + "orr %[arm_switch_reg], %[level], #0x80\n" + "msr cpsr, %[arm_switch_reg]\n" + ARM_SWITCH_BACK + : [arm_switch_reg] "=&r" (arm_switch_reg), [level] "=&r" (level) ); return level; @@ -222,54 +253,46 @@ static inline uint32_t arm_interrupt_disable( void ) static inline void arm_interrupt_enable( uint32_t level ) { - #ifdef __thumb__ - uint32_t reg; - - asm volatile ( - THUMB_TO_ARM - "msr cpsr, %1\n" - ARM_TO_THUMB - : "=r" (reg) - : "r" (level) - ); - #else - asm volatile ( - "msr cpsr, %0" - : - : "r" (level) - ); - #endif + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "msr cpsr, %[level]\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [level] "r" (level) + ); } static inline void arm_interrupt_flash( uint32_t level ) { - uint32_t reg; + uint32_t arm_switch_reg; asm volatile ( - THUMB_TO_ARM - "mrs %0, cpsr\n" - "msr cpsr, %1\n" - "msr cpsr, %0\n" - ARM_TO_THUMB - : "=r" (reg) - : "r" (level) + ARM_SWITCH_TO_ARM + "mrs %[arm_switch_reg], cpsr\n" + "msr cpsr, %[level]\n" + "msr cpsr, %[arm_switch_reg]\n" + ARM_SWITCH_BACK + : [arm_switch_reg] "=&r" (arm_switch_reg) + : [level] "r" (level) ); } static inline uint32_t arm_status_irq_enable( void ) { - uint32_t reg; + uint32_t arm_switch_reg; uint32_t psr; RTEMS_COMPILER_MEMORY_BARRIER(); asm volatile ( - THUMB_TO_ARM - "mrs %1, cpsr\n" - "bic %0, %1, #0x80\n" - "msr cpsr, %0\n" - ARM_TO_THUMB - : "=r" (reg), "=r" (psr) + ARM_SWITCH_TO_ARM + "mrs %[psr], cpsr\n" + "bic %[arm_switch_reg], %[psr], #0x80\n" + "msr cpsr, %[arm_switch_reg]\n" + ARM_SWITCH_BACK + : [arm_switch_reg] "=&r" (arm_switch_reg), [psr] "=&r" (psr) ); return psr; @@ -277,23 +300,15 @@ static inline uint32_t arm_status_irq_enable( void ) static inline void arm_status_restore( uint32_t psr ) { - #ifdef __thumb__ - uint32_t reg; - - asm volatile ( - THUMB_TO_ARM - "msr cpsr, %1\n" - ARM_TO_THUMB - : "=r" (reg) - : "r" (psr) - ); - #else - asm volatile ( - "msr cpsr, %0" - : - : "r" (psr) - ); - #endif + ARM_SWITCH_REGISTERS; + + asm volatile ( + ARM_SWITCH_TO_ARM + "msr cpsr, %[psr]\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [psr] "r" (psr) + ); RTEMS_COMPILER_MEMORY_BARRIER(); } @@ -402,16 +417,42 @@ static inline uint16_t CPU_swap_u16( uint16_t value ) extern uint32_t arm_cpu_mode; -void arm_exc_abort_data( void ); +typedef struct { + uint32_t r0; + uint32_t r1; + uint32_t r2; + uint32_t r3; + uint32_t r4; + uint32_t r5; + uint32_t r6; + uint32_t r7; + uint32_t r8; + uint32_t r9; + uint32_t r10; + uint32_t r11; + uint32_t r12; + uint32_t sp; + uint32_t lr; + uint32_t pc; + uint32_t cpsr; +} arm_cpu_context; + +typedef void arm_exc_abort_handler( arm_cpu_context *context ); + +void arm_exc_data_abort_set_handler( arm_exc_abort_handler handler ); + +void arm_exc_data_abort( void ); + +void arm_exc_prefetch_abort_set_handler( arm_exc_abort_handler handler ); + +void arm_exc_prefetch_abort( void ); -void arm_exc_abort_prefetch( void ); +void bsp_interrupt_dispatch( void ); void arm_exc_interrupt( void ); void arm_exc_undefined( void ); -void bsp_interrupt_dispatch( void ); - #ifdef __cplusplus } #endif -- cgit v1.2.3