diff options
author | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2009-07-21 08:38:04 +0000 |
---|---|---|
committer | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2009-07-21 08:38:04 +0000 |
commit | d374492cc69fa8bd041852d868ae379b79c59ba4 (patch) | |
tree | 14fa506e5c9564844d5fa0436ae4d2d456a74dda | |
parent | Update to binutils-2.19.51-20090721. (diff) | |
download | rtems-d374492cc69fa8bd041852d868ae379b79c59ba4.tar.bz2 |
Update for MPC55XX changes
25 files changed, 3814 insertions, 700 deletions
diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/ChangeLog b/c/src/lib/libbsp/powerpc/mpc55xxevb/ChangeLog index 9571bc25ce..350323837d 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/ChangeLog +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/ChangeLog @@ -1,3 +1,12 @@ +2009-07-20 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * clock/clock-config.c, include/smsc9218i.h, network/smsc9218i.c: New + files. + * network/network.c: Removed file. + * Makefile.am, README, bsp_specs, preinstall.am, include/bsp.h, + startup/bspstart.c, startup/sd-card-init.c, tests/tests.c: Changes + throughout. + 2009-07-16 Joel Sherrill <joel.sherrill@oarcorp.com> * configure.ac: Rename BSP_BOOTCARD_OPTIONS to diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/Makefile.am b/c/src/lib/libbsp/powerpc/mpc55xxevb/Makefile.am index c1c00c35d0..ba126700e5 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/Makefile.am +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/Makefile.am @@ -36,7 +36,10 @@ nodist_include_HEADERS = include/bspopts.h ../../shared/tod.h \ ../../shared/include/coverhd.h include_bsp_HEADERS = include/mpc55xxevb.h \ include/irq-config.h \ + include/smsc9218i.h \ ../../shared/include/irq-generic.h \ + ../../shared/include/irq-info.h \ + ../../shared/include/utility.h \ ../shared/include/tictac.h # startup @@ -45,11 +48,13 @@ libbsp_a_SOURCES += ../../shared/bsplibc.c ../../shared/bsppost.c \ startup/bspstart.c startup/bspgetworkarea.c ../../shared/bsppretaskinghook.c # clock -libbsp_a_SOURCES += ../shared/clock/clock.c +libbsp_a_SOURCES += clock/clock-config.c # irq_generic libbsp_a_SOURCES += ../../shared/src/irq-generic.c \ - ../../shared/src/irq-legacy.c + ../../shared/src/irq-legacy.c \ + ../../shared/src/irq-info.c \ + ../../shared/src/irq-shell.c # tests libbsp_a_SOURCES += ../../shared/timerstub.c @@ -60,7 +65,7 @@ libbsp_a_SOURCES += tests/tests.c startup/sd-card-init.c # Network if HAS_NETWORKING noinst_PROGRAMS += network.rel -network_rel_SOURCES = network/network.c +network_rel_SOURCES = network/smsc9218i.c network_rel_CPPFLAGS = $(AM_CPPFLAGS) -D__INSIDE_RTEMS_BSD_TCPIP_STACK__ -D__BSD_VISIBLE network_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) endif @@ -73,6 +78,7 @@ libbsp_a_LIBADD = ../../../libcpu/@RTEMS_CPU@/shared/cpuIdent.rel \ ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/misc.rel \ ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/irq.rel \ ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/edma.rel \ + ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/emios.rel \ ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/dspi.rel \ ../../../libcpu/@RTEMS_CPU@/@RTEMS_CPU_MODEL@/esci.rel \ ../../../libcpu/@RTEMS_CPU@/@exceptions@/rtems-cpu.rel \ diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/README b/c/src/lib/libbsp/powerpc/mpc55xxevb/README index c0ad9b061d..476433d1ff 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/README +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/README @@ -8,7 +8,6 @@ CPU FAMILY: ppc CPU: PowerPC e200z6 COPROCESSORS: N/A MODE: 32 bit mode -DEBUG MONITOR: BAM PERIPHERALS =========== @@ -21,12 +20,13 @@ DMA: eDMA VIDEO: N/A SCSI: N/A NETWORKING: FEC (not yet supported) + SMSC9218I (external) SPI: DSPI DRIVER INFORMATION ================== -CLOCK DRIVER: Book E decrementer +CLOCK DRIVER: EMIOS channel 23 IOSUPP DRIVER: N/A SHMSUPP: N/A TIMER DRIVER: not yet supported @@ -47,7 +47,7 @@ NOTES BUS WIDTH: 32 bit Flash, 32 bit SDRAM FLASH: 3 MByte -RAM: 128 kByte SDRAM +INTERNAL RAM: 128 kByte SDRAM EXTERNAL RAM: 512 kByte SDRAM diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/bsp_specs b/c/src/lib/libbsp/powerpc/mpc55xxevb/bsp_specs index 855df565be..6675d7b79c 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/bsp_specs +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/bsp_specs @@ -4,10 +4,10 @@ *startfile: %{!qrtems: %(old_startfile)} \ -%{!nostdlib: %{qrtems: ecrti%O%s rtems_crti%O%s start.o%s}} +%{!nostdlib: %{qrtems: ecrti%O%s rtems_crti%O%s crtbegin.o%s start.o%s}} *endfile: -%{!qrtems: %(old_endfile)} %{qrtems: ecrtn.o%s} +%{!qrtems: %(old_endfile)} %{qrtems: crtend.o%s ecrtn.o%s} *link: %{!qrtems: %(old_link)} %{qrtems: -dc -dp -N} diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c b/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c new file mode 100644 index 0000000000..b9601d08d7 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/clock/clock-config.c @@ -0,0 +1,150 @@ +/** + * @file + * + * @ingroup mpc55xx + * + * @brief Clock driver configuration. + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <mpc55xx/regs.h> +#include <mpc55xx/emios.h> + +#include <rtems.h> + +#include <bsp.h> +#include <bsp/irq.h> + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <rtems/status-checks.h> + +#define MPC55XX_CLOCK_EMIOS_CHANNEL (MPC55XX_EMIOS_CHANNEL_NUMBER - 1) + +/* This is defined in clockdrv_shell.h */ +rtems_isr Clock_isr( rtems_vector_number vector); + +#define Clock_driver_support_at_tick() \ + do { \ + union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS; \ + csr.B.FLAG = 1; \ + EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CSR.R = csr.R; \ + } while (0) + +static void mpc55xx_clock_handler_install( void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + sc = mpc55xx_interrupt_handler_install( + MPC55XX_IRQ_EMIOS_GET_REQUEST( MPC55XX_CLOCK_EMIOS_CHANNEL), + "clock", + RTEMS_INTERRUPT_UNIQUE, + MPC55XX_INTC_MIN_PRIORITY, + (rtems_interrupt_handler) Clock_isr, + NULL + ); + RTEMS_CHECK_SC_VOID( sc, "install clock interrupt handler"); +} + +static void mpc55xx_clock_initialize( void) +{ + volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL]; + union EMIOS_CCR_tag ccr = MPC55XX_ZERO_FLAGS; + union EMIOS_CSR_tag csr = MPC55XX_ZERO_FLAGS; + unsigned prescaler = mpc55xx_emios_global_prescaler(); + uint64_t interval = ((uint64_t) bsp_clock_speed + * (uint64_t) rtems_configuration_get_microseconds_per_tick()) / 1000000; + + /* Apply prescaler */ + if (prescaler > 0) { + interval /= (uint64_t) prescaler; + } else { + RTEMS_SYSLOG_ERROR( "unexpected global eMIOS prescaler\n"); + } + + /* Check interval */ + if (interval == 0 || interval > MPC55XX_EMIOS_VALUE_MAX) { + interval = MPC55XX_EMIOS_VALUE_MAX; + RTEMS_SYSLOG_ERROR( "clock timer interval out of range\n"); + } + + /* Configure eMIOS channel */ + + /* Set channel in GPIO mode */ + ccr.B.MODE = MPC55XX_EMIOS_MODE_GPIO_INPUT; + regs->CCR.R = ccr.R; + + /* Clear status flags */ + csr.B.OVR = 1; + csr.B.OVFL = 1; + csr.B.FLAG = 1; + regs->CSR.R = csr.R; + + /* Set timer period */ + regs->CADR.R = (uint32_t) interval - 1; + + /* Set unused registers */ + regs->CBDR.R = 0; + regs->CCNTR.R = 0; + regs->ALTCADR.R = 0; + + /* Set control register */ + ccr.B.MODE = MPC55XX_EMIOS_MODE_MC_UP_INT_CLK; + ccr.B.UCPREN = 1; + ccr.B.FEN = 1; + ccr.B.FREN = 1; + regs->CCR.R = ccr.R; +} + +static void mpc55xx_clock_cleanup( void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + volatile struct EMIOS_CH_tag *regs = &EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL]; + union EMIOS_CCR_tag ccr = MPC55XX_ZERO_FLAGS; + + /* Set channel in GPIO mode */ + ccr.B.MODE = MPC55XX_EMIOS_MODE_GPIO_INPUT; + regs->CCR.R = ccr.R; + + /* Remove interrupt handler */ + sc = rtems_interrupt_handler_remove( + MPC55XX_IRQ_EMIOS_GET_REQUEST( MPC55XX_CLOCK_EMIOS_CHANNEL), + (rtems_interrupt_handler) Clock_isr, + NULL + ); + RTEMS_CHECK_SC_VOID( sc, "remove clock interrupt handler"); +} + +static uint32_t mpc55xx_clock_nanoseconds_since_last_tick( void) +{ + uint64_t clicks = EMIOS.CH [MPC55XX_CLOCK_EMIOS_CHANNEL].CCNTR.R; + uint64_t clock = bsp_clock_speed; + uint64_t ns = (clicks * 1000000000) / clock; + + return (uint32_t) ns; +} + +#define Clock_driver_support_initialize_hardware() mpc55xx_clock_initialize() + +#define Clock_driver_support_install_isr( isr, old_isr) \ + mpc55xx_clock_handler_install() + +#define Clock_driver_support_shutdown_hardware() mpc55xx_clock_cleanup() + +#define Clock_driver_nanoseconds_since_last_tick \ + mpc55xx_clock_nanoseconds_since_last_tick + +/* Include shared source clock driver code */ +#include "../../../../libbsp/shared/clockdrv_shell.h" diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/include/bsp.h b/c/src/lib/libbsp/powerpc/mpc55xxevb/include/bsp.h index 661107f967..57a3c81d48 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/include/bsp.h +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/include/bsp.h @@ -43,7 +43,20 @@ extern unsigned int bsp_clock_speed; /** @brief Time base clicks per micro second */ extern uint32_t bsp_clicks_per_usec; -rtems_status_code mpc55xx_sd_card_init( void); +rtems_status_code mpc55xx_sd_card_init( bool mount); + +/* Network driver configuration */ + +struct rtems_bsdnet_ifconfig; + +int smsc9218i_attach_detach( + struct rtems_bsdnet_ifconfig *config, + int attaching +); + +#define RTEMS_BSP_NETWORK_DRIVER_ATTACH smsc9218i_attach_detach + +#define RTEMS_BSP_NETWORK_DRIVER_NAME "eth0" #endif /* ASM */ diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/include/smsc9218i.h b/c/src/lib/libbsp/powerpc/mpc55xxevb/include/smsc9218i.h new file mode 100644 index 0000000000..9086a1b215 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/include/smsc9218i.h @@ -0,0 +1,795 @@ +/** + * @file + * + * @ingroup mpc55xx + * + * @brief SMSC - LAN9218i + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +/** + * @name Memory Map + * @{ + */ + +typedef struct { + uint32_t rx_fifo_data; + uint32_t rx_fifo_data_aliases [7]; + uint32_t tx_fifo_data; + uint32_t tx_fifo_data_aliases [7]; + uint32_t rx_fifo_status; + uint32_t rx_fifo_status_peek; + uint32_t tx_fifo_status; + uint32_t tx_fifo_status_peek; + uint32_t id_rev; + uint32_t irq_cfg; + uint32_t int_sts; + uint32_t int_en; + uint32_t reserved_0; + uint32_t byte_test; + uint32_t fifo_int; + uint32_t rx_cfg; + uint32_t tx_cfg; + uint32_t hw_cfg; + uint32_t rx_dp_ctl; + uint32_t rx_fifo_inf; + uint32_t tx_fifo_inf; + uint32_t pmt_ctrl; + uint32_t gpio_cfg; + uint32_t gpt_cfg; + uint32_t gpt_cnt; + uint32_t reserved_1; + uint32_t word_swap; + uint32_t free_run; + uint32_t rx_drop; + uint32_t mac_csr_cmd; + uint32_t mac_csr_data; + uint32_t afc_cfg; + uint32_t e2p_cmd; + uint32_t e2p_data; +} smsc9218i_registers; + +volatile smsc9218i_registers *const smsc9218i = (volatile smsc9218i_registers *) 0x3fff8000; + +/** @} */ + +#define SMSC9218I_BIT_POS(pos) \ + ((pos) > 15 ? \ + ((pos) > 23 ? (pos) - 24 : (pos) - 8) \ + : ((pos) > 7 ? (pos) + 8 : (pos) + 24)) + +#define SMSC9218I_FLAG(pos) \ + (1U << SMSC9218I_BIT_POS(pos)) + +#define SMSC9218I_FIELD_8(val, pos) \ + (((val) & 0xff) << SMSC9218I_BIT_POS(pos)) + +#define SMSC9218I_GET_FIELD_8(reg, pos) \ + (((reg) >> SMSC9218I_BIT_POS(pos)) & 0xff) + +#define SMSC9218I_FIELD_16(val, pos) \ + (SMSC9218I_FIELD_8((val) >> 8, (pos) + 8) \ + | SMSC9218I_FIELD_8((val), pos)) + +#define SMSC9218I_GET_FIELD_16(reg, pos) \ + ((SMSC9218I_GET_FIELD_8(reg, (pos) + 8) << 8) \ + | SMSC9218I_GET_FIELD_8(reg, pos)) + +#define SMSC9218I_SWAP(val) \ + ((((val) >> 24) & 0xff) \ + | ((((val) >> 16) & 0xff) << 8) \ + | ((((val) >> 8) & 0xff) << 16) \ + | (((val) & 0xff) << 24)) + +/** + * @name Receive Status + * @{ + */ + +#define SMSC9218I_RX_STS_FILTER_FAIL SMSC9218I_FLAG(30) +#define SMSC9218I_RX_STS_GET_LENGTH(reg) (SMSC9218I_GET_FIELD_16(reg, 16) & 0x3fff) +#define SMSC9218I_RX_STS_ERROR SMSC9218I_FLAG(15) +#define SMSC9218I_RX_STS_BROADCAST SMSC9218I_FLAG(13) +#define SMSC9218I_RX_STS_ERROR_LENGTH SMSC9218I_FLAG(12) +#define SMSC9218I_RX_STS_ERROR_RUNT_FRAME SMSC9218I_FLAG(11) +#define SMSC9218I_RX_STS_MULTICAST SMSC9218I_FLAG(10) +#define SMSC9218I_RX_STS_ERROR_TOO_LONG SMSC9218I_FLAG(7) +#define SMSC9218I_RX_STS_ERROR_COLLISION SMSC9218I_FLAG(6) +#define SMSC9218I_RX_STS_TYPE SMSC9218I_FLAG(5) +#define SMSC9218I_RX_STS_WATCHDOG SMSC9218I_FLAG(4) +#define SMSC9218I_RX_STS_ERROR_MII SMSC9218I_FLAG(3) +#define SMSC9218I_RX_STS_DRIBBLING_BIT SMSC9218I_FLAG(2) +#define SMSC9218I_RX_STS_ERROR_CRC SMSC9218I_FLAG(1) + +/** @} */ + +/** + * @name Transmit Status + * @{ + */ + +#define SMSC9218I_TX_STS_GET_TAG(reg) SMSC9218I_GET_FIELD_16(reg, 16) +#define SMSC9218I_TX_STS_ERROR SMSC9218I_FLAG(15) +#define SMSC9218I_TX_STS_ERROR_LOSS_OF_CARRIER SMSC9218I_FLAG(11) +#define SMSC9218I_TX_STS_ERROR_NO_CARRIER SMSC9218I_FLAG(10) +#define SMSC9218I_TX_STS_ERROR_LATE_COLLISION SMSC9218I_FLAG(9) +#define SMSC9218I_TX_STS_ERROR_EXCESSIVE_COLLISIONS SMSC9218I_FLAG(8) +#define SMSC9218I_TX_STS_ERROR_EXCESSIVE_DEFERRAL SMSC9218I_FLAG(2) +#define SMSC9218I_TX_STS_ERROR_DEFERRED SMSC9218I_FLAG(0) + +/** @} */ + +/** + * @name Transmit Command A + * @{ + */ + +#define SMSC9218I_TX_A_IOC SMSC9218I_FLAG(31) +#define SMSC9218I_TX_A_END_ALIGN_4 0 +#define SMSC9218I_TX_A_END_ALIGN_16 SMSC9218I_FLAG(24) +#define SMSC9218I_TX_A_END_ALIGN_32 SMSC9218I_FLAG(25) +#define SMSC9218I_TX_A_DOFF(val) SMSC9218I_FIELD_8(val, 16) +#define SMSC9218I_TX_A_FIRST SMSC9218I_FLAG(13) +#define SMSC9218I_TX_A_LAST SMSC9218I_FLAG(12) +#define SMSC9218I_TX_A_FRAGMENT_LENGTH(val) SMSC9218I_FIELD_16(val, 0) + +/** @} */ + +/** + * @name Transmit Command B + * @{ + */ + +#define SMSC9218I_TX_B_TAG(val) SMSC9218I_FIELD_16(val, 16) +#define SMSC9218I_TX_B_GET_TAG(reg) SMSC9218I_GET_FIELD_16(reg, 16) +#define SMSC9218I_TX_B_DISABLE_CRC SMSC9218I_FLAG(13) +#define SMSC9218I_TX_B_DISABLE_PAD SMSC9218I_FLAG(12) +#define SMSC9218I_TX_B_FRAME_LENGTH(val) SMSC9218I_FIELD_16(val, 0) + +/** @} */ + +/** + * @name Chip ID and Revision + * @{ + */ + +#define SMSC9218I_ID_REV_GET_ID(reg) SMSC9218I_GET_FIELD_16(reg, 16) +#define SMSC9218I_ID_REV_GET_REV(reg) SMSC9218I_GET_FIELD_16(reg, 0) +#define SMSC9218I_ID_REV_ID_CHIP_118 0x0118U +#define SMSC9218I_ID_REV_ID_CHIP_218 0x118aU + +/** @} */ + +/** + * @name Interrupt Configuration + * @{ + */ + +#define SMSC9218I_IRQ_CFG_INT_DEAS(val) SMSC9218I_FIELD_8(val, 24) +#define SMSC9218I_IRQ_CFG_GET_INT_DEAS(reg) SMSC9218I_GET_FIELD_8(reg, 24) +#define SMSC9218I_IRQ_CFG_INT_DEAS_CLR SMSC9218I_FLAG(14) +#define SMSC9218I_IRQ_CFG_INT_DEAS_STS SMSC9218I_FLAG(13) +#define SMSC9218I_IRQ_CFG_IRQ_INT SMSC9218I_FLAG(12) +#define SMSC9218I_IRQ_CFG_IRQ_EN SMSC9218I_FLAG(8) +#define SMSC9218I_IRQ_CFG_IRQ_POL SMSC9218I_FLAG(4) +#define SMSC9218I_IRQ_CFG_IRQ_TYPE SMSC9218I_FLAG(0) + +/** @} */ + +/** + * @name Interrupt Status + * @{ + */ + +#define SMSC9218I_INT_STS_SW SMSC9218I_FLAG(31) +#define SMSC9218I_INT_STS_TXSTOP SMSC9218I_FLAG(25) +#define SMSC9218I_INT_STS_RXSTOP SMSC9218I_FLAG(24) +#define SMSC9218I_INT_STS_RXDFH SMSC9218I_FLAG(23) +#define SMSC9218I_INT_STS_TIOC SMSC9218I_FLAG(21) +#define SMSC9218I_INT_STS_RXD SMSC9218I_FLAG(20) +#define SMSC9218I_INT_STS_GPT SMSC9218I_FLAG(19) +#define SMSC9218I_INT_STS_PHY SMSC9218I_FLAG(18) +#define SMSC9218I_INT_STS_PME SMSC9218I_FLAG(17) +#define SMSC9218I_INT_STS_TXSO SMSC9218I_FLAG(16) +#define SMSC9218I_INT_STS_RWT SMSC9218I_FLAG(15) +#define SMSC9218I_INT_STS_RXE SMSC9218I_FLAG(14) +#define SMSC9218I_INT_STS_TXE SMSC9218I_FLAG(13) +#define SMSC9218I_INT_STS_TDFO SMSC9218I_FLAG(10) +#define SMSC9218I_INT_STS_TDFA SMSC9218I_FLAG(9) +#define SMSC9218I_INT_STS_TSFF SMSC9218I_FLAG(8) +#define SMSC9218I_INT_STS_TSFL SMSC9218I_FLAG(7) +#define SMSC9218I_INT_STS_RSFF SMSC9218I_FLAG(4) +#define SMSC9218I_INT_STS_RSFL SMSC9218I_FLAG(3) +#define SMSC9218I_INT_STS_GPIO2 SMSC9218I_FLAG(2) +#define SMSC9218I_INT_STS_GPIO1 SMSC9218I_FLAG(1) +#define SMSC9218I_INT_STS_GPIO0 SMSC9218I_FLAG(0) + +/** @} */ + +/** + * @name Interrupt Enable + * @{ + */ + +#define SMSC9218I_INT_EN_SW SMSC9218I_FLAG(31) +#define SMSC9218I_INT_EN_TXSTOP SMSC9218I_FLAG(25) +#define SMSC9218I_INT_EN_RXSTOP SMSC9218I_FLAG(24) +#define SMSC9218I_INT_EN_RXDFH SMSC9218I_FLAG(23) +#define SMSC9218I_INT_EN_TIOC SMSC9218I_FLAG(21) +#define SMSC9218I_INT_EN_RXD SMSC9218I_FLAG(20) +#define SMSC9218I_INT_EN_GPT SMSC9218I_FLAG(19) +#define SMSC9218I_INT_EN_PHY SMSC9218I_FLAG(18) +#define SMSC9218I_INT_EN_PME SMSC9218I_FLAG(17) +#define SMSC9218I_INT_EN_TXSO SMSC9218I_FLAG(16) +#define SMSC9218I_INT_EN_RWT SMSC9218I_FLAG(15) +#define SMSC9218I_INT_EN_RXE SMSC9218I_FLAG(14) +#define SMSC9218I_INT_EN_TXE SMSC9218I_FLAG(13) +#define SMSC9218I_INT_EN_TDFO SMSC9218I_FLAG(10) +#define SMSC9218I_INT_EN_TDFA SMSC9218I_FLAG(9) +#define SMSC9218I_INT_EN_TSFF SMSC9218I_FLAG(8) +#define SMSC9218I_INT_EN_TSFL SMSC9218I_FLAG(7) +#define SMSC9218I_INT_EN_RSFF SMSC9218I_FLAG(4) +#define SMSC9218I_INT_EN_RSFL SMSC9218I_FLAG(3) +#define SMSC9218I_INT_EN_GPIO2 SMSC9218I_FLAG(2) +#define SMSC9218I_INT_EN_GPIO1 SMSC9218I_FLAG(1) +#define SMSC9218I_INT_EN_GPIO0 SMSC9218I_FLAG(0) + +/** @} */ + +/** + * @name Byte Order Testing + * @{ + */ + +#define SMSC9218I_BYTE_TEST SMSC9218I_SWAP(0x87654321U) + +/** @} */ + +/** + * @name FIFO Level Interrupts + * @{ + */ + +#define SMSC9218I_FIFO_INT_TDAL(val) SMSC9218I_FIELD_8(val, 24) +#define SMSC9218I_FIFO_INT_GET_TDAL(reg) SMSC9218I_GET_FIELD_8(reg, 24) +#define SMSC9218I_FIFO_INT_TSL(val) SMSC9218I_FIELD_8(val, 16) +#define SMSC9218I_FIFO_INT_GET_TSL(reg) SMSC9218I_GET_FIELD_8(reg, 16) +#define SMSC9218I_FIFO_INT_RSL(val) SMSC9218I_FIELD_8(val, 0) +#define SMSC9218I_FIFO_INT_GET_RSL(reg) SMSC9218I_GET_FIELD_8(reg, 0) + +/** @} */ + +/** + * @name Receive Configuration + * @{ + */ + +#define SMSC9218I_RX_CFG_END_ALIGN_4 0 +#define SMSC9218I_RX_CFG_END_ALIGN_16 SMSC9218I_FLAG(30) +#define SMSC9218I_RX_CFG_END_ALIGN_32 SMSC9218I_FLAG(31) +#define SMSC9218I_RX_CFG_DMA_CNT(val) SMSC9218I_FIELD_8(val, 24) +#define SMSC9218I_RX_CFG_GET_DMA_CNT(reg) SMSC9218I_GET_FIELD_8(reg, 24) +#define SMSC9218I_RX_CFG_DUMP SMSC9218I_FLAG(15) +#define SMSC9218I_RX_CFG_DOFF(val) SMSC9218I_FIELD_8(val, 8) +#define SMSC9218I_RX_CFG_GET_DOFF(reg) SMSC9218I_GET_FIELD_8(reg, 8) + +/** @} */ + +/** + * @name Transmit Configuration + * @{ + */ + +#define SMSC9218I_TX_CFG_SDUMP SMSC9218I_FLAG(15) +#define SMSC9218I_TX_CFG_DDUMP SMSC9218I_FLAG(14) +#define SMSC9218I_TX_CFG_SAO SMSC9218I_FLAG(2) +#define SMSC9218I_TX_CFG_ON SMSC9218I_FLAG(1) +#define SMSC9218I_TX_CFG_STOP SMSC9218I_FLAG(0) + +/** @} */ + +/** + * @name Hardware Configuration + * @{ + */ + +#define SMSC9218I_HW_CFG_AMDIX SMSC9218I_FLAG(24) +#define SMSC9218I_HW_CFG_MBO SMSC9218I_FLAG(20) +#define SMSC9218I_HW_CFG_TX_FIF_SZ(val) SMSC9218I_FIELD_8(val, 16) +#define SMSC9218I_HW_CFG_GET_TX_FIF_SZ(reg) SMSC9218I_GET_FIELD_8(reg, 16) +#define SMSC9218I_HW_CFG_BITMD_32 SMSC9218I_FLAG(2) +#define SMSC9218I_HW_CFG_SRST_TO SMSC9218I_FLAG(1) +#define SMSC9218I_HW_CFG_SRST SMSC9218I_FLAG(0) + +/** @} */ + +/** + * @name Receive Datapath Control + * @{ + */ + +#define SMSC9218I_RX_DP_CTRL_FFWD SMSC9218I_FLAG(31) + +/** @} */ + +/** + * @name Receive FIFO Information + * @{ + */ + +#define SMSC9218I_RX_FIFO_INF_GET_SUSED(reg) SMSC9218I_GET_FIELD_8(reg, 16) +#define SMSC9218I_RX_FIFO_INF_GET_DUSED(reg) SMSC9218I_GET_FIELD_16(reg, 0) + +/** @} */ + +/** + * @name Transmit FIFO Information + * @{ + */ + +#define SMSC9218I_TX_FIFO_INF_GET_SUSED(reg) SMSC9218I_GET_FIELD_8(reg, 16) +#define SMSC9218I_TX_FIFO_INF_GET_FREE(reg) SMSC9218I_GET_FIELD_16(reg, 0) + +/** @} */ + +/** + * @name Power Management Control + * @{ + */ + +#define SMSC9218I_PMT_CTRL_PM_MODE_D0 0 +#define SMSC9218I_PMT_CTRL_PM_MODE_D1 SMSC9218I_FLAG(12) +#define SMSC9218I_PMT_CTRL_PM_MODE_D2 SMSC9218I_FLAG(13) +#define SMSC9218I_PMT_CTRL_PHY_RST SMSC9218I_FLAG(10) +#define SMSC9218I_PMT_CTRL_WOL_EN SMSC9218I_FLAG(9) +#define SMSC9218I_PMT_CTRL_ED_EN SMSC9218I_FLAG(8) +#define SMSC9218I_PMT_CTRL_PME_TYPE_PUPU SMSC9218I_FLAG(6) +#define SMSC9218I_PMT_CTRL_WUPS_NO 0 +#define SMSC9218I_PMT_CTRL_WUPS_ENERGY SMSC9218I_FLAG(4) +#define SMSC9218I_PMT_CTRL_WUPS_MAGIC SMSC9218I_FLAG(5) +#define SMSC9218I_PMT_CTRL_PME_IND SMSC9218I_FLAG(3) +#define SMSC9218I_PMT_CTRL_PME_POL SMSC9218I_FLAG(2) +#define SMSC9218I_PMT_CTRL_PME_EN SMSC9218I_FLAG(1) +#define SMSC9218I_PMT_CTRL_READY SMSC9218I_FLAG(0) + +/** @} */ + +/** + * @name General Purpose IO Configuration + * @{ + */ + +#define SMSC9218I_GPIO_CFG_LED3 SMSC9218I_FLAG(30) +#define SMSC9218I_GPIO_CFG_LED2 SMSC9218I_FLAG(29) +#define SMSC9218I_GPIO_CFG_LED1 SMSC9218I_FLAG(28) +#define SMSC9218I_GPIO_CFG_GPIO2_INT_POL SMSC9218I_FLAG(26) +#define SMSC9218I_GPIO_CFG_GPIO1_INT_POL SMSC9218I_FLAG(25) +#define SMSC9218I_GPIO_CFG_GPIO0_INT_POL SMSC9218I_FLAG(24) +#define SMSC9218I_GPIO_CFG_GPIOBUF2 SMSC9218I_FLAG(18) +#define SMSC9218I_GPIO_CFG_GPIOBUF1 SMSC9218I_FLAG(17) +#define SMSC9218I_GPIO_CFG_GPIOBUF0 SMSC9218I_FLAG(16) +#define SMSC9218I_GPIO_CFG_GPIODIR2 SMSC9218I_FLAG(10) +#define SMSC9218I_GPIO_CFG_GPIODIR1 SMSC9218I_FLAG(9) +#define SMSC9218I_GPIO_CFG_GPIODIR0 SMSC9218I_FLAG(8) +#define SMSC9218I_GPIO_CFG_GPO4 SMSC9218I_FLAG(4) +#define SMSC9218I_GPIO_CFG_GPO3 SMSC9218I_FLAG(3) +#define SMSC9218I_GPIO_CFG_GPIO0 SMSC9218I_FLAG(0) +#define SMSC9218I_GPIO_CFG_GPIO2 SMSC9218I_FLAG(2) +#define SMSC9218I_GPIO_CFG_GPIO1 SMSC9218I_FLAG(1) + +/** @} */ + +/** + * @name General Purpose Timer Configuration + * @{ + */ + +#define SMSC9218I_GPT_CFG_TIMER_EN SMSC9218I_FLAG(29) +#define SMSC9218I_GPT_CFG_LOAD(val) SMSC9218I_FIELD_16(val, 0) +#define SMSC9218I_GPT_CFG_GET_LOAD(reg) SMSC9218I_GET_FIELD_16(reg, 0) + +/** @} */ + +/** + * @name General Purpose Timer Count + * @{ + */ + +#define SMSC9218I_GPT_CNT_GET_CNT SMSC9218I_GET_FIELD_16(reg, 0) + +/** @} */ + +/** + * @name Word Swap + * @{ + */ + +#define SMSC9218I_ENDIAN_BIG 0xffffffffU + +/** @} */ + +/** + * @name Free Run Counter + * @{ + */ + +#define SMSC9218I_FREE_RUN_GET(reg) SMSC9218I_SWAP(reg) + +/** @} */ + +/** + * @name Receiver Dropped Frames Counter + * @{ + */ + +#define SMSC9218I_RX_DROP_GET(reg) SMSC9218I_SWAP(reg) + +/** @} */ + +/** + * @name MAC Control and Status Synchronizer Command + * @{ + */ + +#define SMSC9218I_MAC_CSR_CMD_BUSY SMSC9218I_FLAG(31) +#define SMSC9218I_MAC_CSR_CMD_READ SMSC9218I_FLAG(30) +#define SMSC9218I_MAC_CSR_CMD_ADDR(val) SMSC9218I_FIELD_8(val, 0) +#define SMSC9218I_MAC_CSR_CMD_GET_ADDR(reg) SMSC9218I_GET_FIELD_8(reg, 0) + +/** @} */ + +/** + * @name MAC Control Register + * @{ + */ + +#define SMSC9218I_MAC_CR 0x00000001U +#define SMSC9218I_MAC_CR_RXALL 0x80000000U +#define SMSC9218I_MAC_CR_HBDIS 0x10000000U +#define SMSC9218I_MAC_CR_RCVOWN 0x00800000U +#define SMSC9218I_MAC_CR_LOOPBK 0x00200000U +#define SMSC9218I_MAC_CR_FDPX 0x00100000U +#define SMSC9218I_MAC_CR_MCPAS 0x00080000U +#define SMSC9218I_MAC_CR_PRMS 0x00040000U +#define SMSC9218I_MAC_CR_INVFILT 0x00020000U +#define SMSC9218I_MAC_CR_PASSBAD 0x00010000U +#define SMSC9218I_MAC_CR_HFILT 0x00008000U +#define SMSC9218I_MAC_CR_HPFILT 0x00002000U +#define SMSC9218I_MAC_CR_LCOLL 0x00001000U +#define SMSC9218I_MAC_CR_BCAST 0x00000800U +#define SMSC9218I_MAC_CR_DISRTY 0x00000400U +#define SMSC9218I_MAC_CR_PADSTR 0x00000100U +#define SMSC9218I_MAC_CR_BOLMT_MASK 0x000000c0U +#define SMSC9218I_MAC_CR_BOLMT_10 0x00000000U +#define SMSC9218I_MAC_CR_BOLMT_8 0x00000040U +#define SMSC9218I_MAC_CR_BOLMT_4 0x00000080U +#define SMSC9218I_MAC_CR_BOLMT_1 0x000000c0U +#define SMSC9218I_MAC_CR_DFCHK 0x00000020U +#define SMSC9218I_MAC_CR_TXEN 0x00000008U +#define SMSC9218I_MAC_CR_RXEN 0x00000004U + +/** @} */ + +/** + * @name MAC Address High + * @{ + */ + +#define SMSC9218I_MAC_ADDRH 0x00000002U +#define SMSC9218I_MAC_ADDRH_MASK 0x0000ffffU + +/** @} */ + +/** + * @name MAC Address Low + * @{ + */ + +#define SMSC9218I_MAC_ADDRL 0x00000003U +#define SMSC9218I_MAC_ADDRL_MASK 0xffffffffU + +/** @} */ + +/** + * @name Multicast Hash Table High + * @{ + */ + +#define SMSC9218I_MAC_HASHH 0x00000004U +#define SMSC9218I_MAC_HASHH_MASK 0xffffffffU + +/** @} */ + +/** + * @name Multicast Hash Table Low + * @{ + */ + +#define SMSC9218I_MAC_HASHL 0x00000005U +#define SMSC9218I_MAC_HASHL_MASK 0xffffffffU + +/** @} */ + +/** + * @name MII Access + * @{ + */ + +#define SMSC9218I_MAC_MII_ACC 0x00000006U +#define SMSC9218I_MAC_MII_ACC_PHY_DEFAULT (1U << 11) +#define SMSC9218I_MAC_MII_ACC_WRITE (1U << 1) +#define SMSC9218I_MAC_MII_ACC_BUSY (1U << 0) +#define SMSC9218I_MAC_MII_ACC_ADDR(addr) ((addr) << 6) + +/** @} */ + +/** + * @name MII Data + * @{ + */ + +#define SMSC9218I_MAC_MII_DATA 0x00000007U + +/** @} */ + +/** + * @name Flow Control + * @{ + */ + +#define SMSC9218I_MAC_FLOW 0x00000008U +#define SMSC9218I_MAC_FLOW_FCPT_MASK 0xffff0000U +#define SMSC9218I_MAC_FLOW_FCPASS 0x00000004U +#define SMSC9218I_MAC_FLOW_FCEN 0x00000002U +#define SMSC9218I_MAC_FLOW_FCBSY 0x00000001U + +/** @} */ + +/** + * @name VLAN1 Tag + * @{ + */ + +#define SMSC9218I_MAC_VLAN1 0x00000009U + +/** @} */ + +/** + * @name VLAN2 Tag + * @{ + */ + +#define SMSC9218I_MAC_VLAN2 0x0000000aU + +/** @} */ + +/** + * @name Wake-up Frame Filter + * @{ + */ + +#define SMSC9218I_MAC_WUFF 0x0000000bU + +/** @} */ + +/** + * @name Wake-up Control and Status + * @{ + */ + +#define SMSC9218I_MAC_WUCSR 0x0000000cU +#define SMSC9218I_MAC_WUCSR_GUE 0x00000200U +#define SMSC9218I_MAC_WUCSR_WUFR 0x00000040U +#define SMSC9218I_MAC_WUCSR_MPR 0x00000020U +#define SMSC9218I_MAC_WUCSR_WUEN 0x00000004U +#define SMSC9218I_MAC_WUCSR_MPEN 0x00000002U + +/** @} */ + +/** + * @name Basic Control + * @{ + */ + +#define SMSC9218I_PHY_BCR 0x00000000U +#define SMSC9218I_PHY_BCR_RST 0x00008000U +#define SMSC9218I_PHY_BCR_LOOPBK 0x00004000U +#define SMSC9218I_PHY_BCR_SS 0x00002000U +#define SMSC9218I_PHY_BCR_ANE 0x00001000U +#define SMSC9218I_PHY_BCR_PWRDN 0x00000800U +#define SMSC9218I_PHY_BCR_RSTAN 0x00000200U +#define SMSC9218I_PHY_BCR_FDPLX 0x00000100U +#define SMSC9218I_PHY_BCR_COLLTST 0x00000080U + +/** @} */ + +/** + * @name Basic Status + * @{ + */ + +#define SMSC9218I_PHY_BSR 0x00000001U +#define SMSC9218I_PHY_BSR_100_T4_ABLE 0x00008000U +#define SMSC9218I_PHY_BSR_100_TX_FDPLX 0x00004000U +#define SMSC9218I_PHY_BSR_100_TX_HDPLX 0x00002000U +#define SMSC9218I_PHY_BSR_10_FDPLX 0x00001000U +#define SMSC9218I_PHY_BSR_10_HDPLX 0x00000800U +#define SMSC9218I_PHY_BSR_ANC 0x00000020U +#define SMSC9218I_PHY_BSR_REM_FAULT 0x00000010U +#define SMSC9218I_PHY_BSR_AN_ABLE 0x00000008U +#define SMSC9218I_PHY_BSR_LINK_STATUS 0x00000004U +#define SMSC9218I_PHY_BSR_JAB_DET 0x00000002U +#define SMSC9218I_PHY_BSR_EXT_CAP 0x00000001U + +/** @} */ + +/** + * @name PHY Identifier 1 + * @{ + */ + +#define SMSC9218I_PHY_ID1 0x00000002U +#define SMSC9218I_PHY_ID1_MASK 0x0000ffffU +#define SMSC9218I_PHY_ID1_LAN9118 0x00000007U +#define SMSC9218I_PHY_ID1_LAN9218 (PHY_ID1_LAN9118) + +/** @} */ + +/** + * @name PHY Identifier 2 + * @{ + */ + +#define SMSC9218I_PHY_ID2 0x00000003U +#define SMSC9218I_PHY_ID2_MASK 0x0000ffffU +#define SMSC9218I_PHY_ID2_MODEL_MASK 0x000003f0U +#define SMSC9218I_PHY_ID2_REV_MASK 0x0000000fU +#define SMSC9218I_PHY_ID2_LAN9118 0x0000c0d1U +#define SMSC9218I_PHY_ID2_LAN9218 0x0000c0c3U + +/** @} */ + +/** + * @name Auto-negotiation Advertisment + * @{ + */ + +#define SMSC9218I_PHY_ANAR 0x00000004U +#define SMSC9218I_PHY_ANAR_NXTPG_CAP 0x00008000U +#define SMSC9218I_PHY_ANAR_REM_FAULT 0x00002000U +#define SMSC9218I_PHY_ANAR_PAUSE_OP_MASK 0x00000c00U +#define SMSC9218I_PHY_ANAR_PAUSE_OP_NONE 0x00000000U +#define SMSC9218I_PHY_ANAR_PAUSE_OP_ASLP 0x00000400U +#define SMSC9218I_PHY_ANAR_PAUSE_OP_SLP 0x00000800U +#define SMSC9218I_PHY_ANAR_PAUSE_OP_BOTH 0x00000c00U +#define SMSC9218I_PHY_ANAR_100_T4_ABLE 0x00000200U +#define SMSC9218I_PHY_ANAR_100_TX_FDPLX 0x00000100U +#define SMSC9218I_PHY_ANAR_100_TX_ABLE 0x00000080U +#define SMSC9218I_PHY_ANAR_10_FDPLX 0x00000040U +#define SMSC9218I_PHY_ANAR_10_ABLE 0x00000020U + +/** @} */ + +/** + * @name Auto-negotiation Link Partner Ability + * @{ + */ + +#define SMSC9218I_PHY_ANLPAR 0x00000005U +#define SMSC9218I_PHY_ANLPAR_NXTPG_CAP 0x00008000U +#define SMSC9218I_PHY_ANLPAR_ACK 0x00004000U +#define SMSC9218I_PHY_ANLPAR_REM_FAULT 0x00002000U +#define SMSC9218I_PHY_ANLPAR_PAUSE_CAP 0x00000400U +#define SMSC9218I_PHY_ANLPAR_100_T4_ABLE 0x00000200U +#define SMSC9218I_PHY_ANLPAR_100_TX_FDPLX 0x00000100U +#define SMSC9218I_PHY_ANLPAR_100_TX_ABLE 0x00000080U +#define SMSC9218I_PHY_ANLPAR_10_FDPLX 0x00000040U +#define SMSC9218I_PHY_ANLPAR_10_ABLE 0x00000020U + +/** @} */ + +/** + * @name Auto-negotiation Expansion + * @{ + */ + +#define SMSC9218I_PHY_ANEXPR 0x00000006U +#define SMSC9218I_PHY_ANEXPR_PARDET_FAULT 0x00000010U +#define SMSC9218I_PHY_ANEXPR_LP_NXTPG_CAP 0x00000008U +#define SMSC9218I_PHY_ANEXPR_NXTPG_CAP 0x00000004U +#define SMSC9218I_PHY_ANEXPR_NEWPG_REC 0x00000002U +#define SMSC9218I_PHY_ANEXPR_LP_AN_ABLE 0x00000001U + +/** @} */ + +/** + * @name Mode Control and Status + * @{ + */ + +#define SMSC9218I_PHY_MCSR 0x00000011U +#define SMSC9218I_PHY_MCSR_EDPWRDOWN 0x00002000U +#define SMSC9218I_PHY_MCSR_ENERGYON 0x00000002U + +/** @} */ + +/** + * @name Special Modes + * @{ + */ + +#define SMSC9218I_PHY_SPMODES 0x00000012U + +/** @} */ + +/** + * @name Special Control and Status Indications + * @{ + */ + +#define SMSC9218I_PHY_CSIR 0x0000001bU +#define SMSC9218I_PHY_CSIR_SQEOFF 0x00000800U +#define SMSC9218I_PHY_CSIR_FEFIEN 0x00000020U +#define SMSC9218I_PHY_CSIR_XPOL 0x00000010U + +/** @} */ + +/** + * @name Interrupt Source Flag + * @{ + */ + +#define SMSC9218I_PHY_ISR 0x0000001dU +#define SMSC9218I_PHY_ISR_INT7 0x00000080U +#define SMSC9218I_PHY_ISR_INT6 0x00000040U +#define SMSC9218I_PHY_ISR_INT5 0x00000020U +#define SMSC9218I_PHY_ISR_INT4 0x00000010U +#define SMSC9218I_PHY_ISR_INT3 0x00000008U +#define SMSC9218I_PHY_ISR_INT2 0x00000004U +#define SMSC9218I_PHY_ISR_INT1 0x00000002U + +/** @} */ + +/** + * @name Interrupt Mask + * @{ + */ + +#define SMSC9218I_PHY_IMR 0x0000001eU +#define SMSC9218I_PHY_IMR_INT7 0x00000080U +#define SMSC9218I_PHY_IMR_INT6 0x00000040U +#define SMSC9218I_PHY_IMR_INT5 0x00000020U +#define SMSC9218I_PHY_IMR_INT4 0x00000010U +#define SMSC9218I_PHY_IMR_INT3 0x00000008U +#define SMSC9218I_PHY_IMR_INT2 0x00000004U +#define SMSC9218I_PHY_IMR_INT1 0x00000002U + +/** @} */ + +/** + * @name PHY Special Control and Status + * @{ + */ + +#define SMSC9218I_PHY_PHYSCSR 0x0000001fU +#define SMSC9218I_PHY_PHYSCSR_ANDONE 0x00001000U +#define SMSC9218I_PHY_PHYSCSR_4B5B_EN 0x00000040U +#define SMSC9218I_PHY_PHYSCSR_SPEED_MASK 0x0000001cU +#define SMSC9218I_PHY_PHYSCSR_SPEED_10HD 0x00000004U +#define SMSC9218I_PHY_PHYSCSR_SPEED_10FD 0x00000014U +#define SMSC9218I_PHY_PHYSCSR_SPEED_100HD 0x00000008U +#define SMSC9218I_PHY_PHYSCSR_SPEED_100FD 0x00000018U + +/** @} */ diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/network/smsc9218i.c b/c/src/lib/libbsp/powerpc/mpc55xxevb/network/smsc9218i.c new file mode 100644 index 0000000000..6337743725 --- /dev/null +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/network/smsc9218i.c @@ -0,0 +1,1666 @@ +/** + * @file + * + * @ingroup mpc55xx + * + * @brief SMSC - LAN9218i + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <mpc55xx/regs.h> + +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include <rtems.h> +#include <rtems/rtems_bsdnet.h> +#include <rtems/rtems_mii_ioctl.h> + +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> + +#include <net/if.h> +#include <net/if_arp.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netinet/in_systm.h> +#include <netinet/ip.h> + +#include <mpc55xx/edma.h> + +#include <bsp.h> +#include <bsp/irq.h> +#include <bsp/utility.h> +#include <bsp/smsc9218i.h> + +#include <rtems/status-checks.h> + +#if MCLBYTES != 2048 + #warning "unexpected MCLBYTES value" +#endif + +#define SMSC9218I_EVENT_TX RTEMS_EVENT_1 + +#define SMSC9218I_EVENT_TX_START RTEMS_EVENT_2 + +#define SMSC9218I_EVENT_TX_ERROR RTEMS_EVENT_3 + +#define SMSC9218I_EVENT_RX RTEMS_EVENT_4 + +#define SMSC9218I_EVENT_RX_ERROR RTEMS_EVENT_5 + +#define SMSC9218I_EVENT_PHY RTEMS_EVENT_6 + +#define SMSC9218I_EVENT_EDMA RTEMS_EVENT_7 + +#define SMSC9218I_EVENT_EDMA_ERROR RTEMS_EVENT_8 + +/* Adjust by two bytes for proper IP header alignment */ +#define SMSC9218I_RX_DATA_OFFSET 2 + +#define SMSC9218I_TX_JOBS 16U + +#define SMSC9218I_TX_JOBS_MAX (SMSC9218I_TX_JOBS - 1U) + +/* Maximum number of fragments per frame, see manual section 3.11.3.2 */ +#define SMSC9218I_TX_FRAGMENT_MAX 86 + +#define SMSC9218I_IRQ_CFG_GLOBAL_ENABLE \ + (SMSC9218I_IRQ_CFG_IRQ_EN | SMSC9218I_IRQ_CFG_IRQ_TYPE) + +#define SMSC9218I_IRQ_CFG_GLOBAL_DISABLE SMSC9218I_IRQ_CFG_IRQ_TYPE + +#define SMSC9218I_EDMA_RX_CHANNEL 48 + +#define SMSC9218I_EDMA_RX_TCD_CDF 0x10004 + +#define SMSC9218I_EDMA_RX_TCD_BMF 0x10003 + +#define SMSC9218I_EDMA_TX_CHANNEL 49 + +#define SMSC9218I_EDMA_TX_TCD_BMF_LINK 0x10011 + +#define SMSC9218I_EDMA_TX_TCD_BMF_INTERRUPT 0x10003 + +#define SMSC9218I_EDMA_TX_TCD_BMF_CLEAR 0x10000 + +#ifdef DEBUG + #define SMSC9218I_PRINTF(...) printf(__VA_ARGS__) + #define SMSC9218I_PRINTK(...) printk(__VA_ARGS__) +#else + #define SMSC9218I_PRINTF(...) + #define SMSC9218I_PRINTK(...) +#endif + +typedef enum { + SMSC9218I_NOT_INITIALIZED, + SMSC9218I_CONFIGURED, + SMSC9218I_STARTED, + SMSC9218I_RUNNING +} smsc9218i_state; + +typedef struct { + struct arpcom arpcom; + struct rtems_mdio_info mdio_info; + smsc9218i_state state; + rtems_id receive_task; + rtems_id transmit_task; + mpc55xx_edma_channel_entry edma_receive; + mpc55xx_edma_channel_entry edma_transmit; + unsigned received_frames; + unsigned receive_interrupts; + unsigned transmitted_frames; + unsigned transmit_interrupts; + unsigned receive_too_long_errors; + unsigned receive_collision_errors; + unsigned receive_crc_errors; + unsigned receive_edma_errors; + unsigned transmit_errors; + unsigned transmit_edma_errors; +} smsc9218i_driver_entry; + +typedef struct { + uint32_t a; + uint32_t b; +} smsc9218i_transmit_command; + +typedef struct { + struct tcd_t command_tcd_table [SMSC9218I_TX_JOBS]; + struct tcd_t data_tcd_table [SMSC9218I_TX_JOBS]; + smsc9218i_transmit_command command_table [SMSC9218I_TX_JOBS]; + struct mbuf *fragment_table [SMSC9218I_TX_JOBS]; + struct mbuf *frame; + struct mbuf *next_fragment; + unsigned empty_index; + unsigned transfer_index; + unsigned transfer_last_index; + unsigned todo_index; + unsigned empty; + unsigned transfer; + unsigned todo; + uint32_t frame_length; + uint32_t command_b; + uint16_t tag; + bool done; +} smsc9218i_transmit_job_control; + +static void smsc9218i_edma_done( + mpc55xx_edma_channel_entry *e, + uint32_t error_status +) +{ + rtems_event_set event = error_status == 0 ? + SMSC9218I_EVENT_EDMA : SMSC9218I_EVENT_EDMA_ERROR; + + SMSC9218I_PRINTK( + "edma: id = 0x%08x, error status = 0x%08x\n", + e->id, + error_status + ); + + rtems_event_send(e->id, event); +} + +static smsc9218i_driver_entry smsc9218i_driver_data = { + .state = SMSC9218I_NOT_INITIALIZED, + .receive_task = RTEMS_ID_NONE, + .transmit_task = RTEMS_ID_NONE, + .edma_receive = { + .channel = SMSC9218I_EDMA_RX_CHANNEL, + .done = smsc9218i_edma_done, + .id = RTEMS_ID_NONE + }, + .edma_transmit = { + .channel = SMSC9218I_EDMA_TX_CHANNEL, + .done = smsc9218i_edma_done, + .id = RTEMS_ID_NONE + } +}; + +static void smsc9218i_mac_wait(volatile smsc9218i_registers *regs) +{ + while (IS_FLAG_SET(regs->mac_csr_cmd, SMSC9218I_MAC_CSR_CMD_BUSY)) { + /* Wait */ + } +} + +static void smsc9218i_mac_write( + volatile smsc9218i_registers *regs, + uint32_t address, + uint32_t data +) +{ + smsc9218i_mac_wait(regs); + regs->mac_csr_data = SMSC9218I_SWAP(data); + regs->mac_csr_cmd = SMSC9218I_MAC_CSR_CMD_BUSY + | SMSC9218I_MAC_CSR_CMD_ADDR(address); + smsc9218i_mac_wait(regs); +} + +static uint32_t smsc9218i_mac_read( + volatile smsc9218i_registers *regs, + uint32_t address +) +{ + uint32_t mac_csr_data = 0; + + smsc9218i_mac_wait(regs); + regs->mac_csr_cmd = SMSC9218I_MAC_CSR_CMD_BUSY + | SMSC9218I_MAC_CSR_CMD_READ + | SMSC9218I_MAC_CSR_CMD_ADDR(address); + smsc9218i_mac_wait(regs); + mac_csr_data = regs->mac_csr_data; + + return SMSC9218I_SWAP(mac_csr_data); +} + +static void smsc9218i_phy_wait(volatile smsc9218i_registers *regs) +{ + uint32_t mac_mii_acc = 0; + + do { + mac_mii_acc = smsc9218i_mac_read(regs, SMSC9218I_MAC_MII_ACC); + } while (IS_FLAG_SET(mac_mii_acc, SMSC9218I_MAC_MII_ACC_BUSY)); +} + +static void smsc9218i_phy_write( + volatile smsc9218i_registers *regs, + uint32_t address, + uint32_t data +) +{ + smsc9218i_phy_wait(regs); + smsc9218i_mac_write(regs, SMSC9218I_MAC_MII_DATA, data); + smsc9218i_mac_write( + regs, + SMSC9218I_MAC_MII_ACC, + SMSC9218I_MAC_MII_ACC_PHY_DEFAULT + | SMSC9218I_MAC_MII_ACC_BUSY + | SMSC9218I_MAC_MII_ACC_WRITE + | SMSC9218I_MAC_MII_ACC_ADDR(address) + ); + smsc9218i_phy_wait(regs); +} + +static uint32_t smsc9218i_phy_read( + volatile smsc9218i_registers *regs, + uint32_t address +) +{ + smsc9218i_phy_wait(regs); + smsc9218i_mac_write( + regs, + SMSC9218I_MAC_MII_ACC, + SMSC9218I_MAC_MII_ACC_PHY_DEFAULT + | SMSC9218I_MAC_MII_ACC_BUSY + | SMSC9218I_MAC_MII_ACC_ADDR(address) + ); + smsc9218i_phy_wait(regs); + return smsc9218i_mac_read(regs, SMSC9218I_MAC_MII_DATA); +} + +static void smsc9218i_enable_promiscous_mode( + volatile smsc9218i_registers *regs, + bool enable +) +{ + uint32_t flags = SMSC9218I_MAC_CR_RXALL | SMSC9218I_MAC_CR_PRMS; + uint32_t mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR); + + if (enable) { + mac_cr = SET_FLAGS(mac_cr, flags); + } else { + mac_cr = CLEAR_FLAGS(mac_cr, flags); + } + + smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, mac_cr); +} + +static void smsc9218i_register_dump(volatile smsc9218i_registers *regs) +{ + uint32_t reg = 0; + + reg = regs->id_rev; + printf( + "id_rev: 0x%08" PRIx32 " (ID = 0x%04" PRIx32 + ", revision = 0x%04" PRIx32 ")\n", + SMSC9218I_SWAP(reg), + SMSC9218I_ID_REV_GET_ID(reg), + SMSC9218I_ID_REV_GET_REV(reg) + ); + + reg = regs->irq_cfg; + printf("irq_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->int_sts; + printf("int_sts: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->int_en; + printf("int_en: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->byte_test; + printf("byte_test: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->fifo_int; + printf("fifo_int: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->rx_cfg; + printf("rx_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->tx_cfg; + printf("tx_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->hw_cfg; + printf("hw_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->rx_dp_ctl; + printf("rx_dp_ctl: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->rx_fifo_inf; + printf( + "rx_fifo_inf: 0x%08" PRIx32 " (status unused = %" PRIu32 + ", data unused = %" PRIu32 ")\n", + SMSC9218I_SWAP(reg), + SMSC9218I_RX_FIFO_INF_GET_SUSED(reg), + SMSC9218I_RX_FIFO_INF_GET_DUSED(reg) + ); + + reg = regs->tx_fifo_inf; + printf( + "tx_fifo_inf: 0x%08" PRIx32 " (status unused = %" PRIu32 + ", free = %" PRIu32 ")\n", + SMSC9218I_SWAP(reg), + SMSC9218I_TX_FIFO_INF_GET_SUSED(reg), + SMSC9218I_TX_FIFO_INF_GET_FREE(reg) + ); + + reg = regs->pmt_ctrl; + printf("pmt_ctrl: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->gpio_cfg; + printf("gpio_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->gpt_cfg; + printf("gpt_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->gpt_cnt; + printf("gpt_cnt: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->word_swap; + printf("word_swap: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->free_run; + printf("free_run: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->rx_drop; + printf("rx_drop: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + reg = regs->afc_cfg; + printf("afc_cfg: 0x%08" PRIx32 "\n", SMSC9218I_SWAP(reg)); + + printf("mac: cr: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_CR)); + printf("mac: addrh: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_ADDRH)); + printf("mac: addrl: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_ADDRL)); + printf("mac: hashh: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_HASHH)); + printf("mac: hashl: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_HASHL)); + printf("mac: mii_acc: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_MII_ACC)); + printf("mac: mii_data: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_MII_DATA)); + printf("mac: flow: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_FLOW)); + printf("mac: vlan1: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_VLAN1)); + printf("mac: vlan2: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_VLAN2)); + printf("mac: wuff: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_WUFF)); + printf("mac: wucsr: 0x%08" PRIx32 "\n", smsc9218i_mac_read(regs, SMSC9218I_MAC_WUCSR)); + + printf("phy: bcr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_BCR)); + printf("phy: bsr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_BSR)); + printf("phy: id1: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_ID1)); + printf("phy: id2: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_ID2)); + printf("phy: anar: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_ANAR)); + printf("phy: anlpar: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_ANLPAR)); + printf("phy: anexpr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_ANEXPR)); + printf("phy: mcsr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_MCSR)); + printf("phy: spmodes: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_SPMODES)); + printf("phy: cisr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_CSIR)); + printf("phy: isr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_ISR)); + printf("phy: imr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_IMR)); + printf("phy: physcsr: 0x%08" PRIx32 "\n", smsc9218i_phy_read(regs, SMSC9218I_PHY_PHYSCSR)); +} + +static void smsc9218i_interrupt_handler( + rtems_vector_number vector, + void *arg +) +{ + smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg; + volatile smsc9218i_registers *const regs = smsc9218i; + rtems_event_set re = 0; + rtems_event_set te = 0; + uint32_t int_en = regs->int_en; + uint32_t int_sts = regs->int_sts & int_en; + #ifdef DEBUG + uint32_t irq_cfg = regs->irq_cfg; + #endif + + /* Get interrupt status */ + SMSC9218I_PRINTK( + "interrupt: irq_cfg = 0x%08x, int_sts = 0x%08x, int_en = 0x%08x\n", + SMSC9218I_SWAP(irq_cfg), + SMSC9218I_SWAP(int_sts), + SMSC9218I_SWAP(int_en) + ); + + /* Disable module interrupts */ + regs->irq_cfg = SMSC9218I_IRQ_CFG_GLOBAL_DISABLE; + + /* Clear external interrupt status */ + SIU.EISR.R = 1; + + /* Clear interrupts */ + regs->int_sts = int_sts; + + /* Check receive interrupts */ + if (IS_FLAG_SET(int_sts, SMSC9218I_INT_STS_RSFL)) { + int_en = CLEAR_FLAG(int_en, SMSC9218I_INT_EN_RSFL); + re = SMSC9218I_EVENT_RX; + } + + /* Check PHY interrupts */ + if (IS_FLAG_SET(int_sts, SMSC9218I_INT_STS_PHY)) { + int_en = CLEAR_FLAG(int_en, SMSC9218I_INT_EN_PHY); + re = SET_FLAG(re, SMSC9218I_EVENT_PHY); + } + + /* Send events to receive task */ + if (re != 0) { + SMSC9218I_PRINTK("interrupt: receive: 0x%08x\n", re); + ++e->receive_interrupts; + (void) rtems_event_send(e->receive_task, re); + } + + /* Check transmit interrupts */ + if (IS_FLAG_SET(int_sts, SMSC9218I_INT_STS_TDFA)) { + int_en = CLEAR_FLAG(int_en, SMSC9218I_INT_EN_TDFA); + te = SMSC9218I_EVENT_TX; + } + + /* Send events to transmit task */ + if (te != 0) { + SMSC9218I_PRINTK("interrupt: transmit: 0x%08x\n", te); + ++e->transmit_interrupts; + (void) rtems_event_send(e->transmit_task, te); + } + + /* Update interrupt enable */ + regs->int_en = int_en; + + /* Enable module interrupts */ + regs->irq_cfg = SMSC9218I_IRQ_CFG_GLOBAL_ENABLE; +} + +static void smsc9218i_enable_receive_interrupts( + volatile smsc9218i_registers *regs +) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + regs->int_en = SET_FLAG(regs->int_en, SMSC9218I_INT_EN_RSFL); + rtems_interrupt_enable(level); +} + +static void smsc9218i_enable_transmit_interrupts( + volatile smsc9218i_registers *regs +) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + regs->int_en = SET_FLAG(regs->int_en, SMSC9218I_INT_EN_TDFA); + rtems_interrupt_enable(level); +} + +static void smsc9218i_enable_phy_interrupts( + volatile smsc9218i_registers *regs +) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + regs->int_en = SET_FLAG(regs->int_en, SMSC9218I_INT_EN_PHY); + rtems_interrupt_enable(level); +} + +static struct mbuf *smsc9218i_new_mbuf(struct ifnet *ifp, bool wait) +{ + struct mbuf *m = NULL; + int mw = wait ? M_WAIT : M_DONTWAIT; + + MGETHDR(m, mw, MT_DATA); + if (m != NULL) { + MCLGET(m, mw); + if (IS_FLAG_SET(m->m_flags, M_EXT)) { + /* Set receive interface */ + m->m_pkthdr.rcvif = ifp; + + return m; + } else { + m_freem(m); + } + } + + return NULL; +} + +static void smsc9218i_receive_task(void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_event_set events = 0; + smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg; + struct ifnet *ifp = &e->arpcom.ac_if; + volatile smsc9218i_registers *const regs = smsc9218i; + volatile struct tcd_t *tcd = &EDMA.TCD [e->edma_receive.channel]; + struct tcd_t tcd_init = EDMA_TCD_DEFAULT; + uint32_t mac_cr = 0; + + SMSC9218I_PRINTF("%s\n", __func__); + + /* Obtain receive eDMA channel */ + e->edma_receive.id = e->receive_task; + sc = mpc55xx_edma_obtain_channel(&e->edma_receive); + RTEMS_CLEANUP_SC(sc, cleanup, "obtain receive eDMA channel"); + + /* Setup receive eDMA channel */ + tcd_init.SDF.B.SSIZE = 2; + tcd_init.SDF.B.DSIZE = 2; + tcd_init.SADDR = (uint32_t) ®s->rx_fifo_data; + *tcd = tcd_init; + + /* Configure receiver */ + regs->rx_cfg = SMSC9218I_RX_CFG_END_ALIGN_4 + | SMSC9218I_RX_CFG_DOFF(SMSC9218I_RX_DATA_OFFSET); + + /* Enable MAC receiver */ + mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR) | SMSC9218I_MAC_CR_RXEN; + smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, mac_cr); + + /* Enable receive interrupts */ + smsc9218i_enable_receive_interrupts(regs); + + /* Enable PHY interrupts */ + smsc9218i_phy_write( + regs, + SMSC9218I_PHY_IMR, + SMSC9218I_PHY_IMR_INT4 | SMSC9218I_PHY_IMR_INT6 + ); + smsc9218i_enable_phy_interrupts(regs); + + SMSC9218I_PRINTF( + "rx: phy_isr = 0x%08" PRIx32 ", phy_imr = 0x%08" PRIx32 "\n", + smsc9218i_phy_read(regs, SMSC9218I_PHY_ISR), + smsc9218i_phy_read(regs, SMSC9218I_PHY_IMR) + ); + + /* Main event loop */ + while (true) { + uint32_t rx_fifo_inf = 0; + uint32_t status_used = 0; + + /* Wait for events */ + sc = rtems_bsdnet_event_receive( + SMSC9218I_EVENT_RX | SMSC9218I_EVENT_PHY, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + RTEMS_CLEANUP_SC(sc, cleanup, "wait for events"); + + if (IS_FLAG_SET(events, SMSC9218I_EVENT_PHY)) { + uint32_t phy_isr = smsc9218i_phy_read(regs, SMSC9218I_PHY_ISR); + + /* TODO */ + + printf("rx: PHY event: 0x%08" PRIx32 "\n", phy_isr); + + smsc9218i_enable_phy_interrupts(regs); + } + + rx_fifo_inf = regs->rx_fifo_inf; + status_used = SMSC9218I_RX_FIFO_INF_GET_SUSED(rx_fifo_inf); + + SMSC9218I_PRINTF( + "rx: wake up: events = 0x%08" PRIx32 ", status used = %" PRIu32 "\n", + events, + status_used + ); + + while (status_used > 0) { + uint32_t rx_fifo_status = regs->rx_fifo_status; + uint32_t frame_length = SMSC9218I_RX_STS_GET_LENGTH(rx_fifo_status); + uint32_t data_length = frame_length + SMSC9218I_RX_DATA_OFFSET; + uint32_t data_misalign = data_length % 4; + + /* Align data length on four byte boundary */ + if (data_misalign > 0) { + data_length += 4 - data_misalign; + } + + SMSC9218I_PRINTF( + "rx: status = 0x%08" PRIx32 ", frame length = %" PRIu32 + ", data length = %" PRIu32 ", data used = %" PRIu32 "\n", + SMSC9218I_SWAP(rx_fifo_status), + frame_length, + data_length, + SMSC9218I_RX_FIFO_INF_GET_DUSED(rx_fifo_inf) + ); + + if (IS_FLAG_CLEARED(rx_fifo_status, SMSC9218I_RX_STS_ERROR)) { + struct mbuf *m = smsc9218i_new_mbuf(ifp, true); + struct ether_header *eh = (struct ether_header *) + (mtod(m, char *) + SMSC9218I_RX_DATA_OFFSET); + int mbuf_length = (int) frame_length - ETHER_HDR_LEN - ETHER_CRC_LEN; + char *data = mtod(m, char *); + + /* Update mbuf */ + m->m_len = mbuf_length; + m->m_pkthdr.len = mbuf_length; + m->m_data = data + ETHER_HDR_LEN + SMSC9218I_RX_DATA_OFFSET; + + /* Invalidate data cache */ + rtems_cache_invalidate_multiple_data_lines(data, data_length); + + /* Start eDMA transfer */ + tcd->DADDR = (uint32_t) data; + tcd->NBYTES = data_length; + tcd->CDF.R = SMSC9218I_EDMA_RX_TCD_CDF; + tcd->BMF.R = SMSC9218I_EDMA_RX_TCD_BMF; + + /* Wait for eDMA events */ + sc = rtems_bsdnet_event_receive( + SMSC9218I_EVENT_EDMA | SMSC9218I_EVENT_EDMA_ERROR, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + RTEMS_CHECK_SC_TASK(sc, "wait for eDMA events"); + + if (IS_FLAG_CLEARED(events, SMSC9218I_EVENT_EDMA_ERROR)) { + /* Hand over */ + ether_input(ifp, eh, m); + + /* Increment received frames counter */ + ++e->received_frames; + } else { + /* Increment receive eDMA error counter */ + ++e->receive_edma_errors; + } + + SMSC9218I_PRINTF("rx: eDMA done\n"); + } else { + SMSC9218I_PRINTF("rx: error\n"); + + /* Update error counters */ + if (IS_FLAG_SET(rx_fifo_status, SMSC9218I_RX_STS_ERROR_TOO_LONG)) { + ++e->receive_too_long_errors; + } + if (IS_FLAG_SET(rx_fifo_status, SMSC9218I_RX_STS_ERROR_COLLISION)) { + ++e->receive_collision_errors; + } + if (IS_FLAG_SET(rx_fifo_status, SMSC9218I_RX_STS_ERROR_CRC)) { + ++e->receive_crc_errors; + } + + /* Discard frame */ + if (frame_length > 16) { + /* Fast forward */ + regs->rx_dp_ctl = SMSC9218I_RX_DP_CTRL_FFWD; + + while (IS_FLAG_SET(regs->rx_dp_ctl, SMSC9218I_RX_DP_CTRL_FFWD)) { + /* Wait */ + } + } else { + uint32_t len = data_length / 4; + uint32_t i = 0; + + /* Discard data */ + for (i = 0; i < len; ++i) { + regs->rx_fifo_data; + } + } + } + + /* Clear FIFO level status */ + regs->int_sts = SMSC9218I_INT_STS_RSFL; + + /* Next FIFO status */ + rx_fifo_inf = regs->rx_fifo_inf; + status_used = SMSC9218I_RX_FIFO_INF_GET_SUSED(rx_fifo_inf); + } + + SMSC9218I_PRINTF("rx: done\n"); + + /* Nothing to do, enable receive interrupts */ + smsc9218i_enable_receive_interrupts(regs); + } + +cleanup: + + /* Release network semaphore */ + rtems_bsdnet_semaphore_release(); + + /* Terminate self */ + (void) rtems_task_delete(RTEMS_SELF); +} + +static void smsc9218i_transmit_job_dump( + smsc9218i_transmit_job_control *jc, + const char *msg +) +{ + char out [SMSC9218I_TX_JOBS + 1]; + unsigned c = 0; + unsigned s = 0; + + out [SMSC9218I_TX_JOBS] = '\0'; + + memset(out, '?', SMSC9218I_TX_JOBS); + + c = jc->todo_index; + s = jc->empty; + while (s > 0) { + out [c] = 'E'; + --s; + if (c < SMSC9218I_TX_JOBS_MAX) { + ++c; + } else { + c = 0; + } + } + + c = jc->transfer_index; + s = jc->todo; + while (s > 0) { + out [c] = 'T'; + --s; + if (c < SMSC9218I_TX_JOBS_MAX) { + ++c; + } else { + c = 0; + } + } + + c = jc->empty_index; + s = jc->transfer; + while (s > 0) { + out [c] = 'D'; + --s; + if (c < SMSC9218I_TX_JOBS_MAX) { + ++c; + } else { + c = 0; + } + } + + printf( + "tx: %s: %02u:%02u:%02u %s\n", + msg, + jc->empty, + jc->todo, + jc->transfer, + out + ); +} + +static struct mbuf *smsc9218i_next_transmit_fragment( + struct ifnet *ifp, + smsc9218i_transmit_job_control *jc +) +{ + struct mbuf *m = jc->next_fragment; + + if (m != NULL) { + /* Next fragment is from the current frame */ + jc->next_fragment = m->m_next; + } else { + /* Dequeue first fragment of the next frame */ + IF_DEQUEUE(&ifp->if_snd, m); + + /* Update frame head */ + jc->frame = m; + + if (m != NULL) { + struct mbuf *n = m; + struct mbuf *p = NULL; + uint32_t frame_length = 0; + unsigned fragments = 0; + + /* Calculate frame length and fragment number */ + do { + int len = n->m_len; + + if (len > 0) { + ++fragments; + frame_length += (uint32_t) len; + + if (len < 4) { + printf("FIXME\n"); + } + + /* Next fragment */ + p = n; + n = n->m_next; + } else { + /* Discard empty fragment and get next */ + n = m_free(n); + + /* Remove fragment from list */ + if (p != NULL) { + p->m_next = n; + } else { + jc->frame = n; + } + } + } while (n != NULL); + + if (fragments > SMSC9218I_TX_FRAGMENT_MAX) { + printf("FIXME\n"); + } + + /* Set frame length */ + jc->frame_length = frame_length; + + /* Update next fragment */ + jc->next_fragment = jc->frame->m_next; + + /* Update tag */ + ++jc->tag; + + /* Command B */ + jc->command_b = SMSC9218I_TX_B_TAG(jc->tag) + | SMSC9218I_TX_B_FRAME_LENGTH(jc->frame_length); + + SMSC9218I_PRINTF( + "tx: next frame: tag = %u, frame length = %" PRIu32 + ", fragments = %u\n", + (unsigned) jc->tag, + frame_length, + fragments + ); + } else { + /* The transmit queue is empty, we have no next fragment */ + jc->next_fragment = NULL; + + /* Interface is now inactive */ + ifp->if_flags = CLEAR_FLAG(ifp->if_flags, IFF_OACTIVE); + + /* Transmit task may wait for events */ + jc->done = true; + + SMSC9218I_PRINTF("tx: inactive\n"); + } + } + + return m; +} + +static void smsc9218i_transmit_create_jobs( + smsc9218i_transmit_job_control *jc, + volatile smsc9218i_registers *const regs, + struct ifnet *ifp +) +{ + unsigned n = jc->empty; + + if (n > 0) { + unsigned c = jc->todo_index; + unsigned i = 0; + + #ifdef DEBUG + smsc9218i_transmit_job_dump(jc, "create"); + #endif + + for (i = 0; i < n; ++i) { + struct mbuf *m = smsc9218i_next_transmit_fragment(ifp, jc); + + if (m != NULL) { + uint32_t first = m == jc->frame ? SMSC9218I_TX_A_FIRST : 0; + uint32_t last = m->m_next == NULL ? SMSC9218I_TX_A_LAST : 0; + uint32_t fragment_length = (uint32_t) m->m_len; + uint32_t fragment_misalign = (uint32_t) (mtod(m, uintptr_t) % 4); + uint32_t data_length = fragment_misalign + fragment_length; + uint32_t data_misalign = data_length % 4; + uint32_t data = (uint32_t) (mtod(m, char *) - fragment_misalign); + + /* Align data length on four byte boundary */ + if (data_misalign > 0) { + data_length += 4 - data_misalign; + } + + /* Cache flush for fragment data */ + rtems_cache_flush_multiple_data_lines( + (const void *) data, + data_length + ); + + asm volatile ( "sync"); + + /* Remember fragement */ + jc->fragment_table [c] = m; + + /* Command A and B */ + jc->command_table [c].a = SMSC9218I_TX_A_END_ALIGN_4 + | SMSC9218I_TX_A_DOFF(fragment_misalign) + | SMSC9218I_TX_A_FRAGMENT_LENGTH(fragment_length) + | first + | last; + jc->command_table [c].b = jc->command_b; + + /* Data TCD */ + jc->data_tcd_table [c].SADDR = data; + jc->data_tcd_table [c].NBYTES = data_length; + + SMSC9218I_PRINTF("tx: create: index = %u\n", c); + } else { + /* Nothing to do */ + break; + } + + if (c < SMSC9218I_TX_JOBS_MAX) { + ++c; + } else { + c = 0; + } + } + + /* Increment jobs to do */ + jc->todo += i; + + /* Decrement empty count */ + jc->empty -= i; + + /* Update todo index */ + jc->todo_index = c; + + #ifdef DEBUG + smsc9218i_transmit_job_dump(jc, "create done"); + #endif + } else { + /* Transmit task may wait for events */ + jc->done = true; + } +} + +static void smsc9218i_transmit_do_jobs( + smsc9218i_transmit_job_control *jc, + volatile smsc9218i_registers *const regs, + smsc9218i_driver_entry *e +) +{ + if (jc->transfer == 0) { + uint32_t tx_fifo_inf = regs->tx_fifo_inf; + uint32_t data_free = SMSC9218I_TX_FIFO_INF_GET_FREE(tx_fifo_inf); + unsigned c = jc->transfer_index; + unsigned last_index = c; + unsigned i = 0; + unsigned n = jc->todo; + struct tcd_t *p = NULL; + + #ifdef DEBUG + smsc9218i_transmit_job_dump(jc, "transfer"); + #endif + + for (i = 0; i < n; ++i) { + struct tcd_t *tcd = &jc->data_tcd_table [c]; + uint32_t data_length = tcd->NBYTES; + + if (data_length <= data_free) { + /* Reduce free FIFO space */ + data_free -= data_length; + + /* Index of last TCD */ + last_index = c; + + /* Cache flush for previous data TCD */ + if (p != NULL) { + rtems_cache_flush_multiple_data_lines(p, sizeof(*p)); + } + } else { + break; + } + + p = tcd; + if (c < SMSC9218I_TX_JOBS_MAX) { + ++c; + } else { + c = 0; + } + } + + if (i > 0) { + volatile struct tcd_t *channel = &EDMA.TCD [e->edma_transmit.channel]; + struct tcd_t *start = &jc->command_tcd_table [jc->transfer_index]; + struct tcd_t *last = &jc->data_tcd_table [last_index]; + + /* New transfer index */ + jc->transfer_index = c; + + /* New last transfer index */ + jc->transfer_last_index = last_index; + + /* Set jobs in transfer */ + jc->transfer = i; + + /* Decrement jobs to do */ + jc->todo -= i; + + /* Cache flush for command table */ + rtems_cache_flush_multiple_data_lines( + jc->command_table, + sizeof(jc->command_table) + ); + + /* Enable interrupt for last data TCD */ + last->BMF.R = SMSC9218I_EDMA_TX_TCD_BMF_INTERRUPT; + + /* Cache flush for last data TCD */ + rtems_cache_flush_multiple_data_lines(last, sizeof(*last)); + + /* Start eDMA transfer */ + channel->SADDR = start->SADDR; + channel->SDF.R = start->SDF.R; + channel->NBYTES = start->NBYTES; + channel->SLAST = start->SLAST; + channel->DADDR = start->DADDR; + channel->CDF.R = start->CDF.R; + channel->DLAST_SGA = start->DLAST_SGA; + channel->BMF.R = SMSC9218I_EDMA_TX_TCD_BMF_CLEAR; + channel->BMF.R = start->BMF.R; + + /* Transmit task may wait for events */ + jc->done = true; + } else if (n > 0) { + /* We need to wait until the FIFO has more free space */ + smsc9218i_enable_transmit_interrupts(regs); + + /* Transmit task may wait for events */ + jc->done = true; + } + + #ifdef DEBUG + smsc9218i_transmit_job_dump(jc, "transfer done"); + #endif + } +} + +static void smsc9218i_transmit_finish_jobs( + smsc9218i_transmit_job_control *jc, + volatile smsc9218i_registers *const regs, + smsc9218i_driver_entry *e, + rtems_event_set events +) +{ + uint32_t tx_fifo_inf = regs->tx_fifo_inf; + uint32_t status_used = SMSC9218I_TX_FIFO_INF_GET_SUSED(tx_fifo_inf); + uint32_t s = 0; + unsigned n = jc->transfer; + + for (s = 0; s < status_used; ++s) { + uint32_t tx_fifo_status = regs->tx_fifo_status; + + if (IS_FLAG_CLEARED(tx_fifo_status, SMSC9218I_TX_STS_ERROR)) { + ++e->transmitted_frames; + } else { + ++e->transmit_errors; + } + + SMSC9218I_PRINTF( + "tx: transmit status: tag = %" PRIu32 ", status = 0x%08" PRIx32 "\n", + SMSC9218I_TX_STS_GET_TAG(tx_fifo_status), + SMSC9218I_SWAP(tx_fifo_status) + ); + } + + if ( + IS_ANY_FLAG_SET(events, SMSC9218I_EVENT_EDMA | SMSC9218I_EVENT_EDMA_ERROR) + && n > 0 + ) { + unsigned c = jc->empty_index; + unsigned i = 0; + + #ifdef DEBUG + smsc9218i_transmit_job_dump(jc, "finish"); + #endif + + if (IS_FLAG_SET(events, SMSC9218I_EVENT_EDMA_ERROR)) { + ++e->transmit_edma_errors; + } + + /* Restore last data TCD */ + jc->data_tcd_table [jc->transfer_last_index].BMF.R = + SMSC9218I_EDMA_TX_TCD_BMF_LINK; + + for (i = 0; i < n; ++i) { + /* Free fragment buffer */ + m_free(jc->fragment_table [c]); + + if (c < SMSC9218I_TX_JOBS_MAX) { + ++c; + } else { + c = 0; + } + } + + /* Increment empty count */ + jc->empty += n; + + /* New empty index */ + jc->empty_index = jc->transfer_index; + + /* Clear jobs in transfer */ + jc->transfer = 0; + + /* Update empty index */ + jc->empty_index = c; + + #ifdef DEBUG + smsc9218i_transmit_job_dump(jc, "finish done"); + #endif + } +} + +/* FIXME */ +static smsc9218i_transmit_job_control smsc_jc __attribute__ ((aligned (32))) = { + .frame = NULL, + .next_fragment = NULL, + .frame_length = 0, + .tag = 0, + .command_b = 0, + .done = false, + .empty_index = 0, + .transfer_index = 0, + .todo_index = 0, + .empty = SMSC9218I_TX_JOBS, + .transfer = 0, + .todo = 0 +}; + +static void smsc9218i_transmit_task(void *arg) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_event_set events = 0; + smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg; + struct ifnet *ifp = &e->arpcom.ac_if; + volatile smsc9218i_registers *const regs = smsc9218i; + uint32_t mac_cr = 0; + smsc9218i_transmit_job_control *jc = &smsc_jc; + unsigned i = 0; + + SMSC9218I_PRINTF("%s\n", __func__); + + /* Obtain transmit eDMA channel */ + e->edma_transmit.id = e->transmit_task; + sc = mpc55xx_edma_obtain_channel(&e->edma_transmit); + RTEMS_CLEANUP_SC(sc, cleanup, "obtain transmit eDMA channel"); + + /* Setup transmit eDMA descriptors */ + for (i = 0; i < SMSC9218I_TX_JOBS; ++i) { + unsigned ii = i < SMSC9218I_TX_JOBS_MAX ? i + 1 : 0; + struct tcd_t tcd = EDMA_TCD_DEFAULT; + struct tcd_t *command_tcd = &jc->command_tcd_table [i]; + struct tcd_t *data_tcd = &jc->data_tcd_table [i]; + struct tcd_t *next_command_tcd = &jc->command_tcd_table [ii]; + + tcd.SDF.B.SSIZE = 2; + tcd.SDF.B.SOFF = 4; + tcd.SDF.B.DSIZE = 2; + tcd.CDF.B.CITER = 1; + tcd.BMF.R = SMSC9218I_EDMA_TX_TCD_BMF_LINK; + tcd.DADDR = (uint32_t) ®s->tx_fifo_data; + + tcd.DLAST_SGA = (uint32_t) next_command_tcd; + *data_tcd = tcd; + + tcd.SADDR = (uint32_t) &jc->command_table [i].a; + tcd.NBYTES = 8; + tcd.DLAST_SGA = (uint32_t) data_tcd; + *command_tcd = tcd; + } + + /* + * Cache flush for command TCD. The content of the command TCD remains + * invariant. + */ + rtems_cache_flush_multiple_data_lines( + jc->command_tcd_table, + sizeof(jc->command_tcd_table) + ); + + /* Configure transmitter */ + regs->tx_cfg = SMSC9218I_TX_CFG_SAO | SMSC9218I_TX_CFG_ON; + + /* Enable MAC transmitter */ + mac_cr = smsc9218i_mac_read(regs, SMSC9218I_MAC_CR) | SMSC9218I_MAC_CR_TXEN; + smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, mac_cr); + + /* Main event loop */ + while (true) { + /* Wait for events */ + sc = rtems_bsdnet_event_receive( + SMSC9218I_EVENT_TX + | SMSC9218I_EVENT_TX_START + | SMSC9218I_EVENT_EDMA + | SMSC9218I_EVENT_EDMA_ERROR, + RTEMS_EVENT_ANY | RTEMS_WAIT, + RTEMS_NO_TIMEOUT, + &events + ); + RTEMS_CLEANUP_SC(sc, cleanup, "wait for events"); + + SMSC9218I_PRINTF("tx: wake up: events = 0x%08" PRIx32 "\n", events); + + do { + jc->done = false; + smsc9218i_transmit_finish_jobs(jc, regs, e, events); + smsc9218i_transmit_create_jobs(jc, regs, ifp); + smsc9218i_transmit_do_jobs(jc, regs, e); + } while (!jc->done); + + SMSC9218I_PRINTF("tx: done\n"); + } + +cleanup: + + /* Release network semaphore */ + rtems_bsdnet_semaphore_release(); + + /* Terminate self */ + (void) rtems_task_delete(RTEMS_SELF); +} + +static void smsc9218i_test_macros(void) +{ + unsigned i = 0; + unsigned byte_test = 0x87654321U; + unsigned val8 = 0xa5; + unsigned val16 = 0xa55a; + int r = 0; + + r = SMSC9218I_SWAP(SMSC9218I_BYTE_TEST) == byte_test; + printf("[%i] SMSC9218I_SWAP\n", r); + + for (i = 0; i < 32; ++i) { + r = SMSC9218I_SWAP(SMSC9218I_FLAG(i)) == (1U << i); + printf("[%i] flag: %u\n", r, i); + } + + for (i = 0; i < 32; i += 8) { + r = SMSC9218I_SWAP(SMSC9218I_FIELD_8(val8, i)) == (val8 << i); + printf("[%i] field 8: %u\n", r, i); + } + + for (i = 0; i < 32; i += 16) { + r = SMSC9218I_SWAP(SMSC9218I_FIELD_16(val16, i)) == (val16 << i); + printf("[%i] field 16: %u\n", r, i); + } + + for (i = 0; i < 32; i += 8) { + r = SMSC9218I_GET_FIELD_8(SMSC9218I_BYTE_TEST, i) + == ((byte_test >> i) & 0xffU); + printf("[%i] get field 8: %u\n", r, i); + } + + for (i = 0; i < 32; i += 16) { + r = SMSC9218I_GET_FIELD_16(SMSC9218I_BYTE_TEST, i) + == ((byte_test >> i) & 0xffffU); + printf("[%i] get field 16: %u\n", r, i); + } +} + +static void smsc9218i_set_mac_address( + volatile smsc9218i_registers *regs, + unsigned char address [6] +) +{ + smsc9218i_mac_write( + regs, + SMSC9218I_MAC_ADDRL, + ((uint32_t) address [3] << 24) | ((uint32_t) address [2] << 16) + | ((uint32_t) address [1] << 8) | (uint32_t) address [0] + ); + smsc9218i_mac_write( + regs, + SMSC9218I_MAC_ADDRH, + ((uint32_t) address [5] << 8) | (uint32_t) address [4] + ); +} + +static void smsc9218i_mac_address_dump(volatile smsc9218i_registers *regs) +{ + uint32_t low = smsc9218i_mac_read(regs, SMSC9218I_MAC_ADDRL); + uint32_t high = smsc9218i_mac_read(regs, SMSC9218I_MAC_ADDRH); + + printf( + "MAC address: %02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 + ":%02" PRIx32 ":%02" PRIx32 ":%02" PRIx32 "\n", + low & 0xff, + (low >> 8) & 0xff, + (low >> 16) & 0xff, + (low >> 24) & 0xff, + high & 0xff, + (high >> 8) & 0xff + ); +} + +static void smsc9218i_interrupt_init( + smsc9218i_driver_entry *e, + volatile smsc9218i_registers *regs +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + union SIU_PCR_tag pcr = MPC55XX_ZERO_FLAGS; + union SIU_DIRER_tag direr = MPC55XX_ZERO_FLAGS; + union SIU_DIRSR_tag dirsr = MPC55XX_ZERO_FLAGS; + union SIU_ORER_tag orer = MPC55XX_ZERO_FLAGS; + union SIU_IREER_tag ireer = MPC55XX_ZERO_FLAGS; + union SIU_IFEER_tag ifeer = MPC55XX_ZERO_FLAGS; + union SIU_IDFR_tag idfr = MPC55XX_ZERO_FLAGS; + rtems_interrupt_level level; + + /* Configure IRQ input pin */ + pcr.B.PA = 2; + pcr.B.OBE = 0; + pcr.B.IBE = 1; + pcr.B.DSC = 0; + pcr.B.ODE = 0; + pcr.B.HYS = 0; + pcr.B.SRC = 3; + pcr.B.WPE = 0; + pcr.B.WPS = 1; + SIU.PCR [193].R = pcr.R; + + /* DMA/Interrupt Request Select */ + rtems_interrupt_disable(level); + dirsr.R = SIU.DIRSR.R; + dirsr.B.DIRS0 = 0; + SIU.DIRSR.R = dirsr.R; + rtems_interrupt_enable(level); + + /* Overrun Request Enable */ + rtems_interrupt_disable(level); + orer.R = SIU.ORER.R; + orer.B.ORE0 = 0; + SIU.ORER.R = orer.R; + rtems_interrupt_enable(level); + + /* IRQ Rising-Edge Enable */ + rtems_interrupt_disable(level); + ireer.R = SIU.IREER.R; + ireer.B.IREE0 = 0; + SIU.IREER.R = ireer.R; + rtems_interrupt_enable(level); + + /* IRQ Falling-Edge Enable */ + rtems_interrupt_disable(level); + ifeer.R = SIU.IFEER.R; + ifeer.B.IFEE0 = 1; + SIU.IFEER.R = ifeer.R; + rtems_interrupt_enable(level); + + /* IRQ Digital Filter */ + rtems_interrupt_disable(level); + idfr.R = SIU.IDFR.R; + idfr.B.DFL = 0; + SIU.IDFR.R = idfr.R; + rtems_interrupt_enable(level); + + /* Clear external interrupt status */ + SIU.EISR.R = 1; + + /* DMA/Interrupt Request Enable */ + rtems_interrupt_disable(level); + direr.R = SIU.DIRER.R; + direr.B.EIRE0 = 1; + SIU.DIRER.R = direr.R; + rtems_interrupt_enable(level); + + /* Install interrupt handler */ + sc = rtems_interrupt_handler_install( + MPC55XX_IRQ_SIU_EXTERNAL_0, + "SMSC9218i", + RTEMS_INTERRUPT_UNIQUE, + smsc9218i_interrupt_handler, + e + ); + RTEMS_SYSLOG_ERROR_SC(sc, "install interrupt handler\n"); + + /* Enable interrupts and use push-pull driver (active low) */ + regs->irq_cfg = SMSC9218I_IRQ_CFG_GLOBAL_ENABLE; +} + +static void smsc9218i_reset_signal(bool signal) +{ + SIU.GPDO [186].R = signal ? 1 : 0; +} + +static void smsc9218i_reset_signal_init(void) +{ + union SIU_PCR_tag pcr = MPC55XX_ZERO_FLAGS; + + smsc9218i_reset_signal(true); + + pcr.B.PA = 0; + pcr.B.OBE = 1; + pcr.B.IBE = 0; + pcr.B.DSC = 0; + pcr.B.ODE = 0; + pcr.B.HYS = 0; + pcr.B.SRC = 3; + pcr.B.WPE = 1; + pcr.B.WPS = 1; + + SIU.PCR [186].R = pcr.R; +} + +static void smsc9218i_interface_init(void *arg) +{ + smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) arg; + struct ifnet *ifp = &e->arpcom.ac_if; + volatile smsc9218i_registers *const regs = smsc9218i; + + SMSC9218I_PRINTF("%s\n", __func__); + + if (e->state == SMSC9218I_CONFIGURED) { + /* Hardware reset */ + smsc9218i_reset_signal_init(); + smsc9218i_reset_signal(false); + rtems_bsp_delay(200); + smsc9218i_reset_signal(true); + + /* Register dump */ + smsc9218i_register_dump(regs); + + /* Set hardware configuration */ + regs->hw_cfg = SMSC9218I_HW_CFG_MBO | SMSC9218I_HW_CFG_TX_FIF_SZ(5); + + /* MAC address */ + smsc9218i_set_mac_address(regs, e->arpcom.ac_enaddr); + smsc9218i_mac_address_dump(regs); + + /* Initialize interrupts */ + smsc9218i_interrupt_init(e, regs); + + /* Set MAC control */ + smsc9218i_mac_write(regs, SMSC9218I_MAC_CR, SMSC9218I_MAC_CR_FDPX); + + /* Set FIFO interrupts */ + regs->fifo_int = SMSC9218I_FIFO_INT_TDAL(32); + + /* Start receive task */ + if (e->receive_task == RTEMS_ID_NONE) { + e->receive_task = rtems_bsdnet_newproc( + "ntrx", + 4096, + smsc9218i_receive_task, + e + ); + } + + /* Start transmit task */ + if (e->transmit_task == RTEMS_ID_NONE) { + e->transmit_task = rtems_bsdnet_newproc( + "nttx", + 4096, + smsc9218i_transmit_task, + e + ); + } + + /* Change state */ + if (e->receive_task != RTEMS_ID_NONE + && e->transmit_task != RTEMS_ID_NONE) { + e->state = SMSC9218I_STARTED; + } + } + + if (e->state == SMSC9218I_STARTED) { + /* Enable promiscous mode */ + smsc9218i_enable_promiscous_mode( + regs, + IS_FLAG_SET(ifp->if_flags, IFF_PROMISC) + ); + + /* Set interface to running state */ + ifp->if_flags = SET_FLAG(ifp->if_flags, IFF_RUNNING); + + /* Change state */ + e->state = SMSC9218I_RUNNING; + } +} + +static void smsc9218i_interface_stats(const smsc9218i_driver_entry *e) +{ + printf("received frames: %u\n", e->received_frames); + printf("receive interrupts: %u\n", e->receive_interrupts); + printf("transmitted frames: %u\n", e->transmitted_frames); + printf("transmit interrupts: %u\n", e->transmit_interrupts); + printf("receive to long errors: %u\n", e->receive_too_long_errors); + printf("receive collision errors: %u\n", e->receive_collision_errors); + printf("receive CRC errors: %u\n", e->receive_crc_errors); + printf("receive eDMA errors: %u\n", e->receive_edma_errors); + printf("transmit errors: %u\n", e->transmit_errors); + printf("transmit eDMA errors: %u\n", e->transmit_edma_errors); +} + +static int smsc9218i_interface_ioctl( + struct ifnet *ifp, + ioctl_command_t command, + caddr_t data +) { + smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) ifp->if_softc; + int rv = 0; + + SMSC9218I_PRINTF("%s\n", __func__); + + switch (command) { + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + rtems_mii_ioctl(&e->mdio_info, e, (int) command, (int *) data); + break; + case SIOCGIFADDR: + case SIOCSIFADDR: + ether_ioctl(ifp, command, data); + break; + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_RUNNING) { + /* TODO: off */ + } + if (ifp->if_flags & IFF_UP) { + ifp->if_flags = SET_FLAG(ifp->if_flags, IFF_RUNNING); + /* TODO: init */ + } + break; + case SIO_RTEMS_SHOW_STATS: + smsc9218i_interface_stats(e); + break; + default: + rv = EINVAL; + break; + } + + return rv; +} + +static void smsc9218i_interface_start(struct ifnet *ifp) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + smsc9218i_driver_entry *e = (smsc9218i_driver_entry *) ifp->if_softc; + + /* Interface is now active */ + ifp->if_flags = SET_FLAG(ifp->if_flags, IFF_OACTIVE); + + sc = rtems_event_send(e->transmit_task, SMSC9218I_EVENT_TX_START); + RTEMS_SYSLOG_ERROR_SC(sc, "send transmit start event"); +} + +static void smsc9218i_interface_watchdog(struct ifnet *ifp) +{ + SMSC9218I_PRINTF("%s\n", __func__); +} + +static int smsc9218i_attach(struct rtems_bsdnet_ifconfig *config) +{ + smsc9218i_driver_entry *e = &smsc9218i_driver_data; + struct ifnet *ifp = &e->arpcom.ac_if; + char *unit_name = NULL; + int unit_number = rtems_bsdnet_parse_driver_name(config, &unit_name); + + /* Check parameter */ + if (unit_number < 0) { + RTEMS_SYSLOG_ERROR("parse error for interface name\n"); + return 0; + } + if (unit_number != 0) { + RTEMS_DO_CLEANUP(smsc9218i_attach_cleanup, "unexpected unit number"); + } + if (config->hardware_address == NULL) { + RTEMS_DO_CLEANUP(smsc9218i_attach_cleanup, "MAC address missing"); + } + if (e->state != SMSC9218I_NOT_INITIALIZED) { + RTEMS_DO_CLEANUP(smsc9218i_attach_cleanup, "already attached"); + } + + /* Interrupt number */ + config->irno = MPC55XX_IRQ_SIU_EXTERNAL_0; + + /* Device control */ + config->drv_ctrl = e; + + /* Receive unit number */ + config->rbuf_count = 0; + + /* Transmit unit number */ + config->xbuf_count = 0; + + /* Copy MAC address */ + memcpy(e->arpcom.ac_enaddr, config->hardware_address, ETHER_ADDR_LEN); + + /* Set interface data */ + ifp->if_softc = e; + ifp->if_unit = (short) unit_number; + ifp->if_name = unit_name; + ifp->if_mtu = config->mtu > 0 ? (u_long) config->mtu : ETHERMTU; + ifp->if_init = smsc9218i_interface_init; + ifp->if_ioctl = smsc9218i_interface_ioctl; + ifp->if_start = smsc9218i_interface_start; + ifp->if_output = ether_output; + ifp->if_watchdog = smsc9218i_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 = SMSC9218I_CONFIGURED; + + /* Attach the interface */ + if_attach(ifp); + ether_ifattach(ifp); + + return 1; + +smsc9218i_attach_cleanup: + + /* FIXME: Type */ + free(unit_name, (int) 0xdeadbeef); + + return 0; +} + +int smsc9218i_attach_detach( + struct rtems_bsdnet_ifconfig *config, + int attaching +) { + /* FIXME: Return value */ + + if (attaching) { + return smsc9218i_attach(config); + } else { + /* TODO */ + return 0; + } +} diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/preinstall.am b/c/src/lib/libbsp/powerpc/mpc55xxevb/preinstall.am index 0c09030c07..4b20c47566 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/preinstall.am +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/preinstall.am @@ -85,10 +85,22 @@ $(PROJECT_INCLUDE)/bsp/irq-config.h: include/irq-config.h $(PROJECT_INCLUDE)/bsp $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-config.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-config.h +$(PROJECT_INCLUDE)/bsp/smsc9218i.h: include/smsc9218i.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/smsc9218i.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/smsc9218i.h + $(PROJECT_INCLUDE)/bsp/irq-generic.h: ../../shared/include/irq-generic.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-generic.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-generic.h +$(PROJECT_INCLUDE)/bsp/irq-info.h: ../../shared/include/irq-info.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/irq-info.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/irq-info.h + +$(PROJECT_INCLUDE)/bsp/utility.h: ../../shared/include/utility.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/utility.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/utility.h + $(PROJECT_INCLUDE)/bsp/tictac.h: ../shared/include/tictac.h $(PROJECT_INCLUDE)/bsp/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/tictac.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/tictac.h diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/startup/bspstart.c b/c/src/lib/libbsp/powerpc/mpc55xxevb/startup/bspstart.c index 690a72a092..a4cb7b4483 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/startup/bspstart.c +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/startup/bspstart.c @@ -92,28 +92,11 @@ void bsp_predriver_hook() static void mpc55xx_ebi_init() { - struct EBI_CS_tag cs = { BR : MPC55XX_ZERO_FLAGS, OR : MPC55XX_ZERO_FLAGS }; + struct EBI_CS_tag cs = { .BR = MPC55XX_ZERO_FLAGS, .OR = MPC55XX_ZERO_FLAGS }; union SIU_PCR_tag pcr = MPC55XX_ZERO_FLAGS; + struct MMU_tag mmu = MMU_DEFAULT; int i = 0; - /* External SRAM (0 wait states, 512kB, 4 word burst) */ - cs.BR.B.BA = 0; - cs.BR.B.PS = 1; - cs.BR.B.BL = 1; - cs.BR.B.WEBS = 0; - cs.BR.B.TBDIP = 0; - cs.BR.B.BI = 1; /* TODO: Enable burst */ - cs.BR.B.V = 1; - - cs.OR.B.AM = 0x1fff0; - cs.OR.B.SCY = 0; - cs.OR.B.BSCY = 0; - - EBI.CS [0] = cs; - - /* !CS [0] */ - SIU.PCR [0].R = 0x443; - /* ADDR [8 : 31] */ for (i = 4; i < 4 + 24; ++i) { SIU.PCR [i].R = 0x440; @@ -140,6 +123,64 @@ static void mpc55xx_ebi_init() /* !TS */ SIU.PCR [69].R = 0x443; + + /* External SRAM (2 wait states, 512kB, 4 word burst) */ + + cs.BR.B.BA = 0; + cs.BR.B.PS = 1; + cs.BR.B.BL = 1; + cs.BR.B.WEBS = 0; + cs.BR.B.TBDIP = 0; + cs.BR.B.BI = 1; /* TODO: Enable burst */ + cs.BR.B.V = 1; + + cs.OR.B.AM = 0x1fff0; + cs.OR.B.SCY = 0; + cs.OR.B.BSCY = 0; + + EBI.CS [0] = cs; + + /* !CS [0] */ + SIU.PCR [0].R = 0x443; + + /* External Ethernet Controller (3 wait states, 64kB) */ + + mmu.MAS0.B.ESEL = 5; + mmu.MAS1.B.VALID = 1; + mmu.MAS1.B.IPROT = 1; + mmu.MAS1.B.TSIZ = 1; + mmu.MAS2.B.EPN = 0x3fff8; + mmu.MAS2.B.I = 1; + mmu.MAS2.B.G = 1; + mmu.MAS3.B.RPN = 0x3fff8; + mmu.MAS3.B.UW = 1; + mmu.MAS3.B.SW = 1; + mmu.MAS3.B.UR = 1; + mmu.MAS3.B.SR = 1; + + PPC_SET_SPECIAL_PURPOSE_REGISTER( FREESCALE_EIS_MAS0, mmu.MAS0.R); + PPC_SET_SPECIAL_PURPOSE_REGISTER( FREESCALE_EIS_MAS1, mmu.MAS1.R); + PPC_SET_SPECIAL_PURPOSE_REGISTER( FREESCALE_EIS_MAS2, mmu.MAS2.R); + PPC_SET_SPECIAL_PURPOSE_REGISTER( FREESCALE_EIS_MAS3, mmu.MAS3.R); + + asm volatile ("tlbwe"); + + cs.BR.B.BA = 0x7fff; + cs.BR.B.PS = 1; + cs.BR.B.BL = 0; + cs.BR.B.WEBS = 0; + cs.BR.B.TBDIP = 0; + cs.BR.B.BI = 1; + cs.BR.B.V = 1; + + cs.OR.B.AM = 0x1ffff; + cs.OR.B.SCY = 1; + cs.OR.B.BSCY = 0; + + EBI.CS [3] = cs; + + /* !CS [3] */ + SIU.PCR [3].R = 0x443; } /** @@ -198,7 +239,8 @@ void bsp_start(void) DEBUG_DONE(); } - RTEMS_DEBUG_PRINT( "BSP start done\n"); + /* Initialize eMIOS */ + mpc55xx_emios_initialize( 1); return; diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/startup/sd-card-init.c b/c/src/lib/libbsp/powerpc/mpc55xxevb/startup/sd-card-init.c index 37308f420e..c18382a0cd 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/startup/sd-card-init.c +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/startup/sd-card-init.c @@ -18,20 +18,16 @@ * LICENSE in this distribution or at http://www.rtems.com/license/LICENSE. */ -#include <stdio.h> +#include <stdio.h> #include <mpc55xx/mpc55xx.h> #include <mpc55xx/regs.h> #include <mpc55xx/dspi.h> -#include <libchip/spi-sd-card.h> - -#define DEBUG +#include <bsp.h> #include <rtems/status-checks.h> -#include <bsp.h> - static rtems_status_code mpc55xx_dspi_init(void) { int rv = 0; @@ -88,17 +84,14 @@ static rtems_status_code mpc55xx_dspi_init(void) return RTEMS_SUCCESSFUL; } -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <dirent.h> #include <stdio.h> #include <rtems/fsmount.h> #include <rtems/dosfs.h> -#include <rtems/ide_part_table.h> +#include <rtems/bdpart.h> #include <rtems/console.h> +#include <libchip/spi-sd-card.h> + #define MPC55XX_DEVICE "sd-card-a" #define MPC55XX_DEVICE_FILE "/dev/" MPC55XX_DEVICE #define MPC55XX_PARTITION "/dev/sd-card-a1" @@ -117,21 +110,10 @@ static fstab_t mpc55xx_fs_table [] = { { } }; -#define SD_CARD_NUMBER 1 - -sd_card_driver_entry sd_card_driver_table [SD_CARD_NUMBER] = { { -#if 0 - .driver = { - .ops = &sd_card_driver_ops, - .size = sizeof( sd_card_driver_entry) - }, - .table_index = 0, - .minor = 0, -#endif - .device_name = "sd-card-a", -#if 0 - .disk_device_name = "/dev/sd-card-a", -#endif +sd_card_driver_entry sd_card_driver_table [] = { + { + .device_name = "/dev/sd-card-a", + .bus = 0, .transfer_mode = SD_CARD_TRANSFER_MODE_DEFAULT, .command = SD_CARD_COMMAND_DEFAULT, /* response : whatever, */ @@ -140,13 +122,15 @@ sd_card_driver_entry sd_card_driver_table [SD_CARD_NUMBER] = { { .block_number = 0, .block_size = 0, .block_size_shift = 0, - .busy = 1, - .verbose = 1, - .schedule_if_busy = 0, + .busy = true, + .verbose = true, + .schedule_if_busy = false } }; -rtems_status_code mpc55xx_sd_card_init(void) +size_t sd_card_driver_table_size = sizeof( sd_card_driver_table) / sizeof( sd_card_driver_table [0]); + +rtems_status_code mpc55xx_sd_card_init( bool mount) { rtems_status_code sc = RTEMS_SUCCESSFUL; int rv = 0; @@ -157,17 +141,18 @@ rtems_status_code mpc55xx_sd_card_init(void) sc = mpc55xx_dspi_init(); RTEMS_CHECK_SC( rv, "Intitalize DSPI bus"); - rv = rtems_libi2c_register_drv( e->device_name, (rtems_libi2c_drv_t *) e, mpc55xx_dspi_bus_table [0].bus_number, 0); - RTEMS_CHECK_RV_SC( rv, "Register SD Card driver"); + e->bus = mpc55xx_dspi_bus_table [0].bus_number; - sc = rtems_ide_part_table_initialize( MPC55XX_DEVICE_FILE); - RTEMS_CHECK_SC( sc, "Initialize IDE partition table"); + sc = sd_card_register(); + RTEMS_CHECK_SC( sc, "Register SD Card"); - rv = mkdir( MPC55XX_MOUNT_POINT, S_IRWXU); - RTEMS_CHECK_RV_SC( rv, "Create mount point"); + if (mount) { + sc = rtems_bdpart_register_from_disk( MPC55XX_DEVICE_FILE); + RTEMS_CHECK_SC( sc, "Initialize IDE partition table"); - rv = rtems_fsmount( mpc55xx_fs_table, sizeof( mpc55xx_fs_table) / sizeof( mpc55xx_fs_table [0]), NULL); - RTEMS_CHECK_RV_SC( rv, "Mount file systems"); + rv = rtems_fsmount( mpc55xx_fs_table, sizeof( mpc55xx_fs_table) / sizeof( mpc55xx_fs_table [0]), NULL); + RTEMS_CHECK_RV_SC( rv, "Mount file systems"); + } return RTEMS_SUCCESSFUL; } diff --git a/c/src/lib/libbsp/powerpc/mpc55xxevb/tests/tests.c b/c/src/lib/libbsp/powerpc/mpc55xxevb/tests/tests.c index 352e862c83..d1310a5c86 100644 --- a/c/src/lib/libbsp/powerpc/mpc55xxevb/tests/tests.c +++ b/c/src/lib/libbsp/powerpc/mpc55xxevb/tests/tests.c @@ -36,8 +36,6 @@ #include <libcpu/powerpc-utility.h> -/* #define DEBUG */ - #include <rtems/status-checks.h> static rtems_driver_address_table test_mpc55xx_drv_ops = { @@ -216,7 +214,10 @@ rtems_status_code mpc55xx_dspi_register(void) union SIU_PCR_tag pcr = MPC55XX_ZERO_FLAGS; printk( "Boot time: %u\n", ppc_time_base()); + + /* test_mpc55xx_intc( 0); + */ rv = rtems_libi2c_initialize(); RTEMS_CHECK_RV_SC( rv, "rtems_libi2c_initialize"); @@ -268,7 +269,7 @@ rtems_status_code mpc55xx_dspi_register(void) sc = rtems_semaphore_create ( rtems_build_name ( 'P', 'I', 'N', 'G'), 1, - RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY, + RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY, RTEMS_NO_PRIORITY, &test_mpc55xx_dspi_ping ); @@ -277,7 +278,7 @@ rtems_status_code mpc55xx_dspi_register(void) sc = rtems_semaphore_create ( rtems_build_name ( 'P', 'O', 'N', 'G'), 0, - RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY, + RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY, RTEMS_NO_PRIORITY, &test_mpc55xx_dspi_pong ); @@ -325,6 +326,8 @@ rtems_status_code mpc55xx_dspi_register(void) sc = rtems_task_start( sd_card_task_id, test_sd_card, 0); RTEMS_CHECK_SC( sc, "rtems_task_start"); + return RTEMS_SUCCESSFUL; + rtems_id intc_id; sc = rtems_task_create( rtems_build_name( 'I', 'N', 'T', 'C'), @@ -338,12 +341,11 @@ rtems_status_code mpc55xx_dspi_register(void) sc = rtems_task_start( intc_id, test_mpc55xx_intc, 0); RTEMS_CHECK_SC( sc, "rtems_task_start"); - sc = rtems_task_delete( RTEMS_SELF); - RTEMS_CHECK_SC( sc, "rtems_task_delete"); - return RTEMS_SUCCESSFUL; } +#if 0 + #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> @@ -421,35 +423,6 @@ static int test_sd_card_print_dir( const char* dirname, unsigned level) return 0; } -#define SD_CARD_NUMBER 1 - -static sd_card_driver_entry sd_card_driver_table_XXX [SD_CARD_NUMBER] = { { -#if 0 - driver : { - ops : &sd_card_driver_ops, - size : sizeof( sd_card_driver_entry) - }, - table_index : 0, - minor : 0, -#endif - device_name : "sd-card-a", -#if 0 - disk_device_name : "/dev/sd-card-a", -#endif - transfer_mode : SD_CARD_TRANSFER_MODE_DEFAULT, - command : SD_CARD_COMMAND_DEFAULT, - /* response : whatever, */ - response_index : SD_CARD_COMMAND_SIZE, - n_ac_max : SD_CARD_N_AC_MAX_DEFAULT, - block_number : 0, - block_size : 0, - block_size_shift : 0, - busy : 1, - verbose : 1, - schedule_if_busy : 0, - } -}; - rtems_task test_sd_card( rtems_task_argument arg) { rtems_status_code sc = RTEMS_SUCCESSFUL; @@ -484,17 +457,19 @@ rtems_task test_sd_card( rtems_task_argument arg) sc = rtems_ide_part_table_initialize( TEST_SD_CARD_DEVICE_FILE); RTEMS_CHECK_SC_TASK( sc, "Initialize IDE partition table"); - rv = test_sd_card_print_dir( "/dev", 0); - RTEMS_CHECK_RV_TASK( rv, "Print directory"); - rv = mkdir( TEST_SD_CARD_MOUNT_POINT, S_IRWXU); RTEMS_CHECK_RV_TASK( rv, "Create mount point"); rv = rtems_fsmount( test_sd_card_fs_table, sizeof( test_sd_card_fs_table) / sizeof( test_sd_card_fs_table [0]), NULL); RTEMS_CHECK_RV_TASK( rv, "Mount file systems"); - /*rv = test_sd_card_print_dir( TEST_SD_CARD_MOUNT_POINT, 0); */ - /*RTEMS_CHECK_RV_TASK( rv, "Print directory"); */ + rv = test_sd_card_print_dir( "/dev", 0); + RTEMS_CHECK_RV_TASK( rv, "Print directory"); + + rv = test_sd_card_print_dir( TEST_SD_CARD_MOUNT_POINT, 0); + RTEMS_CHECK_RV_TASK( rv, "Print directory"); + + (void) rtems_task_delete( RTEMS_SELF); rv = mkdir( TEST_SD_CARD_DIRECTORY, S_IRWXU); @@ -523,6 +498,8 @@ rtems_task test_sd_card( rtems_task_argument arg) rv = test_sd_card_print_dir( TEST_SD_CARD_DIRECTORY, 0); RTEMS_CHECK_RV_TASK( rv, "Print directory"); + (void) rtems_task_delete( RTEMS_SELF); + #if 0 /* Write */ @@ -561,35 +538,46 @@ rtems_task test_sd_card( rtems_task_argument arg) RTEMS_CHECK_RV_TASK( rv, "close"); #endif - sc = rtems_task_delete( RTEMS_SELF); - RTEMS_CHECK_SC_TASK( sc, "rtems_task_delete"); + (void) rtems_task_delete( RTEMS_SELF); } +#endif + #define ITER 4 #define BUFSIZE (128 * ITER) static char inbuf [BUFSIZE]; static char outbuf [BUFSIZE]; +static void test_mpc55xx_edma_done( mpc55xx_edma_channel_entry *e, uint32_t error_status) +{ + rtems_semaphore_release( e->id); + + if (error_status != 0) { + printk( "%s: Error status: 0x%08x\n", __func__, error_status); + } +} + static rtems_status_code test_mpc55xx_edma(void) { rtems_status_code sc = RTEMS_SUCCESSFUL; - int rv = 0; - int channel = 0; - uint32_t error_status = 0; - rtems_id transfer_update; + mpc55xx_edma_channel_entry e = { + .channel = 0, + .done = test_mpc55xx_edma_done, + .id = RTEMS_ID_NONE + }; sc = rtems_semaphore_create ( rtems_build_name ( 'T', 'S', 'T', 'C'), 0, - RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY, + RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_PRIORITY, RTEMS_NO_PRIORITY, - &transfer_update + &e.id ); RTEMS_CHECK_SC( sc, "rtems_semaphore_create"); - rv = mpc55xx_edma_obtain_channel( channel, &error_status, transfer_update); - RTEMS_CHECK_RV( rv, "mpc55xx_edma_obtain_channel"); + sc = mpc55xx_edma_obtain_channel( &e); + RTEMS_CHECK_RV( sc, "mpc55xx_edma_obtain_channel"); int i = 0; for (i = 0; i < BUFSIZE; ++i) { @@ -599,39 +587,40 @@ static rtems_status_code test_mpc55xx_edma(void) rtems_cache_flush_multiple_data_lines( inbuf, BUFSIZE); rtems_cache_flush_multiple_data_lines( outbuf, BUFSIZE); - struct tcd_t tcd = MPC55XX_EDMA_TCD_DEFAULT; + struct tcd_t tcd = EDMA_TCD_DEFAULT; tcd.SADDR = (uint32_t) &inbuf; tcd.DADDR = (uint32_t) &outbuf; tcd.NBYTES = BUFSIZE / ITER; tcd.SLAST = -BUFSIZE; - tcd.CITER = ITER; - tcd.BITER = ITER; - tcd.INT_HALF = 1; + tcd.CDF.B.CITER = ITER; + tcd.BMF.B.BITER = ITER; + tcd.BMF.B.INT_HALF = 1; - EDMA.TCD [channel] = tcd; + EDMA.TCD [e.channel] = tcd; while (1) { while (1) { - if (EDMA.TCD [channel].DONE == 1) { - EDMA.TCD [channel].DONE = 0; + if (EDMA.TCD [e.channel].BMF.B.DONE == 1) { + EDMA.TCD [e.channel].BMF.B.DONE = 0; printk( "%s: Done\n", __func__); break; - } else if (EDMA.TCD [channel].ACTIVE == 0) { - EDMA.SSBR.R = channel; - printk( "%s: Start: %i (%i)\n", __func__, EDMA.TCD [channel].CITER, EDMA.TCD [channel].BITER); + } else if (EDMA.TCD [e.channel].BMF.B.ACTIVE == 0) { + EDMA.SSBR.R = e.channel; + printk( "%s: Start: %i (%i)\n", __func__, EDMA.TCD [e.channel].CDF.B.CITER, EDMA.TCD [e.channel].BMF.B.BITER); } - sc = rtems_semaphore_obtain( transfer_update, RTEMS_WAIT, 10); + sc = rtems_semaphore_obtain( e.id, RTEMS_WAIT, 10); if (sc == RTEMS_TIMEOUT) { continue; } RTEMS_CHECK_SC( sc, "rtems_semaphore_obtain"); } - printk( "%s: Error status: 0x%08x\n", __func__, error_status); } - return sc; + return RTEMS_SUCCESSFUL; } +#include <stdlib.h> + static unsigned test_mpc55xx_intc_counter = 0; static inline void test_mpc55xx_intc_worker( void *data) @@ -667,11 +656,15 @@ static int test_mpc55xx_intc_handler_data [MPC55XX_IRQ_SOFTWARE_NUMBER]; static rtems_task test_mpc55xx_intc( rtems_task_argument arg) { + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_irq_connect_data e = { + .on = NULL, + .off = NULL, + .isOn = NULL + }; volatile int i = 0; int p = 0; unsigned s = 0; - rtems_irq_connect_data e; - rtems_status_code sc = RTEMS_SUCCESSFUL; for (i = MPC55XX_IRQ_SOFTWARE_MIN, p = MPC55XX_INTC_MIN_PRIORITY; i <= MPC55XX_IRQ_SOFTWARE_MAX; ++i, ++p) { test_mpc55xx_intc_handler_data [i] = i; @@ -684,12 +677,12 @@ static rtems_task test_mpc55xx_intc( rtems_task_argument arg) } e.hdl = test_mpc55xx_intc_handler_2; - if (BSP_install_rtems_shared_irq_handler( &e) != RTEMS_SUCCESSFUL) { + if (BSP_install_rtems_shared_irq_handler( &e) != 1) { BSP_panic( "Handler install 2 failed"); } e.hdl = test_mpc55xx_intc_handler_3; - if (BSP_install_rtems_shared_irq_handler( &e) != RTEMS_SUCCESSFUL) { + if (BSP_install_rtems_shared_irq_handler( &e) != 1) { BSP_panic( "Handler install 3 failed"); } } diff --git a/c/src/lib/libcpu/powerpc/ChangeLog b/c/src/lib/libcpu/powerpc/ChangeLog index 9c233309f7..e26b2f3dc7 100644 --- a/c/src/lib/libcpu/powerpc/ChangeLog +++ b/c/src/lib/libcpu/powerpc/ChangeLog @@ -1,3 +1,11 @@ +2009-07-20 Sebastian Huber <sebastian.huber@embedded-brains.de> + + * Makefile.am, preinstall.am: Update for MPC55XX changes. + * mpc55xx/emios/emios.c, mpc55xx/include/emios.h: New files. + * mpc55xx/dspi/dspi.c, mpc55xx/edma/edma.c, mpc55xx/esci/esci.c, + mpc55xx/include/dspi.h, mpc55xx/include/edma.h, mpc55xx/include/irq.h, + mpc55xx/include/regs.h, mpc55xx/irq/irq.c: Changes throughout. + 2009-05-05 Jennifer Averett <jennifer.averett@OARcorp.com> * mpc6xx/mmu/bat.c, new-exceptions/e500_raw_exc_init.c, diff --git a/c/src/lib/libcpu/powerpc/Makefile.am b/c/src/lib/libcpu/powerpc/Makefile.am index 233ff89372..7393193d5a 100644 --- a/c/src/lib/libcpu/powerpc/Makefile.am +++ b/c/src/lib/libcpu/powerpc/Makefile.am @@ -419,6 +419,7 @@ include_mpc55xx_HEADERS = mpc55xx/include/regs.h \ mpc55xx/include/reg-defs.h \ mpc55xx/include/dspi.h \ mpc55xx/include/edma.h \ + mpc55xx/include/emios.h \ mpc55xx/include/mpc55xx.h \ mpc55xx/include/esci.h \ mpc55xx/include/watchdog.h @@ -433,12 +434,17 @@ noinst_PROGRAMS += mpc55xx/fec.rel mpc55xx_fec_rel_SOURCES = mpc55xx/fec/fec.c mpc55xx_fec_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) -# EMDA +# eDMA noinst_PROGRAMS += mpc55xx/edma.rel mpc55xx_edma_rel_SOURCES = mpc55xx/edma/edma.c mpc55xx_edma_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) -# ESCI +# eMIOS +noinst_PROGRAMS += mpc55xx/emios.rel +mpc55xx_emios_rel_SOURCES = mpc55xx/emios/emios.c +mpc55xx_emios_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) + +# eSCI noinst_PROGRAMS += mpc55xx/esci.rel mpc55xx_esci_rel_SOURCES = mpc55xx/esci/esci.c mpc55xx_esci_rel_LDFLAGS = $(RTEMS_RELLDFLAGS) diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c b/c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c index 8473eb13b7..91ea95056b 100644 --- a/c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c +++ b/c/src/lib/libcpu/powerpc/mpc55xx/dspi/dspi.c @@ -20,7 +20,6 @@ #include <mpc55xx/regs.h> #include <mpc55xx/dspi.h> -#include <mpc55xx/edma.h> #include <mpc55xx/mpc55xx.h> #include <libcpu/powerpc-utility.h> @@ -111,6 +110,15 @@ static const mpc55xx_dspi_baudrate_scaler_entry mpc55xx_dspi_baudrate_scaler_tab { 229376, 3, 15 }, }; +static void mpc55xx_dspi_edma_done( mpc55xx_edma_channel_entry *e, uint32_t error_status) +{ + rtems_semaphore_release( e->id); + + if (error_status != 0) { + RTEMS_SYSLOG_ERROR( "eDMA error: 0x%08x\n", error_status); + } +} + static mpc55xx_dspi_baudrate_scaler_entry mpc55xx_dspi_search_baudrate_scaler( uint32_t scaler, int min, int mid, int max) { if (scaler <= mpc55xx_dspi_baudrate_scaler_table [mid].scaler) { @@ -151,49 +159,49 @@ static rtems_status_code mpc55xx_dspi_init( rtems_libi2c_bus_t *bus) union DSPI_MCR_tag mcr = MPC55XX_ZERO_FLAGS; union DSPI_CTAR_tag ctar = MPC55XX_ZERO_FLAGS; union DSPI_RSER_tag rser = MPC55XX_ZERO_FLAGS; - struct tcd_t tcd_push = MPC55XX_EDMA_TCD_DEFAULT; + struct tcd_t tcd_push = EDMA_TCD_DEFAULT; int i = 0; /* eDMA receive */ sc = rtems_semaphore_create ( rtems_build_name ( 'S', 'P', 'I', 'R'), 0, - RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY, - RTEMS_NO_PRIORITY, - &e->edma_channel_receive_update + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &e->edma_receive.id ); - RTEMS_CHECK_SC( sc, "Create receive update semaphore"); + RTEMS_CHECK_SC( sc, "create receive update semaphore"); - sc = mpc55xx_edma_obtain_channel( e->edma_channel_receive, &e->edma_channel_receive_error, e->edma_channel_receive_update); - RTEMS_CHECK_SC( sc, "Obtain receive eDMA channel"); + sc = mpc55xx_edma_obtain_channel( &e->edma_receive); + RTEMS_CHECK_SC( sc, "obtain receive eDMA channel"); /* eDMA transmit */ sc = rtems_semaphore_create ( rtems_build_name ( 'S', 'P', 'I', 'T'), 0, - RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY, - RTEMS_NO_PRIORITY, - &e->edma_channel_transmit_update + RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &e->edma_transmit.id ); - RTEMS_CHECK_SC( sc, "Create transmit update semaphore"); + RTEMS_CHECK_SC( sc, "create transmit update semaphore"); - sc = mpc55xx_edma_obtain_channel( e->edma_channel_transmit, &e->edma_channel_transmit_error, e->edma_channel_transmit_update); - RTEMS_CHECK_SC( sc, "Obtain transmit eDMA channel"); + sc = mpc55xx_edma_obtain_channel( &e->edma_transmit); + RTEMS_CHECK_SC( sc, "obtain transmit eDMA channel"); - sc = mpc55xx_edma_obtain_channel( e->edma_channel_push, NULL, RTEMS_ID_NONE); - RTEMS_CHECK_SC( sc, "Obtain push eDMA channel"); + sc = mpc55xx_edma_obtain_channel( &e->edma_push); + RTEMS_CHECK_SC( sc, "obtain push eDMA channel"); tcd_push.SADDR = mpc55xx_dspi_push_data_address( e); - tcd_push.SSIZE = 2; - tcd_push.SOFF = 0; + tcd_push.SDF.B.SSIZE = 2; + tcd_push.SDF.B.SOFF = 0; tcd_push.DADDR = (uint32_t) &e->regs->PUSHR.R; - tcd_push.DSIZE = 2; - tcd_push.DOFF = 0; + tcd_push.SDF.B.DSIZE = 2; + tcd_push.CDF.B.DOFF = 0; tcd_push.NBYTES = 4; - tcd_push.CITER = 1; - tcd_push.BITER = 1; + tcd_push.CDF.B.CITER = 1; + tcd_push.BMF.B.BITER = 1; - EDMA.TCD [e->edma_channel_push] = tcd_push; + EDMA.TCD [e->edma_push.channel] = tcd_push; /* Module Control Register */ mcr.B.MSTR = e->master ? 1 : 0; @@ -324,8 +332,6 @@ static int mpc55xx_dspi_set_transfer_mode( rtems_libi2c_bus_t *bus, const rtems_ { mpc55xx_dspi_bus_entry *e = (mpc55xx_dspi_bus_entry *) bus; union DSPI_CTAR_tag ctar = MPC55XX_ZERO_FLAGS; - uint32_t scaler = bsp_clock_speed / mode->baudrate; - mpc55xx_dspi_baudrate_scaler_entry bse = mpc55xx_dspi_search_baudrate_scaler( scaler, 0, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE / 2, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE); if (mode->bits_per_char != 8) { return -RTEMS_INVALID_NUMBER; @@ -335,9 +341,6 @@ static int mpc55xx_dspi_set_transfer_mode( rtems_libi2c_bus_t *bus, const rtems_ ctar.R = e->regs->CTAR [MPC55XX_DSPI_CTAR_DEFAULT].R; - ctar.B.PBR = bse.pbr; - ctar.B.BR = bse.br; - ctar.B.PCSSCK = 0; ctar.B.CSSCK = 0; ctar.B.PASC = 0; @@ -347,6 +350,16 @@ static int mpc55xx_dspi_set_transfer_mode( rtems_libi2c_bus_t *bus, const rtems_ ctar.B.CPOL = mode->clock_inv ? 1 : 0; ctar.B.CPHA = mode->clock_phs ? 1 : 0; + if (mode->baudrate != e->baud) { + uint32_t scaler = bsp_clock_speed / mode->baudrate; + mpc55xx_dspi_baudrate_scaler_entry bse = mpc55xx_dspi_search_baudrate_scaler( scaler, 0, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE / 2, MPC55XX_DSPI_BAUDRATE_SCALER_TABLE_SIZE); + + ctar.B.PBR = bse.pbr; + ctar.B.BR = bse.br; + + e->baud = mode->baudrate; + } + e->regs->CTAR [MPC55XX_DSPI_CTAR_DEFAULT].R = ctar.R; return 0; @@ -363,9 +376,9 @@ static int mpc55xx_dspi_set_transfer_mode( rtems_libi2c_bus_t *bus, const rtems_ * idle_push_data [label="Idle Push Data"]; * out [shape=box,label="Output Buffer"]; * edge [color=red,fontcolor=red]; - * push -> idle_push_data [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_transmit"]; - * push -> out [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_transmit"]; - * out -> push_data [label="Channel Link",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_push"]; + * push -> idle_push_data [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_transmit"]; + * push -> out [label="Transmit Request",URL="\ref mpc55xx_dspi_bus_entry::edma_transmit"]; + * out -> push_data [label="Channel Link",URL="\ref mpc55xx_dspi_bus_entry::edma_push"]; * edge [color=blue,fontcolor=blue]; * out -> push_data [label="Data"]; * push_data -> push [label="Data"]; @@ -380,8 +393,8 @@ static int mpc55xx_dspi_set_transfer_mode( rtems_libi2c_bus_t *bus, const rtems_ * nirvana [label="Nirvana"]; * in [shape=box,label="Input Buffer"]; * edge [color=red,fontcolor=red]; - * pop -> nirvana [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_receive"]; - * pop -> in [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_channel_receive"]; + * pop -> nirvana [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_receive"]; + * pop -> in [label="Receive Request",URL="\ref mpc55xx_dspi_bus_entry::edma_receive"]; * edge [color=blue,fontcolor=blue]; * pop -> nirvana [label="Data"]; * pop -> in [label="Data"]; @@ -424,11 +437,11 @@ static int mpc55xx_dspi_read_write( rtems_libi2c_bus_t *bus, unsigned char *in, n_nc = (int) mpc55xx_non_cache_aligned_size( in); n_c = (int) mpc55xx_cache_aligned_size( in, (size_t) n); if (n_c > EDMA_TCD_BITER_LINKED_SIZE) { - RTEMS_SYSLOG_WARNING( "Buffer size out of range, cannot use eDMA\n"); + RTEMS_SYSLOG_WARNING( "buffer size out of range, cannot use eDMA\n"); n_nc = n; n_c = 0; } else if (n_nc + n_c != n) { - RTEMS_SYSLOG_WARNING( "Input buffer not proper cache aligned, cannot use eDMA\n"); + RTEMS_SYSLOG_WARNING( "input buffer not proper cache aligned, cannot use eDMA\n"); n_nc = n; n_c = 0; } @@ -510,8 +523,8 @@ static int mpc55xx_dspi_read_write( rtems_libi2c_bus_t *bus, unsigned char *in, rtems_status_code sc = RTEMS_SUCCESSFUL; unsigned char *in_c = in + n_nc; const unsigned char *out_c = out + n_nc; - struct tcd_t tcd_transmit = MPC55XX_EDMA_TCD_DEFAULT; - struct tcd_t tcd_receive = MPC55XX_EDMA_TCD_DEFAULT; + struct tcd_t tcd_transmit = EDMA_TCD_DEFAULT; + struct tcd_t tcd_receive = EDMA_TCD_DEFAULT; /* Cache operations */ rtems_cache_flush_multiple_data_lines( out_c, (size_t) n_c); @@ -522,52 +535,52 @@ static int mpc55xx_dspi_read_write( rtems_libi2c_bus_t *bus, unsigned char *in, e->push_data.B.TXDATA = e->idle_char; mpc55xx_dspi_store_push_data( e); tcd_transmit.SADDR = mpc55xx_dspi_push_data_address( e); - tcd_transmit.SSIZE = 2; - tcd_transmit.SOFF = 0; + tcd_transmit.SDF.B.SSIZE = 2; + tcd_transmit.SDF.B.SOFF = 0; tcd_transmit.DADDR = (uint32_t) push; - tcd_transmit.DSIZE = 2; - tcd_transmit.DOFF = 0; + tcd_transmit.SDF.B.DSIZE = 2; + tcd_transmit.CDF.B.DOFF = 0; tcd_transmit.NBYTES = 4; - tcd_transmit.CITER = n_c; - tcd_transmit.BITER = n_c; + tcd_transmit.CDF.B.CITER = n_c; + tcd_transmit.BMF.B.BITER = n_c; } else { - EDMA.CDSBR.R = e->edma_channel_transmit; + EDMA.CDSBR.R = e->edma_transmit.channel; tcd_transmit.SADDR = (uint32_t) out_c; - tcd_transmit.SSIZE = 0; - tcd_transmit.SOFF = 1; + tcd_transmit.SDF.B.SSIZE = 0; + tcd_transmit.SDF.B.SOFF = 1; tcd_transmit.DADDR = mpc55xx_dspi_push_data_address( e) + 3; - tcd_transmit.DSIZE = 0; - tcd_transmit.DOFF = 0; + tcd_transmit.SDF.B.DSIZE = 0; + tcd_transmit.CDF.B.DOFF = 0; tcd_transmit.NBYTES = 1; - tcd_transmit.CITERE_LINK = 1; - tcd_transmit.BITERE_LINK = 1; - tcd_transmit.MAJORLINKCH = e->edma_channel_push; - tcd_transmit.CITER = EDMA_TCD_LINK_AND_BITER( e->edma_channel_push, n_c); - tcd_transmit.BITER = EDMA_TCD_LINK_AND_BITER( e->edma_channel_push, n_c); - tcd_transmit.MAJORE_LINK = 1; + tcd_transmit.CDF.B.CITERE_LINK = 1; + tcd_transmit.BMF.B.BITERE_LINK = 1; + tcd_transmit.BMF.B.MAJORLINKCH = e->edma_push.channel; + tcd_transmit.CDF.B.CITER = EDMA_TCD_LINK_AND_BITER( e->edma_push.channel, n_c); + tcd_transmit.BMF.B.BITER = EDMA_TCD_LINK_AND_BITER( e->edma_push.channel, n_c); + tcd_transmit.BMF.B.MAJORE_LINK = 1; } - tcd_transmit.D_REQ = 1; - tcd_transmit.INT_MAJ = 1; - EDMA.TCD [e->edma_channel_transmit] = tcd_transmit; + tcd_transmit.BMF.B.D_REQ = 1; + tcd_transmit.BMF.B.INT_MAJ = 1; + EDMA.TCD [e->edma_transmit.channel] = tcd_transmit; /* Set receive TCD */ if (in == NULL) { - tcd_receive.DOFF = 0; + tcd_receive.CDF.B.DOFF = 0; tcd_receive.DADDR = mpc55xx_dspi_nirvana_address( e); } else { - tcd_receive.DOFF = 1; + tcd_receive.CDF.B.DOFF = 1; tcd_receive.DADDR = (uint32_t) in_c; } tcd_receive.SADDR = (uint32_t) pop + 3; - tcd_receive.SSIZE = 0; - tcd_receive.SOFF = 0; - tcd_receive.DSIZE = 0; + tcd_receive.SDF.B.SSIZE = 0; + tcd_receive.SDF.B.SOFF = 0; + tcd_receive.SDF.B.DSIZE = 0; tcd_receive.NBYTES = 1; - tcd_receive.D_REQ = 1; - tcd_receive.INT_MAJ = 1; - tcd_receive.CITER = n_c; - tcd_receive.BITER = n_c; - EDMA.TCD [e->edma_channel_receive] = tcd_receive; + tcd_receive.BMF.B.D_REQ = 1; + tcd_receive.BMF.B.INT_MAJ = 1; + tcd_receive.CDF.B.CITER = n_c; + tcd_receive.BMF.B.BITER = n_c; + EDMA.TCD [e->edma_receive.channel] = tcd_receive; /* Clear request flags */ sr.R = 0; @@ -576,28 +589,16 @@ static int mpc55xx_dspi_read_write( rtems_libi2c_bus_t *bus, unsigned char *in, status->R = sr.R; /* Enable hardware requests */ - sc = mpc55xx_edma_enable_hardware_requests( e->edma_channel_receive, true); - RTEMS_CHECK_SC_RV( sc, "Enable receive hardware requests"); - sc = mpc55xx_edma_enable_hardware_requests( e->edma_channel_transmit, true); - RTEMS_CHECK_SC_RV( sc, "Enable transmit hardware requests"); + mpc55xx_edma_enable_hardware_requests( e->edma_receive.channel, true); + mpc55xx_edma_enable_hardware_requests( e->edma_transmit.channel, true); /* Wait for transmit update */ - sc = rtems_semaphore_obtain( e->edma_channel_transmit_update, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - RTEMS_CHECK_SC_RV( sc, "Transmit update"); - if (e->edma_channel_transmit_error != 0) { - RTEMS_SYSLOG_ERROR( "Transmit error status: 0x%08x\n", e->edma_channel_transmit_error); - e->edma_channel_transmit_error = 0; - return -RTEMS_IO_ERROR; - } + sc = rtems_semaphore_obtain( e->edma_transmit.id, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + RTEMS_CHECK_SC_RV( sc, "transmit update"); /* Wait for receive update */ - sc = rtems_semaphore_obtain( e->edma_channel_receive_update, RTEMS_WAIT, RTEMS_NO_TIMEOUT); - RTEMS_CHECK_SC_RV( sc, "Receive update"); - if (e->edma_channel_receive_error != 0) { - RTEMS_SYSLOG_ERROR( "Receive error status: 0x%08x\n", e->edma_channel_receive_error); - e->edma_channel_receive_error = 0; - return -RTEMS_IO_ERROR; - } + sc = rtems_semaphore_obtain( e->edma_receive.id, RTEMS_WAIT, RTEMS_NO_TIMEOUT); + RTEMS_CHECK_SC_RV( sc, "receive update"); } return n; @@ -659,7 +660,8 @@ static const rtems_libi2c_bus_ops_t mpc55xx_dspi_ops = { .ioctl = mpc55xx_dspi_ioctl }; -mpc55xx_dspi_bus_entry mpc55xx_dspi_bus_table [MPC55XX_DSPI_NUMBER] = { { +mpc55xx_dspi_bus_entry mpc55xx_dspi_bus_table [MPC55XX_DSPI_NUMBER] = { + { /* DSPI A */ .bus = { .ops = &mpc55xx_dspi_ops, @@ -668,16 +670,25 @@ mpc55xx_dspi_bus_entry mpc55xx_dspi_bus_table [MPC55XX_DSPI_NUMBER] = { { .table_index = 0, .bus_number = 0, .regs = &DSPI_A, - .master = 1, + .master = true, .push_data = MPC55XX_ZERO_FLAGS, - .edma_channel_transmit = 32, - .edma_channel_push = 43, - .edma_channel_receive = 33, - .edma_channel_transmit_update = 0, - .edma_channel_receive_update = 0, - .edma_channel_transmit_error = 0, - .edma_channel_receive_error = 0, + .edma_transmit = { + .channel = 32, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, + .edma_push = { + .channel = 43, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, + .edma_receive = { + .channel = 33, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, .idle_char = 0xffffffff, + .baud = 0 }, { /* DSPI B */ .bus = { @@ -687,16 +698,25 @@ mpc55xx_dspi_bus_entry mpc55xx_dspi_bus_table [MPC55XX_DSPI_NUMBER] = { { .table_index = 1, .bus_number = 0, .regs = &DSPI_B, - .master = 1, + .master = true, .push_data = MPC55XX_ZERO_FLAGS, - .edma_channel_transmit = 12, - .edma_channel_push = 10, - .edma_channel_receive = 13, - .edma_channel_transmit_update = 0, - .edma_channel_receive_update = 0, - .edma_channel_transmit_error = 0, - .edma_channel_receive_error = 0, + .edma_transmit = { + .channel = 12, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, + .edma_push = { + .channel = 10, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, + .edma_receive = { + .channel = 13, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, .idle_char = 0xffffffff, + .baud = 0 }, { /* DSPI C */ .bus = { @@ -706,16 +726,25 @@ mpc55xx_dspi_bus_entry mpc55xx_dspi_bus_table [MPC55XX_DSPI_NUMBER] = { { .table_index = 2, .bus_number = 0, .regs = &DSPI_C, - .master = 1, + .master = true, .push_data = MPC55XX_ZERO_FLAGS, - .edma_channel_transmit = 14, - .edma_channel_push = 11, - .edma_channel_receive = 15, - .edma_channel_transmit_update = 0, - .edma_channel_receive_update = 0, - .edma_channel_transmit_error = 0, - .edma_channel_receive_error = 0, + .edma_transmit = { + .channel = 14, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, + .edma_push = { + .channel = 11, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, + .edma_receive = { + .channel = 15, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, .idle_char = 0xffffffff, + .baud = 0 }, { /* DSPI D */ .bus = { @@ -725,15 +754,24 @@ mpc55xx_dspi_bus_entry mpc55xx_dspi_bus_table [MPC55XX_DSPI_NUMBER] = { { .table_index = 3, .bus_number = 0, .regs = &DSPI_D, - .master = 1, + .master = true, .push_data = MPC55XX_ZERO_FLAGS, - .edma_channel_transmit = 16, - .edma_channel_push = 18, - .edma_channel_receive = 17, - .edma_channel_transmit_update = 0, - .edma_channel_receive_update = 0, - .edma_channel_transmit_error = 0, - .edma_channel_receive_error = 0, + .edma_transmit = { + .channel = 16, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, + .edma_push = { + .channel = 18, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, + .edma_receive = { + .channel = 17, + .done = mpc55xx_dspi_edma_done, + .id = RTEMS_ID_NONE + }, .idle_char = 0xffffffff, - }, + .baud = 0 + } }; diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c b/c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c index 1572cce0b2..dc7adc136e 100644 --- a/c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c +++ b/c/src/lib/libcpu/powerpc/mpc55xx/edma/edma.c @@ -22,164 +22,148 @@ #include <mpc55xx/edma.h> #include <mpc55xx/mpc55xx.h> -#include <bsp/irq.h> - #include <string.h> +#include <bsp/irq.h> +#include <bsp/utility.h> + #define RTEMS_STATUS_CHECKS_USE_PRINTK #include <rtems/status-checks.h> -#define MPC55XX_EDMA_CHANNEL_NUMBER 64 -#define MPC55XX_EDMA_INVALID_CHANNEL UINT8_MAX -#define MPC55XX_EDMA_IS_CHANNEL_INVALID( i) ((i) < 0 || (i) >= MPC55XX_EDMA_CHANNEL_NUMBER) - -#define MPC55XX_EDMA_IRQ_PRIORITY MPC55XX_INTC_MIN_PRIORITY +#define MPC55XX_EDMA_CHANNEL_NUMBER 64U -typedef struct { - uint8_t channel; - rtems_id transfer_update; - uint32_t *error_status; -} mpc55xx_edma_channel_entry; +#define MPC55XX_EDMA_INVALID_CHANNEL MPC55XX_EDMA_CHANNEL_NUMBER -static mpc55xx_edma_channel_entry mpc55xx_edma_channel_table [MPC55XX_EDMA_CHANNEL_NUMBER]; +#define MPC55XX_EDMA_IS_CHANNEL_INVALID( i) ((unsigned) (i) >= MPC55XX_EDMA_CHANNEL_NUMBER) -static uint32_t mpc55xx_edma_channel_occupation_low = 0; +#define MPC55XX_EDMA_IS_CHANNEL_VALID( i) ((unsigned) (i) < MPC55XX_EDMA_CHANNEL_NUMBER) -static uint32_t mpc55xx_edma_channel_occupation_high = 0; +#define MPC55XX_EDMA_IRQ_PRIORITY MPC55XX_INTC_DEFAULT_PRIORITY -static rtems_id mpc55xx_edma_channel_occupation_mutex = RTEMS_ID_NONE; +#define MPC55XX_EDMA_CHANNEL_FLAG( channel) ((uint64_t) 1 << (channel)) -static uint8_t mpc55xx_edma_irq_error_low_channel = 0; +static uint64_t mpc55xx_edma_channel_occupation = 0; -static uint8_t mpc55xx_edma_irq_error_high_channel = 32; +static rtems_chain_control mpc55xx_edma_channel_chain; -static void mpc55xx_edma_irq_handler( rtems_vector_number vector, void *data) +static void mpc55xx_edma_interrupt_handler( rtems_vector_number vector, void *arg) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - mpc55xx_edma_channel_entry *e = (mpc55xx_edma_channel_entry *) data; + mpc55xx_edma_channel_entry *e = (mpc55xx_edma_channel_entry *) arg; + #ifdef DEBUG uint32_t citer = EDMA.TCD [e->channel].CITERE_LINK ? EDMA.TCD [e->channel].CITER & EDMA_TCD_BITER_LINKED_MASK : EDMA.TCD [e->channel].CITER; - RTEMS_DEBUG_PRINT( "Channel %i (CITER = %i)\n", e->channel, citer); + RTEMS_DEBUG_PRINT( "channel %i (CITER = %i)\n", e->channel, citer); #endif /* DEBUG */ - EDMA.CIRQR.R = e->channel; - sc = rtems_semaphore_release( e->transfer_update); - RTEMS_SYSLOG_WARNING_SC( sc, "Transfer update semaphore release"); -} -static void mpc55xx_edma_irq_update_error_table( uint8_t *link_table, uint8_t *error_table, int channel) -{ - int i = 0; - error_table [channel] = 1; - for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) { - if (channel == link_table [i] && error_table [i] == 0) { - mpc55xx_edma_irq_update_error_table( link_table, error_table, i); - } - } + /* Clear interrupt */ + EDMA.CIRQR.R = (uint8_t) e->channel; + + /* Notify user */ + e->done( e, 0); } -static void mpc55xx_edma_irq_error_handler( rtems_vector_number vector, void *data) +static void mpc55xx_edma_interrupt_error_handler( rtems_vector_number vector, void *arg) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - uint8_t channel_start = *((uint8_t *) data); - uint8_t channel_end = (uint8_t) (channel_start + 32); - int i = 0; - uint32_t mask = 0x1; - uint32_t error_register = 0; - uint8_t channel_link_table [MPC55XX_EDMA_CHANNEL_NUMBER]; - uint8_t channel_error_table [MPC55XX_EDMA_CHANNEL_NUMBER]; - - /* Error register */ - if (channel_start < 32) { - error_register = EDMA.ERL.R; - } else if (channel_start < 64) { - error_register = EDMA.ERH.R; - } - RTEMS_DEBUG_PRINT( "Error register %s: 0x%08x\n", channel_start < 32 ? "low" : "high", error_register); + rtems_chain_control *chain = &mpc55xx_edma_channel_chain; + rtems_chain_node *node = chain->first; + unsigned i = 0; + uint64_t error_status = EDMA.ESR.R; + uint64_t error_channels = ((uint64_t) EDMA.ERH.R << 32) | EDMA.ERL.R; + uint64_t error_channels_update = 0; + + RTEMS_DEBUG_PRINT( "error channels: %08x %08x\n", (unsigned) (error_channels >> 32), (unsigned) error_channels); + + /* Mark all channels that are linked to a channel with errors */ + do { + error_channels_update = 0; + + for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) { + uint64_t channel_flags = 0; + unsigned minor_link = i; + unsigned major_link = i; + + /* Check if we have linked channels */ + if (EDMA.TCD [i].BMF.B.BITERE_LINK) { + minor_link = EDMA_TCD_BITER_LINK( i); + } + if (EDMA.TCD [i].BMF.B.MAJORE_LINK) { + major_link = EDMA.TCD [i].BMF.B.MAJORLINKCH; + } - /* Fill channel link table */ - for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) { - if (EDMA.TCD [i].BITERE_LINK && EDMA.TCD [i].CITER != EDMA.TCD [i].BITER) { - channel_link_table [i] = (uint8_t) EDMA_TCD_BITER_LINK( i); - } else if (EDMA.TCD [i].MAJORE_LINK && EDMA.TCD [i].CITER == EDMA.TCD [i].BITER) { - channel_link_table [i] = EDMA.TCD [i].MAJORLINKCH; - } else { - channel_link_table [i] = MPC55XX_EDMA_INVALID_CHANNEL; - } - channel_error_table [i] = 0; - } + /* Set flags related to this channel */ + channel_flags = MPC55XX_EDMA_CHANNEL_FLAG( i) | MPC55XX_EDMA_CHANNEL_FLAG( minor_link) | MPC55XX_EDMA_CHANNEL_FLAG( major_link); + + /* Any errors in these channels? */ + if (IS_ANY_FLAG_SET( error_channels, channel_flags)) { + /* Get new error channels */ + uint64_t update = (error_channels & channel_flags) ^ channel_flags; - /* Search for channels with errors */ - for (i = channel_start; i < channel_end; ++i) { - if ((error_register & mask) != 0) { - mpc55xx_edma_irq_update_error_table( channel_link_table, channel_error_table, i); + /* Update error channels */ + error_channels = SET_FLAGS( error_channels, channel_flags); + + /* Contribute to the update of this round */ + error_channels_update = SET_FLAGS( error_channels_update, update); + } } - mask <<= 1; - } + } while (error_channels_update != 0); + + RTEMS_DEBUG_PRINT( "error channels (all): %08x %08x\n", (unsigned) (error_channels >> 32), (unsigned) error_channels); /* Process the channels related to errors */ - error_register = EDMA.ESR.R; - for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) { - if (channel_error_table [i]) { - mpc55xx_edma_channel_entry *e = &mpc55xx_edma_channel_table [i]; - if (e->error_status != NULL) { - *e->error_status = error_register; - } - sc = mpc55xx_edma_enable_hardware_requests( i, false); - RTEMS_SYSLOG_ERROR_SC( sc, "Disable hardware requests"); - sc = rtems_semaphore_release( e->transfer_update); - RTEMS_SYSLOG_WARNING_SC( sc, "Transfer update semaphore release"); + while (!rtems_chain_is_tail( chain, node)) { + mpc55xx_edma_channel_entry *e = (mpc55xx_edma_channel_entry *) node; + + if (IS_FLAG_SET( error_channels, MPC55XX_EDMA_CHANNEL_FLAG( e->channel))) { + mpc55xx_edma_enable_hardware_requests( e->channel, false); + + /* Notify user */ + e->done( e, error_status); } + + node = node->next; } /* Clear the error interrupt requests */ for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) { - if (channel_error_table [i]) { + if (IS_FLAG_SET( error_channels, MPC55XX_EDMA_CHANNEL_FLAG( i))) { EDMA.CER.R = (uint8_t) i; } } } -rtems_status_code mpc55xx_edma_enable_hardware_requests( int channel, bool enable) +void mpc55xx_edma_enable_hardware_requests( unsigned channel, bool enable) { - if (MPC55XX_EDMA_IS_CHANNEL_INVALID( channel)) { - return RTEMS_INVALID_NUMBER; - } - if (enable) { - EDMA.SERQR.R = (uint8_t) channel; + if (MPC55XX_EDMA_IS_CHANNEL_VALID( channel)) { + if (enable) { + EDMA.SERQR.R = (uint8_t) channel; + } else { + EDMA.CERQR.R = (uint8_t) channel; + } } else { - EDMA.CERQR.R = (uint8_t) channel; + RTEMS_SYSLOG_ERROR( "invalid channel number\n"); } - return RTEMS_SUCCESSFUL; } -rtems_status_code mpc55xx_edma_enable_error_interrupts( int channel, bool enable) +void mpc55xx_edma_enable_error_interrupts( unsigned channel, bool enable) { - if (MPC55XX_EDMA_IS_CHANNEL_INVALID( channel)) { - return RTEMS_INVALID_NUMBER; - } - if (enable) { - EDMA.SEEIR.R = channel; + if (MPC55XX_EDMA_IS_CHANNEL_VALID( channel)) { + if (enable) { + EDMA.SEEIR.R = (uint8_t) channel; + } else { + EDMA.CEEIR.R = (uint8_t) channel; + } } else { - EDMA.CEEIR.R = channel; + RTEMS_SYSLOG_ERROR( "invalid channel number\n"); } - return RTEMS_SUCCESSFUL; } rtems_status_code mpc55xx_edma_init() { rtems_status_code sc = RTEMS_SUCCESSFUL; - int i = 0; - - /* Channel occupation mutex */ - sc = rtems_semaphore_create ( - rtems_build_name ( 'D', 'M', 'A', 'O'), - 1, - RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY, - RTEMS_NO_PRIORITY, - &mpc55xx_edma_channel_occupation_mutex - ); - RTEMS_CHECK_SC( sc, "Create channel occupation mutex"); + + /* Initialize channel chain */ + rtems_chain_initialize_empty( &mpc55xx_edma_channel_chain); /* Arbitration mode: round robin */ EDMA.CR.B.ERCA = 1; @@ -188,92 +172,101 @@ rtems_status_code mpc55xx_edma_init() /* Clear TCDs */ memset( &EDMA.TCD [0], 0, sizeof( EDMA.TCD)); - /* Channel table */ - for (i = 0; i < MPC55XX_EDMA_CHANNEL_NUMBER; ++i) { - mpc55xx_edma_channel_table [i].channel = i; - mpc55xx_edma_channel_table [i].transfer_update = RTEMS_ID_NONE; - mpc55xx_edma_channel_table [i].error_status = NULL; - } - - /* Error interrupt handler */ + /* Error interrupt handlers */ sc = mpc55xx_interrupt_handler_install( MPC55XX_IRQ_EDMA_ERROR_LOW, - MPC55XX_EDMA_IRQ_PRIORITY, "eDMA Error (Low)", RTEMS_INTERRUPT_UNIQUE, - mpc55xx_edma_irq_error_handler, - &mpc55xx_edma_irq_error_low_channel + MPC55XX_EDMA_IRQ_PRIORITY, + mpc55xx_edma_interrupt_error_handler, + NULL ); - RTEMS_CHECK_SC( sc, "Install low error interrupt handler"); + RTEMS_CHECK_SC( sc, "install low error interrupt handler"); sc = mpc55xx_interrupt_handler_install( MPC55XX_IRQ_EDMA_ERROR_HIGH, - MPC55XX_EDMA_IRQ_PRIORITY, "eDMA Error (High)", RTEMS_INTERRUPT_UNIQUE, - mpc55xx_edma_irq_error_handler, - &mpc55xx_edma_irq_error_high_channel + MPC55XX_EDMA_IRQ_PRIORITY, + mpc55xx_edma_interrupt_error_handler, + NULL ); - RTEMS_CHECK_SC( sc, "Install high error interrupt handler"); + RTEMS_CHECK_SC( sc, "install high error interrupt handler"); return RTEMS_SUCCESSFUL; } -rtems_status_code mpc55xx_edma_obtain_channel( int channel, uint32_t *error_status, rtems_id transfer_update) +rtems_status_code mpc55xx_edma_obtain_channel( mpc55xx_edma_channel_entry *e) { rtems_status_code sc = RTEMS_SUCCESSFUL; - int channel_occupied = 1; + rtems_interrupt_level level; + uint64_t channel_occupation = 0; - if (MPC55XX_EDMA_IS_CHANNEL_INVALID( channel)) { + if (MPC55XX_EDMA_IS_CHANNEL_INVALID( e->channel)) { return RTEMS_INVALID_NUMBER; } - /* Check occupation */ - sc = rtems_semaphore_obtain( mpc55xx_edma_channel_occupation_mutex, RTEMS_WAIT, 0); - RTEMS_CHECK_SC( sc, "Obtain channel occupation mutex"); - if (channel < 32) { - channel_occupied = mpc55xx_edma_channel_occupation_low & (0x1 << channel); - if (!channel_occupied) { - mpc55xx_edma_channel_occupation_low |= 0x1 << channel; - } - } else if (channel < 64) { - channel_occupied = mpc55xx_edma_channel_occupation_high & (0x1 << (channel - 32)); - if (!channel_occupied) { - mpc55xx_edma_channel_occupation_high |= 0x1 << (channel - 32); - } + /* Test and set channel occupation flag */ + rtems_interrupt_disable( level); + channel_occupation = mpc55xx_edma_channel_occupation; + if (IS_FLAG_CLEARED( channel_occupation, MPC55XX_EDMA_CHANNEL_FLAG( e->channel))) { + mpc55xx_edma_channel_occupation = SET_FLAG( channel_occupation, MPC55XX_EDMA_CHANNEL_FLAG( e->channel)); } - if (channel_occupied) { - sc = rtems_semaphore_release( mpc55xx_edma_channel_occupation_mutex); - RTEMS_SYSLOG_WARNING_SC( sc, "Release occupation mutex"); + rtems_interrupt_enable( level); + + /* Check channel occupation flag */ + if (IS_FLAG_SET( channel_occupation, MPC55XX_EDMA_CHANNEL_FLAG( e->channel))) { return RTEMS_RESOURCE_IN_USE; - } else { - sc = rtems_semaphore_release( mpc55xx_edma_channel_occupation_mutex); - RTEMS_CHECK_SC( sc, "Release channel occupation mutex"); } - /* Channel data */ - mpc55xx_edma_channel_table [channel].transfer_update = transfer_update; - mpc55xx_edma_channel_table [channel].error_status = error_status; - /* Interrupt handler */ sc = mpc55xx_interrupt_handler_install( - MPC55XX_IRQ_EDMA_GET_REQUEST( channel), - MPC55XX_EDMA_IRQ_PRIORITY, + MPC55XX_IRQ_EDMA_GET_REQUEST( e->channel), "eDMA Channel", RTEMS_INTERRUPT_SHARED, - mpc55xx_edma_irq_handler, - &mpc55xx_edma_channel_table [channel] + MPC55XX_EDMA_IRQ_PRIORITY, + mpc55xx_edma_interrupt_handler, + e ); - RTEMS_CHECK_SC( sc, "Install channel interrupt handler"); + RTEMS_CHECK_SC( sc, "install channel interrupt handler"); /* Enable error interrupts */ - sc = mpc55xx_edma_enable_error_interrupts( channel, true); - RTEMS_CHECK_SC( sc, "Enable error interrupts"); + mpc55xx_edma_enable_error_interrupts( e->channel, true); + + /* Prepend channel entry to channel list */ + rtems_chain_prepend( &mpc55xx_edma_channel_chain, &e->node); return RTEMS_SUCCESSFUL; } -rtems_status_code mpc55xx_edma_release_channel( int channel) +rtems_status_code mpc55xx_edma_release_channel( mpc55xx_edma_channel_entry *e) { - // TODO - return RTEMS_NOT_IMPLEMENTED; + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_interrupt_level level; + + /* Clear channel occupation flag */ + rtems_interrupt_disable( level); + mpc55xx_edma_channel_occupation = CLEAR_FLAG( mpc55xx_edma_channel_occupation, MPC55XX_EDMA_CHANNEL_FLAG( e->channel)); + rtems_interrupt_enable( level); + + /* Disable hardware requests */ + mpc55xx_edma_enable_hardware_requests( e->channel, false); + + /* Disable error interrupts */ + mpc55xx_edma_enable_error_interrupts( e->channel, false); + + /* Extract channel entry from channel chain */ + rtems_chain_extract( &e->node); + + /* Remove interrupt handler */ + sc = rtems_interrupt_handler_remove( + MPC55XX_IRQ_EDMA_GET_REQUEST( e->channel), + mpc55xx_edma_interrupt_handler, + e + ); + RTEMS_CHECK_SC( sc, "remove channel interrupt handler"); + + /* Notify user */ + e->done( e, 0); + + return RTEMS_SUCCESSFUL; } diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/emios/emios.c b/c/src/lib/libcpu/powerpc/mpc55xx/emios/emios.c new file mode 100644 index 0000000000..90cbcd3664 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc55xx/emios/emios.c @@ -0,0 +1,109 @@ +/** + * @file + * + * @ingroup mpc55xx + * + * @brief Enhanced Modular Input Output Subsystem (eMIOS). + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#include <mpc55xx/regs.h> +#include <mpc55xx/emios.h> +#include <mpc55xx/mpc55xx.h> + +#include <bsp/irq.h> +#include <bsp/utility.h> + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include <rtems/status-checks.h> + +/** + * @brief Initialize the eMIOS module. + * + * The module is enabled. It is configured to use the internal clock. The + * global prescaler value is set to @a prescaler. If the value is greater than + * the maximum the maxium value will be used instead. A prescaler value of + * zero disables the clock. + * + * @note No protection against concurrent execution. + */ +void mpc55xx_emios_initialize( unsigned prescaler) +{ + union EMIOS_MCR_tag mcr = MPC55XX_ZERO_FLAGS; + + /* Enable module */ + mcr.B.MDIS = 0; + + /* Disable debug mode */ + mcr.B.FRZ = 1; + + /* Enable global time base */ + mcr.B.GTBE = 1; + + /* Disable global prescaler (= disable clock) */ + mcr.B.GPREN = 0; + + /* Set MCR */ + EMIOS.MCR.R = mcr.R; + + /* Set OUDR */ + EMIOS.OUDR.R = 0; + + /* Set global prescaler value */ + mpc55xx_emios_set_global_prescaler( prescaler); +} + +/** + * @brief Returns the global prescaler value of the eMIOS module. + */ +unsigned mpc55xx_emios_global_prescaler( void) +{ + union EMIOS_MCR_tag mcr = EMIOS.MCR; + + if (mcr.B.GPREN != 0) { + return mcr.B.GPRE + 1; + } else { + return 0; + } +} + +/** + * @brief Sets the global prescaler value of the eMIOS module. + * + * The global prescaler value is set to @a prescaler. If the value is greater + * than the maximum the maxium value will be used instead. A prescaler value + * of zero disables the clock. + * + * @note No protection against concurrent execution. + */ +void mpc55xx_emios_set_global_prescaler( unsigned prescaler) +{ + union EMIOS_MCR_tag mcr = EMIOS.MCR; + + /* Enable or disable the global prescaler */ + mcr.B.GPREN = prescaler > 0 ? 1 : 0; + + /* Set global prescaler value */ + if (prescaler > 256) { + prescaler = 256; + } else if (prescaler < 1) { + prescaler = 1; + } + mcr.B.GPRE = prescaler - 1; + + /* Set MCR */ + EMIOS.MCR.R = mcr.R; +} diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/esci/esci.c b/c/src/lib/libcpu/powerpc/mpc55xx/esci/esci.c index 4f5eb38e96..88265d4de7 100644 --- a/c/src/lib/libcpu/powerpc/mpc55xx/esci/esci.c +++ b/c/src/lib/libcpu/powerpc/mpc55xx/esci/esci.c @@ -41,7 +41,7 @@ #define TERMIOS_CR2 CR2 #undef CR2 -#define MPC55XX_ESCI_IRQ_PRIORITY MPC55XX_INTC_MIN_PRIORITY +#define MPC55XX_ESCI_IRQ_PRIORITY MPC55XX_INTC_DEFAULT_PRIORITY #define MPC55XX_ESCI_IS_MINOR_INVALD(minor) ((minor) < 0 || (minor) >= MPC55XX_ESCI_NUMBER) @@ -73,12 +73,7 @@ mpc55xx_esci_driver_entry mpc55xx_esci_driver_table [MPC55XX_ESCI_NUMBER] = { { * @brief Default termios configuration. */ static const struct termios mpc55xx_esci_termios_default = { - 0, - 0, - CS8 | CREAD | CLOCAL | B115200, - 0, - 0, - { 0 } + .c_cflag = CS8 | CREAD | CLOCAL | B115200 }; /** @@ -119,17 +114,56 @@ static inline void mpc55xx_esci_write_char( mpc55xx_esci_driver_entry *e, uint8_ volatile union ESCI_SR_tag *status = &e->regs->SR; volatile union ESCI_DR_tag *data = &e->regs->DR; union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS; + rtems_interrupt_level level; - while (status->B.TDRE == 0) { - /* Wait */ + /* Set clear flag */ + sr.B.TDRE = 1; + + while (true) { + rtems_interrupt_disable( level); + if (status->B.TDRE != 0) { + /* Clear flag */ + status->R = sr.R; + + /* Write */ + data->B.D = c; + + /* Done */ + rtems_interrupt_enable( level); + break; + } + rtems_interrupt_enable( level); + + while (status->B.TDRE == 0) { + /* Wait */ + } } +} - /* Clear flag */ - sr.B.TDRE = 1; - status->R = sr.R; +static inline void mpc55xx_esci_interrupts_enable( mpc55xx_esci_driver_entry *e) +{ + union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS; + rtems_interrupt_level level; - /* Write */ - data->B.D = c; + rtems_interrupt_disable( level); + cr1.R = e->regs->CR1.R; + cr1.B.RIE = 1; + cr1.B.TIE = 1; + e->regs->CR1.R = cr1.R; + rtems_interrupt_enable( level); +} + +static inline void mpc55xx_esci_interrupts_disable( mpc55xx_esci_driver_entry *e) +{ + union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS; + rtems_interrupt_level level; + + rtems_interrupt_disable( level); + cr1.R = e->regs->CR1.R; + cr1.B.RIE = 0; + cr1.B.TIE = 0; + e->regs->CR1.R = cr1.R; + rtems_interrupt_enable( level); } /** @} */ @@ -146,8 +180,8 @@ static inline void mpc55xx_esci_write_char( mpc55xx_esci_driver_entry *e, uint8_ */ static int mpc55xx_esci_termios_first_open( int major, int minor, void *arg) { + int rv = 0; mpc55xx_esci_driver_entry *e = &mpc55xx_esci_driver_table [minor]; - union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS; struct rtems_termios_tty *tty = ((rtems_libio_open_close_args_t *) arg)->iop->data1; /* Check minor number */ @@ -160,12 +194,12 @@ static int mpc55xx_esci_termios_first_open( int major, int minor, void *arg) /* Enable interrupts */ if (MPC55XX_ESCI_USE_INTERRUPTS( e)) { - cr1.R = e->regs->CR1.R; - cr1.B.RIE = 1; - cr1.B.TIE = 1; - e->regs->CR1.R = cr1.R; + mpc55xx_esci_interrupts_enable( e); } + rv = rtems_termios_set_initial_baud( e->tty, 115200); + RTEMS_CHECK_RV_SC( rv, "Set initial baud"); + return RTEMS_SUCCESSFUL; } @@ -177,7 +211,6 @@ static int mpc55xx_esci_termios_first_open( int major, int minor, void *arg) static int mpc55xx_esci_termios_last_close( int major, int minor, void* arg) { mpc55xx_esci_driver_entry *e = &mpc55xx_esci_driver_table [minor]; - union ESCI_CR1_tag cr1 = MPC55XX_ZERO_FLAGS; /* Check minor number */ if (MPC55XX_ESCI_IS_MINOR_INVALD( minor)) { @@ -185,10 +218,7 @@ static int mpc55xx_esci_termios_last_close( int major, int minor, void* arg) } /* Disable interrupts */ - cr1.R = e->regs->CR1.R; - cr1.B.RIE = 0; - cr1.B.TIE = 0; - e->regs->CR1.R = cr1.R; + mpc55xx_esci_interrupts_disable( e); /* Disconnect TTY */ e->tty = NULL; @@ -204,13 +234,20 @@ static int mpc55xx_esci_termios_last_close( int major, int minor, void* arg) static int mpc55xx_esci_termios_poll_read( int minor) { mpc55xx_esci_driver_entry *e = &mpc55xx_esci_driver_table [minor]; - - /* Check minor number */ - if (MPC55XX_ESCI_IS_MINOR_INVALD( minor)) { + volatile union ESCI_SR_tag *status = &e->regs->SR; + volatile union ESCI_DR_tag *data = &e->regs->DR; + union ESCI_SR_tag sr = MPC55XX_ZERO_FLAGS; + + if (status->B.RDRF == 0) { return -1; } - return (int) mpc55xx_esci_read_char( e); + /* Clear flag */ + sr.B.RDRF = 1; + status->R = sr.R; + + /* Read */ + return data->B.D; } /** @@ -231,9 +268,6 @@ static int mpc55xx_esci_termios_poll_write( int minor, const char *out, int n) /* Write */ for (i = 0; i < n; ++i) { mpc55xx_esci_write_char( e, out [i]); - if (out [i] == '\n') { - mpc55xx_esci_write_char( e, '\r'); - } } return 0; @@ -479,9 +513,9 @@ rtems_device_driver console_initialize( rtems_device_major_number major, rtems_d if (MPC55XX_ESCI_USE_INTERRUPTS( e)) { sc = mpc55xx_interrupt_handler_install( e->irq_number, - MPC55XX_ESCI_IRQ_PRIORITY, "eSCI", RTEMS_INTERRUPT_UNIQUE, + MPC55XX_ESCI_IRQ_PRIORITY, mpc55xx_esci_termios_interrupt_handler, e ); @@ -511,13 +545,7 @@ rtems_device_driver console_open( rtems_device_major_number major, rtems_device_ } else { sc = rtems_termios_open( major, minor, arg, &mpc55xx_esci_termios_callbacks_polled); } - if (sc != RTEMS_SUCCESSFUL) { - return sc; - } - rv = rtems_termios_set_initial_baud( e->tty, 115200); - if (rv < 0) { - return RTEMS_IO_ERROR; - } + RTEMS_CHECK_SC( sc, "Open"); } return RTEMS_SUCCESSFUL; @@ -623,10 +651,13 @@ static int mpc55xx_esci_output_char_minor = 0; static void mpc55xx_esci_output_char( char c) { mpc55xx_esci_driver_entry *e = &mpc55xx_esci_driver_table [mpc55xx_esci_output_char_minor]; + + mpc55xx_esci_interrupts_disable( e); mpc55xx_esci_write_char( e, c); if (c == '\n') { mpc55xx_esci_write_char( e, '\r'); } + mpc55xx_esci_interrupts_enable( e); } static void mpc55xx_esci_output_char_nop( char c) @@ -636,15 +667,17 @@ static void mpc55xx_esci_output_char_nop( char c) static void mpc55xx_esci_output_char_init( char c) { - int console_found = 0; + bool console_found = false; int i = 0; + for (i = 0; i < MPC55XX_ESCI_NUMBER; ++i) { if (mpc55xx_esci_driver_table [i].console) { - console_found = 1; + console_found = true; mpc55xx_esci_output_char_minor = i; break; } } + if (console_found) { BSP_output_char = mpc55xx_esci_output_char; mpc55xx_esci_termios_set_attributes( mpc55xx_esci_output_char_minor, &mpc55xx_esci_termios_default); diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/include/dspi.h b/c/src/lib/libcpu/powerpc/mpc55xx/include/dspi.h index 4ad2479851..fd4b7fe414 100644 --- a/c/src/lib/libcpu/powerpc/mpc55xx/include/dspi.h +++ b/c/src/lib/libcpu/powerpc/mpc55xx/include/dspi.h @@ -29,6 +29,8 @@ #include <rtems/libi2c.h> +#include <mpc55xx/edma.h> + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -64,7 +66,7 @@ typedef struct { /** * @brief Selects SPI master or slave mode. */ - int master; + bool master; /** * @brief Data for the Push Register. @@ -72,50 +74,35 @@ typedef struct { union DSPI_PUSHR_tag push_data; /** - * @brief eDMA channel for transmission. + * @brief eDMA entry for transmission. * - * The channel is fixed to particular DSPI. + * The channel is fixed to a particular DSPI. */ - int edma_channel_transmit; + mpc55xx_edma_channel_entry edma_transmit; /** - * @brief eDMA channel to generate the push data. + * @brief eDMA entry for push data generation. * - * You can choose any available channel. + * You can choose every available channel. */ - int edma_channel_push; + mpc55xx_edma_channel_entry edma_push; /** - * @brief eDMA channel for receiving. + * @brief eDMA entry for receiving. * - * The channel is fixed to particular DSPI. - */ - int edma_channel_receive; - - /** - * @brief Semaphore ID for a transmit update. - */ - rtems_id edma_channel_transmit_update; - - /** - * @brief Semaphore ID for a receive update. + * The channel is fixed to a particular DSPI. */ - rtems_id edma_channel_receive_update; + mpc55xx_edma_channel_entry edma_receive; /** - * @brief Transmit error status. - */ - uint32_t edma_channel_transmit_error; - - /** - * @brief Receive error status. + * @brief Idle character transmitted in read only mode. */ - uint32_t edma_channel_receive_error; + uint32_t idle_char; /** - * @brief Idle character transmitted in read only mode. + * @brief Current baud. */ - uint32_t idle_char; + uint32_t baud; } mpc55xx_dspi_bus_entry; /** diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/include/edma.h b/c/src/lib/libcpu/powerpc/mpc55xx/include/edma.h index 5d4751955c..a8ff09a101 100644 --- a/c/src/lib/libcpu/powerpc/mpc55xx/include/edma.h +++ b/c/src/lib/libcpu/powerpc/mpc55xx/include/edma.h @@ -22,78 +22,31 @@ #define LIBCPU_POWERPC_MPC55XX_EDMA_H #include <stdbool.h> +#include <stdint.h> #include <rtems.h> +#include <rtems/chain.h> #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#define MPC55XX_EDMA_TCD_DEFAULT { \ - .SADDR = 0, \ - .SMOD = 0, \ - .SSIZE = 0x2, \ - .SOFF = 4, \ - .DADDR = 0, \ - .DMOD = 0, \ - .DSIZE = 0x2, \ - .DOFF = 4, \ - .NBYTES = 0, \ - .SLAST = 0, \ - .CITER = 1, \ - .BITER = 1, \ - .MAJORLINKCH = 0, \ - .CITERE_LINK = 0, \ - .BITERE_LINK = 0, \ - .MAJORE_LINK = 0, \ - .E_SG = 0, \ - .DLAST_SGA = 0, \ - .D_REQ = 0, \ - .BWC = 0, \ - .INT_HALF = 0, \ - .INT_MAJ = 0, \ - .DONE = 0, \ - .ACTIVE = 0, \ - .START = 0, \ -} - -#define MPC55XX_EDMA_TCD_ALT_DEFAULT { \ - .SADDR = 0, \ - .SMOD = 0, \ - .SSIZE = 2, \ - .DMOD = 0, \ - .DSIZE = 2, \ - .SOFF = 4, \ - .NBYTES = 0, \ - .SLAST = 0, \ - .DADDR = 0, \ - .CITERE_LINK = 0, \ - .CITERLINKCH = 0, \ - .CITER = 0, \ - .DOFF = 4, \ - .DLAST_SGA = 0, \ - .BITERE_LINK = 0, \ - .BITERLINKCH = 0, \ - .BITER = 0, \ - .BWC = 0, \ - .MAJORLINKCH = 0, \ - .DONE = 0, \ - .ACTIVE = 0, \ - .MAJORE_LINK = 0, \ - .E_SG = 0, \ - .D_REQ = 0, \ - .INT_HALF = 0, \ - .INT_MAJ = 0, \ - .START = 0, \ -} +typedef struct mpc55xx_edma_channel_entry { + rtems_chain_node node; + unsigned channel; + void (*done)( struct mpc55xx_edma_channel_entry *, uint32_t); + rtems_id id; +} mpc55xx_edma_channel_entry; rtems_status_code mpc55xx_edma_init(); -rtems_status_code mpc55xx_edma_obtain_channel( int channel, uint32_t *error_status, rtems_id transfer_update); +rtems_status_code mpc55xx_edma_obtain_channel( mpc55xx_edma_channel_entry *e); + +rtems_status_code mpc55xx_edma_release_channel( mpc55xx_edma_channel_entry *e); -rtems_status_code mpc55xx_edma_enable_hardware_requests( int channel, bool enable); +void mpc55xx_edma_enable_hardware_requests( unsigned channel, bool enable); -rtems_status_code mpc55xx_edma_enable_error_interrupts( int channel, bool enable); +void mpc55xx_edma_enable_error_interrupts( unsigned channel, bool enable); #ifdef __cplusplus } diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/include/emios.h b/c/src/lib/libcpu/powerpc/mpc55xx/include/emios.h new file mode 100644 index 0000000000..6925958d27 --- /dev/null +++ b/c/src/lib/libcpu/powerpc/mpc55xx/include/emios.h @@ -0,0 +1,192 @@ +/** + * @file + * + * @ingroup mpc55xx + * + * @brief Enhanced Modular Input Output Subsystem (eMIOS). + */ + +/* + * Copyright (c) 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.com/license/LICENSE. + */ + +#ifndef LIBCPU_POWERPC_MPC55XX_EMIOS_H +#define LIBCPU_POWERPC_MPC55XX_EMIOS_H + +#include <stdbool.h> +#include <stdint.h> + +#include <rtems.h> +#include <rtems/chain.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @name eMIOS - Modes + * + * @{ + */ + +#define MPC55XX_EMIOS_MODE_GPIO_INPUT 0U +#define MPC55XX_EMIOS_MODE_GPIO_OUTPUT 1U +#define MPC55XX_EMIOS_MODE_SAIC 2U +#define MPC55XX_EMIOS_MODE_SAOC 3U +#define MPC55XX_EMIOS_MODE_IPWM 4U +#define MPC55XX_EMIOS_MODE_IPM 5U +#define MPC55XX_EMIOS_MODE_DAOC_SECOND 6U +#define MPC55XX_EMIOS_MODE_DAOC_BOTH 7U +#define MPC55XX_EMIOS_MODE_PEA_ACCU_CONT 8U +#define MPC55XX_EMIOS_MODE_PEA_ACCU_SINGLE 9U +#define MPC55XX_EMIOS_MODE_PEA_COUNT_CONT 10U +#define MPC55XX_EMIOS_MODE_PEA_COUNT_SINGLE 11U +#define MPC55XX_EMIOS_MODE_QDEC_COUNT_DIR 12U +#define MPC55XX_EMIOS_MODE_QDEC_PHASE 13U +#define MPC55XX_EMIOS_MODE_WPTA 14U +#define MPC55XX_EMIOS_MODE_RESERVED_15 15U +#define MPC55XX_EMIOS_MODE_MC_UP_INT_CLK 16U +#define MPC55XX_EMIOS_MODE_MC_UP_EXT_CLK 17U +#define MPC55XX_EMIOS_MODE_RESERVED_18 18U +#define MPC55XX_EMIOS_MODE_RESERVED_19 19U +#define MPC55XX_EMIOS_MODE_MC_UP_DOWN_INT_CLK 20U +#define MPC55XX_EMIOS_MODE_MC_UP_DOWN_EXT_CLK 21U +#define MPC55XX_EMIOS_MODE_MC_UP_DOWN_CHANGE_INT_CLK 22U +#define MPC55XX_EMIOS_MODE_MC_UP_DOWN_CHANGE_EXT_CLK 23U +#define MPC55XX_EMIOS_MODE_OPWFM_B_IMMEDIATE 24U +#define MPC55XX_EMIOS_MODE_OPWFM_B_NEXT_PERIOD 25U +#define MPC55XX_EMIOS_MODE_OPWFM_AB_IMMEDIATE 26U +#define MPC55XX_EMIOS_MODE_OPWFM_AB_NEXT_PERIOD 27U +#define MPC55XX_EMIOS_MODE_OPWMC_TRAIL_TRAIL 28U +#define MPC55XX_EMIOS_MODE_OPWMC_TRAIL_LEAD 29U +#define MPC55XX_EMIOS_MODE_OPWMC_BOTH_TRAIL 30U +#define MPC55XX_EMIOS_MODE_OPWMC_BOTH_LEAD 31U +#define MPC55XX_EMIOS_MODE_OPWM_B_IMMEDIATE 32U +#define MPC55XX_EMIOS_MODE_OPWM_B_NEXT_PERIOD 33U +#define MPC55XX_EMIOS_MODE_OPWM_AB_IMMEDIATE 34U +#define MPC55XX_EMIOS_MODE_OPWM_AB_NEXT_PERIOD 35U +#define MPC55XX_EMIOS_MODE_RESERVED_36 36U +#define MPC55XX_EMIOS_MODE_RESERVED_37 37U +#define MPC55XX_EMIOS_MODE_RESERVED_38 38U +#define MPC55XX_EMIOS_MODE_RESERVED_39 39U +#define MPC55XX_EMIOS_MODE_RESERVED_40 40U +#define MPC55XX_EMIOS_MODE_RESERVED_41 41U +#define MPC55XX_EMIOS_MODE_RESERVED_42 42U +#define MPC55XX_EMIOS_MODE_RESERVED_43 43U +#define MPC55XX_EMIOS_MODE_RESERVED_44 44U +#define MPC55XX_EMIOS_MODE_RESERVED_45 45U +#define MPC55XX_EMIOS_MODE_RESERVED_46 46U +#define MPC55XX_EMIOS_MODE_RESERVED_47 47U +#define MPC55XX_EMIOS_MODE_RESERVED_48 48U +#define MPC55XX_EMIOS_MODE_RESERVED_49 49U +#define MPC55XX_EMIOS_MODE_RESERVED_50 50U +#define MPC55XX_EMIOS_MODE_RESERVED_51 51U +#define MPC55XX_EMIOS_MODE_RESERVED_52 52U +#define MPC55XX_EMIOS_MODE_RESERVED_53 53U +#define MPC55XX_EMIOS_MODE_RESERVED_54 54U +#define MPC55XX_EMIOS_MODE_RESERVED_55 55U +#define MPC55XX_EMIOS_MODE_RESERVED_56 56U +#define MPC55XX_EMIOS_MODE_RESERVED_57 57U +#define MPC55XX_EMIOS_MODE_RESERVED_58 58U +#define MPC55XX_EMIOS_MODE_RESERVED_59 59U +#define MPC55XX_EMIOS_MODE_RESERVED_60 60U +#define MPC55XX_EMIOS_MODE_RESERVED_61 61U +#define MPC55XX_EMIOS_MODE_RESERVED_62 62U +#define MPC55XX_EMIOS_MODE_RESERVED_63 63U +#define MPC55XX_EMIOS_MODE_RESERVED_64 64U +#define MPC55XX_EMIOS_MODE_RESERVED_65 65U +#define MPC55XX_EMIOS_MODE_RESERVED_66 66U +#define MPC55XX_EMIOS_MODE_RESERVED_67 67U +#define MPC55XX_EMIOS_MODE_RESERVED_68 68U +#define MPC55XX_EMIOS_MODE_RESERVED_69 69U +#define MPC55XX_EMIOS_MODE_RESERVED_70 70U +#define MPC55XX_EMIOS_MODE_RESERVED_71 71U +#define MPC55XX_EMIOS_MODE_RESERVED_72 72U +#define MPC55XX_EMIOS_MODE_RESERVED_73 73U +#define MPC55XX_EMIOS_MODE_RESERVED_74 74U +#define MPC55XX_EMIOS_MODE_RESERVED_75 75U +#define MPC55XX_EMIOS_MODE_RESERVED_76 76U +#define MPC55XX_EMIOS_MODE_RESERVED_77 77U +#define MPC55XX_EMIOS_MODE_RESERVED_78 78U +#define MPC55XX_EMIOS_MODE_RESERVED_79 79U +#define MPC55XX_EMIOS_MODE_MCB_UP_INT_CLK 80U +#define MPC55XX_EMIOS_MODE_MCB_UP_EXT_CLK 81U +#define MPC55XX_EMIOS_MODE_RESERVED_82 82U +#define MPC55XX_EMIOS_MODE_RESERVED_83 83U +#define MPC55XX_EMIOS_MODE_MCB_UP_DOWN_ONE_INT_CLK 84U +#define MPC55XX_EMIOS_MODE_MCB_UP_DOWN_ONE_EXT_CLK 85U +#define MPC55XX_EMIOS_MODE_MCB_UP_DOWN_BOTH_INT_CLK 86U +#define MPC55XX_EMIOS_MODE_MCB_UP_DOWN_BOTH_EXT_CLK 87U +#define MPC55XX_EMIOS_MODE_OPWFMB_B 88U +#define MPC55XX_EMIOS_MODE_RESERVED_89 89U +#define MPC55XX_EMIOS_MODE_OPWFMB_AB 90U +#define MPC55XX_EMIOS_MODE_RESERVED_91 91U +#define MPC55XX_EMIOS_MODE_OPWMCB_TRAIL_TRAIL 92U +#define MPC55XX_EMIOS_MODE_OPWMCB_TRAIL_LEAD 93U +#define MPC55XX_EMIOS_MODE_OPWMCB_BOTH_TRAIL 94U +#define MPC55XX_EMIOS_MODE_OPWMCB_BOTH_LEAD 95U +#define MPC55XX_EMIOS_MODE_OPWMB_SECOND 96U +#define MPC55XX_EMIOS_MODE_RESERVED_97 97U +#define MPC55XX_EMIOS_MODE_OPWMB_BOTH 98U +#define MPC55XX_EMIOS_MODE_RESERVED_99 99U +#define MPC55XX_EMIOS_MODE_RESERVED_100 100U +#define MPC55XX_EMIOS_MODE_RESERVED_101 101U +#define MPC55XX_EMIOS_MODE_RESERVED_102 102U +#define MPC55XX_EMIOS_MODE_RESERVED_103 103U +#define MPC55XX_EMIOS_MODE_RESERVED_104 104U +#define MPC55XX_EMIOS_MODE_RESERVED_105 105U +#define MPC55XX_EMIOS_MODE_RESERVED_106 106U +#define MPC55XX_EMIOS_MODE_RESERVED_107 107U +#define MPC55XX_EMIOS_MODE_RESERVED_108 108U +#define MPC55XX_EMIOS_MODE_RESERVED_109 109U +#define MPC55XX_EMIOS_MODE_RESERVED_110 110U +#define MPC55XX_EMIOS_MODE_RESERVED_111 111U +#define MPC55XX_EMIOS_MODE_RESERVED_112 112U +#define MPC55XX_EMIOS_MODE_RESERVED_113 113U +#define MPC55XX_EMIOS_MODE_RESERVED_114 114U +#define MPC55XX_EMIOS_MODE_RESERVED_115 115U +#define MPC55XX_EMIOS_MODE_RESERVED_116 116U +#define MPC55XX_EMIOS_MODE_RESERVED_117 117U +#define MPC55XX_EMIOS_MODE_RESERVED_118 118U +#define MPC55XX_EMIOS_MODE_RESERVED_119 119U +#define MPC55XX_EMIOS_MODE_RESERVED_120 120U +#define MPC55XX_EMIOS_MODE_RESERVED_121 121U +#define MPC55XX_EMIOS_MODE_RESERVED_122 122U +#define MPC55XX_EMIOS_MODE_RESERVED_123 123U +#define MPC55XX_EMIOS_MODE_RESERVED_124 124U +#define MPC55XX_EMIOS_MODE_RESERVED_125 125U +#define MPC55XX_EMIOS_MODE_RESERVED_126 126U +#define MPC55XX_EMIOS_MODE_RESERVED_127 127U + +/** @} */ + +#define MPC55XX_EMIOS_CHANNEL_NUMBER 24U + +#define MPC55XX_EMIOS_VALUE_MAX 0x00ffffffU + +#define MPC55XX_EMIOS_IS_CHANNEL_VALID( c) \ + ((unsigned) (c) < MPC55XX_EMIOS_CHANNEL_NUMBER) + +#define MPC55XX_EMIOS_IS_CHANNEL_INVALID( c) \ + (!MPC55XX_EMIOS_IS_CHANNEL_VALID( c)) + +void mpc55xx_emios_initialize( unsigned prescaler); + +unsigned mpc55xx_emios_global_prescaler( void); + +void mpc55xx_emios_set_global_prescaler( unsigned prescaler); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBCPU_POWERPC_MPC55XX_EMIOS_H */ diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/include/irq.h b/c/src/lib/libcpu/powerpc/mpc55xx/include/irq.h index 90a129c234..6b2be34fe5 100644 --- a/c/src/lib/libcpu/powerpc/mpc55xx/include/irq.h +++ b/c/src/lib/libcpu/powerpc/mpc55xx/include/irq.h @@ -33,57 +33,74 @@ extern "C" { */ /* Basics */ -#define MPC55XX_IRQ_MIN 0 -#define MPC55XX_IRQ_MAX 328 +#define MPC55XX_IRQ_MIN 0U +#define MPC55XX_IRQ_MAX 328U #define MPC55XX_IRQ_BASE MPC55XX_IRQ_MIN -#define MPC55XX_IRQ_NUMBER (MPC55XX_IRQ_MAX + 1) +#define MPC55XX_IRQ_NUMBER (MPC55XX_IRQ_MAX + 1U) /* Software interrupts */ -#define MPC55XX_IRQ_SOFTWARE_MIN 0 -#define MPC55XX_IRQ_SOFTWARE_MAX 7 -#define MPC55XX_IRQ_SOFTWARE_NUMBER (MPC55XX_IRQ_SOFTWARE_MAX + 1) +#define MPC55XX_IRQ_SOFTWARE_MIN 0U +#define MPC55XX_IRQ_SOFTWARE_MAX 7U +#define MPC55XX_IRQ_SOFTWARE_GET_INDEX( v) (v) +#define MPC55XX_IRQ_SOFTWARE_GET_REQUEST( i) (i) +#define MPC55XX_IRQ_SOFTWARE_NUMBER (MPC55XX_IRQ_SOFTWARE_MAX + 1U) /* eDMA interrupts */ -#define MPC55XX_IRQ_EDMA_ERROR_LOW 10 -#define MPC55XX_IRQ_EDMA_ERROR_HIGH 210 -#define MPC55XX_IRQ_EDMA_REQUEST_LOW_MIN 11 -#define MPC55XX_IRQ_EDMA_REQUEST_LOW_MAX 42 -#define MPC55XX_IRQ_EDMA_REQUEST_HIGH_MIN 211 -#define MPC55XX_IRQ_EDMA_REQUEST_HIGH_MAX 242 -#define MPC55XX_IRQ_EDMA_GET_CHANNEL( i) (((i) > MPC55XX_IRQ_EDMA_REQUEST_LOW_MAX) ? ((i) - MPC55XX_IRQ_EDMA_REQUEST_HIGH_MIN + 32) : ((i) - MPC55XX_IRQ_EDMA_REQUEST_LOW_MIN)) -#define MPC55XX_IRQ_EDMA_GET_REQUEST( c) (((c) > 31) ? ((c) + MPC55XX_IRQ_EDMA_REQUEST_HIGH_MIN - 32) : ((c) + MPC55XX_IRQ_EDMA_REQUEST_LOW_MIN)) +#define MPC55XX_IRQ_EDMA_ERROR_LOW 10U +#define MPC55XX_IRQ_EDMA_ERROR_HIGH 210U +#define MPC55XX_IRQ_EDMA_REQUEST_LOW_MIN 11U +#define MPC55XX_IRQ_EDMA_REQUEST_LOW_MAX 42U +#define MPC55XX_IRQ_EDMA_REQUEST_HIGH_MIN 211U +#define MPC55XX_IRQ_EDMA_REQUEST_HIGH_MAX 242U +#define MPC55XX_IRQ_EDMA_GET_CHANNEL( v) (((v) > MPC55XX_IRQ_EDMA_REQUEST_LOW_MAX) ? ((v) + 32U - MPC55XX_IRQ_EDMA_REQUEST_HIGH_MIN) : ((v) - MPC55XX_IRQ_EDMA_REQUEST_LOW_MIN)) +#define MPC55XX_IRQ_EDMA_GET_REQUEST( c) (((c) >= 32U) ? ((c) - 32U + MPC55XX_IRQ_EDMA_REQUEST_HIGH_MIN) : ((c) + MPC55XX_IRQ_EDMA_REQUEST_LOW_MIN)) + +/* SIU external interrupts */ +#define MPC55XX_IRQ_SIU_EXTERNAL_0 46U +#define MPC55XX_IRQ_SIU_EXTERNAL_1 47U +#define MPC55XX_IRQ_SIU_EXTERNAL_2 48U +#define MPC55XX_IRQ_SIU_EXTERNAL_3 49U +#define MPC55XX_IRQ_SIU_EXTERNAL_4_15 50U + +/* eMIOS interrupts */ +#define MPC55XX_IRQ_EMIOS_REQUEST_LOW_MIN 51U +#define MPC55XX_IRQ_EMIOS_REQUEST_LOW_MAX 66U +#define MPC55XX_IRQ_EMIOS_REQUEST_HIGH_MIN 202U +#define MPC55XX_IRQ_EMIOS_REQUEST_HIGH_MAX 209U +#define MPC55XX_IRQ_EMIOS_GET_CHANNEL( v) (((v) > MPC55XX_IRQ_EMIOS_REQUEST_LOW_MAX) ? ((v) + 16U - MPC55XX_IRQ_EMIOS_REQUEST_HIGH_MIN) : ((v) - MPC55XX_IRQ_EMIOS_REQUEST_LOW_MIN)) +#define MPC55XX_IRQ_EMIOS_GET_REQUEST( c) (((c) >= 16U) ? ((c) - 16U + MPC55XX_IRQ_EMIOS_REQUEST_HIGH_MIN) : ((c) + MPC55XX_IRQ_EMIOS_REQUEST_LOW_MIN)) /* Checks */ -#define MPC55XX_IRQ_IS_VALID(i) ((i) >= MPC55XX_IRQ_MIN && (i) <= MPC55XX_IRQ_MAX) -#define MPC55XX_IRQ_IS_SOFTWARE(i) ((i) >= MPC55XX_IRQ_SOFTWARE_MIN && (i) <= MPC55XX_IRQ_SOFTWARE_MAX) +#define MPC55XX_IRQ_IS_VALID(v) ((v) >= MPC55XX_IRQ_MIN && (v) <= MPC55XX_IRQ_MAX) +#define MPC55XX_IRQ_IS_SOFTWARE(v) ((v) >= MPC55XX_IRQ_SOFTWARE_MIN && (v) <= MPC55XX_IRQ_SOFTWARE_MAX) /* * Interrupt controller */ -#define MPC55XX_INTC_INVALID_PRIORITY -1 -#define MPC55XX_INTC_DISABLED_PRIORITY 0 -#define MPC55XX_INTC_MIN_PRIORITY 1 -#define MPC55XX_INTC_MAX_PRIORITY 15 -#define MPC55XX_INTC_DEFAULT_PRIORITY MPC55XX_INTC_MIN_PRIORITY +#define MPC55XX_INTC_MIN_PRIORITY 1U +#define MPC55XX_INTC_MAX_PRIORITY 15U +#define MPC55XX_INTC_DISABLED_PRIORITY 0U +#define MPC55XX_INTC_INVALID_PRIORITY (MPC55XX_INTC_MAX_PRIORITY + 1) +#define MPC55XX_INTC_DEFAULT_PRIORITY (MPC55XX_INTC_MIN_PRIORITY + 1) #define MPC55XX_INTC_IS_VALID_PRIORITY(p) ((p) >= MPC55XX_INTC_DISABLED_PRIORITY && (p) <= MPC55XX_INTC_MAX_PRIORITY) rtems_status_code mpc55xx_interrupt_handler_install( rtems_vector_number vector, - int priority, const char *info, rtems_option options, + unsigned priority, rtems_interrupt_handler handler, void *arg ); -rtems_status_code mpc55xx_intc_get_priority( int i, int *p); +rtems_status_code mpc55xx_intc_get_priority( rtems_vector_number vector, unsigned *priority); -rtems_status_code mpc55xx_intc_set_priority( int i, int p); +rtems_status_code mpc55xx_intc_set_priority( rtems_vector_number vector, unsigned priority); -rtems_status_code mpc55xx_intc_raise_software_irq( int i); +rtems_status_code mpc55xx_intc_raise_software_irq( rtems_vector_number vector); -rtems_status_code mpc55xx_intc_clear_software_irq( int i); +rtems_status_code mpc55xx_intc_clear_software_irq( rtems_vector_number vector); #ifdef __cplusplus }; diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/include/regs.h b/c/src/lib/libcpu/powerpc/mpc55xx/include/regs.h index c68068e648..acee4face9 100644 --- a/c/src/lib/libcpu/powerpc/mpc55xx/include/regs.h +++ b/c/src/lib/libcpu/powerpc/mpc55xx/include/regs.h @@ -666,7 +666,7 @@ extern "C" { } B; } SRCR; - union { /* External Interrupt Status Register */ + union SIU_EISR_tag { /* External Interrupt Status Register */ uint32_t R; struct { uint32_t:16; @@ -689,7 +689,7 @@ extern "C" { } B; } EISR; - union { /* DMA/Interrupt Request Enable Register */ + union SIU_DIRER_tag { /* DMA/Interrupt Request Enable Register */ uint32_t R; struct { uint32_t:16; @@ -712,7 +712,7 @@ extern "C" { } B; } DIRER; - union { /* DMA/Interrupt Select Register */ + union SIU_DIRSR_tag { /* DMA/Interrupt Select Register */ uint32_t R; struct { uint32_t:28; @@ -723,7 +723,7 @@ extern "C" { } B; } DIRSR; - union { /* Overrun Status Register */ + union SIU_OSR_tag { /* Overrun Status Register */ uint32_t R; struct { uint32_t:16; @@ -746,7 +746,7 @@ extern "C" { } B; } OSR; - union { /* Overrun Request Enable Register */ + union SIU_ORER_tag { /* Overrun Request Enable Register */ uint32_t R; struct { uint32_t:16; @@ -769,7 +769,7 @@ extern "C" { } B; } ORER; - union { /* External IRQ Rising-Edge Event Enable Register */ + union SIU_IREER_tag { /* External IRQ Rising-Edge Event Enable Register */ uint32_t R; struct { uint32_t:16; @@ -792,7 +792,7 @@ extern "C" { } B; } IREER; - union { /* External IRQ Falling-Edge Event Enable Register */ + union SIU_IFEER_tag { /* External IRQ Falling-Edge Event Enable Register */ uint32_t R; struct { uint32_t:16; @@ -815,7 +815,7 @@ extern "C" { } B; } IFEER; - union { /* External IRQ Digital Filter Register */ + union SIU_IDFR_tag { /* External IRQ Digital Filter Register */ uint32_t R; struct { uint32_t:28; @@ -963,7 +963,7 @@ extern "C" { /* MODULE : EMIOS */ /****************************************************************************/ struct EMIOS_tag { - union { + union EMIOS_MCR_tag { uint32_t R; struct { uint32_t:1; @@ -979,7 +979,7 @@ extern "C" { } B; } MCR; /* Module Configuration Register */ - union { + union EMIOS_GFR_tag { uint32_t R; struct { uint32_t:8; @@ -1010,7 +1010,7 @@ extern "C" { } B; } GFR; /* Global FLAG Register */ - union { + union EMIOS_OUDR_tag { uint32_t R; struct { uint32_t:8; @@ -1043,7 +1043,7 @@ extern "C" { uint32_t emios_reserved[5]; - struct { + struct EMIOS_CH_tag { union { uint32_t R; /* Channel A Data Register */ } CADR; @@ -1056,7 +1056,7 @@ extern "C" { uint32_t R; /* Channel Counter Register */ } CCNTR; - union { + union EMIOS_CCR_tag { uint32_t R; struct { uint32_t FREN:1; @@ -1080,7 +1080,7 @@ extern "C" { } B; } CCR; /* Channel Control Register */ - union { + union EMIOS_CSR_tag { uint32_t R; struct { uint32_t OVR:1; @@ -2165,19 +2165,19 @@ extern "C" { union { uint16_t R; - } SWTCR; //Software Watchdog Timer Control + } SWTCR; /* Software Watchdog Timer Control */ uint8_t ecsm_reserved3[3]; union { uint8_t R; - } SWTSR; //SWT Service Register + } SWTSR; /* SWT Service Register */ uint8_t ecsm_reserved4[3]; union { uint8_t R; - } SWTIR; //SWT Interrupt Register + } SWTIR; /* SWT Interrupt Register */ uint32_t ecsm_reserved5a[1]; @@ -2210,7 +2210,7 @@ extern "C" { uint8_t ERNCR:1; uint8_t EFNCR:1; } B; - } ECR; //ECC Configuration Register + } ECR; /* ECC Configuration Register */ uint8_t mcm_reserved8[3]; @@ -2221,7 +2221,7 @@ extern "C" { uint8_t RNCE:1; uint8_t FNCE:1; } B; - } ESR; //ECC Status Register + } ESR; /* ECC Status Register */ uint16_t ecsm_reserved9; @@ -2234,7 +2234,7 @@ extern "C" { uint16_t:1; uint16_t ERRBIT:7; } B; - } EEGR; //ECC Error Generation Register + } EEGR; /* ECC Error Generation Register */ uint32_t ecsm_reserved10; @@ -2243,7 +2243,7 @@ extern "C" { struct { uint32_t FEAR:32; } B; - } FEAR; //Flash ECC Address Register + } FEAR; /* Flash ECC Address Register */ uint16_t ecsm_reserved11; @@ -2253,7 +2253,7 @@ extern "C" { uint8_t:4; uint8_t FEMR:4; } B; - } FEMR; //Flash ECC Master Register + } FEMR; /* Flash ECC Master Register */ union { uint8_t R; @@ -2265,28 +2265,28 @@ extern "C" { uint8_t PROT2:1; uint8_t PROT3:1; } B; - } FEAT; //Flash ECC Attributes Register + } FEAT; /* Flash ECC Attributes Register */ union { uint32_t R; struct { uint32_t FEDH:32; } B; - } FEDRH; //Flash ECC Data High Register + } FEDRH; /* Flash ECC Data High Register */ union { uint32_t R; struct { uint32_t FEDL:32; } B; - } FEDRL; //Flash ECC Data Low Register + } FEDRL; /* Flash ECC Data Low Register */ union { uint32_t R; struct { uint32_t REAR:32; } B; - } REAR; //RAM ECC Address + } REAR; /* RAM ECC Address */ uint8_t ecsm_reserved12[2]; @@ -2296,7 +2296,7 @@ extern "C" { uint8_t:4; uint8_t REMR:4; } B; - } REMR; //RAM ECC Master + } REMR; /* RAM ECC Master */ union { uint8_t R; @@ -2308,21 +2308,21 @@ extern "C" { uint8_t PROT2:1; uint8_t PROT3:1; } B; - } REAT; // RAM ECC Attributes Register + } REAT; /* RAM ECC Attributes Register */ union { uint32_t R; struct { uint32_t REDH:32; } B; - } REDRH; //RAM ECC Data High Register + } REDRH; /* RAM ECC Data High Register */ union { uint32_t R; struct { uint32_t REDL:32; } B; - } REDRL; //RAMECC Data Low Register + } REDRL; /* RAMECC Data Low Register */ }; /****************************************************************************/ @@ -2728,41 +2728,88 @@ extern "C" { struct tcd_t { uint32_t SADDR; /* source address */ - uint16_t SMOD:5; /* source address modulo */ - uint16_t SSIZE:3; /* source transfer size */ - uint16_t DMOD:5; /* destination address modulo */ - uint16_t DSIZE:3; /* destination transfer size */ - int16_t SOFF; /* signed source address offset */ + /* Source and destination fields */ + union tcd_SDF_tag { + uint32_t R; + struct { + uint16_t SMOD:5; /* source address modulo */ + uint16_t SSIZE:3; /* source transfer size */ + uint16_t DMOD:5; /* destination address modulo */ + uint16_t DSIZE:3; /* destination transfer size */ + int16_t SOFF; /* signed source address offset */ + } B; + } SDF; uint32_t NBYTES; /* inner (minor) byte count */ int32_t SLAST; /* last destination address adjustment, or - scatter/gather address (if e_sg = 1) */ - uint32_t DADDR; /* destination address */ - uint16_t CITERE_LINK:1; - uint16_t CITER:15; + uint32_t DADDR; /* destination address */ - int16_t DOFF; /* signed destination address offset */ + /* CITER and destination fields */ + union tcd_CDF_tag { + uint32_t R; + struct { + uint16_t CITERE_LINK:1; + uint16_t CITER:15; + int16_t DOFF; /* signed destination address offset */ + } B; + struct { + uint16_t CITERE_LINK:1; + uint16_t CITERLINKCH:6; + uint16_t CITER:9; + int16_t DOFF; + } B_ALT; + } CDF; int32_t DLAST_SGA; - uint16_t BITERE_LINK:1; /* beginning ("major") iteration count */ - uint16_t BITER:15; - - uint16_t BWC:2; /* bandwidth control */ - uint16_t MAJORLINKCH:6; /* enable channel-to-channel link */ - uint16_t DONE:1; /* channel done */ - uint16_t ACTIVE:1; /* channel active */ - uint16_t MAJORE_LINK:1; /* enable channel-to-channel link */ - uint16_t E_SG:1; /* enable scatter/gather descriptor */ - uint16_t D_REQ:1; /* disable ipd_req when done */ - uint16_t INT_HALF:1; /* interrupt on citer = (biter >> 1) */ - uint16_t INT_MAJ:1; /* interrupt on major loop completion */ - uint16_t START:1; /* explicit channel start */ + /* BITER and misc fields */ + union tcd_BMF_tag { + uint32_t R; + struct { + uint32_t BITERE_LINK:1; /* beginning ("major") iteration count */ + uint32_t BITER:15; + uint32_t BWC:2; /* bandwidth control */ + uint32_t MAJORLINKCH:6; /* enable channel-to-channel link */ + uint32_t DONE:1; /* channel done */ + uint32_t ACTIVE:1; /* channel active */ + uint32_t MAJORE_LINK:1; /* enable channel-to-channel link */ + uint32_t E_SG:1; /* enable scatter/gather descriptor */ + uint32_t D_REQ:1; /* disable ipd_req when done */ + uint32_t INT_HALF:1; /* interrupt on citer = (biter >> 1) */ + uint32_t INT_MAJ:1; /* interrupt on major loop completion */ + uint32_t START:1; /* explicit channel start */ + } B; + struct { + uint32_t BITERE_LINK:1; + uint32_t BITERLINKCH:6; + uint32_t BITER:9; + uint32_t BWC:2; + uint32_t MAJORLINKCH:6; + uint32_t DONE:1; + uint32_t ACTIVE:1; + uint32_t MAJORE_LINK:1; + uint32_t E_SG:1; + uint32_t D_REQ:1; + uint32_t INT_HALF:1; + uint32_t INT_MAJ:1; + uint32_t START:1; + } B_ALT; + } BMF; } TCD[64]; /* transfer_control_descriptor */ + }; + static const struct tcd_t EDMA_TCD_DEFAULT = { + .SADDR = 0, + .SDF = { .R = 0 }, + .NBYTES = 0, + .SLAST = 0, + .DADDR = 0, + .CDF = { .R = 0 }, + .DLAST_SGA = 0, + .BMF = { .R = 0 } }; #define EDMA_TCD_BITER_MASK 0x7fff @@ -2775,50 +2822,8 @@ extern "C" { #define EDMA_TCD_LINK_AND_BITER( link, biter) (((link) << 9) + ((biter) & EDMA_TCD_BITER_LINKED_MASK)) -#define EDMA_TCD_BITER_LINK( channel) (EDMA.TCD [(channel)].BITER >> 9) - -/* This is outside of the eDMA structure */ -/* There are 2 possible ways to use the citer bit field, this structure */ -/* uses the different format from the main structure. */ - struct tcd_alt_t { - uint32_t SADDR; /* source address */ - - uint16_t SMOD:5; /* source address modulo */ - uint16_t SSIZE:3; /* source transfer size */ - uint16_t DMOD:5; /* destination address modulo */ - uint16_t DSIZE:3; /* destination transfer size */ - int16_t SOFF; /* signed source address offset */ - - uint32_t NBYTES; /* inner (minor) byte count */ +#define EDMA_TCD_BITER_LINK( channel) (EDMA.TCD [(channel)].BMF.B.BITER >> 9) - int32_t SLAST; /* last destination address adjustment, or - - scatter/gather address (if e_sg = 1) */ - uint32_t DADDR; /* destination address */ - - uint16_t CITERE_LINK:1; - uint16_t CITERLINKCH:6; - uint16_t CITER:9; - - int16_t DOFF; /* signed destination address offset */ - - int32_t DLAST_SGA; - - uint16_t BITERE_LINK:1; /* beginning (major) iteration count */ - uint16_t BITERLINKCH:6; - uint16_t BITER:9; - - uint16_t BWC:2; /* bandwidth control */ - uint16_t MAJORLINKCH:6; /* enable channel-to-channel link */ - uint16_t DONE:1; /* channel done */ - uint16_t ACTIVE:1; /* channel active */ - uint16_t MAJORE_LINK:1; /* enable channel-to-channel link */ - uint16_t E_SG:1; /* enable scatter/gather descriptor */ - uint16_t D_REQ:1; /* disable ipd_req when done */ - uint16_t INT_HALF:1; /* interrupt on citer = (biter >> 1) */ - uint16_t INT_MAJ:1; /* interrupt on major loop completion */ - uint16_t START:1; /* explicit channel start */ - }; /* transfer_control_descriptor */ /****************************************************************************/ /* MODULE : INTC */ /****************************************************************************/ @@ -4249,6 +4254,105 @@ extern "C" { }; +/****************************************************************************/ +/* MMU */ +/****************************************************************************/ + struct MMU_tag { + union { + uint32_t R; + struct { + uint32_t : 2; + uint32_t TLBSEL : 2; + uint32_t : 7; + uint32_t ESEL : 5; + uint32_t : 11; + uint32_t NV : 5; + } B; + } MAS0; + + union { + uint32_t R; + struct { + uint32_t VALID : 1; + uint32_t IPROT : 1; + uint32_t : 6; + uint32_t TID : 8; + uint32_t : 3; + uint32_t TS : 1; + uint32_t TSIZ : 4; + uint32_t : 8; + } B; + } MAS1; + + union { + uint32_t R; + struct { + uint32_t EPN : 20; + uint32_t : 7; + uint32_t W : 1; + uint32_t I : 1; + uint32_t M : 1; + uint32_t G : 1; + uint32_t E : 1; + } B; + } MAS2; + + union { + uint32_t R; + struct { + uint32_t RPN : 20; + uint32_t : 2; + uint32_t U0 : 1; + uint32_t U1 : 1; + uint32_t U2 : 1; + uint32_t U3 : 1; + uint32_t UX : 1; + uint32_t SX : 1; + uint32_t UW : 1; + uint32_t SW : 1; + uint32_t UR : 1; + uint32_t SR : 1; + } B; + } MAS3; + + union { + uint32_t R; + struct { + uint32_t : 2; + uint32_t TLBSELD : 2; + uint32_t : 10; + uint32_t TIDSELD : 2; + uint32_t : 4; + uint32_t TSIZED : 4; + uint32_t : 3; + uint32_t WD : 1; + uint32_t ID : 1; + uint32_t MD : 1; + uint32_t GD : 1; + uint32_t ED : 1; + } B; + } MAS4; + + union { + uint32_t R; + struct { + uint32_t : 8; + uint32_t SPID : 8; + uint32_t : 15; + uint32_t SAS : 1; + } B; + } MAS6; + }; + + static const struct MMU_tag MMU_DEFAULT = { + .MAS0 = { .R = 0x10000000 }, + .MAS1 = { .R = 0 }, + .MAS2 = { .R = 0 }, + .MAS3 = { .R = 0 }, + .MAS4 = { .R = 0 }, + .MAS6 = { .R = 0 } + }; + /* Define memories */ #define SRAM_START 0x40000000 @@ -4308,7 +4412,7 @@ extern "C" { /********************************************************************* * * Copyright: - * Freescale Semiconductor, INC. All Rights Reserved. + * Freescale Semiconductor, INC. All Rights Reserved. * You are hereby granted a copyright license to use, modify, and * distribute the SOFTWARE so long as this entire notice is * retained without alteration in any modified and/or redistributed diff --git a/c/src/lib/libcpu/powerpc/mpc55xx/irq/irq.c b/c/src/lib/libcpu/powerpc/mpc55xx/irq/irq.c index 50071eb9e7..34d5bef763 100644 --- a/c/src/lib/libcpu/powerpc/mpc55xx/irq/irq.c +++ b/c/src/lib/libcpu/powerpc/mpc55xx/irq/irq.c @@ -21,6 +21,7 @@ #include <mpc55xx/regs.h> #include <libcpu/raw_exception.h> +#include <libcpu/powerpc-utility.h> #include <bsp/irq.h> #include <bsp/irq-generic.h> @@ -31,27 +32,27 @@ #include <rtems/status-checks.h> /** - * @brief Returns the priority @a p of IRQ @a i from the INTC. + * @brief Returns the priority @a priority of IRQ @a vector from the INTC. */ -rtems_status_code mpc55xx_intc_get_priority( int i, int *p) +rtems_status_code mpc55xx_intc_get_priority( rtems_vector_number vector, unsigned *priority) { - if (MPC55XX_IRQ_IS_VALID( i)) { - *p = INTC.PSR [i].B.PRI; + if (MPC55XX_IRQ_IS_VALID( vector)) { + *priority = INTC.PSR [vector].B.PRI; return RTEMS_SUCCESSFUL; } else { - *p = MPC55XX_INTC_INVALID_PRIORITY; + *priority = MPC55XX_INTC_INVALID_PRIORITY; return RTEMS_INVALID_NUMBER; } } /** - * @brief Sets the priority of IRQ @a i to @a p at the INTC. + * @brief Sets the priority of IRQ @a vector to @a priority at the INTC. */ -rtems_status_code mpc55xx_intc_set_priority( int i, int p) +rtems_status_code mpc55xx_intc_set_priority( rtems_vector_number vector, unsigned priority) { - if (MPC55XX_IRQ_IS_VALID( i) && MPC55XX_INTC_IS_VALID_PRIORITY( p)) { - INTC.PSR [i].B.PRI = p; - if (INTC.PSR [i].B.PRI == p) { + if (MPC55XX_IRQ_IS_VALID( vector) && MPC55XX_INTC_IS_VALID_PRIORITY( priority)) { + INTC.PSR [vector].B.PRI = priority; + if (INTC.PSR [vector].B.PRI == priority) { return RTEMS_SUCCESSFUL; } else { return RTEMS_IO_ERROR; @@ -62,12 +63,12 @@ rtems_status_code mpc55xx_intc_set_priority( int i, int p) } /** - * @brief Raises the software IRQ with number @a i. + * @brief Raises the software IRQ with number @a vector. */ -rtems_status_code mpc55xx_intc_raise_software_irq( int i) +rtems_status_code mpc55xx_intc_raise_software_irq( rtems_vector_number vector) { - if (MPC55XX_IRQ_IS_SOFTWARE( i)) { - INTC.SSCIR [i].B.SET = 1; + if (MPC55XX_IRQ_IS_SOFTWARE( vector)) { + INTC.SSCIR [vector].B.SET = 1; return RTEMS_SUCCESSFUL; } else { return RTEMS_INVALID_NUMBER; @@ -75,12 +76,12 @@ rtems_status_code mpc55xx_intc_raise_software_irq( int i) } /** - * @brief Clears the software IRQ with number @a i. + * @brief Clears the software IRQ with number @a vector. */ -rtems_status_code mpc55xx_intc_clear_software_irq( int i) +rtems_status_code mpc55xx_intc_clear_software_irq( rtems_vector_number vector) { - if (MPC55XX_IRQ_IS_SOFTWARE( i)) { - INTC.SSCIR [i].B.CLR = 1; + if (MPC55XX_IRQ_IS_SOFTWARE( vector)) { + INTC.SSCIR [vector].B.CLR = 1; return RTEMS_SUCCESSFUL; } else { return RTEMS_INVALID_NUMBER; @@ -92,18 +93,19 @@ rtems_status_code mpc55xx_intc_clear_software_irq( int i) */ rtems_status_code mpc55xx_interrupt_handler_install( rtems_vector_number vector, - int priority, const char *info, rtems_option options, + unsigned priority, rtems_interrupt_handler handler, void *arg ) { - rtems_status_code sc = RTEMS_SUCCESSFUL; - if (MPC55XX_IRQ_IS_VALID( vector) && MPC55XX_INTC_IS_VALID_PRIORITY( priority)) { + rtems_status_code sc = RTEMS_SUCCESSFUL; + sc = rtems_interrupt_handler_install( vector, info, options, handler, arg); RTEMS_CHECK_SC( sc, "Install interrupt handler"); + return mpc55xx_intc_set_priority( vector, priority); } else { return RTEMS_INVALID_NUMBER; @@ -116,19 +118,16 @@ rtems_status_code mpc55xx_interrupt_handler_install( static int mpc55xx_external_exception_handler( BSP_Exception_frame *frame, unsigned exception_number) { /* Acknowlege interrupt request */ - rtems_vector_number vector_number = INTC.IACKR.B.INTVEC; - - /* Save current interrupt level */ - uint32_t level = _ISR_Get_level(); + rtems_vector_number vector = INTC.IACKR.B.INTVEC; - /* Enable all interrupts */ - _ISR_Set_level( 0); + /* Save machine state and enable external exceptions */ + uint32_t msr = ppc_external_exceptions_enable(); /* Dispatch interrupt handlers */ - bsp_interrupt_handler_dispatch( vector_number); + bsp_interrupt_handler_dispatch( vector); - /* Restore interrupt level */ - _ISR_Set_level( level); + /* Restore machine state */ + ppc_external_exceptions_disable( msr); /* End of interrupt */ INTC.EOIR.R = 1; diff --git a/c/src/lib/libcpu/powerpc/preinstall.am b/c/src/lib/libcpu/powerpc/preinstall.am index e6b86878b5..0207fc3c96 100644 --- a/c/src/lib/libcpu/powerpc/preinstall.am +++ b/c/src/lib/libcpu/powerpc/preinstall.am @@ -287,6 +287,10 @@ $(PROJECT_INCLUDE)/mpc55xx/edma.h: mpc55xx/include/edma.h $(PROJECT_INCLUDE)/mpc $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/mpc55xx/edma.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/mpc55xx/edma.h +$(PROJECT_INCLUDE)/mpc55xx/emios.h: mpc55xx/include/emios.h $(PROJECT_INCLUDE)/mpc55xx/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/mpc55xx/emios.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/mpc55xx/emios.h + $(PROJECT_INCLUDE)/mpc55xx/mpc55xx.h: mpc55xx/include/mpc55xx.h $(PROJECT_INCLUDE)/mpc55xx/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/mpc55xx/mpc55xx.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/mpc55xx/mpc55xx.h |