[PATCH 17/17] bsp/altera-cyclone-v: Implement BSP
Ralf Kirchner
ralf.kirchner at embedded-brains.de
Wed Feb 26 10:52:04 UTC 2014
Implemented so far:
- nocache heap for uncached RAM
- basic timer
- level 1 cache handling for arm cache controller
in arm-cache-l1.h
- level 2 L2C-310 cache controller
- MMU
- DWMAC 1000 ethernet controller
- counts for BSP objects
- basic errata handling
- smp startup for second core
---
c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am | 16 +-
c/src/lib/libbsp/arm/altera-cyclone-v/README | 3 +
c/src/lib/libbsp/arm/altera-cyclone-v/configure.ac | 11 +-
.../arm/altera-cyclone-v/console/console-config.c | 167 ++-
.../lib/libbsp/arm/altera-cyclone-v/include/bsp.h | 46 +-
.../lib/libbsp/arm/altera-cyclone-v/include/irq.h | 69 +-
.../libbsp/arm/altera-cyclone-v/include/network.h | 59 +
.../arm/altera-cyclone-v/include/nocache-heap.h | 49 +
.../libbsp/arm/altera-cyclone-v/network/network.c | 1241 ++++++++++++++++++++
.../lib/libbsp/arm/altera-cyclone-v/preinstall.am | 20 +
.../libbsp/arm/altera-cyclone-v/startup/bspreset.c | 10 +-
.../libbsp/arm/altera-cyclone-v/startup/bspstart.c | 112 +-
.../arm/altera-cyclone-v/startup/bspstarthooks.c | 231 +++-
.../startup/linkcmds.altcycv_devkit | 16 +-
.../arm/altera-cyclone-v/startup/nocache-heap.c | 87 ++
15 Dateien geändert, 1944 Zeilen hinzugefügt(+), 193 Zeilen entfernt(-)
create mode 100644 c/src/lib/libbsp/arm/altera-cyclone-v/include/network.h
create mode 100644 c/src/lib/libbsp/arm/altera-cyclone-v/include/nocache-heap.h
create mode 100644 c/src/lib/libbsp/arm/altera-cyclone-v/network/network.c
create mode 100644 c/src/lib/libbsp/arm/altera-cyclone-v/startup/nocache-heap.c
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am b/c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am
index 6b1749b..1cd92af 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/Makefile.am
@@ -33,15 +33,20 @@ include_bsp_HEADERS += ../../shared/include/irq-info.h
include_bsp_HEADERS += ../../shared/include/stackalloc.h
include_bsp_HEADERS += ../../shared/tod.h
include_bsp_HEADERS += ../shared/include/start.h
+include_bsp_HEADERS += ../shared/include/arm-a9mpcore-clock.h
include_bsp_HEADERS += ../shared/include/arm-a9mpcore-irq.h
include_bsp_HEADERS += ../shared/include/arm-a9mpcore-regs.h
include_bsp_HEADERS += ../shared/include/arm-a9mpcore-start.h
include_bsp_HEADERS += ../shared/include/arm-cp15-start.h
+include_bsp_HEADERS += ../shared/include/arm-errata.h
include_bsp_HEADERS += ../shared/include/arm-gic.h
include_bsp_HEADERS += ../shared/include/arm-gic-irq.h
include_bsp_HEADERS += ../shared/include/arm-gic-regs.h
include_bsp_HEADERS += ../shared/include/arm-gic-tm27.h
+include_bsp_HEADERS += ../shared/include/arm-release-id.h
include_bsp_HEADERS += include/irq.h
+include_bsp_HEADERS += include/network.h
+include_bsp_HEADERS += include/nocache-heap.h
# Altera hwlib
include_bsp_HEADERS += hwlib/include/alt_16550_uart.h
@@ -139,6 +144,7 @@ libbsp_a_SOURCES += ../shared/arm-cp15-set-ttb-entries.c
# Startup
libbsp_a_SOURCES += startup/bspreset.c
libbsp_a_SOURCES += startup/bspstart.c
+libbsp_a_SOURCES += startup/nocache-heap.c
# IRQ
libbsp_a_SOURCES += ../../shared/src/irq-default-handler.c
@@ -149,6 +155,9 @@ libbsp_a_SOURCES += ../../shared/src/irq-server.c
libbsp_a_SOURCES += ../../shared/src/irq-shell.c
libbsp_a_SOURCES += ../shared/arm-gic-irq.c
+# Network
+libbsp_a_SOURCES += network/network.c
+
# Console
libbsp_a_SOURCES += ../../shared/console.c
libbsp_a_SOURCES += ../../shared/console_control.c
@@ -163,10 +172,9 @@ libbsp_a_SOURCES += ../shared/arm-a9mpcore-clock-config.c
# Cache
libbsp_a_SOURCES += ../../../libcpu/shared/src/cache_manager.c
-libbsp_a_SOURCES += ../../../libcpu/arm/shared/include/cache_.h
-libbsp_a_CPPFLAGS += -I$(srcdir)/../../../libcpu/arm/shared/include
-#libbsp_a_CPPFLAGS += -I$(srcdir)/startup/linux
-#libbsp_a_SOURCES += startup/linux/cache-l2x0.c
+libbsp_a_SOURCES += ../shared/include/arm-cache-l1.h
+libbsp_a_SOURCES += ../shared/arm-l2c-310/cache_.h
+libbsp_a_CPPFLAGS += -I$(srcdir)/../shared/arm-l2c-310
# Start hooks
libbsp_a_SOURCES += startup/bspstarthooks.c
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/README b/c/src/lib/libbsp/arm/altera-cyclone-v/README
index e69de29..575b72e 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/README
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/README
@@ -0,0 +1,3 @@
+Evaluation board for this BSP:
+- Cyclone V SoC FPGA Development Kit
+- DK-DEV-5CSXC6N/ES-0L
\ No newline at end of file
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/configure.ac b/c/src/lib/libbsp/arm/altera-cyclone-v/configure.ac
index bcf5b10..561a192 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/configure.ac
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/configure.ac
@@ -24,7 +24,7 @@ AM_CONDITIONAL(HAS_NETWORKING,test "$HAS_NETWORKING" = "yes")
RTEMS_BSPOPTS_SET([BSP_START_RESET_VECTOR],[*],[])
RTEMS_BSPOPTS_HELP([BSP_START_RESET_VECTOR],[reset vector address for BSP start])
-RTEMS_BSPOPTS_SET([BSP_ARM_A9MPCORE_PERIPHCLK],[altcycv_devkit*],[666666667U])
+RTEMS_BSPOPTS_SET([BSP_ARM_A9MPCORE_PERIPHCLK],[altcycv_devkit*],[200000000U])
RTEMS_BSPOPTS_SET([BSP_ARM_A9MPCORE_PERIPHCLK],[*],[100000000U])
RTEMS_BSPOPTS_HELP([BSP_ARM_A9MPCORE_PERIPHCLK],[ARM Cortex-A9 MPCore PERIPHCLK clock frequency in Hz])
@@ -37,6 +37,15 @@ simulation times.])
RTEMS_BSPOPTS_SET([BSP_CONSOLE_MINOR],[*],[0])
RTEMS_BSPOPTS_HELP([BSP_CONSOLE_MINOR],[minor number of console device])
+RTEMS_BSPOPTS_SET([CYCLONE_V_CONFIG_CONSOLE],[*],[0])
+RTEMS_BSPOPTS_HELP([CYCLONE_V_CONFIG_CONSOLE],[configuration for console (UART 0)])
+
+RTEMS_BSPOPTS_SET([CYCLONE_V_CONFIG_UART_1],[*],[0])
+RTEMS_BSPOPTS_HELP([CYCLONE_V_CONFIG_UART_1],[configuration for UART 1])
+
+RTEMS_BSPOPTS_SET([CYCLONE_V_UART_BAUD],[*],[115200U])
+RTEMS_BSPOPTS_HELP([CYCLONE_V_UART_BAUD],[baud for UARTs])
+
RTEMS_CHECK_SMP
AM_CONDITIONAL(HAS_SMP,[test "$rtems_cv_HAS_SMP" = "yes"])
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/console/console-config.c b/c/src/lib/libbsp/arm/altera-cyclone-v/console/console-config.c
index acad744..7e4dad9 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/console/console-config.c
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/console/console-config.c
@@ -12,56 +12,151 @@
* http://www.rtems.com/license/LICENSE.
*/
+#include <assert.h>
+#include <stdint.h>
+#include <stdbool.h>
#include <libchip/serial.h>
+#include <libchip/ns16550.h>
#include <bsp.h>
#include <bsp/irq.h>
+#include <bsp/alt_16550_uart.h>
+#include <socal/alt_rstmgr.h>
+#include <socal/socal.h>
+#include <socal/alt_uart.h>
+#include <socal/hps.h>
+
+bool cyclone_v_uart_probe( int minor );
+
+static uint8_t cyclone_v_uart_get_register(uintptr_t addr, uint8_t i)
+{
+ volatile uint32_t *reg = (volatile uint32_t *) addr;
+
+ return (uint8_t) reg [i];
+}
+
+static void cyclone_v_uart_set_register(uintptr_t addr, uint8_t i, uint8_t val)
+{
+ volatile uint32_t *reg = (volatile uint32_t *) addr;
+
+ reg [i] = val;
+}
console_tbl Console_Configuration_Ports[] = {
-#if 0
+#ifdef CYCLONE_V_CONFIG_CONSOLE
+ {
+ .sDeviceName = "/dev/ttyS0",
+ .deviceType = SERIAL_NS16550,
+ .pDeviceFns = &ns16550_fns,
+ .deviceProbe = cyclone_v_uart_probe,
+ .pDeviceFlow = NULL,
+ .ulMargin = 16,
+ .ulHysteresis = 8,
+ .pDeviceParams = (void *)CYCLONE_V_UART_BAUD,
+ .ulCtrlPort1 = (uint32_t)ALT_UART0_ADDR,
+ .ulCtrlPort2 = 0,
+ .ulDataPort = (uint32_t)ALT_UART0_ADDR,
+ .getRegister = cyclone_v_uart_get_register,
+ .setRegister = cyclone_v_uart_set_register,
+ .getData = NULL,
+ .setData = NULL,
+ .ulClock = 0,
+ .ulIntVector = ALT_INT_INTERRUPT_UART0
+ },
+#endif
+#ifdef CYCLONE_V_CONFIG_UART_1
{
- .sDeviceName = "/dev/ttyS0",
- .deviceType = SERIAL_CUSTOM,
- .pDeviceFns = &altcycv_uart_fns,
- .deviceProbe = NULL,
- .pDeviceFlow = NULL,
- .ulMargin = 0,
- .ulHysteresis = 0,
- .pDeviceParams = (void *) 115200,
- .ulCtrlPort1 = 0xe0000000,
- .ulCtrlPort2 = 0,
- .ulDataPort = 0,
- .getRegister = NULL,
- .setRegister = NULL,
- .getData = NULL,
- .setData = NULL,
- .ulClock = 0,
- .ulIntVector = ALTCYCV_IRQ_UART_0
- }, {
- .sDeviceName = "/dev/ttyS1",
- .deviceType = SERIAL_CUSTOM,
- .pDeviceFns = &altcycv_uart_fns,
- .deviceProbe = NULL,
- .pDeviceFlow = NULL,
- .ulMargin = 0,
- .ulHysteresis = 0,
- .pDeviceParams = (void *) 115200,
- .ulCtrlPort1 = 0xe0001000,
- .ulCtrlPort2 = 0,
- .ulDataPort = 0,
- .getRegister = NULL,
- .setRegister = NULL,
- .getData = NULL,
- .setData = NULL,
- .ulClock = 0,
- .ulIntVector = ALTCYCV_IRQ_UART_1
+ .sDeviceName = "/dev/ttyS1",
+ .deviceType = SERIAL_NS16550,
+ .pDeviceFns = &ns16550_fns,
+ .deviceProbe = cyclone_v_uart_probe,
+ .pDeviceFlow = NULL,
+ .ulMargin = 16,
+ .ulHysteresis = 8,
+ .pDeviceParams = (void *)CYCLONE_V_UART_BAUD,
+ .ulCtrlPort1 = (uint32_t)ALT_UART1_ADDR,
+ .ulCtrlPort2 = 0,
+ .ulDataPort = (uint32_t)ALT_UART1_ADDR,
+ .getRegister = cyclone_v_uart_get_register,
+ .setRegister = cyclone_v_uart_set_register,
+ .getData = NULL,
+ .setData = NULL,
+ .ulClock = 0,
+ .ulIntVector = ALT_INT_INTERRUPT_UART1
}
#endif
};
+
unsigned long Console_Configuration_Count =
RTEMS_ARRAY_SIZE(Console_Configuration_Ports);
+bool cyclone_v_uart_probe(int minor)
+{
+ bool ret = true;
+ uint32_t uart_set_mask;
+ uint32_t ucr;
+ ALT_STATUS_CODE sc;
+ void* location;
+
+ // The ALT_CLK_L4_SP is required for all SoCFPGA UARTs. Check that it's enabled.
+ assert( alt_clk_is_enabled(ALT_CLK_L4_SP) == ALT_E_TRUE );
+ if ( alt_clk_is_enabled(ALT_CLK_L4_SP) != ALT_E_TRUE ) {
+ ret = false;
+ }
+
+ if ( ret ) {
+ switch(minor)
+ {
+ case(0):
+ /* UART 0 */
+ uart_set_mask = ALT_RSTMGR_PERMODRST_UART0_SET_MSK;
+ location = ALT_UART0_ADDR;
+ break;
+ case(1):
+ /* UART 1 */
+ uart_set_mask = ALT_RSTMGR_PERMODRST_UART1_SET_MSK;
+ location = ALT_UART1_ADDR;
+ break;
+ default:
+ /* Unknown case */
+ assert( minor == 0 || minor == 1 );
+ ret = false;
+ break;
+ }
+ }
+ if ( ret ) {
+ sc = alt_clk_freq_get(ALT_CLK_L4_SP, &Console_Configuration_Ports[minor].ulClock);
+ assert( sc == ALT_E_SUCCESS );
+ if ( sc != ALT_E_SUCCESS ) {
+ ret = false;
+ }
+ }
+
+ if ( ret ) {
+ // Bring UART out of reset.
+ alt_clrbits_word(ALT_RSTMGR_PERMODRST_ADDR, uart_set_mask);
+
+ // Verify the UCR (UART Component Version)
+ ucr = alt_read_word( ALT_UART_UCV_ADDR( location ) );
+
+ assert( ucr == ALT_UART_UCV_UART_COMPONENT_VER_RESET );
+ if ( ucr != ALT_UART_UCV_UART_COMPONENT_VER_RESET ) {
+ ret = false;
+ }
+ }
+
+ if ( ret ) {
+ // Write SRR::UR (Shadow Reset Register :: UART Reset)
+ alt_write_word( ALT_UART_SRR_ADDR( location ), ALT_UART_SRR_UR_SET_MSK );
+
+ // Read the MSR to work around case:119085.
+ (void)alt_read_word( ALT_UART_MSR_ADDR( location ) );
+ }
+
+ return ret;
+}
+
static void output_char(char c)
{
int minor = (int) Console_Port_Minor;
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/include/bsp.h b/c/src/lib/libbsp/arm/altera-cyclone-v/include/bsp.h
index 8d872ee..6f08ed5 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/include/bsp.h
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/include/bsp.h
@@ -26,25 +26,51 @@
#include <rtems/clockdrv.h>
#include <bsp/default-initial-extension.h>
+#include <bsp/arm-release-id.h>
+#if defined(RTEMS_NETWORKING)
+ #include <bsp/network.h>
+#endif /* defined(RTEMS_NETWORKING) */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
-#define BSP_ARM_A9MPCORE_SCU_BASE 0xf8f00000
+#define BSP_ARM_A9MPCORE_SCU_BASE 0xFFFEC000
-#define BSP_ARM_GIC_CPUIF_BASE 0xf8f00100
+#define BSP_ARM_GIC_CPUIF_BASE ( BSP_ARM_A9MPCORE_SCU_BASE + 0x00000100 )
-#define BSP_ARM_A9MPCORE_PT_BASE 0xf8f00600
+#define BSP_ARM_A9MPCORE_GT_BASE ( BSP_ARM_A9MPCORE_SCU_BASE + 0x00000200 )
-#define BSP_ARM_GIC_DIST_BASE 0xf8f01000
+#define BSP_ARM_GIC_DIST_BASE ( BSP_ARM_A9MPCORE_SCU_BASE + 0x00001000 )
-typedef enum {
- BSP_ARM_A9MPCORE_FATAL_CLOCK_IRQ_INSTALL,
- BSP_ARM_A9MPCORE_FATAL_CLOCK_IRQ_REMOVE
-} altcycv_fatal_code;
+#define BSP_ARM_L2CC_BASE 0xFFFEF000U
+#define BSP_ARM_MAX_CORES_PER_CONTROLLER 2
-void altcycv_fatal(altcycv_fatal_code code) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE;
+#ifndef RTEMS_NETWORKING
+ /** @brief Number of semaphores created by the driver */
+ #define BSP_NETWORK_SEMAPHORE_COUNT 0
+
+ /** @brief Number of tasks created by the driver */
+ #define BSP_NETWORK_TASK_COUNT 0
+
+ /* Network #defines from bsp/network.h */
+ #define RTEMS_BSP_NETWORK_DRIVER_ATTACH
+ #define RTEMS_BSP_NETWORK_DRIVER_NAME
+#else
+ /* Network #defines from bsp/network.h */
+ #define RTEMS_BSP_NETWORK_DRIVER_ATTACH NETWORK_IF_ATTACH_DETACH
+ #define RTEMS_BSP_NETWORK_DRIVER_NAME NETWORK_IF_NAME
+#endif /* RTEMS_NETWORKING */
+
+#define BSP_SEMAPHORE_COUNT \
+ ( \
+ BSP_NETWORK_SEMAPHORE_COUNT \
+ )
+
+#define BSP_TASK_COUNT \
+ ( \
+ BSP_NETWORK_TASK_COUNT \
+ )
#ifdef __cplusplus
}
@@ -52,4 +78,4 @@ void altcycv_fatal(altcycv_fatal_code code) RTEMS_COMPILER_NO_RETURN_ATTRIBUTE;
#endif /* ASM */
-#endif /* LIBBSP_ARM_ALTCYCV_BSP_H */
+#endif /* LIBBSP_ARM_ALTCYCV_BSP_H */
\ No newline at end of file
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/include/irq.h b/c/src/lib/libbsp/arm/altera-cyclone-v/include/irq.h
index d548e5b..aeee41e 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/include/irq.h
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/include/irq.h
@@ -22,74 +22,15 @@
#include <bsp/arm-a9mpcore-irq.h>
#include <bsp/arm-gic-irq.h>
+#include <bsp/alt_interrupt_common.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
-#define ALTCYCV_IRQ_CPU_0 32
-#define ALTCYCV_IRQ_CPU_1 33
-#define ALTCYCV_IRQ_L2_CACHE 34
-#define ALTCYCV_IRQ_OCM 35
-#define ALTCYCV_IRQ_PMU_0 37
-#define ALTCYCV_IRQ_PMU_1 38
-#define ALTCYCV_IRQ_XADC 39
-#define ALTCYCV_IRQ_DVI 40
-#define ALTCYCV_IRQ_SWDT 41
-#define ALTCYCV_IRQ_TTC_0_0 42
-#define ALTCYCV_IRQ_TTC_1_0 43
-#define ALTCYCV_IRQ_TTC_2_0 44
-#define ALTCYCV_IRQ_DMAC_ABORT 45
-#define ALTCYCV_IRQ_DMAC_0 46
-#define ALTCYCV_IRQ_DMAC_1 47
-#define ALTCYCV_IRQ_DMAC_2 48
-#define ALTCYCV_IRQ_DMAC_3 49
-#define ALTCYCV_IRQ_SMC 50
-#define ALTCYCV_IRQ_QUAD_SPI 51
-#define ALTCYCV_IRQ_GPIO 52
-#define ALTCYCV_IRQ_USB_0 53
-#define ALTCYCV_IRQ_ETHERNET_0 54
-#define ALTCYCV_IRQ_ETHERNET_0_WAKEUP 55
-#define ALTCYCV_IRQ_SDIO_0 56
-#define ALTCYCV_IRQ_I2C_0 57
-#define ALTCYCV_IRQ_SPI_0 58
-#define ALTCYCV_IRQ_UART_0 59
-#define ALTCYCV_IRQ_CAN_0 60
-#define ALTCYCV_IRQ_FPGA_0 61
-#define ALTCYCV_IRQ_FPGA_1 62
-#define ALTCYCV_IRQ_FPGA_2 63
-#define ALTCYCV_IRQ_FPGA_3 64
-#define ALTCYCV_IRQ_FPGA_4 65
-#define ALTCYCV_IRQ_FPGA_5 66
-#define ALTCYCV_IRQ_FPGA_6 67
-#define ALTCYCV_IRQ_FPGA_7 68
-#define ALTCYCV_IRQ_TTC_0_1 69
-#define ALTCYCV_IRQ_TTC_1_1 70
-#define ALTCYCV_IRQ_TTC_2_1 71
-#define ALTCYCV_IRQ_DMAC_4 72
-#define ALTCYCV_IRQ_DMAC_5 73
-#define ALTCYCV_IRQ_DMAC_6 74
-#define ALTCYCV_IRQ_DMAC_7 75
-#define ALTCYCV_IRQ_USB_1 76
-#define ALTCYCV_IRQ_ETHERNET_1 77
-#define ALTCYCV_IRQ_ETHERNET_1_WAKEUP 78
-#define ALTCYCV_IRQ_SDIO_1 79
-#define ALTCYCV_IRQ_I2C_1 80
-#define ALTCYCV_IRQ_SPI_1 81
-#define ALTCYCV_IRQ_UART_1 82
-#define ALTCYCV_IRQ_CAN_1 83
-#define ALTCYCV_IRQ_FPGA_8 84
-#define ALTCYCV_IRQ_FPGA_9 85
-#define ALTCYCV_IRQ_FPGA_10 86
-#define ALTCYCV_IRQ_FPGA_11 87
-#define ALTCYCV_IRQ_FPGA_12 88
-#define ALTCYCV_IRQ_FPGA_13 89
-#define ALTCYCV_IRQ_FPGA_14 90
-#define ALTCYCV_IRQ_FPGA_15 91
-#define ALTCYCV_IRQ_PARITY 92
-
-#define BSP_INTERRUPT_VECTOR_MIN 0
-#define BSP_INTERRUPT_VECTOR_MAX 92
+/* Use interrupt IDs as defined in alt_interrupt_common.h */
+#define BSP_INTERRUPT_VECTOR_MIN ALT_INT_INTERRUPT_SGI0
+#define BSP_INTERRUPT_VECTOR_MAX ALT_INT_INTERRUPT_RAM_ECC_UNCORRECTED_IRQ
#ifdef __cplusplus
}
@@ -97,4 +38,4 @@ extern "C" {
#endif /* ASM */
-#endif /* LIBBSP_ARM_ALTCYCV_IRQ_H */
+#endif /* LIBBSP_ARM_ALTCYCV_IRQ_H */
\ No newline at end of file
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/include/network.h b/c/src/lib/libbsp/arm/altera-cyclone-v/include/network.h
new file mode 100644
index 0000000..7a4553b
--- /dev/null
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/include/network.h
@@ -0,0 +1,59 @@
+/**
+ * @file network.h
+ *
+ * @ingroup [GROUP NAME]
+ *
+ * @brief Network Driver
+ *
+ * API header for the network driver of this BSP
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef NETWORK_H_
+#define NETWORK_H_
+
+#include <rtems/rtems_bsdnet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Number of semaphores created by the driver */
+#define BSP_NETWORK_SEMAPHORE_COUNT 1
+
+/** @brief Number of tasks created by the driver */
+#define BSP_NETWORK_TASK_COUNT 2
+
+/** @brief Network interface attach detach
+ *
+ * Attaches a network interface.
+ * NOTE: Detaching is not supported!
+ */
+int network_if_attach_detach(
+ struct rtems_bsdnet_ifconfig *config,
+ int attaching );
+
+/** @brief Alias */
+#define NETWORK_IF_ATTACH_DETACH network_if_attach_detach
+
+/** @brief Interface name */
+#define NETWORK_IF_NAME "eth0"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* NETWORK_H_ */
\ No newline at end of file
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/include/nocache-heap.h b/c/src/lib/libbsp/arm/altera-cyclone-v/include/nocache-heap.h
new file mode 100644
index 0000000..d827584
--- /dev/null
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/include/nocache-heap.h
@@ -0,0 +1,49 @@
+/**
+ * @file nocache-heap.h
+ *
+ * @ingroup [GROUP NAME]
+ *
+ * @brief Heap handling for uncached RAM
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#ifndef NOCACHE_HEAP_H_
+#define NOCACHE_HEAP_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** @brief Nocache alloc.
+ *
+ * Allocate memory from uncached heap.
+ * @param size Number of bytes to be allocated.
+ * @retval Pointer to the allocated memory.
+ */
+void *nocache_malloc( const size_t size );
+
+/** @brief Nocache free.
+ *
+ * Release memory from uncached heap.
+ * @param ptr Address of the memory to be released.
+ */
+void nocache_free( void *ptr );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* NOCACHE_HEAP_H_ */
\ No newline at end of file
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/network/network.c b/c/src/lib/libbsp/arm/altera-cyclone-v/network/network.c
new file mode 100644
index 0000000..e1a0b29
--- /dev/null
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/network/network.c
@@ -0,0 +1,1241 @@
+/**
+ * @file network.c
+ *
+ * @ingroup [GROUP NAME]
+ *
+ * @brief Network Driver
+ *
+ * This driver is a wrapper for the DWMAC 1000 driver from libchip.
+ * The DWMAC 1000 driver is an on-chip Synopsys IP Ethernet controllers
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+
+#include <rtems.h>
+
+#if defined(RTEMS_NETWORKING)
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <rtems.h>
+#include <rtems/config.h>
+#include <bsp.h>
+#include <bsp/irq.h>
+#include <bsp/linker-symbols.h>
+#include <bsp/alt_clock_manager.h>
+#include <bsp/alt_interrupt_common.h>
+#include <bsp/alt_generalpurpose_io.h>
+
+//#include <bsp/network.h>
+#include "socal/alt_emac.h"
+#include "socal/alt_rstmgr.h"
+#include "socal/alt_sysmgr.h"
+#include "socal/hps.h"
+#include "socal/socal.h"
+#include <libchip/dwmac.h>
+#include "../include/nocache-heap.h" /* TODO: Convert to #include <bsp/nocache-heap.h> */
+
+/** @brief Pin mask for the interrupt from the ethernet PHY */
+#define NETWORK_PIN_MASK_PHY_INTERRUPT 0x00000040U
+
+/** @brief Ethernet PHY status */
+typedef enum {
+ /** @brief The ethernet PHY is off */
+ NETWORK_IF_PHY_STATUS_OFF,
+
+ /** @brief The ethernet PHY is on an initialized, but stopped */
+ NETWORK_IF_PHY_STATUS_STOPPED,
+
+ /** @brief The ethernet PHY is started and will generate requested events */
+ NETWORK_IF_PHY_STATUS_STARTED,
+
+ /** @brief Number of ethernet PHY statuses */
+ NETWORK_IF_PHY_STATUS_COUNT
+} network_if_phy_status;
+
+/** @brief Phy context
+ *
+ * ethernet PHY device context
+ */
+typedef struct {
+ /** @brief PHY device status */
+ network_if_phy_status status;
+
+ /** @brief An interrupt mask which corresponds to currently requested events */
+ uint16_t irq_mask;
+} network_if_phy_context;
+
+/** @brief Phy context initializer
+ *
+ * @retval Initialized network PHY context
+ */
+#define NETWORK_IF_PHY_CONTEXT_INITIALIZER( \
+ ) \
+ { \
+ NETWORK_IF_PHY_STATUS_OFF, \
+ 0 \
+ }
+
+/** @brief Network interface controller ID
+ *
+ * Identifies the network interface controller handled by the driver
+ */
+typedef enum {
+ /** @brief ID for EMAC0 */
+ NETWORK_IF_NIC_ID_EMAC0,
+
+ /** @brief ID for EMAC1 */
+ NETWORK_IF_NIC_ID_EMAC1,
+
+ /** @brief Number of network interface controller IDs */
+ NETWORK_IF_NIC_ID_COUNT
+} network_if_nic_id;
+
+/** @brief Network interface context
+ *
+ * Context for the micro controller specific part of the DWMAC 1000 n
+ * etwork driver
+ */
+typedef struct {
+ /** @brief Network interface controller ID */
+ network_if_nic_id nic_id;
+
+ /** @brief Driver context
+ *
+ * Address of the context of the low level DWMAC 1000 driver from libchip */
+ void *driver_context;
+
+ /** @brief Ethernet PHY context */
+ network_if_phy_context phy;
+
+ /* TODO: Create network context on micro controller level */
+} network_if_context;
+
+/** @brief Network interface context initializer
+ *
+ * Initializer for the context of a network interface
+ * @param nic_id ID of the network interface controller
+ * @param driver_context Address of the context of the low level DWMAC 1000
+ * driver from libchip
+ * @retval Initialized network interface context
+ */
+#define NETWORK_IF_CONTEXT_INITIALIZER( \
+ nic_id, \
+ driver_context \
+ ) \
+ { \
+ nic_id, \
+ driver_context, \
+ NETWORK_IF_PHY_CONTEXT_INITIALIZER() \
+ }
+
+/*********************************************************************************
+* Helper Methods
+*********************************************************************************/
+
+/** @brief Altera status code to errno
+ *
+ * Convert Altera status code to errno error number
+ * @param status Altera status code as returned by methods from Alteras HWLib
+ * @retval Converted errno error number from errno.h
+ */
+static int network_if_altera_status_code_to_errno( ALT_STATUS_CODE status )
+{
+ int eno = 0;
+
+ switch ( status ) {
+ /*!
+ * Indicates a FALSE condition.
+ */
+ case ALT_E_FALSE:
+
+ /*!
+ * Indicates a TRUE condition.
+ */
+ case ALT_E_TRUE:
+
+ /*! The operation was successful. */
+ /* case ALT_E_SUCCESS: */
+ eno = 0;
+ break;
+
+ /*! The operation failed. */
+ case ALT_E_ERROR:
+
+ /*! An invalid option was selected. */
+ case ALT_E_INV_OPTION:
+ eno = EIO; /* I/O error */
+ break;
+
+ /*! FPGA configuration error detected.*/
+ case ALT_E_FPGA_CFG:
+ eno = ECANCELED; /* Operation canceled */
+ break;
+
+ /*! FPGA CRC error detected. */
+ case ALT_E_FPGA_CRC:
+
+ /*! An error occurred on the FPGA configuration bitstream input source. */
+ case ALT_E_FPGA_CFG_STM:
+ eno = EPROTO; /* Protocol error */
+ break;
+
+ /*! The FPGA is powered off. */
+ case ALT_E_FPGA_PWR_OFF:
+ eno = ENODEV; /* No such device */
+ break;
+
+ /*! The SoC does not currently control the FPGA. */
+ case ALT_E_FPGA_NO_SOC_CTRL:
+
+ /*! The FPGA is not in USER mode. */
+ case ALT_E_FPGA_NOT_USER_MODE:
+ eno = EPERM; /* Not super-user */
+ break;
+
+ /*! An argument violates a range constraint. */
+ case ALT_E_ARG_RANGE:
+
+ /*! A bad argument value was passed. */
+ case ALT_E_BAD_ARG:
+
+ /*! The argument value is reserved or unavailable. */
+ case ALT_E_RESERVED:
+ eno = EINVAL; /* Invalid argument */
+ break;
+
+ /*! The operation is invalid or illegal. */
+ case ALT_E_BAD_OPERATION:
+
+ /*! The version ID is invalid. */
+ case ALT_E_BAD_VERSION:
+ eno = EFAULT; /* Bad address */
+ break;
+
+ /*! An operation or response timeout period expired. */
+ case ALT_E_TMO:
+
+ /*! A clock is not enabled or violates an operational constraint. */
+ case ALT_E_BAD_CLK:
+ eno = ETIME; /* Timer expired */
+ break;
+
+ /*! The buffer does not contain enough free space for the operation. */
+ case ALT_E_BUF_OVF:
+ eno = ENOMEM; /* Not enough core */
+ break;
+ default:
+
+ /* Unknown case. Implement it! */
+ assert( 0 == 1 );
+ eno = EIO;
+ break;
+ }
+
+ return eno;
+}
+
+/** @brief PHY check chip ID
+ *
+ * Check the chip-ID of the KSZ8842 ethernet PHY.
+ * @param context Address of the network context
+ * @retval 0 if chip could be identified, error code from errno.h otherwise.
+ */
+static int network_if_phy_check_chip_id( network_if_context *context )
+{
+ int eno;
+ uint16_t reg;
+
+ eno = dwmac_if_read_from_phy(
+ context->driver_context,
+ 2,
+ ®
+ );
+
+ if ( eno == 0 ) {
+ if ( reg != 0x0022 ) { /* PHY ID part 1 */
+ eno = ENXIO;
+ } else {
+ eno = dwmac_if_read_from_phy(
+ context->driver_context,
+ 3,
+ ®
+ );
+
+ if ( eno == 0 ) {
+ if ( ( ( reg & 0xFC00 ) >> 10 ) != 0x0005 ) { /* PHY ID part 2 */
+ eno = ENXIO;
+ } else if ( ( ( reg & 0x03F0 ) >> 4 ) != 0x0021 ) { /* Manufacturers model number */
+ eno = ENXIO;
+ }
+ }
+ }
+ }
+
+ return eno;
+}
+
+/*********************************************************************************
+* Callback Methods
+*********************************************************************************/
+
+/** @brief NIC enable
+ *
+ * Enables (powers up) the network interface card.
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+static int network_if_nic_enable( void *arg )
+{
+ int eno = 0;
+ network_if_context *context = (network_if_context *) arg;
+ ALT_CLK_t module_clk = ALT_CLK_EMAC0;
+ uint32_t permodrst_clr_msk = ALT_RSTMGR_PERMODRST_EMAC0_CLR_MSK;
+
+ switch ( context->nic_id ) {
+ case NETWORK_IF_NIC_ID_EMAC0:
+ {
+ module_clk = ALT_CLK_EMAC0;
+ permodrst_clr_msk = ALT_RSTMGR_PERMODRST_EMAC0_CLR_MSK;
+ }
+ break;
+ case NETWORK_IF_NIC_ID_EMAC1:
+ {
+ module_clk = ALT_CLK_EMAC1;
+ permodrst_clr_msk = ALT_RSTMGR_PERMODRST_EMAC1_CLR_MSK;
+ }
+ break;
+
+ case NETWORK_IF_NIC_ID_COUNT:
+
+ /* Invalid case */
+ eno = ENODEV;
+ break;
+ default:
+
+ /* Unknown case */
+ eno = ENOTSUP;
+ break;
+ }
+
+ /* Pin mux configuration is handled by the Preloader. Thus no
+ * pin mux configuration here. */
+
+ /* Enable the clock for the EMAC module */
+ if ( eno == 0 ) {
+ if ( ALT_E_FALSE == alt_clk_is_enabled( module_clk ) ) {
+ ALT_STATUS_CODE status = alt_clk_clock_enable( module_clk );
+ eno = network_if_altera_status_code_to_errno( status );
+ }
+ }
+
+ /* Finish reset for the EMAC module */
+ if ( eno == 0 ) {
+ uint32_t reg = alt_read_word( ALT_RSTMGR_PERMODRST_ADDR );
+ alt_write_word( ALT_RSTMGR_PERMODRST_ADDR, reg & permodrst_clr_msk );
+ }
+
+ return eno;
+}
+
+/** @brief NIC disable.
+ *
+ * Disables (powers down) the network interface card.
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+static int network_if_nic_disable( void *arg )
+{
+ int eno = 0;
+ network_if_context *context = (network_if_context *) arg;
+ ALT_CLK_t module_clk = ALT_CLK_EMAC0;
+ uint32_t permodrst_set_msk = ALT_RSTMGR_PERMODRST_EMAC0_SET_MSK;
+
+ switch ( context->nic_id ) {
+ case NETWORK_IF_NIC_ID_EMAC0:
+ module_clk = ALT_CLK_EMAC0;
+ permodrst_set_msk = ALT_RSTMGR_PERMODRST_EMAC0_SET_MSK;
+ break;
+ case NETWORK_IF_NIC_ID_EMAC1:
+ module_clk = ALT_CLK_EMAC1;
+ permodrst_set_msk = ALT_RSTMGR_PERMODRST_EMAC1_SET_MSK;
+ break;
+
+ case NETWORK_IF_NIC_ID_COUNT:
+
+ /* Invalid case */
+ eno = ENODEV;
+ break;
+ default:
+
+ /* Unknown case */
+ eno = ENOTSUP;
+ break;
+ }
+
+ /* Enter rest status for the EMAC module */
+ if ( eno == 0 ) {
+ uint32_t reg = alt_read_word( ALT_RSTMGR_PERMODRST_ADDR );
+ alt_write_word( ALT_RSTMGR_PERMODRST_ADDR, reg | permodrst_set_msk );
+ }
+
+ /* Disable the clock for the EMAC module */
+ if ( eno == 0 ) {
+ if ( ALT_E_TRUE == alt_clk_is_enabled( module_clk ) ) {
+ ALT_STATUS_CODE status = alt_clk_clock_disable( module_clk );
+ eno = network_if_altera_status_code_to_errno( status );
+ }
+ }
+
+ return eno;
+}
+
+/** @brief PHY disable.
+ *
+ * Disables (powers down) the network PHY.
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+static int network_if_phy_disable( void *arg )
+{
+ int eno = 0;
+ network_if_context *self = (network_if_context *) arg;
+ uint32_t mask;
+ ALT_STATUS_CODE status_code;
+
+ /* The power pin of the PHY is hard wire to board power control and
+ * the PHY supports interrupts, This means we can not power it down
+ * and we don't need to stop a timer for polling PHY events. */
+
+ status_code = alt_gpio_port_int_mask_set(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT,
+ NETWORK_PIN_MASK_PHY_INTERRUPT
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+
+ if ( eno == 0 ) {
+ mask = alt_gpio_port_int_enable_get( ALT_GPIO_PORTB );
+ status_code = alt_gpio_port_int_enable(
+ ALT_GPIO_PORTB,
+ mask & ~NETWORK_PIN_MASK_PHY_INTERRUPT
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+ }
+
+ if ( eno == 0 ) {
+ status_code = alt_gpio_port_int_status_clear(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+ }
+
+ if ( eno == 0 ) {
+ self->phy.status = NETWORK_IF_PHY_STATUS_OFF;
+ }
+
+ return eno;
+}
+
+/** @brief PHY enable.
+ *
+ * Enables (powers up) the network PHY.
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+static int network_if_phy_enable( void *arg )
+{
+ int eno = 0;
+ network_if_context *self = (network_if_context *) arg;
+ ALT_STATUS_CODE status_code;
+
+ /* The power pin of the PHY is hard wire to board power control and
+ * the PHY supports interrupts, This means we can not power it up
+ * and we don't need to start a timer for polling PHY events. */
+
+ eno = network_if_phy_check_chip_id( self );
+
+ if ( eno == 0 ) {
+ /* The phy is already enabled and we will reset it */
+ eno = network_if_phy_disable( self );
+
+ if ( eno == 0 ) {
+ rtems_task_wake_after( rtems_clock_get_ticks_per_second() / 100 );
+ }
+ } else {
+ eno = 0;
+ }
+
+ status_code = alt_gpio_port_datadir_set(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT,
+ 0
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+
+ if ( eno == 0 ) {
+ status_code = alt_gpio_port_int_type_set(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT,
+ 0
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+ }
+
+ if ( eno == 0 ) {
+ status_code = alt_gpio_port_int_pol_set(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT,
+ 1
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+ }
+
+ if ( eno == 0 ) {
+ status_code = alt_gpio_port_debounce_set(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT,
+ 0
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+ }
+
+ if ( eno == 0 ) {
+ status_code = alt_gpio_port_int_enable(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+ }
+
+ if ( eno == 0 ) {
+ status_code = alt_gpio_port_int_mask_set(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT,
+ 0
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+ }
+
+ if ( eno == 0 ) {
+ status_code = alt_gpio_port_int_status_clear(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+ }
+
+ if ( eno == 0 ) {
+ self->phy.status = NETWORK_IF_PHY_STATUS_STOPPED;
+ }
+
+ return eno;
+}
+
+/** @brief Clear phy event status.
+ *
+ * Clears all PHY event statuses.
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+int network_if_phy_event_status_clear( void *arg )
+{
+ int eno;
+ ALT_STATUS_CODE status_code;
+
+ (void) arg;
+
+ /* Clear the interrupt status */
+ status_code = alt_gpio_port_int_status_clear(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+
+ if ( eno == 0 ) {
+ /* Unmask the interrupt (was masked within interrupt handler) */
+ status_code = alt_gpio_port_int_mask_set(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT,
+ 0
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+ }
+
+ return eno;
+}
+
+/**
+ * @brief Get the PHY event status.
+ *
+ * Reports status on PHY events (e.g. PHY interrupts).
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @param[out] event_set Pointer to a buffer for a set of events for which a
+ * PHY status change was detected.
+ * For events see @see dwmac_phy_event.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+int network_if_phy_events_status_get(
+ void *arg,
+ dwmac_phy_event *event_set )
+{
+ int eno = 0;
+ uint16_t reg = 0;
+ network_if_context *self = (network_if_context *) arg;
+
+ eno = dwmac_if_read_from_phy(
+ self->driver_context,
+ 0x1B,
+ ®
+ );
+
+ if ( eno == 0 ) {
+ if ( ( reg & 0x80 ) != 0 ) {
+ *event_set |= PHY_EVENT_JABBER;
+ }
+
+ if ( ( reg & 0x40 ) != 0 ) {
+ *event_set |= PHY_EVENT_RECEIVE_ERROR;
+ }
+
+ if ( ( reg & 0x20 ) != 0 ) {
+ *event_set |= PHY_EVENT_PAGE_RECEIVE;
+ }
+
+ if ( ( reg & 0x10 ) != 0 ) {
+ *event_set |= PHY_EVENT_PARALLEL_DETECT_FAULT;
+ }
+
+ if ( ( reg & 0x08 ) != 0 ) {
+ *event_set |= PHY_EVENT_LINK_PARTNER_ACK;
+ }
+
+ if ( ( reg & 0x04 ) != 0 ) {
+ *event_set |= PHY_EVENT_LINK_DOWN;
+ }
+
+ if ( ( reg & 0x02 ) != 0 ) {
+ *event_set |= PHY_EVENT_REMOTE_FAULT;
+ }
+
+ if ( ( reg & 0x01 ) != 0 ) {
+ *event_set |= PHY_EVENT_LINK_UP;
+ }
+ }
+
+ return eno;
+}
+
+/** @brief Network PHY interrupt handler
+ *
+ * Handling method for interrupts from the PHY.
+ * @param arg Address of the network interface context
+ */
+static void network_if_phy_interrupt_handler( void *arg )
+{
+ int eno = 0;
+ network_if_context *self = (network_if_context *) arg;
+ uint32_t reg;
+
+ reg = alt_gpio_port_int_status_get( ALT_GPIO_PORTB );
+
+ if ( reg & NETWORK_PIN_MASK_PHY_INTERRUPT ) {
+ /* We have a level interrupt and we expect the driver to do
+ * the actual interrupt handling from within a task context.
+ * Thus we have to mask the interrupt. A call to
+ * network_if_phy_event_status_clear() will unmask it */
+ ALT_STATUS_CODE status_code = alt_gpio_port_int_mask_set(
+ ALT_GPIO_PORTB,
+ NETWORK_PIN_MASK_PHY_INTERRUPT,
+ NETWORK_PIN_MASK_PHY_INTERRUPT
+ );
+ eno = network_if_altera_status_code_to_errno( status_code );
+
+ if ( eno == 0 ) {
+ eno = dwmac_if_handle_phy_event(
+ self->driver_context
+ );
+ }
+ }
+
+ assert( eno == 0 );
+}
+
+/** @brief PHY event enable.
+ *
+ * Enables generation of events for an event set.
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @param[in] event_set Set of events. For these events shall get generated
+ * upon PHY status change.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+static int network_if_phy_event_enable(
+ void *arg,
+ const dwmac_phy_event event_set )
+{
+ int eno = 0;
+ uint16_t reg = 0;
+ network_if_context *self = (network_if_context *) arg;
+ network_if_phy_status old_status = self->phy.status;
+
+ if ( arg != NULL ) {
+ switch ( self->phy.status ) {
+ case NETWORK_IF_PHY_STATUS_OFF:
+ break;
+ case NETWORK_IF_PHY_STATUS_STOPPED:
+ break;
+ case NETWORK_IF_PHY_STATUS_STARTED:
+ {
+ eno = dwmac_if_read_from_phy(
+ self->driver_context,
+ 0x1B,
+ ®
+ );
+
+ if ( eno == 0 ) {
+ /* Disable all interrupts, but leave interrupt status bits untouched */
+ reg &= 0x00FF;
+ eno = dwmac_if_write_to_phy(
+ self->driver_context,
+ 0x1B,
+ reg
+ );
+ }
+
+ if ( eno == 0 ) {
+ self->phy.irq_mask = 0;
+ self->phy.status = NETWORK_IF_PHY_STATUS_STOPPED;
+ }
+ }
+ break;
+ case NETWORK_IF_PHY_STATUS_COUNT:
+ {
+ /* Invalid case */
+ assert( self->phy.status != NETWORK_IF_PHY_STATUS_COUNT );
+ eno = ENOTSUP;
+ }
+ break;
+ default:
+ {
+ /* Unknown case */
+ assert(
+ self->phy.status == NETWORK_IF_PHY_STATUS_OFF
+ || self->phy.status == NETWORK_IF_PHY_STATUS_STOPPED
+ || self->phy.status == NETWORK_IF_PHY_STATUS_STARTED
+ );
+ eno = ENOTSUP;
+ }
+ break;
+ }
+
+ if ( eno == 0 ) {
+ /* Select interrupts to enable */
+ if ( ( event_set & PHY_EVENT_JABBER ) != 0 ) {
+ reg |= 0x8000;
+ }
+
+ if ( ( event_set & PHY_EVENT_RECEIVE_ERROR ) != 0 ) {
+ reg |= 0x4000;
+ }
+
+ if ( ( event_set & PHY_EVENT_PAGE_RECEIVE ) != 0 ) {
+ reg |= 0x2000;
+ }
+
+ if ( ( event_set & PHY_EVENT_PARALLEL_DETECT_FAULT ) != 0 ) {
+ reg |= 0x1000;
+ }
+
+ if ( ( event_set & PHY_EVENT_LINK_PARTNER_ACK ) != 0 ) {
+ reg |= 0x0800;
+ }
+
+ if ( ( event_set & PHY_EVENT_LINK_DOWN ) != 0 ) {
+ reg |= 0x0400;
+ }
+
+ if ( ( event_set & PHY_EVENT_REMOTE_FAULT ) != 0 ) {
+ reg |= 0x0200;
+ }
+
+ if ( ( event_set & PHY_EVENT_LINK_UP ) != 0 ) {
+ reg |= 0x100;
+ }
+
+ switch ( old_status ) {
+ case NETWORK_IF_PHY_STATUS_OFF:
+ break;
+ case NETWORK_IF_PHY_STATUS_STOPPED:
+ break;
+ case NETWORK_IF_PHY_STATUS_STARTED:
+ {
+ if ( eno == 0 ) {
+ /* Modify interrupt enable bits, but leave interrupt status bits untouched */
+ eno = dwmac_if_write_to_phy(
+ self->driver_context,
+ 0x1B,
+ reg & 0xFF00
+ );
+ }
+ }
+ break;
+ case NETWORK_IF_PHY_STATUS_COUNT:
+ {
+ /* Invalid case */
+ assert( self->phy.status != NETWORK_IF_PHY_STATUS_COUNT );
+ eno = ENOTSUP;
+ }
+ break;
+ default:
+ {
+ /* Unknown case */
+ assert(
+ self->phy.status == NETWORK_IF_PHY_STATUS_OFF
+ || self->phy.status == NETWORK_IF_PHY_STATUS_STOPPED
+ || self->phy.status == NETWORK_IF_PHY_STATUS_STARTED
+ );
+ eno = ENOTSUP;
+ }
+ break;
+ }
+
+ if ( eno == 0 ) {
+ self->phy.irq_mask = reg & 0xFF00;
+ }
+ }
+ }
+
+ return eno;
+}
+
+/**
+ * @brief Stop the network PHY.
+ *
+ * Do anything necessary to stop the network PHY (stop generating events, ...).
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+int network_if_phy_stop( void *arg )
+{
+ int eno = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ network_if_context *self = (network_if_context *) arg;
+
+ switch ( self->phy.status ) {
+ case NETWORK_IF_PHY_STATUS_OFF:
+ break;
+ case NETWORK_IF_PHY_STATUS_STOPPED:
+ break;
+ case NETWORK_IF_PHY_STATUS_STARTED:
+ {
+ /* Remove any selected interrupts */
+ eno = dwmac_if_write_to_phy(
+ self->driver_context,
+ 0x1B,
+ 0
+ );
+
+ if ( eno == 0 ) {
+ uint16_t reg;
+
+ /* Clear interrupt status bits by reading them */
+ eno = dwmac_if_read_from_phy(
+ self->driver_context,
+ 0x1B,
+ ®
+ );
+ }
+
+ if ( eno == 0 ) {
+ self->phy.irq_mask = 0;
+
+ /* Remove interrupt handler */
+ sc = rtems_interrupt_handler_remove(
+ ALT_INT_INTERRUPT_GPIO1,
+ network_if_phy_interrupt_handler,
+ self
+ );
+ eno = rtems_status_code_to_errno( sc );
+
+ if ( eno == 0 ) {
+ self->phy.status = NETWORK_IF_PHY_STATUS_STOPPED;
+ }
+ }
+ }
+ break;
+ case NETWORK_IF_PHY_STATUS_COUNT:
+ {
+ /* Invalid case */
+ assert( self->phy.status != NETWORK_IF_PHY_STATUS_COUNT );
+ eno = ENOTSUP;
+ }
+ break;
+ default:
+ {
+ /* Unknown case */
+ assert(
+ self->phy.status == NETWORK_IF_PHY_STATUS_OFF
+ || self->phy.status == NETWORK_IF_PHY_STATUS_STOPPED
+ || self->phy.status == NETWORK_IF_PHY_STATUS_STARTED
+ );
+ eno = ENOTSUP;
+ }
+ break;
+ }
+
+ return eno;
+}
+
+/**
+ * @brief Start the network PHY.
+ *
+ * Do anything necessary to start the network PHY (start generating
+ * events, ...).
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+int network_if_phy_start( void *arg )
+{
+ int eno = 0;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ network_if_context *self = (network_if_context *) arg;
+
+ switch ( self->phy.status ) {
+ case NETWORK_IF_PHY_STATUS_OFF:
+ {
+ assert( self->phy.status != NETWORK_IF_PHY_STATUS_OFF );
+ eno = EHOSTDOWN;
+ }
+ break;
+ case NETWORK_IF_PHY_STATUS_STOPPED:
+
+ /* Disable all interrupts */
+ eno = dwmac_if_write_to_phy(
+ self->driver_context,
+ 0x1B,
+ 0
+ );
+
+ if ( eno == 0 ) {
+ }
+
+ if ( eno == 0 ) {
+ /* Install interrupt handler */
+ sc = rtems_interrupt_handler_install(
+ ALT_INT_INTERRUPT_GPIO1,
+ NULL,
+ RTEMS_INTERRUPT_SHARED,
+ network_if_phy_interrupt_handler,
+ self
+ );
+ eno = rtems_status_code_to_errno( sc );
+ }
+
+ if ( eno == 0 ) {
+ /* Enable interrupts */
+ eno = dwmac_if_write_to_phy(
+ self->driver_context,
+ 0x1B,
+ self->phy.irq_mask
+ );
+ }
+
+ break;
+ case NETWORK_IF_PHY_STATUS_STARTED:
+ {
+ uint16_t irq_mask = self->phy.irq_mask;
+
+ /* Re-start the phy */
+ eno = network_if_phy_stop( self );
+
+ if ( eno == 0 ) {
+ self->phy.irq_mask = irq_mask;
+
+ eno = network_if_phy_start(
+ self
+ );
+ }
+ }
+ break;
+
+ case NETWORK_IF_PHY_STATUS_COUNT:
+ {
+ /* Invalid case */
+ assert( self->phy.status != NETWORK_IF_PHY_STATUS_COUNT );
+ eno = ENOTSUP;
+ }
+ break;
+ default:
+ {
+ /* Unknown case */
+ assert(
+ self->phy.status == NETWORK_IF_PHY_STATUS_OFF
+ || self->phy.status == NETWORK_IF_PHY_STATUS_STOPPED
+ || self->phy.status == NETWORK_IF_PHY_STATUS_STARTED
+ );
+ eno = ENOTSUP;
+ }
+ break;
+ }
+
+ if ( eno == 0 ) {
+ self->phy.status = NETWORK_IF_PHY_STATUS_STARTED;
+ }
+
+ return eno;
+}
+
+/**
+ * @brief Allocate nocache RAM.
+ *
+ * Allocate uncached RAM.
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @param[out] memory Pointer of a buffer to write the address of the
+ * allocated memory to.
+ * @param[in] size Number of bytes to be allocated
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+int network_if_mem_alloc_nocache(
+ void *arg,
+ void **memory,
+ const size_t size )
+{
+ int eno = EINVAL;
+
+ (void) arg;
+
+ assert( memory != NULL );
+
+ if ( memory != NULL ) {
+ *memory = nocache_malloc( size );
+
+ if ( *memory != NULL ) {
+ eno = 0;
+ } else {
+ eno = ENOMEM;
+ }
+ }
+
+ return eno;
+}
+
+/**
+ * @brief Free nocache RAM.
+ *
+ * Release uncached RAM.
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @param[in] memory Pointer to the memory to be freed.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+int network_if_mem_free_nocache(
+ void *arg,
+ void *memory )
+{
+ int eno = EINVAL;
+
+ (void) arg;
+
+ assert( memory != NULL );
+
+ if ( memory != NULL ) {
+ nocache_free( memory );
+ eno = 0;
+ }
+
+ return eno;
+}
+
+/**
+ * @brief Bus setup.
+ *
+ * Callback method for setting up the system bus for the network driver.
+ * @param[in] arg The void pointer argument passed to
+ * dwmac_network_if_attach_detach.
+ * @retval 0 on success, error code from errno.h on failure.
+ */
+int network_if_bus_setup( void *arg )
+{
+ (void) arg;
+
+ /* Nothing to be done */
+ return 0;
+}
+
+/*********************************************************************************
+* Context Data
+*********************************************************************************/
+
+/** @brief Network interface context */
+static network_if_context context = NETWORK_IF_CONTEXT_INITIALIZER(
+
+ /** @brief Use EMAC1 */
+ NETWORK_IF_NIC_ID_EMAC1,
+
+ /** @brief Address of driver context
+ *
+ * To be assigned with return value of dwmac_network_if_attach_detach */
+ NULL
+ );
+
+/** @brief Network driver DMA configuration data */
+static const dwmac_dma_cfg NETWORK_DMA_CFG = DWMAC_DMA_CFG_INITIALIZER(
+
+ /** @brief Bus mode burst length */
+ DWMAC_DMA_CFG_BUS_MODE_BURST_LENGTH_64,
+
+ /** @brief Bus mode fixed burst? */
+ DWMAC_DMA_CFG_BUS_MODE_BURST_MODE_SINGLE_OR_INCR,
+
+ /** @brief Bus mode mixed burst? */
+ DWMAC_DMA_CFG_BUS_MODE_BURST_NOT_MIXED,
+
+ /** @brief Permit AXI burst length of 4 */
+ DWMAC_DMA_CFG_AXI_BURST_LENGTH_4_NOT_SUPPORTED,
+
+ /** @brief Permit AXI burst length of 8 */
+ DWMAC_DMA_CFG_AXI_BURST_LENGTH_8_NOT_SUPPORTED,
+
+ /** @brief Permit AXI burst length of 16 */
+ DWMAC_DMA_CFG_AXI_BURST_LENGTH_16_NOT_SUPPORTED,
+
+ /** @brief Select boundary crossing mode */
+ DWMAC_DMA_CFG_AXI_BURST_BOUNDARY_4_KB
+ );
+
+/** @brief Network driver configuration data */
+static const dwmac_cfg NETWORK_DRIVER_CFG = DWMAC_CFG_INITIALIZER(
+
+ /** @brief GMII clock rate */
+ 75000000,
+
+ /** @brief Address of the GMAC registers for emac1 */
+ ALT_EMAC1_GMACGRP_ADDR,
+
+ /** @brief Address of the DMA registers for emac1 */
+ ALT_EMAC1_DMAGRP_ADDR,
+
+ /** @brief Address of the PHY on the mdio bus */
+ 4,
+
+ /** @brief Bytes per L1 cache line */
+ 32,
+
+ /** @brief Interrupt number for the EMAC */
+ ALT_INT_INTERRUPT_EMAC1_IRQ,
+
+ /** @brief Set to true if prefetching into cache via PLD is supported */
+ false,
+
+ /** @brief DMA configuration */
+ &NETWORK_DMA_CFG,
+
+ /** @brief Callback method for enabling the network controller */
+ network_if_nic_enable,
+
+ /** @brief Callback method for disabling the network controller */
+ network_if_nic_disable,
+
+ /** @brief Callback method for enabling the PHY */
+ network_if_phy_enable,
+
+ /** @brief Callback method for disabling the PHY */
+ network_if_phy_disable,
+
+ /** @brief Callback which enables PHY events for forwarding to driver */
+ network_if_phy_event_enable,
+
+ /** @brief Callback method for clearing PHY interrupt status */
+ network_if_phy_event_status_clear,
+
+ /** @brief Callback method for getting a set of events from the PHY */
+ network_if_phy_events_status_get,
+
+ /** @brief Callback method for making the PHY start forwarding events */
+ network_if_phy_start,
+
+ /** @brief Callback method for making the PHY stop forwarding events */
+ network_if_phy_stop,
+
+ /** @brief Callback method for allocating uncached memory */
+ network_if_mem_alloc_nocache,
+
+ /** @brief Callback method for freeing uncached memory */
+ network_if_mem_free_nocache,
+
+ /** @brief Callback method for setting up bus upon driver startup */
+ network_if_bus_setup,
+
+ /** @brief Operations for the ethernet mac 1000 */
+ &DWMAC_1000_ETHERNET_MAC_OPS,
+
+ /** @brief Operations for the enhanced DMA descriptors */
+ &DWMAC_DESCRIPTOR_OPS_ENHANCED
+ );
+
+/*********************************************************************************
+* API
+*********************************************************************************/
+
+/** @brief Network interface attach/detach
+ *
+ * The standard attach/detach method for network interfaces.
+ * This methods will call the DWMAC 1000 attach/detach method and pass
+ * configuration data and callback methods into it. Via these the general
+ * DWMAC 1000 driver is able the handle micro controller specific things.
+ * NOTE: Detaching is NOT supported!
+ * @param config Configuration parameters from and for the BSD network stack.
+ * @param attaching True if attaching the driver to the network stack, false if.
+ * detaching
+ * @retval 0 if successful, error code from errno.h if not.
+ */
+int network_if_attach_detach(
+ struct rtems_bsdnet_ifconfig *config,
+ int attaching )
+{
+ int eno = 0;
+
+ assert( config != NULL );
+
+ /* Network controller initialization */
+ context.driver_context = dwmac_network_if_attach_detach(
+ config,
+ &NETWORK_DRIVER_CFG,
+ &context,
+ attaching
+ );
+
+ if ( context.driver_context == NULL ) {
+ eno = EFAULT;
+ }
+
+ return eno;
+}
+
+#endif /* defined(RTEMS_NETWORKING) */
\ No newline at end of file
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/preinstall.am b/c/src/lib/libbsp/arm/altera-cyclone-v/preinstall.am
index d59525a..5d4fd83 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/preinstall.am
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/preinstall.am
@@ -86,6 +86,10 @@ $(PROJECT_INCLUDE)/bsp/start.h: ../shared/include/start.h $(PROJECT_INCLUDE)/bsp
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/start.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/start.h
+$(PROJECT_INCLUDE)/bsp/arm-a9mpcore-clock.h: ../shared/include/arm-a9mpcore-clock.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/arm-a9mpcore-clock.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/arm-a9mpcore-clock.h
+
$(PROJECT_INCLUDE)/bsp/arm-a9mpcore-irq.h: ../shared/include/arm-a9mpcore-irq.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/arm-a9mpcore-irq.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/arm-a9mpcore-irq.h
@@ -102,6 +106,10 @@ $(PROJECT_INCLUDE)/bsp/arm-cp15-start.h: ../shared/include/arm-cp15-start.h $(PR
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/arm-cp15-start.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/arm-cp15-start.h
+$(PROJECT_INCLUDE)/bsp/arm-errata.h: ../shared/include/arm-errata.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/arm-errata.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/arm-errata.h
+
$(PROJECT_INCLUDE)/bsp/arm-gic.h: ../shared/include/arm-gic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/arm-gic.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/arm-gic.h
@@ -118,10 +126,22 @@ $(PROJECT_INCLUDE)/bsp/arm-gic-tm27.h: ../shared/include/arm-gic-tm27.h $(PROJEC
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/arm-gic-tm27.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/arm-gic-tm27.h
+$(PROJECT_INCLUDE)/bsp/arm-release-id.h: ../shared/include/arm-release-id.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/arm-release-id.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/arm-release-id.h
+
$(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/network.h: include/network.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/network.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/network.h
+
+$(PROJECT_INCLUDE)/bsp/nocache-heap.h: include/nocache-heap.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/nocache-heap.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/nocache-heap.h
+
$(PROJECT_INCLUDE)/bsp/alt_16550_uart.h: hwlib/include/alt_16550_uart.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/alt_16550_uart.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/alt_16550_uart.h
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspreset.c b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspreset.c
index 658f870..6a60db7 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspreset.c
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspreset.c
@@ -13,14 +13,10 @@
*/
#include <bsp/bootcard.h>
+#include <bsp/alt_reset_manager.h>
void bsp_reset(void)
{
- volatile uint32_t *slcr_unlock = (volatile uint32_t *) 0xf8000008;
- volatile uint32_t *pss_rst_ctrl = (volatile uint32_t *) 0xf8000200;
-
- while (true) {
- *slcr_unlock = 0xdf0d;
- *pss_rst_ctrl = 0x1;
- }
+ /* Simply call the reset method from alteras HWLIB */
+ (void) alt_reset_cold_reset();
}
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspstart.c b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspstart.c
index 40459bb..58f38b9 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspstart.c
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspstart.c
@@ -12,16 +12,120 @@
* http://www.rtems.com/license/LICENSE.
*/
+/*#define DEBUG_ECC_ERROR*/ /* TODO: Delete DEBUG_ECC_ERROR after implementation phase */
+
+#include <assert.h>
+#include <stdint.h>
#include <bsp.h>
#include <bsp/bootcard.h>
#include <bsp/irq-generic.h>
+#include <bsp/alt_interrupt_common.h>
+#include <bsp/linker-symbols.h>
+#include <bsp/start.h>
+#include <rtems/config.h>
+#include <socal/alt_rstmgr.h>
+#include <socal/alt_sysmgr.h>
+#include <socal/hps.h>
+#ifdef DEBUG_ECC_ERROR
+ #include <rtems/irq-extension.h>
+ #include <socal/socal.h>
+ #include <socal/alt_sdr.h>
+#endif /* DEBUG_ECC_ERROR */
+
+#ifndef MIN
+#define MIN( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) )
+#endif
-void altcycv_fatal(altcycv_fatal_code code)
+#ifdef DEBUG_ECC_ERROR
+static void irq_handler_ddr_ecc_error( void *arg )
{
- rtems_fatal(RTEMS_FATAL_SOURCE_BSP_SPECIFIC, code);
+ (void) arg;
+ uint32_t cal_success =
+ ALT_SDR_CTL_DRAMSTS_CALSUCCESS_GET(
+ *( (uint32_t *) ALT_SDR_CTL_DRAMSTS_ADDR ) );
+ uint32_t cal_fail = ALT_SDR_CTL_DRAMSTS_CALFAIL_GET(
+ *( (uint32_t *) ALT_SDR_CTL_DRAMSTS_ADDR ) );
+ uint32_t single_bit_error =
+ ALT_SDR_CTL_DRAMSTS_SBEERR_GET( *( (uint32_t *) ALT_SDR_CTL_DRAMSTS_ADDR ) );
+ uint32_t double_bit_error =
+ ALT_SDR_CTL_DRAMSTS_DBEERR_GET( *( (uint32_t *) ALT_SDR_CTL_DRAMSTS_ADDR ) );
+ uint32_t auto_correction_dropped = ALT_SDR_CTL_DRAMSTS_CORRDROP_GET(
+ *( (uint32_t *) ALT_SDR_CTL_DRAMSTS_ADDR ) );
+ volatile uint32_t erraddr =
+ ALT_SDR_CTL_ERRADDR_ADDR_GET(
+ *(volatile uint32_t *) ALT_SDR_CTL_ERRADDR_ADDR );
+
+ /* Simply avoid a compiler warning */
+ ++cal_success;
+ ++cal_fail;
+ ++single_bit_error;
+ ++double_bit_error;
+ ++auto_correction_dropped;
+ ++erraddr;
+
+ alt_setbits_word( ALT_SDR_CTL_DRAMINTR_ADDR,
+ ALT_SDR_CTL_DRAMINTR_INTRCLR_SET_MSK );
}
-void bsp_start(void)
+static void setup_ecc_interrupt( void )
{
- bsp_interrupt_initialize();
+ rtems_status_code sc = rtems_interrupt_handler_install(
+ ALT_INT_INTERRUPT_DDR_ECC_ERROR_IRQ,
+ NULL,
+ RTEMS_INTERRUPT_UNIQUE,
+ irq_handler_ddr_ecc_error,
+ NULL
+ );
+
+
+ assert( sc == RTEMS_SUCCESSFUL );
}
+
+#else
+ #define setup_ecc_interrupt()
+#endif /* DEBUG_ECC_ERROR */
+
+static unsigned int bspstart_cores_started = 1;
+
+#ifdef RTEMS_SMP
+static void bsp_start_secondary_cores( void )
+{
+ volatile uint32_t *mpumodrst = ALT_RSTMGR_MPUMODRST_ADDR;
+ uint32_t *cpu1_start_addr = (
+ ALT_SYSMGR_ROMCODE_ADDR + ALT_SYSMGR_ROMCODE_CPU1STARTADDR_OFST );
+ const uint32_t CORES = MIN(
+ (uintptr_t) bsp_processor_count,
+ rtems_configuration_get_maximum_processors() );
+ unsigned int index;
+
+
+ /* Memory would get overwritten if a too small processor count
+ * would be specified */
+ assert( (uintptr_t) bsp_processor_count >= BSP_ARM_MAX_CORES_PER_CONTROLLER );
+
+ if ( (uintptr_t) bsp_processor_count >= BSP_ARM_MAX_CORES_PER_CONTROLLER
+ && bspstart_cores_started < CORES ) {
+ for ( index = 1; index < CORES; ++index ) {
+ /* set the start address from where the core will execute */
+ (*cpu1_start_addr) = ALT_SYSMGR_ROMCODE_CPU1STARTADDR_VALUE_SET(
+ (uintptr_t) _start );
+
+ /* Make the core finish it's reset */
+ (*mpumodrst) &= ~ALT_RSTMGR_MPUMODRST_CPU1_SET_MSK;
+ ++bspstart_cores_started;
+ }
+ }
+}
+
+#else
+
+/* Nothing to be done */
+ #define bsp_start_secondary_cores()
+#endif /* #ifdef RTEMS_SMP */
+
+void bsp_start( void )
+{
+ bsp_interrupt_initialize();
+ setup_ecc_interrupt();
+ bsp_start_secondary_cores();
+}
\ No newline at end of file
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspstarthooks.c b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspstarthooks.c
index 9831084..dd3821b 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspstarthooks.c
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/bspstarthooks.c
@@ -17,6 +17,13 @@
#include <bsp/arm-cp15-start.h>
#include <bsp/arm-a9mpcore-start.h>
#include <bsp/linker-symbols.h>
+#include <socal/alt_sdr.h>
+#include <alt_address_space.h>
+#include <socal/socal.h>
+#include <socal/hps.h>
+#include "../include/arm-cache-l1.h"
+
+/*#define DEBUG_ECC_ERROR*/ /* TODO: Delete DEBUG_ECC_ERROR after the implementation phase */
#ifdef RTEMS_SMP
#define MMU_DATA_READ_WRITE ARMV7_MMU_DATA_READ_WRITE_SHAREABLE
@@ -24,84 +31,178 @@
#define MMU_DATA_READ_WRITE ARMV7_MMU_DATA_READ_WRITE_CACHED
#endif
+/* 1 MB reset default value for address filtering start */
+#define BSPSTART_L2_CACHE_ADDR_FILTERING_START_RESET 0x100000
+
+#ifndef BSPSTARTHOOKS_MIN
+#define BSPSTARTHOOKS_MIN( a, b ) ( ( a ) < ( b ) ? ( a ) : ( b ) )
+#endif
+
+LINKER_SYMBOL( bsp_section_nocache_size );
+LINKER_SYMBOL( bsp_section_nocache_end );
+LINKER_SYMBOL( bsp_section_nocache_begin );
+
BSP_START_DATA_SECTION static const arm_cp15_start_section_config
-altcycv_mmu_config_table[] = {
+ altcycv_mmu_config_table[] = {
+ ARMV7_CP15_START_DEFAULT_SECTIONS,
{
- .begin = (uint32_t) bsp_section_fast_text_begin,
- .end = (uint32_t) bsp_section_fast_text_end,
- .flags = ARMV7_MMU_CODE_CACHED
- }, {
- .begin = (uint32_t) bsp_section_fast_data_begin,
- .end = (uint32_t) bsp_section_fast_data_end,
- .flags = MMU_DATA_READ_WRITE
- }, {
- .begin = (uint32_t) bsp_section_start_begin,
- .end = (uint32_t) bsp_section_start_end,
- .flags = ARMV7_MMU_CODE_CACHED
- }, {
- .begin = (uint32_t) bsp_section_vector_begin,
- .end = (uint32_t) bsp_section_vector_end,
- .flags = MMU_DATA_READ_WRITE
- }, {
- .begin = (uint32_t) bsp_section_text_begin,
- .end = (uint32_t) bsp_section_text_end,
- .flags = ARMV7_MMU_CODE_CACHED
- }, {
- .begin = (uint32_t) bsp_section_rodata_begin,
- .end = (uint32_t) bsp_section_rodata_end,
- .flags = ARMV7_MMU_DATA_READ_ONLY_CACHED
- }, {
- .begin = (uint32_t) bsp_section_data_begin,
- .end = (uint32_t) bsp_section_data_end,
- .flags = MMU_DATA_READ_WRITE
- }, {
- .begin = (uint32_t) bsp_section_bss_begin,
- .end = (uint32_t) bsp_section_bss_end,
- .flags = MMU_DATA_READ_WRITE
- }, {
- .begin = (uint32_t) bsp_section_work_begin,
- .end = (uint32_t) bsp_section_work_end,
- .flags = MMU_DATA_READ_WRITE
- }, {
- .begin = (uint32_t) bsp_section_stack_begin,
- .end = (uint32_t) bsp_section_stack_end,
- .flags = MMU_DATA_READ_WRITE
- }, {
- .begin = 0xe0000000U,
- .end = 0xe0200000U,
- .flags = ARMV7_MMU_DEVICE
- }, {
- .begin = 0xf8000000U,
- .end = 0xf9000000U,
+ .begin = (uint32_t) bsp_section_nocache_begin,
+ .end = (uint32_t) bsp_section_nocache_end,
+
+ .flags = ARMV7_MMU_DATA_READ_WRITE | ARM_MMU_SECT_TEX_0
+ }, { /* Periphery area */
+ .begin = 0xFC000000U,
+ .end = 0x00000000U,
.flags = ARMV7_MMU_DEVICE
}
};
-BSP_START_TEXT_SECTION static void setup_mmu_and_cache(void)
+BSP_START_TEXT_SECTION static void setup_mmu_and_cache( const uint32_t CPU_ID )
{
- uint32_t ctrl = arm_cp15_start_setup_mmu_and_cache(
- ARM_CP15_CTRL_A,
- ARM_CP15_CTRL_AFE | ARM_CP15_CTRL_Z
- );
-
- arm_cp15_start_setup_translation_table_and_enable_mmu_and_cache(
- ctrl,
- (uint32_t *) bsp_translation_table_base,
- ARM_MMU_DEFAULT_CLIENT_DOMAIN,
- &altcycv_mmu_config_table[0],
- RTEMS_ARRAY_SIZE(altcycv_mmu_config_table)
- );
+ uint32_t ctrl = arm_cp15_get_control();
+ const uint32_t CORES = BSPSTARTHOOKS_MIN(
+ (uintptr_t) bsp_processor_count,
+ rtems_configuration_get_maximum_processors() );
+
+ /* We expect the L1 caches and program flow prediction to be off */
+ assert( ( ctrl & ARM_CP15_CTRL_I ) == 0 );
+ assert( ( ctrl & ARM_CP15_CTRL_C ) == 0 );
+ assert( ( ctrl & ARM_CP15_CTRL_Z ) == 0 );
+
+ ctrl = arm_cp15_start_setup_mmu_and_cache(
+ ARM_CP15_CTRL_A | ARM_CP15_CTRL_M,
+ ARM_CP15_CTRL_AFE
+ );
+
+ if( CPU_ID == 0 ) {
+ arm_cp15_start_setup_translation_table(
+ (uint32_t *) bsp_translation_table_base,
+ ARM_MMU_DEFAULT_CLIENT_DOMAIN,
+ &altcycv_mmu_config_table[0],
+ RTEMS_ARRAY_SIZE( altcycv_mmu_config_table )
+ );
+ } else {
+ /* FIXME: Sharing the translation table between processors is brittle */
+ arm_cp15_set_translation_table_base((uint32_t *) bsp_translation_table_base);
+ }
+
+ /* Enable MMU */
+ ctrl |= ARM_CP15_CTRL_M;
+
+ arm_cp15_set_control( ctrl );
+
+ if( CPU_ID == (CORES - 1) ) {
+ /* Enable all cache levels for the last core */
+ rtems_cache_enable_instruction();
+ rtems_cache_enable_data();
+ } else {
+ /* Enable only L1 cache */
+ arm_cache_l1_enable_data();
+ arm_cache_l1_enable_instruction();
+ }
+
+ /* Enable flow control prediction aka. branch prediction */
+
+/* TODO: With the current network stack 06-Feb2014 in_checksum()
+ * becomes a severe performance bottle neck with branch prediction enabled
+ ctrl |= ARM_CP15_CTRL_Z;
+ arm_cp15_set_control(ctrl);*/
}
-BSP_START_TEXT_SECTION void bsp_start_hook_0(void)
+BSP_START_TEXT_SECTION void bsp_start_hook_0( void )
{
- arm_a9mpcore_start_hook_0();
+ uint32_t ctrl;
+ volatile a9mpcore_scu *scu = (volatile a9mpcore_scu *) BSP_ARM_A9MPCORE_SCU_BASE;
+ uint32_t cpu_id = arm_cortex_a9_get_multiprocessor_cpu_id();
+ const uint32_t CORES = BSPSTARTHOOKS_MIN(
+ (uintptr_t) bsp_processor_count,
+ rtems_configuration_get_maximum_processors() );
+
+ assert( cpu_id < CORES );
+
+ if( cpu_id < CORES ) {
+
+ (void)arm_cp15_mmu_disable( 32 );
+
+ ctrl = arm_cp15_get_control();
+ ctrl &= ~( ARM_CP15_CTRL_I | ARM_CP15_CTRL_C | ARM_CP15_CTRL_Z );
+ arm_cp15_set_control( ctrl );
+
+ if( cpu_id == 0 ) {
+ /* Enable Snoop Control Unit (SCU) */
+ arm_a9mpcore_start_scu_enable( scu );
+ }
+
+#ifdef RTEMS_SMP
+ /* Enable cache coherency support for this processor */
+ uint32_t actlr = arm_cp15_get_auxiliary_control();
+ actlr |= ARM_CORTEX_A9_ACTL_SMP;
+ arm_cp15_set_auxiliary_control(actlr);
+#endif
+
+ if (cpu_id == 0) {
+ arm_a9mpcore_start_scu_invalidate(cpu_id, 0xF);
+ }
+
+ setup_mmu_and_cache( cpu_id );
+
+#ifdef RTEMS_SMP
+ if (cpu_id != 0) {
+ arm_a9mpcore_start_set_vector_base();
+
+ arm_gic_irq_initialize_secondary_cpu();
+
+ arm_cp15_set_domain_access_control(
+ ARM_CP15_DAC_DOMAIN(ARM_MMU_DEFAULT_CLIENT_DOMAIN, ARM_CP15_DAC_CLIENT)
+ );
+ _SMP_Start_multitasking_on_secondary_processor();
+ }
+#endif
+ } else {
+ /* FIXME: Shutdown processor */
+ while (1) {
+ __asm__ volatile ("wfi");
+ }
+ }
}
-BSP_START_TEXT_SECTION void bsp_start_hook_1(void)
+BSP_START_TEXT_SECTION void bsp_start_hook_1( void )
{
+ uint32_t addr_filt_start;
+ uint32_t addr_filt_end;
+
+
+#ifndef DEBUG_ECC_ERROR
+
+ /* FIXME: Disable ECC. Preloader respectively UBoot enable ECC.
+ But they do run without interrupts. Our BSP will enable interrupts
+ and get spurious ECC error interrupts. Thus we disasable ECC
+ until we either know about a better handling or Altera has modified
+ it's SDRAM settings to not create possibly false ECC errors */
+ uint32_t ctlcfg = alt_read_word( ALT_SDR_CTL_CTLCFG_ADDR );
+ ctlcfg &= ALT_SDR_CTL_CTLCFG_ECCEN_CLR_MSK;
+ alt_write_word( ALT_SDR_CTL_CTLCFG_ADDR, ctlcfg );
+#endif
+
+ /* Perform L3 remap register programming first by setting the desired new MPU
+ address space 0 mapping. Assume BOOTROM in order to be able to boot the second core. */
+ alt_addr_space_remap(
+ ALT_ADDR_SPACE_MPU_ZERO_AT_BOOTROM,
+ ALT_ADDR_SPACE_NONMPU_ZERO_AT_SDRAM,
+ ALT_ADDR_SPACE_H2F_ACCESSIBLE,
+ ALT_ADDR_SPACE_LWH2F_ACCESSIBLE );
+
+ /* Next, adjust the L2 cache address filtering range. Set the start address to
+ the default reset value and retain the existing end address configuration. */
+ alt_l2_addr_filter_cfg_get( &addr_filt_start, &addr_filt_end );
+
+ if ( addr_filt_start != BSPSTART_L2_CACHE_ADDR_FILTERING_START_RESET ) {
+ alt_l2_addr_filter_cfg_set( BSPSTART_L2_CACHE_ADDR_FILTERING_START_RESET,
+ addr_filt_end );
+ }
+
arm_a9mpcore_start_hook_1();
bsp_start_copy_sections();
- setup_mmu_and_cache();
+
bsp_start_clear_bss();
-}
+}
\ No newline at end of file
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/startup/linkcmds.altcycv_devkit b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/linkcmds.altcycv_devkit
index 2bb0f82..60f99a0 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/startup/linkcmds.altcycv_devkit
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/linkcmds.altcycv_devkit
@@ -1,6 +1,18 @@
MEMORY {
- RAM_MMU : ORIGIN = 0x00100000, LENGTH = 16k
- RAM : ORIGIN = 0x00104000, LENGTH = 512M - 1M - 16k
+ RAM_MMU : ORIGIN = 0x00100000, LENGTH = 16k
+ NOCACHE : ORIGIN = 0x00200000, LENGTH = 1M
+ RAM : ORIGIN = 0x00300000, LENGTH = 1024M - 1M - 1M - 1M
+}
+
+SECTIONS {
+ .nocache : {
+ bsp_section_nocache_begin = .;
+ *(SORT(.bsp_nocache*))
+ bsp_section_nocache_end = .;
+ } > NOCACHE AT > NOCACHE
+ bsp_section_nocache_size = bsp_section_nocache_end - bsp_section_nocache_begin;
+ bsp_section_nocache_load_begin = LOADADDR (.nocache);
+ bsp_section_nocache_load_end = bsp_section_nocache_load_begin + bsp_section_nocache_size;
}
INCLUDE linkcmds.altcycv
diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/startup/nocache-heap.c b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/nocache-heap.c
new file mode 100644
index 0000000..0c5e526
--- /dev/null
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/startup/nocache-heap.c
@@ -0,0 +1,87 @@
+/**
+ * @file nocache-heap.c
+ *
+ * @ingroup [GROUP NAME]
+ *
+ * @brief Heap handling for uncached RAM
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.org/license/LICENSE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <bsp/linker-symbols.h>
+#include "../include/nocache-heap.h" /* TODO: Convert to #include <bsp/nocache-heap.h> */
+#include <rtems/score/heapimpl.h>
+
+/** @brief Uncached RAM pool
+ *
+ * Allocate the whole bsp_nocache for the nocache heap */
+static char nocache_pool[1024
+ * 1024] __attribute__( ( section( ".bsp_nocache" ) ) );
+
+/** @brief Nocache heap
+ *
+ * Heap control for the uncached RAM heap */
+static Heap_Control nocache_heap;
+
+/** @brief Init nocache heap
+ *
+ * Constructor for the uncached RAM heap
+ * @retval 0 on succuss, error code from errno.h on failure
+ */
+__attribute__( ( constructor ) ) int nocache_init_heap( void )
+{
+ int eno = 0;
+ uintptr_t heap_status = 0;
+
+
+ heap_status = _Heap_Initialize(
+ &nocache_heap,
+ &nocache_pool[0],
+ sizeof( nocache_pool ),
+ 0
+ );
+
+ if ( heap_status == 0 ) {
+ eno = ENOMEM;
+ }
+
+ return eno;
+}
+
+/** @brief Allocate uncached RAM
+ *
+ * Allocates RAM from the uncached heap
+ * @param size Number of bytes to be allocated
+ * @retval Pointer to the allocated RAM
+ */
+void *nocache_malloc( const size_t size )
+{
+ return _Heap_Allocate( &nocache_heap, size );
+}
+
+/** @brief Free uncached RAM
+ *
+ * Releases RAM from the uncached heap
+ * @param ptr Address of the RAM to be released
+ */
+void nocache_free( void *ptr )
+{
+ if ( ptr != NULL ) {
+ bool ok = _Heap_Free( &nocache_heap, ptr );
+ assert( ok );
+ }
+}
\ No newline at end of file
--
1.7.10.4
More information about the devel
mailing list