From 74df15caecf05c9c2007e71b5a185d3c289a6152 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 25 Apr 2018 10:40:40 +0200 Subject: bsp/lpc24xx: Move source files to bsps This patch is a part of the BSP source reorganization. Update #3285. --- bsps/arm/lpc24xx/fb/lcd.c | 122 ++++ bsps/arm/lpc24xx/spi/ssp.c | 652 ++++++++++++++++++++++ bsps/arm/lpc24xx/start/bspidle.c | 39 ++ bsps/arm/lpc24xx/start/dma-copy.c | 194 +++++++ bsps/arm/lpc24xx/start/dma.c | 102 ++++ bsps/arm/lpc24xx/start/io.c | 570 +++++++++++++++++++ bsps/arm/lpc24xx/start/restart.c | 52 ++ bsps/arm/lpc24xx/start/system-clocks.c | 167 ++++++ bsps/arm/lpc24xx/start/timer.c | 56 ++ c/src/lib/libbsp/arm/lpc24xx/Makefile.am | 18 +- c/src/lib/libbsp/arm/lpc24xx/misc/bspidle.c | 39 -- c/src/lib/libbsp/arm/lpc24xx/misc/dma-copy.c | 194 ------- c/src/lib/libbsp/arm/lpc24xx/misc/dma.c | 102 ---- c/src/lib/libbsp/arm/lpc24xx/misc/io.c | 570 ------------------- c/src/lib/libbsp/arm/lpc24xx/misc/lcd.c | 122 ---- c/src/lib/libbsp/arm/lpc24xx/misc/restart.c | 52 -- c/src/lib/libbsp/arm/lpc24xx/misc/system-clocks.c | 167 ------ c/src/lib/libbsp/arm/lpc24xx/misc/timer.c | 56 -- c/src/lib/libbsp/arm/lpc24xx/ssp/ssp.c | 652 ---------------------- 19 files changed, 1963 insertions(+), 1963 deletions(-) create mode 100644 bsps/arm/lpc24xx/fb/lcd.c create mode 100644 bsps/arm/lpc24xx/spi/ssp.c create mode 100644 bsps/arm/lpc24xx/start/bspidle.c create mode 100644 bsps/arm/lpc24xx/start/dma-copy.c create mode 100644 bsps/arm/lpc24xx/start/dma.c create mode 100644 bsps/arm/lpc24xx/start/io.c create mode 100644 bsps/arm/lpc24xx/start/restart.c create mode 100644 bsps/arm/lpc24xx/start/system-clocks.c create mode 100644 bsps/arm/lpc24xx/start/timer.c delete mode 100644 c/src/lib/libbsp/arm/lpc24xx/misc/bspidle.c delete mode 100644 c/src/lib/libbsp/arm/lpc24xx/misc/dma-copy.c delete mode 100644 c/src/lib/libbsp/arm/lpc24xx/misc/dma.c delete mode 100644 c/src/lib/libbsp/arm/lpc24xx/misc/io.c delete mode 100644 c/src/lib/libbsp/arm/lpc24xx/misc/lcd.c delete mode 100644 c/src/lib/libbsp/arm/lpc24xx/misc/restart.c delete mode 100644 c/src/lib/libbsp/arm/lpc24xx/misc/system-clocks.c delete mode 100644 c/src/lib/libbsp/arm/lpc24xx/misc/timer.c delete mode 100644 c/src/lib/libbsp/arm/lpc24xx/ssp/ssp.c diff --git a/bsps/arm/lpc24xx/fb/lcd.c b/bsps/arm/lpc24xx/fb/lcd.c new file mode 100644 index 0000000000..9474eec18a --- /dev/null +++ b/bsps/arm/lpc24xx/fb/lcd.c @@ -0,0 +1,122 @@ +/** + * @file + * + * @ingroup lpc24xx_lcd + * + * @brief LCD support. + */ + +/* + * Copyright (c) 2010-2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include + +#include +#include +#include +#include +#include + +#ifdef ARM_MULTILIB_ARCH_V4 + #define LCD_ENABLE BSP_BIT32(0) +#endif + +rtems_status_code lpc24xx_lcd_set_mode( + lpc24xx_lcd_mode mode, + const lpc24xx_pin_range *pins +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + bool enable = false; + + switch (mode) { + case LCD_MODE_STN_4_BIT: + case LCD_MODE_STN_8_BIT: + case LCD_MODE_STN_DUAL_PANEL_4_BIT: + case LCD_MODE_STN_DUAL_PANEL_8_BIT: + case LCD_MODE_TFT_12_BIT_4_4_4: + case LCD_MODE_TFT_16_BIT_5_6_5: + case LCD_MODE_TFT_16_BIT_1_5_5_5: + case LCD_MODE_TFT_24_BIT: + enable = true; + break; + case LCD_MODE_DISABLED: + enable = false; + break; + default: + sc = RTEMS_IO_ERROR; + break; + } + + if (sc == RTEMS_SUCCESSFUL) { + if (enable) { + sc = lpc24xx_module_enable(LPC24XX_MODULE_LCD, LPC24XX_MODULE_PCLK_DEFAULT); + assert(sc == RTEMS_SUCCESSFUL); + + #ifdef ARM_MULTILIB_ARCH_V4 + PINSEL11 = BSP_FLD32(mode, 1, 3) | LCD_ENABLE; + #endif + + sc = lpc24xx_pin_config(pins, LPC24XX_PIN_SET_FUNCTION); + assert(sc == RTEMS_SUCCESSFUL); + } else { + if (lpc24xx_lcd_current_mode() != LCD_MODE_DISABLED) { + uint32_t lcd_ctrl = LCD_CTRL; + + /* Disable power */ + lcd_ctrl &= ~BSP_BIT32(11); + LCD_CTRL = lcd_ctrl; + + lpc24xx_micro_seconds_delay(100000); + + /* Disable all signals */ + lcd_ctrl &= ~BSP_BIT32(0); + LCD_CTRL = lcd_ctrl; + } + + sc = lpc24xx_pin_config(pins, LPC24XX_PIN_SET_INPUT); + assert(sc == RTEMS_SUCCESSFUL); + + #ifdef ARM_MULTILIB_ARCH_V4 + PINSEL11 = 0; + #endif + + sc = lpc24xx_module_disable(LPC24XX_MODULE_LCD); + assert(sc == RTEMS_SUCCESSFUL); + } + } + + return sc; +} + +lpc24xx_lcd_mode lpc24xx_lcd_current_mode(void) +{ + #ifdef ARM_MULTILIB_ARCH_V4 + uint32_t pinsel11 = PINSEL11; + + if ((PCONP & BSP_BIT32(20)) != 0 && (pinsel11 & LCD_ENABLE) != 0) { + return BSP_FLD32GET(pinsel11, 1, 3); + } else { + return LCD_MODE_DISABLED; + } + #else + volatile lpc17xx_scb *scb = &LPC17XX_SCB; + + if ((scb->pconp & LPC17XX_SCB_PCONP_LCD) != 0) { + return LCD_CTRL & 0xae; + } else { + return LCD_MODE_DISABLED; + } + #endif +} diff --git a/bsps/arm/lpc24xx/spi/ssp.c b/bsps/arm/lpc24xx/spi/ssp.c new file mode 100644 index 0000000000..6563d047b2 --- /dev/null +++ b/bsps/arm/lpc24xx/spi/ssp.c @@ -0,0 +1,652 @@ +/** + * @file + * + * @ingroup lpc24xx_libi2c + * + * @brief LibI2C bus driver for the Synchronous Serial Port (SSP). + */ + +/* + * Copyright (c) 2008 + * Embedded Brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * rtems@embedded-brains.de + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#define RTEMS_STATUS_CHECKS_USE_PRINTK + +#include + +#define LPC24XX_SSP_NUMBER 2 + +#define LPC24XX_SSP_FIFO_SIZE 8 + +#define LPC24XX_SSP_BAUD_RATE 2000000 + +typedef enum { + LPC24XX_SSP_DMA_INVALID = 0, + LPC24XX_SSP_DMA_AVAILABLE = 1, + LPC24XX_SSP_DMA_NOT_INITIALIZED = 2, + LPC24XX_SSP_DMA_INITIALIZATION = 3, + LPC24XX_SSP_DMA_TRANSFER_FLAG = 0x80000000U, + LPC24XX_SSP_DMA_WAIT = 1 | LPC24XX_SSP_DMA_TRANSFER_FLAG, + LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_0 = 2 | LPC24XX_SSP_DMA_TRANSFER_FLAG, + LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_1 = 3 | LPC24XX_SSP_DMA_TRANSFER_FLAG, + LPC24XX_SSP_DMA_ERROR = 4 | LPC24XX_SSP_DMA_TRANSFER_FLAG, + LPC24XX_SSP_DMA_DONE = 5 | LPC24XX_SSP_DMA_TRANSFER_FLAG +} lpc24xx_ssp_dma_status; + +typedef struct { + rtems_libi2c_bus_t bus; + volatile lpc24xx_ssp *regs; + unsigned clock; + uint32_t idle_char; +} lpc24xx_ssp_bus_entry; + +typedef struct { + lpc24xx_ssp_dma_status status; + lpc24xx_ssp_bus_entry *bus; + rtems_libi2c_read_write_done_t done; + int n; + void *arg; +} lpc24xx_ssp_dma_entry; + +static lpc24xx_ssp_dma_entry lpc24xx_ssp_dma_data = { + .status = LPC24XX_SSP_DMA_NOT_INITIALIZED, + .bus = NULL, + .done = NULL, + .n = 0, + .arg = NULL +}; + +static uint32_t lpc24xx_ssp_trash = 0; + +static inline bool lpc24xx_ssp_is_busy(const lpc24xx_ssp_bus_entry *bus) +{ + return lpc24xx_ssp_dma_data.bus == bus + && lpc24xx_ssp_dma_data.status != LPC24XX_SSP_DMA_AVAILABLE; +} + +static void lpc24xx_ssp_handler(void *arg) +{ + lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) arg; + volatile lpc24xx_ssp *regs = e->regs; + uint32_t mis = regs->mis; + uint32_t icr = 0; + + if ((mis & SSP_MIS_RORRIS) != 0) { + /* TODO */ + icr |= SSP_ICR_RORRIS; + } + + regs->icr = icr; +} + +static void lpc24xx_ssp_dma_handler(void *arg) +{ + lpc24xx_ssp_dma_entry *e = (lpc24xx_ssp_dma_entry *) arg; + lpc24xx_ssp_dma_status status = e->status; + uint32_t tc = 0; + uint32_t err = 0; + int rv = 0; + + /* Return if we are not in a transfer status */ + if ((status & LPC24XX_SSP_DMA_TRANSFER_FLAG) == 0) { + return; + } + + /* Get interrupt status */ + tc = GPDMA_INT_TCSTAT; + err = GPDMA_INT_ERR_STAT; + + /* Clear interrupt status */ + GPDMA_INT_TCCLR = tc; + GPDMA_INT_ERR_CLR = err; + + /* Change status */ + if (err == 0) { + switch (status) { + case LPC24XX_SSP_DMA_WAIT: + if ((tc & (GPDMA_STATUS_CH_0 | GPDMA_STATUS_CH_1)) != 0) { + status = LPC24XX_SSP_DMA_DONE; + } else if ((tc & GPDMA_STATUS_CH_0) != 0) { + status = LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_1; + } else if ((tc & GPDMA_STATUS_CH_1) != 0) { + status = LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_0; + } + break; + case LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_0: + if ((tc & GPDMA_STATUS_CH_1) != 0) { + status = LPC24XX_SSP_DMA_ERROR; + } else if ((tc & GPDMA_STATUS_CH_0) != 0) { + status = LPC24XX_SSP_DMA_DONE; + } + break; + case LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_1: + if ((tc & GPDMA_STATUS_CH_0) != 0) { + status = LPC24XX_SSP_DMA_ERROR; + } else if ((tc & GPDMA_STATUS_CH_1) != 0) { + status = LPC24XX_SSP_DMA_DONE; + } + break; + default: + status = LPC24XX_SSP_DMA_ERROR; + break; + } + } else { + status = LPC24XX_SSP_DMA_ERROR; + } + + /* Error cleanup */ + if (status == LPC24XX_SSP_DMA_ERROR) { + lpc24xx_dma_channel_disable(0, true); + lpc24xx_dma_channel_disable(1, true); + status = LPC24XX_SSP_DMA_DONE; + rv = -RTEMS_IO_ERROR; + } + + /* Done */ + if (status == LPC24XX_SSP_DMA_DONE) { + status = LPC24XX_SSP_DMA_AVAILABLE; + if (e->done != NULL) { + e->done(rv, e->n, e->arg); + e->done = NULL; + } + } + + /* Set status */ + e->status = status; +} + +static rtems_status_code lpc24xx_ssp_init(rtems_libi2c_bus_t *bus) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_interrupt_level level; + lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; + volatile lpc24xx_ssp *regs = e->regs; + unsigned pclk = lpc24xx_cclk(); + unsigned pre = + ((pclk + LPC24XX_SSP_BAUD_RATE - 1) / LPC24XX_SSP_BAUD_RATE + 1) & ~1U; + lpc24xx_module module = LPC24XX_MODULE_SSP_0; + rtems_vector_number vector = UINT32_MAX; + + if (lpc24xx_ssp_dma_data.status == LPC24XX_SSP_DMA_NOT_INITIALIZED) { + lpc24xx_ssp_dma_status status = LPC24XX_SSP_DMA_INVALID; + + /* Test and set DMA support status */ + rtems_interrupt_disable(level); + status = lpc24xx_ssp_dma_data.status; + if (status == LPC24XX_SSP_DMA_NOT_INITIALIZED) { + lpc24xx_ssp_dma_data.status = LPC24XX_SSP_DMA_INITIALIZATION; + } + rtems_interrupt_enable(level); + + if (status == LPC24XX_SSP_DMA_NOT_INITIALIZED) { + /* Install DMA interrupt handler */ + sc = rtems_interrupt_handler_install( + LPC24XX_IRQ_DMA, + "SSP DMA", + RTEMS_INTERRUPT_SHARED, + lpc24xx_ssp_dma_handler, + &lpc24xx_ssp_dma_data + ); + RTEMS_CHECK_SC(sc, "install DMA interrupt handler"); + + /* Set DMA support status */ + lpc24xx_ssp_dma_data.status = LPC24XX_SSP_DMA_AVAILABLE; + } + } + + /* Disable module */ + regs->cr1 = 0; + + switch ((uintptr_t) regs) { + case SSP0_BASE_ADDR: + module = LPC24XX_MODULE_SSP_0; + vector = LPC24XX_IRQ_SPI_SSP_0; + break; + case SSP1_BASE_ADDR: + module = LPC24XX_MODULE_SSP_1; + vector = LPC24XX_IRQ_SSP_1; + break; + default: + return RTEMS_IO_ERROR; + } + + /* Set clock select */ + sc = lpc24xx_module_enable(module, LPC24XX_MODULE_PCLK_DEFAULT); + RTEMS_CHECK_SC(sc, "enable module clock"); + + /* Set serial clock rate to save value */ + regs->cr0 = SET_SSP_CR0_SCR(0, 255); + + /* Set clock prescaler */ + if (pre > 254) { + pre = 254; + } else if (pre < 2) { + pre = 2; + } + regs->cpsr = pre; + + /* Save clock value */ + e->clock = pclk / pre; + + /* Enable module and loop back mode */ + regs->cr1 = SSP_CR1_LBM | SSP_CR1_SSE; + + /* Install interrupt handler */ + sc = rtems_interrupt_handler_install( + vector, + "SSP", + RTEMS_INTERRUPT_UNIQUE, + lpc24xx_ssp_handler, + e + ); + RTEMS_CHECK_SC(sc, "install interrupt handler"); + + /* Enable receiver overrun interrupts */ + e->regs->imsc = SSP_IMSC_RORIM; + + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code lpc24xx_ssp_send_start(rtems_libi2c_bus_t *bus) +{ + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code lpc24xx_ssp_send_stop(rtems_libi2c_bus_t *bus) +{ + lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; + + /* Release DMA support */ + if (lpc24xx_ssp_dma_data.bus == e) { + if (lpc24xx_ssp_dma_data.status == LPC24XX_SSP_DMA_AVAILABLE) { + lpc24xx_dma_channel_release(0); + lpc24xx_dma_channel_release(1); + lpc24xx_ssp_dma_data.bus = NULL; + } else { + return RTEMS_RESOURCE_IN_USE; + } + } + + return RTEMS_SUCCESSFUL; +} + +static rtems_status_code lpc24xx_ssp_send_addr( + rtems_libi2c_bus_t *bus, + uint32_t addr, + int rw +) +{ + lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; + + if (lpc24xx_ssp_is_busy(e)) { + return RTEMS_RESOURCE_IN_USE; + } + + return RTEMS_SUCCESSFUL; +} + +static int lpc24xx_ssp_set_transfer_mode( + rtems_libi2c_bus_t *bus, + const rtems_libi2c_tfr_mode_t *mode +) +{ + lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; + volatile lpc24xx_ssp *regs = e->regs; + unsigned clk = e->clock; + unsigned br = mode->baudrate; + unsigned scr = (clk + br - 1) / br; + + if (lpc24xx_ssp_is_busy(e)) { + return -RTEMS_RESOURCE_IN_USE; + } + + if (mode->bits_per_char != 8) { + return -RTEMS_INVALID_NUMBER; + } + + if (mode->lsb_first) { + return -RTEMS_INVALID_NUMBER; + } + + if (br == 0) { + return -RTEMS_INVALID_NUMBER; + } + + /* Compute new prescaler if necessary */ + if (scr > 256 || scr < 1) { + unsigned pre = regs->cpsr; + unsigned pclk = clk * pre; + + while (scr > 256) { + if (pre > 252) { + return -RTEMS_INVALID_NUMBER; + } + pre += 2; + clk = pclk / pre; + scr = (clk + br - 1) / br; + } + + while (scr < 1) { + if (pre < 4) { + return -RTEMS_INVALID_NUMBER; + } + pre -= 2; + clk = pclk / pre; + scr = (clk + br - 1) / br; + } + + regs->cpsr = pre; + e->clock = clk; + } + + /* Adjust SCR */ + --scr; + + e->idle_char = mode->idle_char; + + while ((regs->sr & SSP_SR_TFE) == 0) { + /* Wait */ + } + + regs->cr0 = SET_SSP_CR0_DSS(0, 0x7) + | SET_SSP_CR0_SCR(0, scr) + | (mode->clock_inv ? SSP_CR0_CPOL : 0) + | (mode->clock_phs ? SSP_CR0_CPHA : 0); + + return 0; +} + +static int lpc24xx_ssp_read_write( + rtems_libi2c_bus_t *bus, + unsigned char *in, + const unsigned char *out, + int n +) +{ + lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; + volatile lpc24xx_ssp *regs = e->regs; + int r = 0; + int w = 0; + int dr = 1; + int dw = 1; + int m = 0; + uint32_t sr = regs->sr; + unsigned char trash = 0; + unsigned char idle_char = (unsigned char) e->idle_char; + + if (lpc24xx_ssp_is_busy(e)) { + return -RTEMS_RESOURCE_IN_USE; + } + + if (n < 0) { + return -RTEMS_INVALID_SIZE; + } + + /* Disable DMA on SSP */ + regs->dmacr = 0; + + if (in == NULL) { + dr = 0; + in = &trash; + } + + if (out == NULL) { + dw = 0; + out = &idle_char; + } + + /* + * Assumption: The transmit and receive FIFOs are empty. If this assumption + * is not true an input buffer overflow may occur or we may never exit the + * loop due to data loss. This is only possible if entities external to this + * driver operate on the SSP. + */ + + while (w < n) { + /* FIFO capacity */ + m = w - r; + + /* Write */ + if ((sr & SSP_SR_TNF) != 0 && m < LPC24XX_SSP_FIFO_SIZE) { + regs->dr = *out; + ++w; + out += dw; + } + + /* Read */ + if ((sr & SSP_SR_RNE) != 0) { + *in = (unsigned char) regs->dr; + ++r; + in += dr; + } + + /* New status */ + sr = regs->sr; + } + + /* Read outstanding input */ + while (r < n) { + /* Wait */ + do { + sr = regs->sr; + } while ((sr & SSP_SR_RNE) == 0); + + /* Read */ + *in = (unsigned char) regs->dr; + ++r; + in += dr; + } + + return n; +} + +static int lpc24xx_ssp_read_write_async( + rtems_libi2c_bus_t *bus, + unsigned char *in, + const unsigned char *out, + int n, + rtems_libi2c_read_write_done_t done, + void *arg +) +{ + rtems_interrupt_level level; + lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; + volatile lpc24xx_ssp *ssp = e->regs; + volatile lpc24xx_dma_channel *receive_channel = GPDMA_CH_BASE_ADDR(0); + volatile lpc24xx_dma_channel *transmit_channel = GPDMA_CH_BASE_ADDR(1); + uint32_t di = GPDMA_CH_CTRL_DI; + uint32_t si = GPDMA_CH_CTRL_SI; + + if (n < 0 || n > (int) GPDMA_CH_CTRL_TSZ_MAX) { + return -RTEMS_INVALID_SIZE; + } + + /* Try to reserve DMA support for this bus */ + if (lpc24xx_ssp_dma_data.bus == NULL) { + rtems_interrupt_disable(level); + if (lpc24xx_ssp_dma_data.bus == NULL) { + lpc24xx_ssp_dma_data.bus = e; + } + rtems_interrupt_enable(level); + + /* Try to obtain DMA channels */ + if (lpc24xx_ssp_dma_data.bus == e) { + rtems_status_code cs0 = lpc24xx_dma_channel_obtain(0); + rtems_status_code cs1 = lpc24xx_dma_channel_obtain(1); + + if (cs0 != RTEMS_SUCCESSFUL || cs1 != RTEMS_SUCCESSFUL) { + if (cs0 == RTEMS_SUCCESSFUL) { + lpc24xx_dma_channel_release(0); + } + if (cs1 == RTEMS_SUCCESSFUL) { + lpc24xx_dma_channel_release(1); + } + lpc24xx_ssp_dma_data.bus = NULL; + } + } + } + + /* Check if DMA support is available */ + if (lpc24xx_ssp_dma_data.bus != e + || lpc24xx_ssp_dma_data.status != LPC24XX_SSP_DMA_AVAILABLE) { + return -RTEMS_RESOURCE_IN_USE; + } + + /* Set DMA support status and parameter */ + lpc24xx_ssp_dma_data.status = LPC24XX_SSP_DMA_WAIT; + lpc24xx_ssp_dma_data.done = done; + lpc24xx_ssp_dma_data.n = n; + lpc24xx_ssp_dma_data.arg = arg; + + /* Enable DMA on SSP */ + ssp->dmacr = SSP_DMACR_RXDMAE | SSP_DMACR_TXDMAE; + + /* Receive */ + if (in != NULL) { + receive_channel->desc.dest = (uint32_t) in; + } else { + receive_channel->desc.dest = (uint32_t) &lpc24xx_ssp_trash; + di = 0; + } + receive_channel->desc.src = (uint32_t) &ssp->dr; + receive_channel->desc.lli = 0; + receive_channel->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n) + | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_4) + | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_4) + | SET_GPDMA_CH_CTRL_SW(0, GPDMA_CH_CTRL_W_8) + | SET_GPDMA_CH_CTRL_DW(0, GPDMA_CH_CTRL_W_8) + | GPDMA_CH_CTRL_ITC + | di; + receive_channel->cfg = SET_GPDMA_CH_CFG_SRCPER(0, GPDMA_CH_CFG_PER_SSP1_RX) + | SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_PER_TO_MEM_DMA) + | GPDMA_CH_CFG_IE + | GPDMA_CH_CFG_ITC + | GPDMA_CH_CFG_EN; + + /* Transmit */ + if (out != NULL) { + transmit_channel->desc.src = (uint32_t) out; + } else { + transmit_channel->desc.src = (uint32_t) &e->idle_char; + si = 0; + } + transmit_channel->desc.dest = (uint32_t) &ssp->dr; + transmit_channel->desc.lli = 0; + transmit_channel->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n) + | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_4) + | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_4) + | SET_GPDMA_CH_CTRL_SW(0, GPDMA_CH_CTRL_W_8) + | SET_GPDMA_CH_CTRL_DW(0, GPDMA_CH_CTRL_W_8) + | GPDMA_CH_CTRL_ITC + | si; + transmit_channel->cfg = SET_GPDMA_CH_CFG_DESTPER(0, GPDMA_CH_CFG_PER_SSP1_TX) + | SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_MEM_TO_PER_DMA) + | GPDMA_CH_CFG_IE + | GPDMA_CH_CFG_ITC + | GPDMA_CH_CFG_EN; + + return 0; +} + +static int lpc24xx_ssp_read(rtems_libi2c_bus_t *bus, unsigned char *in, int n) +{ + return lpc24xx_ssp_read_write(bus, in, NULL, n); +} + +static int lpc24xx_ssp_write( + rtems_libi2c_bus_t *bus, + unsigned char *out, + int n +) +{ + return lpc24xx_ssp_read_write(bus, NULL, out, n); +} + +static int lpc24xx_ssp_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg) +{ + int rv = -1; + const rtems_libi2c_tfr_mode_t *tm = (const rtems_libi2c_tfr_mode_t *) arg; + rtems_libi2c_read_write_t *rw = (rtems_libi2c_read_write_t *) arg; + rtems_libi2c_read_write_async_t *rwa = + (rtems_libi2c_read_write_async_t *) arg; + + switch (cmd) { + case RTEMS_LIBI2C_IOCTL_READ_WRITE: + rv = lpc24xx_ssp_read_write(bus, rw->rd_buf, rw->wr_buf, rw->byte_cnt); + break; + case RTEMS_LIBI2C_IOCTL_READ_WRITE_ASYNC: + rv = lpc24xx_ssp_read_write_async( + bus, + rwa->rd_buf, + rwa->wr_buf, + rwa->byte_cnt, + rwa->done, + rwa->arg + ); + break; + case RTEMS_LIBI2C_IOCTL_SET_TFRMODE: + rv = lpc24xx_ssp_set_transfer_mode(bus, tm); + break; + default: + rv = -RTEMS_NOT_DEFINED; + break; + } + + return rv; +} + +static const rtems_libi2c_bus_ops_t lpc24xx_ssp_ops = { + .init = lpc24xx_ssp_init, + .send_start = lpc24xx_ssp_send_start, + .send_stop = lpc24xx_ssp_send_stop, + .send_addr = lpc24xx_ssp_send_addr, + .read_bytes = lpc24xx_ssp_read, + .write_bytes = lpc24xx_ssp_write, + .ioctl = lpc24xx_ssp_ioctl +}; + +static lpc24xx_ssp_bus_entry lpc24xx_ssp_bus_table [LPC24XX_SSP_NUMBER] = { + { + /* SSP 0 */ + .bus = { + .ops = &lpc24xx_ssp_ops, + .size = sizeof(lpc24xx_ssp_bus_entry) + }, + .regs = (volatile lpc24xx_ssp *) SSP0_BASE_ADDR, + .clock = 0, + .idle_char = 0xffffffff + }, { + /* SSP 1 */ + .bus = { + .ops = &lpc24xx_ssp_ops, + .size = sizeof(lpc24xx_ssp_bus_entry) + }, + .regs = (volatile lpc24xx_ssp *) SSP1_BASE_ADDR, + .clock = 0, + .idle_char = 0xffffffff + } +}; + +rtems_libi2c_bus_t * const lpc24xx_ssp_0 = + (rtems_libi2c_bus_t *) &lpc24xx_ssp_bus_table [0]; + +rtems_libi2c_bus_t * const lpc24xx_ssp_1 = + (rtems_libi2c_bus_t *) &lpc24xx_ssp_bus_table [1]; diff --git a/bsps/arm/lpc24xx/start/bspidle.c b/bsps/arm/lpc24xx/start/bspidle.c new file mode 100644 index 0000000000..42a3e106f3 --- /dev/null +++ b/bsps/arm/lpc24xx/start/bspidle.c @@ -0,0 +1,39 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * @brief Idle task. + */ + +/* + * Copyright (c) 2008-2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include +#include + +void *bsp_idle_thread(uintptr_t ignored) +{ + while (true) { + #ifdef ARM_MULTILIB_ARCH_V4 + /* + * Set power mode to idle. Causes the processor clock to be stopped, + * while on-chip peripherals remain active. Any enabled interrupt from a + * peripheral or an external interrupt source will cause the processor to + * resume execution. + */ + PCON = 0x1; + #endif + } +} diff --git a/bsps/arm/lpc24xx/start/dma-copy.c b/bsps/arm/lpc24xx/start/dma-copy.c new file mode 100644 index 0000000000..73a8cdc3ab --- /dev/null +++ b/bsps/arm/lpc24xx/start/dma-copy.c @@ -0,0 +1,194 @@ +/** + * @file + * + * @ingroup lpc24xx_dma + * + * @brief Direct memory access (DMA) support. + */ + +/* + * Copyright (c) 2008, 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include +#include +#include + +static rtems_id lpc24xx_dma_sema_table [GPDMA_CH_NUMBER]; + +static bool lpc24xx_dma_status_table [GPDMA_CH_NUMBER]; + +static void lpc24xx_dma_copy_handler(void *arg) +{ + /* Get interrupt status */ + uint32_t tc = GPDMA_INT_TCSTAT; + uint32_t err = GPDMA_INT_ERR_STAT; + + /* Clear interrupt status */ + GPDMA_INT_TCCLR = tc; + GPDMA_INT_ERR_CLR = err; + + /* Check channel 0 */ + if ((tc & GPDMA_STATUS_CH_0) != 0) { + rtems_semaphore_release(lpc24xx_dma_sema_table [0]); + } + lpc24xx_dma_status_table [0] = (err & GPDMA_STATUS_CH_0) == 0; + + /* Check channel 1 */ + if ((tc & GPDMA_STATUS_CH_1) != 0) { + rtems_semaphore_release(lpc24xx_dma_sema_table [1]); + } + lpc24xx_dma_status_table [1] = (err & GPDMA_STATUS_CH_1) == 0; +} + +rtems_status_code lpc24xx_dma_copy_initialize(void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_id id0 = RTEMS_ID_NONE; + rtems_id id1 = RTEMS_ID_NONE; + + /* Create semaphore for channel 0 */ + sc = rtems_semaphore_create( + rtems_build_name('D', 'M', 'A', '0'), + 0, + RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &id0 + ); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + /* Create semaphore for channel 1 */ + sc = rtems_semaphore_create( + rtems_build_name('D', 'M', 'A', '1'), + 0, + RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &id1 + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_semaphore_delete(id0); + + return sc; + } + + /* Install DMA interrupt handler */ + sc = rtems_interrupt_handler_install( + LPC24XX_IRQ_DMA, + "DMA copy", + RTEMS_INTERRUPT_UNIQUE, + lpc24xx_dma_copy_handler, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + rtems_semaphore_delete(id0); + rtems_semaphore_delete(id1); + + return sc; + } + + /* Initialize global data */ + lpc24xx_dma_sema_table [0] = id0; + lpc24xx_dma_sema_table [1] = id1; + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code lpc24xx_dma_copy_release(void) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + rtems_status_code rsc = RTEMS_SUCCESSFUL; + + sc = rtems_interrupt_handler_remove( + LPC24XX_IRQ_DMA, + lpc24xx_dma_copy_handler, + NULL + ); + if (sc != RTEMS_SUCCESSFUL) { + rsc = sc; + } + + sc = rtems_semaphore_delete(lpc24xx_dma_sema_table [0]); + if (sc != RTEMS_SUCCESSFUL) { + rsc = sc; + } + + sc = rtems_semaphore_delete(lpc24xx_dma_sema_table [1]); + if (sc != RTEMS_SUCCESSFUL) { + rsc = sc; + } + + return rsc; +} + +rtems_status_code lpc24xx_dma_copy( + unsigned channel, + void *dest, + const void *src, + size_t n, + size_t width +) +{ + volatile lpc24xx_dma_channel *e = GPDMA_CH_BASE_ADDR(channel); + uint32_t w = GPDMA_CH_CTRL_W_8; + + switch (width) { + case 4: + w = GPDMA_CH_CTRL_W_32; + break; + case 2: + w = GPDMA_CH_CTRL_W_16; + break; + } + + n = n >> w; + + if (n > 0U && n < 4096U) { + e->desc.src = (uint32_t) src; + e->desc.dest = (uint32_t) dest; + e->desc.lli = 0; + e->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n) + | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_1) + | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_1) + | SET_GPDMA_CH_CTRL_SW(0, w) + | SET_GPDMA_CH_CTRL_DW(0, w) + | GPDMA_CH_CTRL_ITC + | GPDMA_CH_CTRL_SI + | GPDMA_CH_CTRL_DI; + e->cfg = SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_MEM_TO_MEM_DMA) + | GPDMA_CH_CFG_IE + | GPDMA_CH_CFG_ITC + | GPDMA_CH_CFG_EN; + } else { + return RTEMS_INVALID_SIZE; + } + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code lpc24xx_dma_copy_wait(unsigned channel) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + sc = rtems_semaphore_obtain( + lpc24xx_dma_sema_table [channel], + RTEMS_WAIT, + RTEMS_NO_TIMEOUT + ); + if (sc != RTEMS_SUCCESSFUL) { + return sc; + } + + return lpc24xx_dma_status_table [channel] + ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR; +} diff --git a/bsps/arm/lpc24xx/start/dma.c b/bsps/arm/lpc24xx/start/dma.c new file mode 100644 index 0000000000..a67760ad3e --- /dev/null +++ b/bsps/arm/lpc24xx/start/dma.c @@ -0,0 +1,102 @@ +/** + * @file + * + * @ingroup lpc24xx_dma + * + * @brief Direct memory access (DMA) support. + */ + +/* + * Copyright (c) 2008-2011 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include + +#include +#include +#include + +/** + * @brief Table that indicates if a channel is currently occupied. + */ +static bool lpc24xx_dma_channel_occupation [GPDMA_CH_NUMBER]; + +void lpc24xx_dma_initialize(void) +{ + /* Enable module power */ + lpc24xx_module_enable(LPC24XX_MODULE_GPDMA, LPC24XX_MODULE_PCLK_DEFAULT); + + /* Disable module */ + GPDMA_CONFIG = 0; + + /* Reset registers */ + GPDMA_SOFT_SREQ = 0; + GPDMA_SOFT_BREQ = 0; + GPDMA_SOFT_LSREQ = 0; + GPDMA_SOFT_LBREQ = 0; + GPDMA_SYNC = 0; + GPDMA_CH0_CFG = 0; + GPDMA_CH1_CFG = 0; + + /* Enable module */ + #if BYTE_ORDER == LITTLE_ENDIAN + GPDMA_CONFIG = GPDMA_CONFIG_EN; + #else + GPDMA_CONFIG = GPDMA_CONFIG_EN | GPDMA_CONFIG_MODE; + #endif +} + +rtems_status_code lpc24xx_dma_channel_obtain(unsigned channel) +{ + if (channel < GPDMA_CH_NUMBER) { + rtems_interrupt_level level; + bool occupation = true; + + rtems_interrupt_disable(level); + occupation = lpc24xx_dma_channel_occupation [channel]; + lpc24xx_dma_channel_occupation [channel] = true; + rtems_interrupt_enable(level); + + return occupation ? RTEMS_RESOURCE_IN_USE : RTEMS_SUCCESSFUL; + } else { + return RTEMS_INVALID_ID; + } +} + +void lpc24xx_dma_channel_release(unsigned channel) +{ + if (channel < GPDMA_CH_NUMBER) { + lpc24xx_dma_channel_occupation [channel] = false; + } +} + +void lpc24xx_dma_channel_disable(unsigned channel, bool force) +{ + if (channel < GPDMA_CH_NUMBER) { + volatile lpc24xx_dma_channel *ch = GPDMA_CH_BASE_ADDR(channel); + uint32_t cfg = ch->cfg; + + if (!force) { + /* Halt */ + ch->cfg |= GPDMA_CH_CFG_HALT; + + /* Wait for inactive */ + do { + cfg = ch->cfg; + } while ((cfg & GPDMA_CH_CFG_ACTIVE) != 0); + } + + /* Disable */ + ch->cfg &= ~GPDMA_CH_CFG_EN; + } +} diff --git a/bsps/arm/lpc24xx/start/io.c b/bsps/arm/lpc24xx/start/io.c new file mode 100644 index 0000000000..c28b5182f0 --- /dev/null +++ b/bsps/arm/lpc24xx/start/io.c @@ -0,0 +1,570 @@ +/** + * @file + * + * @ingroup lpc24xx_io + * + * @brief Input and output module. + */ + +/* + * Copyright (c) 2009-2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include +#include +#include +#include + +#define LPC24XX_PIN_SELECT(index) ((index) >> 4U) + +#define LPC24XX_PIN_SELECT_SHIFT(index) (((index) & 0xfU) << 1U) + +#define LPC24XX_PIN_SELECT_MASK 0x3U + +rtems_status_code lpc24xx_gpio_config( + unsigned index, + lpc24xx_gpio_settings settings +) +{ + if (index <= LPC24XX_IO_INDEX_MAX) { + rtems_interrupt_level level; + uint32_t port = LPC24XX_IO_PORT(index); + uint32_t port_bit = LPC24XX_IO_PORT_BIT(index); + uint32_t output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U; + uint32_t resistor = settings & 0x3U; + #ifdef ARM_MULTILIB_ARCH_V4 + uint32_t select = LPC24XX_PIN_SELECT(index); + uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index); + + /* Get resistor flags */ + switch (resistor) { + case LPC24XX_GPIO_RESISTOR_PULL_UP: + resistor = 0x0U; + break; + case LPC24XX_GPIO_RESISTOR_NONE: + resistor = 0x2U; + break; + case LPC24XX_GPIO_RESISTOR_PULL_DOWN: + resistor = 0x3U; + break; + default: + return RTEMS_INVALID_NUMBER; + } + #else + uint32_t iocon_mask = IOCON_HYS | IOCON_INV + | IOCON_SLEW | IOCON_OD | IOCON_FILTER; + uint32_t iocon = (settings & iocon_mask) | IOCON_ADMODE; + uint32_t iocon_invalid = settings & ~(iocon_mask | LPC24XX_GPIO_OUTPUT); + + /* Get resistor flags */ + switch (resistor) { + case LPC24XX_GPIO_RESISTOR_NONE: + resistor = IOCON_MODE(0); + break; + case LPC24XX_GPIO_RESISTOR_PULL_DOWN: + resistor = IOCON_MODE(1); + break; + case LPC24XX_GPIO_RESISTOR_PULL_UP: + resistor = IOCON_MODE(2); + break; + case LPC17XX_GPIO_HYSTERESIS: + resistor = IOCON_MODE(3); + break; + } + iocon |= resistor; + + if (iocon_invalid != 0) { + return RTEMS_INVALID_NUMBER; + } + + if (output && (settings & LPC17XX_GPIO_INPUT_INVERT) != 0) { + return RTEMS_INVALID_NUMBER; + } + + if ((settings & LPC17XX_GPIO_INPUT_FILTER) == 0) { + iocon |= IOCON_FILTER; + } else { + iocon &= ~IOCON_FILTER; + } + #endif + + rtems_interrupt_disable(level); + + #ifdef ARM_MULTILIB_ARCH_V4 + /* Resistor */ + LPC24XX_PINMODE [select] = + (LPC24XX_PINMODE [select] & ~(LPC24XX_PIN_SELECT_MASK << shift)) + | ((resistor & LPC24XX_PIN_SELECT_MASK) << shift); + #else + LPC17XX_IOCON [index] = iocon; + #endif + + rtems_interrupt_flash(level); + + /* Input or output */ + LPC24XX_FIO [port].dir = + (LPC24XX_FIO [port].dir & ~(1U << port_bit)) | (output << port_bit); + + rtems_interrupt_enable(level); + } else { + return RTEMS_INVALID_ID; + } + + return RTEMS_SUCCESSFUL; +} + +#define LPC24XX_MODULE_ENTRY(mod, pwr, clk, idx) \ + [mod] = { \ + .power = pwr, \ + .clock = clk, \ + .index = idx \ + } + +typedef struct { + unsigned char power : 1; + unsigned char clock : 1; + unsigned char index : 6; +} lpc24xx_module_entry; + +static const lpc24xx_module_entry lpc24xx_module_table [] = { + #ifdef ARM_MULTILIB_ARCH_V4 + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ACF, 0, 1, 15), + #endif + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ADC, 1, 1, 12), + #ifdef ARM_MULTILIB_ARCH_V4 + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_BAT_RAM, 0, 1, 16), + #endif + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_0, 1, 1, 13), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_1, 1, 1, 14), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_DAC, 0, 1, 11), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_EMC, 1, 0, 11), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 0, 30), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPDMA, 1, 1, 29), + #ifdef ARM_MULTILIB_ARCH_V4 + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 17), + #else + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 15), + #endif + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_0, 1, 1, 7), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_1, 1, 1, 19), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_2, 1, 1, 26), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2S, 1, 1, 27), + #ifdef ARM_MULTILIB_ARCH_V4 + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 20), + #else + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 0), + #endif + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCI, 1, 1, 28), + #ifdef ARM_MULTILIB_ARCH_V7M + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCPWM, 1, 1, 17), + #endif + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PCB, 0, 1, 18), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_0, 1, 1, 5), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_1, 1, 1, 6), + #ifdef ARM_MULTILIB_ARCH_V7M + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_QEI, 1, 1, 18), + #endif + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_RTC, 1, 1, 9), + #ifdef ARM_MULTILIB_ARCH_V4 + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SPI, 1, 1, 8), + #endif + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 21), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 10), + #ifdef ARM_MULTILIB_ARCH_V7M + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_2, 1, 1, 20), + #endif + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SYSCON, 0, 1, 30), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_0, 1, 1, 1), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_1, 1, 1, 2), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_2, 1, 1, 22), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_3, 1, 1, 23), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_0, 1, 1, 3), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_1, 1, 1, 4), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_2, 1, 1, 24), + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_3, 1, 1, 25), + #ifdef ARM_MULTILIB_ARCH_V7M + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_4, 1, 1, 8), + #endif + #ifdef ARM_MULTILIB_ARCH_V4 + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_WDT, 0, 1, 0), + #endif + LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_USB, 1, 0, 31) +}; + +static rtems_status_code lpc24xx_module_do_enable( + lpc24xx_module module, + lpc24xx_module_clock clock, + bool enable +) +{ + rtems_interrupt_level level; + bool has_power = false; + bool has_clock = false; + unsigned index = 0; + #ifdef ARM_MULTILIB_ARCH_V7M + volatile lpc17xx_scb *scb = &LPC17XX_SCB; + #endif + + if ((unsigned) module >= LPC24XX_MODULE_COUNT) { + return RTEMS_INVALID_ID; + } + + #ifdef ARM_MULTILIB_ARCH_V4 + if (clock == LPC24XX_MODULE_PCLK_DEFAULT) { + #if LPC24XX_PCLKDIV == 1U + clock = LPC24XX_MODULE_CCLK; + #elif LPC24XX_PCLKDIV == 2U + clock = LPC24XX_MODULE_CCLK_2; + #elif LPC24XX_PCLKDIV == 4U + clock = LPC24XX_MODULE_CCLK_4; + #elif LPC24XX_PCLKDIV == 8U + clock = LPC24XX_MODULE_CCLK_8; + #endif + } + + if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) { + return RTEMS_INVALID_CLOCK; + } + #else + if (clock != LPC24XX_MODULE_PCLK_DEFAULT) { + return RTEMS_INVALID_CLOCK; + } + #endif + + has_power = lpc24xx_module_table [module].power; + has_clock = lpc24xx_module_table [module].clock; + index = lpc24xx_module_table [module].index; + + /* Enable or disable module */ + if (enable) { + if (has_power) { + rtems_interrupt_disable(level); + #ifdef ARM_MULTILIB_ARCH_V4 + PCONP |= 1U << index; + #else + scb->pconp |= 1U << index; + #endif + rtems_interrupt_enable(level); + } + + if (module != LPC24XX_MODULE_USB) { + if (has_clock) { + #ifdef ARM_MULTILIB_ARCH_V4 + unsigned clock_shift = 2U * index; + + rtems_interrupt_disable(level); + if (clock_shift < 32U) { + PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift)) + | (clock << clock_shift); + } else { + clock_shift -= 32U; + PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift)) + | (clock << clock_shift); + } + rtems_interrupt_enable(level); + #endif + } + } else { + #ifdef ARM_MULTILIB_ARCH_V4 + unsigned pllclk = lpc24xx_pllclk(); + unsigned usbsel = pllclk / 48000000U - 1U; + + if ( + usbsel > 15U + || (usbsel % 2U != 1U) + || (pllclk % 48000000U) != 0U + ) { + return RTEMS_INCORRECT_STATE; + } + + USBCLKCFG = usbsel; + #else + uint32_t pllclk = lpc24xx_pllclk(); + uint32_t usbclk = 48000000U; + + if (pllclk % usbclk == 0U) { + uint32_t usbdiv = pllclk / usbclk; + + scb->usbclksel = LPC17XX_SCB_USBCLKSEL_USBDIV(usbdiv) + | LPC17XX_SCB_USBCLKSEL_USBSEL(1); + } else { + return RTEMS_INCORRECT_STATE; + } + #endif + } + } else { + if (has_power) { + rtems_interrupt_disable(level); + #ifdef ARM_MULTILIB_ARCH_V4 + PCONP &= ~(1U << index); + #else + scb->pconp &= ~(1U << index); + #endif + rtems_interrupt_enable(level); + } + } + + return RTEMS_SUCCESSFUL; +} + +rtems_status_code lpc24xx_module_enable( + lpc24xx_module module, + lpc24xx_module_clock clock +) +{ + return lpc24xx_module_do_enable(module, clock, true); +} + +rtems_status_code lpc24xx_module_disable( + lpc24xx_module module +) +{ + return lpc24xx_module_do_enable( + module, + LPC24XX_MODULE_PCLK_DEFAULT, + false + ); +} + +bool lpc24xx_module_is_enabled(lpc24xx_module module) +{ + bool enabled = false; + + if ((unsigned) module < LPC24XX_MODULE_COUNT) { + bool has_power = lpc24xx_module_table [module].power; + + if (has_power) { + unsigned index = lpc24xx_module_table [module].index; + #ifdef ARM_MULTILIB_ARCH_V4 + uint32_t pconp = PCONP; + #else + uint32_t pconp = LPC17XX_SCB.pconp; + #endif + + enabled = (pconp & (1U << index)) != 0; + } else { + enabled = true; + } + } + + return enabled; +} + +typedef rtems_status_code (*lpc24xx_pin_visitor)( + #ifdef ARM_MULTILIB_ARCH_V4 + volatile uint32_t *pinsel, + uint32_t pinsel_mask, + uint32_t pinsel_value, + #else + volatile uint32_t *iocon, + lpc24xx_pin_range pin_range, + #endif + volatile uint32_t *fio_dir, + uint32_t fio_bit +); + +static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code +lpc24xx_pin_set_function( + #ifdef ARM_MULTILIB_ARCH_V4 + volatile uint32_t *pinsel, + uint32_t pinsel_mask, + uint32_t pinsel_value, + #else + volatile uint32_t *iocon, + lpc24xx_pin_range pin_range, + #endif + volatile uint32_t *fio_dir, + uint32_t fio_bit +) +{ + #ifdef ARM_MULTILIB_ARCH_V4 + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + *pinsel = (*pinsel & ~pinsel_mask) | pinsel_value; + rtems_interrupt_enable(level); + #else + uint32_t iocon_extra = 0; + uint32_t iocon_not_analog = IOCON_ADMODE; + + /* TODO */ + switch (pin_range.fields.type) { + case LPC17XX_PIN_TYPE_ADC: + case LPC17XX_PIN_TYPE_DAC: + iocon_not_analog = 0; + break; + case LPC17XX_PIN_TYPE_I2C_FAST_PLUS: + iocon_extra |= IOCON_HS; + break; + case LPC17XX_PIN_TYPE_OPEN_DRAIN: + iocon_extra |= IOCON_OD; + break; + default: + break; + } + + *iocon = IOCON_FUNC(pin_range.fields.function) | iocon_extra | iocon_not_analog; + #endif + + return RTEMS_SUCCESSFUL; +} + +static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_function( + #ifdef ARM_MULTILIB_ARCH_V4 + volatile uint32_t *pinsel, + uint32_t pinsel_mask, + uint32_t pinsel_value, + #else + volatile uint32_t *iocon, + lpc24xx_pin_range pin_range, + #endif + volatile uint32_t *fio_dir, + uint32_t fio_bit +) +{ + #ifdef ARM_MULTILIB_ARCH_V4 + if ((*pinsel & pinsel_mask) == pinsel_value) { + return RTEMS_SUCCESSFUL; + } else { + return RTEMS_IO_ERROR; + } + #else + /* TODO */ + return RTEMS_IO_ERROR; + #endif +} + +static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code +lpc24xx_pin_set_input( + #ifdef ARM_MULTILIB_ARCH_V4 + volatile uint32_t *pinsel, + uint32_t pinsel_mask, + uint32_t pinsel_value, + #else + volatile uint32_t *iocon, + lpc24xx_pin_range pin_range, + #endif + volatile uint32_t *fio_dir, + uint32_t fio_bit +) +{ + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + *fio_dir &= ~fio_bit; + #ifdef ARM_MULTILIB_ARCH_V4 + *pinsel &= ~pinsel_mask; + #else + *iocon = IOCON_MODE(2) | IOCON_ADMODE | IOCON_FILTER; + #endif + rtems_interrupt_enable(level); + + return RTEMS_SUCCESSFUL; +} + +static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_input( + #ifdef ARM_MULTILIB_ARCH_V4 + volatile uint32_t *pinsel, + uint32_t pinsel_mask, + uint32_t pinsel_value, + #else + volatile uint32_t *iocon, + lpc24xx_pin_range pin_range, + #endif + volatile uint32_t *fio_dir, + uint32_t fio_bit +) +{ + rtems_status_code sc = RTEMS_IO_ERROR; + bool is_input = (*fio_dir & fio_bit) == 0; + + if (is_input) { + #ifdef ARM_MULTILIB_ARCH_V4 + bool is_gpio = (*pinsel & pinsel_mask) == 0; + #else + bool is_gpio = IOCON_FUNC_GET(*iocon) == 0; + #endif + + if (is_gpio) { + sc = RTEMS_SUCCESSFUL; + } + } + + return sc; +} + +static BSP_START_DATA_SECTION const lpc24xx_pin_visitor + lpc24xx_pin_visitors [] = { + [LPC24XX_PIN_SET_FUNCTION] = lpc24xx_pin_set_function, + [LPC24XX_PIN_CHECK_FUNCTION] = lpc24xx_pin_check_function, + [LPC24XX_PIN_SET_INPUT] = lpc24xx_pin_set_input, + [LPC24XX_PIN_CHECK_INPUT] = lpc24xx_pin_check_input +}; + +BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_config( + const lpc24xx_pin_range *pins, + lpc24xx_pin_action action +) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + + if ((unsigned) action <= LPC24XX_PIN_CHECK_INPUT) { + lpc24xx_pin_visitor visitor = lpc24xx_pin_visitors [action]; + lpc24xx_pin_range terminal = LPC24XX_PIN_TERMINAL; + lpc24xx_pin_range pin_range = *pins; + uint32_t previous_port_bit = pin_range.fields.port_bit; + + while (sc == RTEMS_SUCCESSFUL && pin_range.value != terminal.value) { + uint32_t port = pin_range.fields.port; + uint32_t port_bit = pin_range.fields.port_bit; + uint32_t port_bit_last = port_bit; + uint32_t range = pin_range.fields.range; + #ifdef ARM_MULTILIB_ARCH_V4 + uint32_t function = pin_range.fields.function; + #endif + volatile uint32_t *fio_dir = &LPC24XX_FIO [port].dir; + + if (range) { + port_bit = previous_port_bit; + } + + while (sc == RTEMS_SUCCESSFUL && port_bit <= port_bit_last) { + uint32_t index = LPC24XX_IO_INDEX_BY_PORT(port, port_bit); + uint32_t fio_bit = 1U << port_bit; + #ifdef ARM_MULTILIB_ARCH_V4 + uint32_t select = LPC24XX_PIN_SELECT(index); + uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index); + volatile uint32_t *pinsel = &LPC24XX_PINSEL [select]; + uint32_t pinsel_mask = LPC24XX_PIN_SELECT_MASK << shift; + uint32_t pinsel_value = (function & LPC24XX_PIN_SELECT_MASK) << shift; + + sc = (*visitor)(pinsel, pinsel_mask, pinsel_value, fio_dir, fio_bit); + #else + volatile uint32_t *iocon = &LPC17XX_IOCON [index]; + + sc = (*visitor)(iocon, pin_range, fio_dir, fio_bit); + #endif + + ++port_bit; + } + + ++pins; + previous_port_bit = port_bit; + pin_range = *pins; + } + } else { + sc = RTEMS_NOT_DEFINED; + } + + return sc; +} diff --git a/bsps/arm/lpc24xx/start/restart.c b/bsps/arm/lpc24xx/start/restart.c new file mode 100644 index 0000000000..627f79d19d --- /dev/null +++ b/bsps/arm/lpc24xx/start/restart.c @@ -0,0 +1,52 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * @brief Restart implementation. + */ + +/* + * Copyright (c) 2011-2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include + +#include + +void bsp_restart(void *addr) +{ + #ifdef ARM_MULTILIB_ARCH_V4 + ARM_SWITCH_REGISTERS; + rtems_interrupt_level level; + + rtems_interrupt_disable(level); + (void) level; + + asm volatile ( + ARM_SWITCH_TO_ARM + "mov pc, %[addr]\n" + ARM_SWITCH_BACK + : ARM_SWITCH_OUTPUT + : [addr] "r" (addr) + ); + #else + rtems_interrupt_level level; + void (*start)(void) = addr; + + rtems_interrupt_disable(level); + (void) level; + + (*start)(); + #endif +} diff --git a/bsps/arm/lpc24xx/start/system-clocks.c b/bsps/arm/lpc24xx/start/system-clocks.c new file mode 100644 index 0000000000..f64fca1bed --- /dev/null +++ b/bsps/arm/lpc24xx/start/system-clocks.c @@ -0,0 +1,167 @@ +/** + * @file + * + * @ingroup lpc24xx_clocks + * + * @brief System clocks. + */ + +/* + * Copyright (c) 2008-2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include + +#include +#include +#include + +/** + * @brief Internal RC oscillator frequency in [Hz]. + */ +#define LPC24XX_OSCILLATOR_INTERNAL 4000000U + +#ifndef LPC24XX_OSCILLATOR_MAIN + #error "unknown main oscillator frequency" +#endif + +#ifndef LPC24XX_OSCILLATOR_RTC + #error "unknown RTC oscillator frequency" +#endif + +void lpc24xx_timer_initialize(void) +{ + /* Reset timer */ + T1TCR = TCR_RST; + + /* Set timer mode */ + T1CTCR = 0; + + /* Set prescaler to zero */ + T1PR = 0; + + /* Reset all interrupt flags */ + T1IR = 0xff; + + /* Do not stop on a match */ + T1MCR = 0; + + /* No captures */ + T1CCR = 0; + + /* Start timer */ + T1TCR = TCR_EN; + + rtems_counter_initialize_converter(LPC24XX_PCLK); +} + +CPU_Counter_ticks _CPU_Counter_read(void) +{ + return lpc24xx_timer(); +} + +void lpc24xx_micro_seconds_delay(unsigned us) +{ + unsigned start = lpc24xx_timer(); + unsigned delay = us * (LPC24XX_PCLK / 1000000); + unsigned elapsed = 0; + + do { + elapsed = lpc24xx_timer() - start; + } while (elapsed < delay); +} + +#ifdef ARM_MULTILIB_ARCH_V7M + static unsigned lpc17xx_sysclk(unsigned clksrcsel) + { + return (clksrcsel & LPC17XX_SCB_CLKSRCSEL_CLKSRC) != 0 ? + LPC24XX_OSCILLATOR_MAIN + : LPC24XX_OSCILLATOR_INTERNAL; + } +#endif + +unsigned lpc24xx_pllclk(void) +{ + #ifdef ARM_MULTILIB_ARCH_V4 + unsigned clksrc = GET_CLKSRCSEL_CLKSRC(CLKSRCSEL); + unsigned pllinclk = 0; + unsigned pllclk = 0; + + /* Get PLL input frequency */ + switch (clksrc) { + case 0: + pllinclk = LPC24XX_OSCILLATOR_INTERNAL; + break; + case 1: + pllinclk = LPC24XX_OSCILLATOR_MAIN; + break; + case 2: + pllinclk = LPC24XX_OSCILLATOR_RTC; + break; + default: + return 0; + } + + /* Get PLL output frequency */ + if ((PLLSTAT & PLLSTAT_PLLC) != 0) { + uint32_t pllcfg = PLLCFG; + unsigned n = GET_PLLCFG_NSEL(pllcfg) + 1; + unsigned m = GET_PLLCFG_MSEL(pllcfg) + 1; + + pllclk = (pllinclk / n) * 2 * m; + } else { + pllclk = pllinclk; + } + #else + volatile lpc17xx_scb *scb = &LPC17XX_SCB; + unsigned sysclk = lpc17xx_sysclk(scb->clksrcsel); + unsigned pllstat = scb->pll_0.stat; + unsigned pllclk = 0; + unsigned enabled_and_locked = LPC17XX_PLL_STAT_PLLE + | LPC17XX_PLL_STAT_PLOCK; + + if ((pllstat & enabled_and_locked) == enabled_and_locked) { + unsigned m = LPC17XX_PLL_SEL_MSEL_GET(pllstat) + 1; + + pllclk = sysclk * m; + } + #endif + + return pllclk; +} + +unsigned lpc24xx_cclk(void) +{ + #ifdef ARM_MULTILIB_ARCH_V4 + /* Get PLL output frequency */ + unsigned pllclk = lpc24xx_pllclk(); + + /* Get CPU frequency */ + unsigned cclk = pllclk / (GET_CCLKCFG_CCLKSEL(CCLKCFG) + 1); + #else + volatile lpc17xx_scb *scb = &LPC17XX_SCB; + unsigned cclksel = scb->cclksel; + unsigned cclk_in = 0; + unsigned cclk = 0; + + if ((cclksel & LPC17XX_SCB_CCLKSEL_CCLKSEL) != 0) { + cclk_in = lpc24xx_pllclk(); + } else { + cclk_in = lpc17xx_sysclk(scb->clksrcsel); + } + + cclk = cclk_in / LPC17XX_SCB_CCLKSEL_CCLKDIV_GET(cclksel); + #endif + + return cclk; +} diff --git a/bsps/arm/lpc24xx/start/timer.c b/bsps/arm/lpc24xx/start/timer.c new file mode 100644 index 0000000000..c700d04566 --- /dev/null +++ b/bsps/arm/lpc24xx/start/timer.c @@ -0,0 +1,56 @@ +/** + * @file + * + * @ingroup lpc24xx + * + * @brief Benchmark timer support. + */ + +/* + * Copyright (c) 2008, 2009 + * embedded brains GmbH + * Obere Lagerstr. 30 + * D-82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include +#include +#include + +#include + +bool benchmark_timer_find_average_overhead = false; + +static uint32_t benchmark_timer_base; + +void benchmark_timer_initialize(void) +{ + benchmark_timer_base = lpc24xx_timer(); +} + +benchmark_timer_t benchmark_timer_read(void) +{ + uint32_t delta = lpc24xx_timer() - benchmark_timer_base; + + if (benchmark_timer_find_average_overhead) { + return delta; + } else { + /* Value determined by tmck for NCS board */ + if (delta > 74) { + return delta - 74; + } else { + return 0; + } + } +} + +void benchmark_timer_disable_subtracting_average_overhead(bool find_average_overhead ) +{ + benchmark_timer_find_average_overhead = find_average_overhead; +} diff --git a/c/src/lib/libbsp/arm/lpc24xx/Makefile.am b/c/src/lib/libbsp/arm/lpc24xx/Makefile.am index a87f7b75c2..14d836f5a8 100644 --- a/c/src/lib/libbsp/arm/lpc24xx/Makefile.am +++ b/c/src/lib/libbsp/arm/lpc24xx/Makefile.am @@ -87,17 +87,17 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/shared/dev/rtc/rtc-support.c librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/rtc/rtc-config.c # Misc -librtemsbsp_a_SOURCES += misc/system-clocks.c -librtemsbsp_a_SOURCES += misc/dma.c -librtemsbsp_a_SOURCES += misc/dma-copy.c -librtemsbsp_a_SOURCES += misc/bspidle.c -librtemsbsp_a_SOURCES += misc/io.c -librtemsbsp_a_SOURCES += misc/lcd.c -librtemsbsp_a_SOURCES += misc/restart.c -librtemsbsp_a_SOURCES += misc/timer.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/start/system-clocks.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/start/dma.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/start/dma-copy.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/start/bspidle.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/start/io.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/fb/lcd.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/start/restart.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/start/timer.c # SSP -librtemsbsp_a_SOURCES += ssp/ssp.c +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/spi/ssp.c # I2C librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/lpc24xx/i2c/i2c.c diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/bspidle.c b/c/src/lib/libbsp/arm/lpc24xx/misc/bspidle.c deleted file mode 100644 index 42a3e106f3..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/misc/bspidle.c +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx - * - * @brief Idle task. - */ - -/* - * Copyright (c) 2008-2011 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include -#include - -void *bsp_idle_thread(uintptr_t ignored) -{ - while (true) { - #ifdef ARM_MULTILIB_ARCH_V4 - /* - * Set power mode to idle. Causes the processor clock to be stopped, - * while on-chip peripherals remain active. Any enabled interrupt from a - * peripheral or an external interrupt source will cause the processor to - * resume execution. - */ - PCON = 0x1; - #endif - } -} diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/dma-copy.c b/c/src/lib/libbsp/arm/lpc24xx/misc/dma-copy.c deleted file mode 100644 index 73a8cdc3ab..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/misc/dma-copy.c +++ /dev/null @@ -1,194 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx_dma - * - * @brief Direct memory access (DMA) support. - */ - -/* - * Copyright (c) 2008, 2009 - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include -#include -#include - -static rtems_id lpc24xx_dma_sema_table [GPDMA_CH_NUMBER]; - -static bool lpc24xx_dma_status_table [GPDMA_CH_NUMBER]; - -static void lpc24xx_dma_copy_handler(void *arg) -{ - /* Get interrupt status */ - uint32_t tc = GPDMA_INT_TCSTAT; - uint32_t err = GPDMA_INT_ERR_STAT; - - /* Clear interrupt status */ - GPDMA_INT_TCCLR = tc; - GPDMA_INT_ERR_CLR = err; - - /* Check channel 0 */ - if ((tc & GPDMA_STATUS_CH_0) != 0) { - rtems_semaphore_release(lpc24xx_dma_sema_table [0]); - } - lpc24xx_dma_status_table [0] = (err & GPDMA_STATUS_CH_0) == 0; - - /* Check channel 1 */ - if ((tc & GPDMA_STATUS_CH_1) != 0) { - rtems_semaphore_release(lpc24xx_dma_sema_table [1]); - } - lpc24xx_dma_status_table [1] = (err & GPDMA_STATUS_CH_1) == 0; -} - -rtems_status_code lpc24xx_dma_copy_initialize(void) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - rtems_id id0 = RTEMS_ID_NONE; - rtems_id id1 = RTEMS_ID_NONE; - - /* Create semaphore for channel 0 */ - sc = rtems_semaphore_create( - rtems_build_name('D', 'M', 'A', '0'), - 0, - RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE, - 0, - &id0 - ); - if (sc != RTEMS_SUCCESSFUL) { - return sc; - } - - /* Create semaphore for channel 1 */ - sc = rtems_semaphore_create( - rtems_build_name('D', 'M', 'A', '1'), - 0, - RTEMS_LOCAL | RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE, - 0, - &id1 - ); - if (sc != RTEMS_SUCCESSFUL) { - rtems_semaphore_delete(id0); - - return sc; - } - - /* Install DMA interrupt handler */ - sc = rtems_interrupt_handler_install( - LPC24XX_IRQ_DMA, - "DMA copy", - RTEMS_INTERRUPT_UNIQUE, - lpc24xx_dma_copy_handler, - NULL - ); - if (sc != RTEMS_SUCCESSFUL) { - rtems_semaphore_delete(id0); - rtems_semaphore_delete(id1); - - return sc; - } - - /* Initialize global data */ - lpc24xx_dma_sema_table [0] = id0; - lpc24xx_dma_sema_table [1] = id1; - - return RTEMS_SUCCESSFUL; -} - -rtems_status_code lpc24xx_dma_copy_release(void) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - rtems_status_code rsc = RTEMS_SUCCESSFUL; - - sc = rtems_interrupt_handler_remove( - LPC24XX_IRQ_DMA, - lpc24xx_dma_copy_handler, - NULL - ); - if (sc != RTEMS_SUCCESSFUL) { - rsc = sc; - } - - sc = rtems_semaphore_delete(lpc24xx_dma_sema_table [0]); - if (sc != RTEMS_SUCCESSFUL) { - rsc = sc; - } - - sc = rtems_semaphore_delete(lpc24xx_dma_sema_table [1]); - if (sc != RTEMS_SUCCESSFUL) { - rsc = sc; - } - - return rsc; -} - -rtems_status_code lpc24xx_dma_copy( - unsigned channel, - void *dest, - const void *src, - size_t n, - size_t width -) -{ - volatile lpc24xx_dma_channel *e = GPDMA_CH_BASE_ADDR(channel); - uint32_t w = GPDMA_CH_CTRL_W_8; - - switch (width) { - case 4: - w = GPDMA_CH_CTRL_W_32; - break; - case 2: - w = GPDMA_CH_CTRL_W_16; - break; - } - - n = n >> w; - - if (n > 0U && n < 4096U) { - e->desc.src = (uint32_t) src; - e->desc.dest = (uint32_t) dest; - e->desc.lli = 0; - e->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n) - | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_1) - | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_1) - | SET_GPDMA_CH_CTRL_SW(0, w) - | SET_GPDMA_CH_CTRL_DW(0, w) - | GPDMA_CH_CTRL_ITC - | GPDMA_CH_CTRL_SI - | GPDMA_CH_CTRL_DI; - e->cfg = SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_MEM_TO_MEM_DMA) - | GPDMA_CH_CFG_IE - | GPDMA_CH_CFG_ITC - | GPDMA_CH_CFG_EN; - } else { - return RTEMS_INVALID_SIZE; - } - - return RTEMS_SUCCESSFUL; -} - -rtems_status_code lpc24xx_dma_copy_wait(unsigned channel) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - - sc = rtems_semaphore_obtain( - lpc24xx_dma_sema_table [channel], - RTEMS_WAIT, - RTEMS_NO_TIMEOUT - ); - if (sc != RTEMS_SUCCESSFUL) { - return sc; - } - - return lpc24xx_dma_status_table [channel] - ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR; -} diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/dma.c b/c/src/lib/libbsp/arm/lpc24xx/misc/dma.c deleted file mode 100644 index a67760ad3e..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/misc/dma.c +++ /dev/null @@ -1,102 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx_dma - * - * @brief Direct memory access (DMA) support. - */ - -/* - * Copyright (c) 2008-2011 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include - -#include -#include -#include - -/** - * @brief Table that indicates if a channel is currently occupied. - */ -static bool lpc24xx_dma_channel_occupation [GPDMA_CH_NUMBER]; - -void lpc24xx_dma_initialize(void) -{ - /* Enable module power */ - lpc24xx_module_enable(LPC24XX_MODULE_GPDMA, LPC24XX_MODULE_PCLK_DEFAULT); - - /* Disable module */ - GPDMA_CONFIG = 0; - - /* Reset registers */ - GPDMA_SOFT_SREQ = 0; - GPDMA_SOFT_BREQ = 0; - GPDMA_SOFT_LSREQ = 0; - GPDMA_SOFT_LBREQ = 0; - GPDMA_SYNC = 0; - GPDMA_CH0_CFG = 0; - GPDMA_CH1_CFG = 0; - - /* Enable module */ - #if BYTE_ORDER == LITTLE_ENDIAN - GPDMA_CONFIG = GPDMA_CONFIG_EN; - #else - GPDMA_CONFIG = GPDMA_CONFIG_EN | GPDMA_CONFIG_MODE; - #endif -} - -rtems_status_code lpc24xx_dma_channel_obtain(unsigned channel) -{ - if (channel < GPDMA_CH_NUMBER) { - rtems_interrupt_level level; - bool occupation = true; - - rtems_interrupt_disable(level); - occupation = lpc24xx_dma_channel_occupation [channel]; - lpc24xx_dma_channel_occupation [channel] = true; - rtems_interrupt_enable(level); - - return occupation ? RTEMS_RESOURCE_IN_USE : RTEMS_SUCCESSFUL; - } else { - return RTEMS_INVALID_ID; - } -} - -void lpc24xx_dma_channel_release(unsigned channel) -{ - if (channel < GPDMA_CH_NUMBER) { - lpc24xx_dma_channel_occupation [channel] = false; - } -} - -void lpc24xx_dma_channel_disable(unsigned channel, bool force) -{ - if (channel < GPDMA_CH_NUMBER) { - volatile lpc24xx_dma_channel *ch = GPDMA_CH_BASE_ADDR(channel); - uint32_t cfg = ch->cfg; - - if (!force) { - /* Halt */ - ch->cfg |= GPDMA_CH_CFG_HALT; - - /* Wait for inactive */ - do { - cfg = ch->cfg; - } while ((cfg & GPDMA_CH_CFG_ACTIVE) != 0); - } - - /* Disable */ - ch->cfg &= ~GPDMA_CH_CFG_EN; - } -} diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/io.c b/c/src/lib/libbsp/arm/lpc24xx/misc/io.c deleted file mode 100644 index c28b5182f0..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/misc/io.c +++ /dev/null @@ -1,570 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx_io - * - * @brief Input and output module. - */ - -/* - * Copyright (c) 2009-2012 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include -#include -#include -#include - -#define LPC24XX_PIN_SELECT(index) ((index) >> 4U) - -#define LPC24XX_PIN_SELECT_SHIFT(index) (((index) & 0xfU) << 1U) - -#define LPC24XX_PIN_SELECT_MASK 0x3U - -rtems_status_code lpc24xx_gpio_config( - unsigned index, - lpc24xx_gpio_settings settings -) -{ - if (index <= LPC24XX_IO_INDEX_MAX) { - rtems_interrupt_level level; - uint32_t port = LPC24XX_IO_PORT(index); - uint32_t port_bit = LPC24XX_IO_PORT_BIT(index); - uint32_t output = (settings & LPC24XX_GPIO_OUTPUT) != 0 ? 1U : 0U; - uint32_t resistor = settings & 0x3U; - #ifdef ARM_MULTILIB_ARCH_V4 - uint32_t select = LPC24XX_PIN_SELECT(index); - uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index); - - /* Get resistor flags */ - switch (resistor) { - case LPC24XX_GPIO_RESISTOR_PULL_UP: - resistor = 0x0U; - break; - case LPC24XX_GPIO_RESISTOR_NONE: - resistor = 0x2U; - break; - case LPC24XX_GPIO_RESISTOR_PULL_DOWN: - resistor = 0x3U; - break; - default: - return RTEMS_INVALID_NUMBER; - } - #else - uint32_t iocon_mask = IOCON_HYS | IOCON_INV - | IOCON_SLEW | IOCON_OD | IOCON_FILTER; - uint32_t iocon = (settings & iocon_mask) | IOCON_ADMODE; - uint32_t iocon_invalid = settings & ~(iocon_mask | LPC24XX_GPIO_OUTPUT); - - /* Get resistor flags */ - switch (resistor) { - case LPC24XX_GPIO_RESISTOR_NONE: - resistor = IOCON_MODE(0); - break; - case LPC24XX_GPIO_RESISTOR_PULL_DOWN: - resistor = IOCON_MODE(1); - break; - case LPC24XX_GPIO_RESISTOR_PULL_UP: - resistor = IOCON_MODE(2); - break; - case LPC17XX_GPIO_HYSTERESIS: - resistor = IOCON_MODE(3); - break; - } - iocon |= resistor; - - if (iocon_invalid != 0) { - return RTEMS_INVALID_NUMBER; - } - - if (output && (settings & LPC17XX_GPIO_INPUT_INVERT) != 0) { - return RTEMS_INVALID_NUMBER; - } - - if ((settings & LPC17XX_GPIO_INPUT_FILTER) == 0) { - iocon |= IOCON_FILTER; - } else { - iocon &= ~IOCON_FILTER; - } - #endif - - rtems_interrupt_disable(level); - - #ifdef ARM_MULTILIB_ARCH_V4 - /* Resistor */ - LPC24XX_PINMODE [select] = - (LPC24XX_PINMODE [select] & ~(LPC24XX_PIN_SELECT_MASK << shift)) - | ((resistor & LPC24XX_PIN_SELECT_MASK) << shift); - #else - LPC17XX_IOCON [index] = iocon; - #endif - - rtems_interrupt_flash(level); - - /* Input or output */ - LPC24XX_FIO [port].dir = - (LPC24XX_FIO [port].dir & ~(1U << port_bit)) | (output << port_bit); - - rtems_interrupt_enable(level); - } else { - return RTEMS_INVALID_ID; - } - - return RTEMS_SUCCESSFUL; -} - -#define LPC24XX_MODULE_ENTRY(mod, pwr, clk, idx) \ - [mod] = { \ - .power = pwr, \ - .clock = clk, \ - .index = idx \ - } - -typedef struct { - unsigned char power : 1; - unsigned char clock : 1; - unsigned char index : 6; -} lpc24xx_module_entry; - -static const lpc24xx_module_entry lpc24xx_module_table [] = { - #ifdef ARM_MULTILIB_ARCH_V4 - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ACF, 0, 1, 15), - #endif - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ADC, 1, 1, 12), - #ifdef ARM_MULTILIB_ARCH_V4 - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_BAT_RAM, 0, 1, 16), - #endif - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_0, 1, 1, 13), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_CAN_1, 1, 1, 14), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_DAC, 0, 1, 11), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_EMC, 1, 0, 11), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_ETHERNET, 1, 0, 30), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPDMA, 1, 1, 29), - #ifdef ARM_MULTILIB_ARCH_V4 - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 17), - #else - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_GPIO, 0, 1, 15), - #endif - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_0, 1, 1, 7), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_1, 1, 1, 19), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2C_2, 1, 1, 26), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_I2S, 1, 1, 27), - #ifdef ARM_MULTILIB_ARCH_V4 - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 20), - #else - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_LCD, 1, 0, 0), - #endif - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCI, 1, 1, 28), - #ifdef ARM_MULTILIB_ARCH_V7M - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_MCPWM, 1, 1, 17), - #endif - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PCB, 0, 1, 18), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_0, 1, 1, 5), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_PWM_1, 1, 1, 6), - #ifdef ARM_MULTILIB_ARCH_V7M - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_QEI, 1, 1, 18), - #endif - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_RTC, 1, 1, 9), - #ifdef ARM_MULTILIB_ARCH_V4 - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SPI, 1, 1, 8), - #endif - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_0, 1, 1, 21), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_1, 1, 1, 10), - #ifdef ARM_MULTILIB_ARCH_V7M - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SSP_2, 1, 1, 20), - #endif - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_SYSCON, 0, 1, 30), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_0, 1, 1, 1), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_1, 1, 1, 2), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_2, 1, 1, 22), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_TIMER_3, 1, 1, 23), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_0, 1, 1, 3), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_1, 1, 1, 4), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_2, 1, 1, 24), - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_3, 1, 1, 25), - #ifdef ARM_MULTILIB_ARCH_V7M - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_UART_4, 1, 1, 8), - #endif - #ifdef ARM_MULTILIB_ARCH_V4 - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_WDT, 0, 1, 0), - #endif - LPC24XX_MODULE_ENTRY(LPC24XX_MODULE_USB, 1, 0, 31) -}; - -static rtems_status_code lpc24xx_module_do_enable( - lpc24xx_module module, - lpc24xx_module_clock clock, - bool enable -) -{ - rtems_interrupt_level level; - bool has_power = false; - bool has_clock = false; - unsigned index = 0; - #ifdef ARM_MULTILIB_ARCH_V7M - volatile lpc17xx_scb *scb = &LPC17XX_SCB; - #endif - - if ((unsigned) module >= LPC24XX_MODULE_COUNT) { - return RTEMS_INVALID_ID; - } - - #ifdef ARM_MULTILIB_ARCH_V4 - if (clock == LPC24XX_MODULE_PCLK_DEFAULT) { - #if LPC24XX_PCLKDIV == 1U - clock = LPC24XX_MODULE_CCLK; - #elif LPC24XX_PCLKDIV == 2U - clock = LPC24XX_MODULE_CCLK_2; - #elif LPC24XX_PCLKDIV == 4U - clock = LPC24XX_MODULE_CCLK_4; - #elif LPC24XX_PCLKDIV == 8U - clock = LPC24XX_MODULE_CCLK_8; - #endif - } - - if ((clock & ~LPC24XX_MODULE_CLOCK_MASK) != 0U) { - return RTEMS_INVALID_CLOCK; - } - #else - if (clock != LPC24XX_MODULE_PCLK_DEFAULT) { - return RTEMS_INVALID_CLOCK; - } - #endif - - has_power = lpc24xx_module_table [module].power; - has_clock = lpc24xx_module_table [module].clock; - index = lpc24xx_module_table [module].index; - - /* Enable or disable module */ - if (enable) { - if (has_power) { - rtems_interrupt_disable(level); - #ifdef ARM_MULTILIB_ARCH_V4 - PCONP |= 1U << index; - #else - scb->pconp |= 1U << index; - #endif - rtems_interrupt_enable(level); - } - - if (module != LPC24XX_MODULE_USB) { - if (has_clock) { - #ifdef ARM_MULTILIB_ARCH_V4 - unsigned clock_shift = 2U * index; - - rtems_interrupt_disable(level); - if (clock_shift < 32U) { - PCLKSEL0 = (PCLKSEL0 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift)) - | (clock << clock_shift); - } else { - clock_shift -= 32U; - PCLKSEL1 = (PCLKSEL1 & ~(LPC24XX_MODULE_CLOCK_MASK << clock_shift)) - | (clock << clock_shift); - } - rtems_interrupt_enable(level); - #endif - } - } else { - #ifdef ARM_MULTILIB_ARCH_V4 - unsigned pllclk = lpc24xx_pllclk(); - unsigned usbsel = pllclk / 48000000U - 1U; - - if ( - usbsel > 15U - || (usbsel % 2U != 1U) - || (pllclk % 48000000U) != 0U - ) { - return RTEMS_INCORRECT_STATE; - } - - USBCLKCFG = usbsel; - #else - uint32_t pllclk = lpc24xx_pllclk(); - uint32_t usbclk = 48000000U; - - if (pllclk % usbclk == 0U) { - uint32_t usbdiv = pllclk / usbclk; - - scb->usbclksel = LPC17XX_SCB_USBCLKSEL_USBDIV(usbdiv) - | LPC17XX_SCB_USBCLKSEL_USBSEL(1); - } else { - return RTEMS_INCORRECT_STATE; - } - #endif - } - } else { - if (has_power) { - rtems_interrupt_disable(level); - #ifdef ARM_MULTILIB_ARCH_V4 - PCONP &= ~(1U << index); - #else - scb->pconp &= ~(1U << index); - #endif - rtems_interrupt_enable(level); - } - } - - return RTEMS_SUCCESSFUL; -} - -rtems_status_code lpc24xx_module_enable( - lpc24xx_module module, - lpc24xx_module_clock clock -) -{ - return lpc24xx_module_do_enable(module, clock, true); -} - -rtems_status_code lpc24xx_module_disable( - lpc24xx_module module -) -{ - return lpc24xx_module_do_enable( - module, - LPC24XX_MODULE_PCLK_DEFAULT, - false - ); -} - -bool lpc24xx_module_is_enabled(lpc24xx_module module) -{ - bool enabled = false; - - if ((unsigned) module < LPC24XX_MODULE_COUNT) { - bool has_power = lpc24xx_module_table [module].power; - - if (has_power) { - unsigned index = lpc24xx_module_table [module].index; - #ifdef ARM_MULTILIB_ARCH_V4 - uint32_t pconp = PCONP; - #else - uint32_t pconp = LPC17XX_SCB.pconp; - #endif - - enabled = (pconp & (1U << index)) != 0; - } else { - enabled = true; - } - } - - return enabled; -} - -typedef rtems_status_code (*lpc24xx_pin_visitor)( - #ifdef ARM_MULTILIB_ARCH_V4 - volatile uint32_t *pinsel, - uint32_t pinsel_mask, - uint32_t pinsel_value, - #else - volatile uint32_t *iocon, - lpc24xx_pin_range pin_range, - #endif - volatile uint32_t *fio_dir, - uint32_t fio_bit -); - -static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code -lpc24xx_pin_set_function( - #ifdef ARM_MULTILIB_ARCH_V4 - volatile uint32_t *pinsel, - uint32_t pinsel_mask, - uint32_t pinsel_value, - #else - volatile uint32_t *iocon, - lpc24xx_pin_range pin_range, - #endif - volatile uint32_t *fio_dir, - uint32_t fio_bit -) -{ - #ifdef ARM_MULTILIB_ARCH_V4 - rtems_interrupt_level level; - - rtems_interrupt_disable(level); - *pinsel = (*pinsel & ~pinsel_mask) | pinsel_value; - rtems_interrupt_enable(level); - #else - uint32_t iocon_extra = 0; - uint32_t iocon_not_analog = IOCON_ADMODE; - - /* TODO */ - switch (pin_range.fields.type) { - case LPC17XX_PIN_TYPE_ADC: - case LPC17XX_PIN_TYPE_DAC: - iocon_not_analog = 0; - break; - case LPC17XX_PIN_TYPE_I2C_FAST_PLUS: - iocon_extra |= IOCON_HS; - break; - case LPC17XX_PIN_TYPE_OPEN_DRAIN: - iocon_extra |= IOCON_OD; - break; - default: - break; - } - - *iocon = IOCON_FUNC(pin_range.fields.function) | iocon_extra | iocon_not_analog; - #endif - - return RTEMS_SUCCESSFUL; -} - -static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_function( - #ifdef ARM_MULTILIB_ARCH_V4 - volatile uint32_t *pinsel, - uint32_t pinsel_mask, - uint32_t pinsel_value, - #else - volatile uint32_t *iocon, - lpc24xx_pin_range pin_range, - #endif - volatile uint32_t *fio_dir, - uint32_t fio_bit -) -{ - #ifdef ARM_MULTILIB_ARCH_V4 - if ((*pinsel & pinsel_mask) == pinsel_value) { - return RTEMS_SUCCESSFUL; - } else { - return RTEMS_IO_ERROR; - } - #else - /* TODO */ - return RTEMS_IO_ERROR; - #endif -} - -static BSP_START_TEXT_SECTION __attribute__((flatten)) rtems_status_code -lpc24xx_pin_set_input( - #ifdef ARM_MULTILIB_ARCH_V4 - volatile uint32_t *pinsel, - uint32_t pinsel_mask, - uint32_t pinsel_value, - #else - volatile uint32_t *iocon, - lpc24xx_pin_range pin_range, - #endif - volatile uint32_t *fio_dir, - uint32_t fio_bit -) -{ - rtems_interrupt_level level; - - rtems_interrupt_disable(level); - *fio_dir &= ~fio_bit; - #ifdef ARM_MULTILIB_ARCH_V4 - *pinsel &= ~pinsel_mask; - #else - *iocon = IOCON_MODE(2) | IOCON_ADMODE | IOCON_FILTER; - #endif - rtems_interrupt_enable(level); - - return RTEMS_SUCCESSFUL; -} - -static BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_check_input( - #ifdef ARM_MULTILIB_ARCH_V4 - volatile uint32_t *pinsel, - uint32_t pinsel_mask, - uint32_t pinsel_value, - #else - volatile uint32_t *iocon, - lpc24xx_pin_range pin_range, - #endif - volatile uint32_t *fio_dir, - uint32_t fio_bit -) -{ - rtems_status_code sc = RTEMS_IO_ERROR; - bool is_input = (*fio_dir & fio_bit) == 0; - - if (is_input) { - #ifdef ARM_MULTILIB_ARCH_V4 - bool is_gpio = (*pinsel & pinsel_mask) == 0; - #else - bool is_gpio = IOCON_FUNC_GET(*iocon) == 0; - #endif - - if (is_gpio) { - sc = RTEMS_SUCCESSFUL; - } - } - - return sc; -} - -static BSP_START_DATA_SECTION const lpc24xx_pin_visitor - lpc24xx_pin_visitors [] = { - [LPC24XX_PIN_SET_FUNCTION] = lpc24xx_pin_set_function, - [LPC24XX_PIN_CHECK_FUNCTION] = lpc24xx_pin_check_function, - [LPC24XX_PIN_SET_INPUT] = lpc24xx_pin_set_input, - [LPC24XX_PIN_CHECK_INPUT] = lpc24xx_pin_check_input -}; - -BSP_START_TEXT_SECTION rtems_status_code lpc24xx_pin_config( - const lpc24xx_pin_range *pins, - lpc24xx_pin_action action -) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - - if ((unsigned) action <= LPC24XX_PIN_CHECK_INPUT) { - lpc24xx_pin_visitor visitor = lpc24xx_pin_visitors [action]; - lpc24xx_pin_range terminal = LPC24XX_PIN_TERMINAL; - lpc24xx_pin_range pin_range = *pins; - uint32_t previous_port_bit = pin_range.fields.port_bit; - - while (sc == RTEMS_SUCCESSFUL && pin_range.value != terminal.value) { - uint32_t port = pin_range.fields.port; - uint32_t port_bit = pin_range.fields.port_bit; - uint32_t port_bit_last = port_bit; - uint32_t range = pin_range.fields.range; - #ifdef ARM_MULTILIB_ARCH_V4 - uint32_t function = pin_range.fields.function; - #endif - volatile uint32_t *fio_dir = &LPC24XX_FIO [port].dir; - - if (range) { - port_bit = previous_port_bit; - } - - while (sc == RTEMS_SUCCESSFUL && port_bit <= port_bit_last) { - uint32_t index = LPC24XX_IO_INDEX_BY_PORT(port, port_bit); - uint32_t fio_bit = 1U << port_bit; - #ifdef ARM_MULTILIB_ARCH_V4 - uint32_t select = LPC24XX_PIN_SELECT(index); - uint32_t shift = LPC24XX_PIN_SELECT_SHIFT(index); - volatile uint32_t *pinsel = &LPC24XX_PINSEL [select]; - uint32_t pinsel_mask = LPC24XX_PIN_SELECT_MASK << shift; - uint32_t pinsel_value = (function & LPC24XX_PIN_SELECT_MASK) << shift; - - sc = (*visitor)(pinsel, pinsel_mask, pinsel_value, fio_dir, fio_bit); - #else - volatile uint32_t *iocon = &LPC17XX_IOCON [index]; - - sc = (*visitor)(iocon, pin_range, fio_dir, fio_bit); - #endif - - ++port_bit; - } - - ++pins; - previous_port_bit = port_bit; - pin_range = *pins; - } - } else { - sc = RTEMS_NOT_DEFINED; - } - - return sc; -} diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/lcd.c b/c/src/lib/libbsp/arm/lpc24xx/misc/lcd.c deleted file mode 100644 index 9474eec18a..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/misc/lcd.c +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx_lcd - * - * @brief LCD support. - */ - -/* - * Copyright (c) 2010-2012 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include - -#include -#include -#include -#include -#include - -#ifdef ARM_MULTILIB_ARCH_V4 - #define LCD_ENABLE BSP_BIT32(0) -#endif - -rtems_status_code lpc24xx_lcd_set_mode( - lpc24xx_lcd_mode mode, - const lpc24xx_pin_range *pins -) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - bool enable = false; - - switch (mode) { - case LCD_MODE_STN_4_BIT: - case LCD_MODE_STN_8_BIT: - case LCD_MODE_STN_DUAL_PANEL_4_BIT: - case LCD_MODE_STN_DUAL_PANEL_8_BIT: - case LCD_MODE_TFT_12_BIT_4_4_4: - case LCD_MODE_TFT_16_BIT_5_6_5: - case LCD_MODE_TFT_16_BIT_1_5_5_5: - case LCD_MODE_TFT_24_BIT: - enable = true; - break; - case LCD_MODE_DISABLED: - enable = false; - break; - default: - sc = RTEMS_IO_ERROR; - break; - } - - if (sc == RTEMS_SUCCESSFUL) { - if (enable) { - sc = lpc24xx_module_enable(LPC24XX_MODULE_LCD, LPC24XX_MODULE_PCLK_DEFAULT); - assert(sc == RTEMS_SUCCESSFUL); - - #ifdef ARM_MULTILIB_ARCH_V4 - PINSEL11 = BSP_FLD32(mode, 1, 3) | LCD_ENABLE; - #endif - - sc = lpc24xx_pin_config(pins, LPC24XX_PIN_SET_FUNCTION); - assert(sc == RTEMS_SUCCESSFUL); - } else { - if (lpc24xx_lcd_current_mode() != LCD_MODE_DISABLED) { - uint32_t lcd_ctrl = LCD_CTRL; - - /* Disable power */ - lcd_ctrl &= ~BSP_BIT32(11); - LCD_CTRL = lcd_ctrl; - - lpc24xx_micro_seconds_delay(100000); - - /* Disable all signals */ - lcd_ctrl &= ~BSP_BIT32(0); - LCD_CTRL = lcd_ctrl; - } - - sc = lpc24xx_pin_config(pins, LPC24XX_PIN_SET_INPUT); - assert(sc == RTEMS_SUCCESSFUL); - - #ifdef ARM_MULTILIB_ARCH_V4 - PINSEL11 = 0; - #endif - - sc = lpc24xx_module_disable(LPC24XX_MODULE_LCD); - assert(sc == RTEMS_SUCCESSFUL); - } - } - - return sc; -} - -lpc24xx_lcd_mode lpc24xx_lcd_current_mode(void) -{ - #ifdef ARM_MULTILIB_ARCH_V4 - uint32_t pinsel11 = PINSEL11; - - if ((PCONP & BSP_BIT32(20)) != 0 && (pinsel11 & LCD_ENABLE) != 0) { - return BSP_FLD32GET(pinsel11, 1, 3); - } else { - return LCD_MODE_DISABLED; - } - #else - volatile lpc17xx_scb *scb = &LPC17XX_SCB; - - if ((scb->pconp & LPC17XX_SCB_PCONP_LCD) != 0) { - return LCD_CTRL & 0xae; - } else { - return LCD_MODE_DISABLED; - } - #endif -} diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/restart.c b/c/src/lib/libbsp/arm/lpc24xx/misc/restart.c deleted file mode 100644 index 627f79d19d..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/misc/restart.c +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx - * - * @brief Restart implementation. - */ - -/* - * Copyright (c) 2011-2014 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Dornierstr. 4 - * 82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include - -#include - -void bsp_restart(void *addr) -{ - #ifdef ARM_MULTILIB_ARCH_V4 - ARM_SWITCH_REGISTERS; - rtems_interrupt_level level; - - rtems_interrupt_disable(level); - (void) level; - - asm volatile ( - ARM_SWITCH_TO_ARM - "mov pc, %[addr]\n" - ARM_SWITCH_BACK - : ARM_SWITCH_OUTPUT - : [addr] "r" (addr) - ); - #else - rtems_interrupt_level level; - void (*start)(void) = addr; - - rtems_interrupt_disable(level); - (void) level; - - (*start)(); - #endif -} diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/system-clocks.c b/c/src/lib/libbsp/arm/lpc24xx/misc/system-clocks.c deleted file mode 100644 index f64fca1bed..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/misc/system-clocks.c +++ /dev/null @@ -1,167 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx_clocks - * - * @brief System clocks. - */ - -/* - * Copyright (c) 2008-2014 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include - -#include -#include -#include - -/** - * @brief Internal RC oscillator frequency in [Hz]. - */ -#define LPC24XX_OSCILLATOR_INTERNAL 4000000U - -#ifndef LPC24XX_OSCILLATOR_MAIN - #error "unknown main oscillator frequency" -#endif - -#ifndef LPC24XX_OSCILLATOR_RTC - #error "unknown RTC oscillator frequency" -#endif - -void lpc24xx_timer_initialize(void) -{ - /* Reset timer */ - T1TCR = TCR_RST; - - /* Set timer mode */ - T1CTCR = 0; - - /* Set prescaler to zero */ - T1PR = 0; - - /* Reset all interrupt flags */ - T1IR = 0xff; - - /* Do not stop on a match */ - T1MCR = 0; - - /* No captures */ - T1CCR = 0; - - /* Start timer */ - T1TCR = TCR_EN; - - rtems_counter_initialize_converter(LPC24XX_PCLK); -} - -CPU_Counter_ticks _CPU_Counter_read(void) -{ - return lpc24xx_timer(); -} - -void lpc24xx_micro_seconds_delay(unsigned us) -{ - unsigned start = lpc24xx_timer(); - unsigned delay = us * (LPC24XX_PCLK / 1000000); - unsigned elapsed = 0; - - do { - elapsed = lpc24xx_timer() - start; - } while (elapsed < delay); -} - -#ifdef ARM_MULTILIB_ARCH_V7M - static unsigned lpc17xx_sysclk(unsigned clksrcsel) - { - return (clksrcsel & LPC17XX_SCB_CLKSRCSEL_CLKSRC) != 0 ? - LPC24XX_OSCILLATOR_MAIN - : LPC24XX_OSCILLATOR_INTERNAL; - } -#endif - -unsigned lpc24xx_pllclk(void) -{ - #ifdef ARM_MULTILIB_ARCH_V4 - unsigned clksrc = GET_CLKSRCSEL_CLKSRC(CLKSRCSEL); - unsigned pllinclk = 0; - unsigned pllclk = 0; - - /* Get PLL input frequency */ - switch (clksrc) { - case 0: - pllinclk = LPC24XX_OSCILLATOR_INTERNAL; - break; - case 1: - pllinclk = LPC24XX_OSCILLATOR_MAIN; - break; - case 2: - pllinclk = LPC24XX_OSCILLATOR_RTC; - break; - default: - return 0; - } - - /* Get PLL output frequency */ - if ((PLLSTAT & PLLSTAT_PLLC) != 0) { - uint32_t pllcfg = PLLCFG; - unsigned n = GET_PLLCFG_NSEL(pllcfg) + 1; - unsigned m = GET_PLLCFG_MSEL(pllcfg) + 1; - - pllclk = (pllinclk / n) * 2 * m; - } else { - pllclk = pllinclk; - } - #else - volatile lpc17xx_scb *scb = &LPC17XX_SCB; - unsigned sysclk = lpc17xx_sysclk(scb->clksrcsel); - unsigned pllstat = scb->pll_0.stat; - unsigned pllclk = 0; - unsigned enabled_and_locked = LPC17XX_PLL_STAT_PLLE - | LPC17XX_PLL_STAT_PLOCK; - - if ((pllstat & enabled_and_locked) == enabled_and_locked) { - unsigned m = LPC17XX_PLL_SEL_MSEL_GET(pllstat) + 1; - - pllclk = sysclk * m; - } - #endif - - return pllclk; -} - -unsigned lpc24xx_cclk(void) -{ - #ifdef ARM_MULTILIB_ARCH_V4 - /* Get PLL output frequency */ - unsigned pllclk = lpc24xx_pllclk(); - - /* Get CPU frequency */ - unsigned cclk = pllclk / (GET_CCLKCFG_CCLKSEL(CCLKCFG) + 1); - #else - volatile lpc17xx_scb *scb = &LPC17XX_SCB; - unsigned cclksel = scb->cclksel; - unsigned cclk_in = 0; - unsigned cclk = 0; - - if ((cclksel & LPC17XX_SCB_CCLKSEL_CCLKSEL) != 0) { - cclk_in = lpc24xx_pllclk(); - } else { - cclk_in = lpc17xx_sysclk(scb->clksrcsel); - } - - cclk = cclk_in / LPC17XX_SCB_CCLKSEL_CCLKDIV_GET(cclksel); - #endif - - return cclk; -} diff --git a/c/src/lib/libbsp/arm/lpc24xx/misc/timer.c b/c/src/lib/libbsp/arm/lpc24xx/misc/timer.c deleted file mode 100644 index c700d04566..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/misc/timer.c +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx - * - * @brief Benchmark timer support. - */ - -/* - * Copyright (c) 2008, 2009 - * embedded brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include -#include -#include - -#include - -bool benchmark_timer_find_average_overhead = false; - -static uint32_t benchmark_timer_base; - -void benchmark_timer_initialize(void) -{ - benchmark_timer_base = lpc24xx_timer(); -} - -benchmark_timer_t benchmark_timer_read(void) -{ - uint32_t delta = lpc24xx_timer() - benchmark_timer_base; - - if (benchmark_timer_find_average_overhead) { - return delta; - } else { - /* Value determined by tmck for NCS board */ - if (delta > 74) { - return delta - 74; - } else { - return 0; - } - } -} - -void benchmark_timer_disable_subtracting_average_overhead(bool find_average_overhead ) -{ - benchmark_timer_find_average_overhead = find_average_overhead; -} diff --git a/c/src/lib/libbsp/arm/lpc24xx/ssp/ssp.c b/c/src/lib/libbsp/arm/lpc24xx/ssp/ssp.c deleted file mode 100644 index 6563d047b2..0000000000 --- a/c/src/lib/libbsp/arm/lpc24xx/ssp/ssp.c +++ /dev/null @@ -1,652 +0,0 @@ -/** - * @file - * - * @ingroup lpc24xx_libi2c - * - * @brief LibI2C bus driver for the Synchronous Serial Port (SSP). - */ - -/* - * Copyright (c) 2008 - * Embedded Brains GmbH - * Obere Lagerstr. 30 - * D-82178 Puchheim - * Germany - * rtems@embedded-brains.de - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.org/license/LICENSE. - */ - -#include - -#include -#include -#include -#include -#include -#include - -#define RTEMS_STATUS_CHECKS_USE_PRINTK - -#include - -#define LPC24XX_SSP_NUMBER 2 - -#define LPC24XX_SSP_FIFO_SIZE 8 - -#define LPC24XX_SSP_BAUD_RATE 2000000 - -typedef enum { - LPC24XX_SSP_DMA_INVALID = 0, - LPC24XX_SSP_DMA_AVAILABLE = 1, - LPC24XX_SSP_DMA_NOT_INITIALIZED = 2, - LPC24XX_SSP_DMA_INITIALIZATION = 3, - LPC24XX_SSP_DMA_TRANSFER_FLAG = 0x80000000U, - LPC24XX_SSP_DMA_WAIT = 1 | LPC24XX_SSP_DMA_TRANSFER_FLAG, - LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_0 = 2 | LPC24XX_SSP_DMA_TRANSFER_FLAG, - LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_1 = 3 | LPC24XX_SSP_DMA_TRANSFER_FLAG, - LPC24XX_SSP_DMA_ERROR = 4 | LPC24XX_SSP_DMA_TRANSFER_FLAG, - LPC24XX_SSP_DMA_DONE = 5 | LPC24XX_SSP_DMA_TRANSFER_FLAG -} lpc24xx_ssp_dma_status; - -typedef struct { - rtems_libi2c_bus_t bus; - volatile lpc24xx_ssp *regs; - unsigned clock; - uint32_t idle_char; -} lpc24xx_ssp_bus_entry; - -typedef struct { - lpc24xx_ssp_dma_status status; - lpc24xx_ssp_bus_entry *bus; - rtems_libi2c_read_write_done_t done; - int n; - void *arg; -} lpc24xx_ssp_dma_entry; - -static lpc24xx_ssp_dma_entry lpc24xx_ssp_dma_data = { - .status = LPC24XX_SSP_DMA_NOT_INITIALIZED, - .bus = NULL, - .done = NULL, - .n = 0, - .arg = NULL -}; - -static uint32_t lpc24xx_ssp_trash = 0; - -static inline bool lpc24xx_ssp_is_busy(const lpc24xx_ssp_bus_entry *bus) -{ - return lpc24xx_ssp_dma_data.bus == bus - && lpc24xx_ssp_dma_data.status != LPC24XX_SSP_DMA_AVAILABLE; -} - -static void lpc24xx_ssp_handler(void *arg) -{ - lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) arg; - volatile lpc24xx_ssp *regs = e->regs; - uint32_t mis = regs->mis; - uint32_t icr = 0; - - if ((mis & SSP_MIS_RORRIS) != 0) { - /* TODO */ - icr |= SSP_ICR_RORRIS; - } - - regs->icr = icr; -} - -static void lpc24xx_ssp_dma_handler(void *arg) -{ - lpc24xx_ssp_dma_entry *e = (lpc24xx_ssp_dma_entry *) arg; - lpc24xx_ssp_dma_status status = e->status; - uint32_t tc = 0; - uint32_t err = 0; - int rv = 0; - - /* Return if we are not in a transfer status */ - if ((status & LPC24XX_SSP_DMA_TRANSFER_FLAG) == 0) { - return; - } - - /* Get interrupt status */ - tc = GPDMA_INT_TCSTAT; - err = GPDMA_INT_ERR_STAT; - - /* Clear interrupt status */ - GPDMA_INT_TCCLR = tc; - GPDMA_INT_ERR_CLR = err; - - /* Change status */ - if (err == 0) { - switch (status) { - case LPC24XX_SSP_DMA_WAIT: - if ((tc & (GPDMA_STATUS_CH_0 | GPDMA_STATUS_CH_1)) != 0) { - status = LPC24XX_SSP_DMA_DONE; - } else if ((tc & GPDMA_STATUS_CH_0) != 0) { - status = LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_1; - } else if ((tc & GPDMA_STATUS_CH_1) != 0) { - status = LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_0; - } - break; - case LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_0: - if ((tc & GPDMA_STATUS_CH_1) != 0) { - status = LPC24XX_SSP_DMA_ERROR; - } else if ((tc & GPDMA_STATUS_CH_0) != 0) { - status = LPC24XX_SSP_DMA_DONE; - } - break; - case LPC24XX_SSP_DMA_WAIT_FOR_CHANNEL_1: - if ((tc & GPDMA_STATUS_CH_0) != 0) { - status = LPC24XX_SSP_DMA_ERROR; - } else if ((tc & GPDMA_STATUS_CH_1) != 0) { - status = LPC24XX_SSP_DMA_DONE; - } - break; - default: - status = LPC24XX_SSP_DMA_ERROR; - break; - } - } else { - status = LPC24XX_SSP_DMA_ERROR; - } - - /* Error cleanup */ - if (status == LPC24XX_SSP_DMA_ERROR) { - lpc24xx_dma_channel_disable(0, true); - lpc24xx_dma_channel_disable(1, true); - status = LPC24XX_SSP_DMA_DONE; - rv = -RTEMS_IO_ERROR; - } - - /* Done */ - if (status == LPC24XX_SSP_DMA_DONE) { - status = LPC24XX_SSP_DMA_AVAILABLE; - if (e->done != NULL) { - e->done(rv, e->n, e->arg); - e->done = NULL; - } - } - - /* Set status */ - e->status = status; -} - -static rtems_status_code lpc24xx_ssp_init(rtems_libi2c_bus_t *bus) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - rtems_interrupt_level level; - lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; - volatile lpc24xx_ssp *regs = e->regs; - unsigned pclk = lpc24xx_cclk(); - unsigned pre = - ((pclk + LPC24XX_SSP_BAUD_RATE - 1) / LPC24XX_SSP_BAUD_RATE + 1) & ~1U; - lpc24xx_module module = LPC24XX_MODULE_SSP_0; - rtems_vector_number vector = UINT32_MAX; - - if (lpc24xx_ssp_dma_data.status == LPC24XX_SSP_DMA_NOT_INITIALIZED) { - lpc24xx_ssp_dma_status status = LPC24XX_SSP_DMA_INVALID; - - /* Test and set DMA support status */ - rtems_interrupt_disable(level); - status = lpc24xx_ssp_dma_data.status; - if (status == LPC24XX_SSP_DMA_NOT_INITIALIZED) { - lpc24xx_ssp_dma_data.status = LPC24XX_SSP_DMA_INITIALIZATION; - } - rtems_interrupt_enable(level); - - if (status == LPC24XX_SSP_DMA_NOT_INITIALIZED) { - /* Install DMA interrupt handler */ - sc = rtems_interrupt_handler_install( - LPC24XX_IRQ_DMA, - "SSP DMA", - RTEMS_INTERRUPT_SHARED, - lpc24xx_ssp_dma_handler, - &lpc24xx_ssp_dma_data - ); - RTEMS_CHECK_SC(sc, "install DMA interrupt handler"); - - /* Set DMA support status */ - lpc24xx_ssp_dma_data.status = LPC24XX_SSP_DMA_AVAILABLE; - } - } - - /* Disable module */ - regs->cr1 = 0; - - switch ((uintptr_t) regs) { - case SSP0_BASE_ADDR: - module = LPC24XX_MODULE_SSP_0; - vector = LPC24XX_IRQ_SPI_SSP_0; - break; - case SSP1_BASE_ADDR: - module = LPC24XX_MODULE_SSP_1; - vector = LPC24XX_IRQ_SSP_1; - break; - default: - return RTEMS_IO_ERROR; - } - - /* Set clock select */ - sc = lpc24xx_module_enable(module, LPC24XX_MODULE_PCLK_DEFAULT); - RTEMS_CHECK_SC(sc, "enable module clock"); - - /* Set serial clock rate to save value */ - regs->cr0 = SET_SSP_CR0_SCR(0, 255); - - /* Set clock prescaler */ - if (pre > 254) { - pre = 254; - } else if (pre < 2) { - pre = 2; - } - regs->cpsr = pre; - - /* Save clock value */ - e->clock = pclk / pre; - - /* Enable module and loop back mode */ - regs->cr1 = SSP_CR1_LBM | SSP_CR1_SSE; - - /* Install interrupt handler */ - sc = rtems_interrupt_handler_install( - vector, - "SSP", - RTEMS_INTERRUPT_UNIQUE, - lpc24xx_ssp_handler, - e - ); - RTEMS_CHECK_SC(sc, "install interrupt handler"); - - /* Enable receiver overrun interrupts */ - e->regs->imsc = SSP_IMSC_RORIM; - - return RTEMS_SUCCESSFUL; -} - -static rtems_status_code lpc24xx_ssp_send_start(rtems_libi2c_bus_t *bus) -{ - return RTEMS_SUCCESSFUL; -} - -static rtems_status_code lpc24xx_ssp_send_stop(rtems_libi2c_bus_t *bus) -{ - lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; - - /* Release DMA support */ - if (lpc24xx_ssp_dma_data.bus == e) { - if (lpc24xx_ssp_dma_data.status == LPC24XX_SSP_DMA_AVAILABLE) { - lpc24xx_dma_channel_release(0); - lpc24xx_dma_channel_release(1); - lpc24xx_ssp_dma_data.bus = NULL; - } else { - return RTEMS_RESOURCE_IN_USE; - } - } - - return RTEMS_SUCCESSFUL; -} - -static rtems_status_code lpc24xx_ssp_send_addr( - rtems_libi2c_bus_t *bus, - uint32_t addr, - int rw -) -{ - lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; - - if (lpc24xx_ssp_is_busy(e)) { - return RTEMS_RESOURCE_IN_USE; - } - - return RTEMS_SUCCESSFUL; -} - -static int lpc24xx_ssp_set_transfer_mode( - rtems_libi2c_bus_t *bus, - const rtems_libi2c_tfr_mode_t *mode -) -{ - lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; - volatile lpc24xx_ssp *regs = e->regs; - unsigned clk = e->clock; - unsigned br = mode->baudrate; - unsigned scr = (clk + br - 1) / br; - - if (lpc24xx_ssp_is_busy(e)) { - return -RTEMS_RESOURCE_IN_USE; - } - - if (mode->bits_per_char != 8) { - return -RTEMS_INVALID_NUMBER; - } - - if (mode->lsb_first) { - return -RTEMS_INVALID_NUMBER; - } - - if (br == 0) { - return -RTEMS_INVALID_NUMBER; - } - - /* Compute new prescaler if necessary */ - if (scr > 256 || scr < 1) { - unsigned pre = regs->cpsr; - unsigned pclk = clk * pre; - - while (scr > 256) { - if (pre > 252) { - return -RTEMS_INVALID_NUMBER; - } - pre += 2; - clk = pclk / pre; - scr = (clk + br - 1) / br; - } - - while (scr < 1) { - if (pre < 4) { - return -RTEMS_INVALID_NUMBER; - } - pre -= 2; - clk = pclk / pre; - scr = (clk + br - 1) / br; - } - - regs->cpsr = pre; - e->clock = clk; - } - - /* Adjust SCR */ - --scr; - - e->idle_char = mode->idle_char; - - while ((regs->sr & SSP_SR_TFE) == 0) { - /* Wait */ - } - - regs->cr0 = SET_SSP_CR0_DSS(0, 0x7) - | SET_SSP_CR0_SCR(0, scr) - | (mode->clock_inv ? SSP_CR0_CPOL : 0) - | (mode->clock_phs ? SSP_CR0_CPHA : 0); - - return 0; -} - -static int lpc24xx_ssp_read_write( - rtems_libi2c_bus_t *bus, - unsigned char *in, - const unsigned char *out, - int n -) -{ - lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; - volatile lpc24xx_ssp *regs = e->regs; - int r = 0; - int w = 0; - int dr = 1; - int dw = 1; - int m = 0; - uint32_t sr = regs->sr; - unsigned char trash = 0; - unsigned char idle_char = (unsigned char) e->idle_char; - - if (lpc24xx_ssp_is_busy(e)) { - return -RTEMS_RESOURCE_IN_USE; - } - - if (n < 0) { - return -RTEMS_INVALID_SIZE; - } - - /* Disable DMA on SSP */ - regs->dmacr = 0; - - if (in == NULL) { - dr = 0; - in = &trash; - } - - if (out == NULL) { - dw = 0; - out = &idle_char; - } - - /* - * Assumption: The transmit and receive FIFOs are empty. If this assumption - * is not true an input buffer overflow may occur or we may never exit the - * loop due to data loss. This is only possible if entities external to this - * driver operate on the SSP. - */ - - while (w < n) { - /* FIFO capacity */ - m = w - r; - - /* Write */ - if ((sr & SSP_SR_TNF) != 0 && m < LPC24XX_SSP_FIFO_SIZE) { - regs->dr = *out; - ++w; - out += dw; - } - - /* Read */ - if ((sr & SSP_SR_RNE) != 0) { - *in = (unsigned char) regs->dr; - ++r; - in += dr; - } - - /* New status */ - sr = regs->sr; - } - - /* Read outstanding input */ - while (r < n) { - /* Wait */ - do { - sr = regs->sr; - } while ((sr & SSP_SR_RNE) == 0); - - /* Read */ - *in = (unsigned char) regs->dr; - ++r; - in += dr; - } - - return n; -} - -static int lpc24xx_ssp_read_write_async( - rtems_libi2c_bus_t *bus, - unsigned char *in, - const unsigned char *out, - int n, - rtems_libi2c_read_write_done_t done, - void *arg -) -{ - rtems_interrupt_level level; - lpc24xx_ssp_bus_entry *e = (lpc24xx_ssp_bus_entry *) bus; - volatile lpc24xx_ssp *ssp = e->regs; - volatile lpc24xx_dma_channel *receive_channel = GPDMA_CH_BASE_ADDR(0); - volatile lpc24xx_dma_channel *transmit_channel = GPDMA_CH_BASE_ADDR(1); - uint32_t di = GPDMA_CH_CTRL_DI; - uint32_t si = GPDMA_CH_CTRL_SI; - - if (n < 0 || n > (int) GPDMA_CH_CTRL_TSZ_MAX) { - return -RTEMS_INVALID_SIZE; - } - - /* Try to reserve DMA support for this bus */ - if (lpc24xx_ssp_dma_data.bus == NULL) { - rtems_interrupt_disable(level); - if (lpc24xx_ssp_dma_data.bus == NULL) { - lpc24xx_ssp_dma_data.bus = e; - } - rtems_interrupt_enable(level); - - /* Try to obtain DMA channels */ - if (lpc24xx_ssp_dma_data.bus == e) { - rtems_status_code cs0 = lpc24xx_dma_channel_obtain(0); - rtems_status_code cs1 = lpc24xx_dma_channel_obtain(1); - - if (cs0 != RTEMS_SUCCESSFUL || cs1 != RTEMS_SUCCESSFUL) { - if (cs0 == RTEMS_SUCCESSFUL) { - lpc24xx_dma_channel_release(0); - } - if (cs1 == RTEMS_SUCCESSFUL) { - lpc24xx_dma_channel_release(1); - } - lpc24xx_ssp_dma_data.bus = NULL; - } - } - } - - /* Check if DMA support is available */ - if (lpc24xx_ssp_dma_data.bus != e - || lpc24xx_ssp_dma_data.status != LPC24XX_SSP_DMA_AVAILABLE) { - return -RTEMS_RESOURCE_IN_USE; - } - - /* Set DMA support status and parameter */ - lpc24xx_ssp_dma_data.status = LPC24XX_SSP_DMA_WAIT; - lpc24xx_ssp_dma_data.done = done; - lpc24xx_ssp_dma_data.n = n; - lpc24xx_ssp_dma_data.arg = arg; - - /* Enable DMA on SSP */ - ssp->dmacr = SSP_DMACR_RXDMAE | SSP_DMACR_TXDMAE; - - /* Receive */ - if (in != NULL) { - receive_channel->desc.dest = (uint32_t) in; - } else { - receive_channel->desc.dest = (uint32_t) &lpc24xx_ssp_trash; - di = 0; - } - receive_channel->desc.src = (uint32_t) &ssp->dr; - receive_channel->desc.lli = 0; - receive_channel->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n) - | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_4) - | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_4) - | SET_GPDMA_CH_CTRL_SW(0, GPDMA_CH_CTRL_W_8) - | SET_GPDMA_CH_CTRL_DW(0, GPDMA_CH_CTRL_W_8) - | GPDMA_CH_CTRL_ITC - | di; - receive_channel->cfg = SET_GPDMA_CH_CFG_SRCPER(0, GPDMA_CH_CFG_PER_SSP1_RX) - | SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_PER_TO_MEM_DMA) - | GPDMA_CH_CFG_IE - | GPDMA_CH_CFG_ITC - | GPDMA_CH_CFG_EN; - - /* Transmit */ - if (out != NULL) { - transmit_channel->desc.src = (uint32_t) out; - } else { - transmit_channel->desc.src = (uint32_t) &e->idle_char; - si = 0; - } - transmit_channel->desc.dest = (uint32_t) &ssp->dr; - transmit_channel->desc.lli = 0; - transmit_channel->desc.ctrl = SET_GPDMA_CH_CTRL_TSZ(0, n) - | SET_GPDMA_CH_CTRL_SBSZ(0, GPDMA_CH_CTRL_BSZ_4) - | SET_GPDMA_CH_CTRL_DBSZ(0, GPDMA_CH_CTRL_BSZ_4) - | SET_GPDMA_CH_CTRL_SW(0, GPDMA_CH_CTRL_W_8) - | SET_GPDMA_CH_CTRL_DW(0, GPDMA_CH_CTRL_W_8) - | GPDMA_CH_CTRL_ITC - | si; - transmit_channel->cfg = SET_GPDMA_CH_CFG_DESTPER(0, GPDMA_CH_CFG_PER_SSP1_TX) - | SET_GPDMA_CH_CFG_FLOW(0, GPDMA_CH_CFG_FLOW_MEM_TO_PER_DMA) - | GPDMA_CH_CFG_IE - | GPDMA_CH_CFG_ITC - | GPDMA_CH_CFG_EN; - - return 0; -} - -static int lpc24xx_ssp_read(rtems_libi2c_bus_t *bus, unsigned char *in, int n) -{ - return lpc24xx_ssp_read_write(bus, in, NULL, n); -} - -static int lpc24xx_ssp_write( - rtems_libi2c_bus_t *bus, - unsigned char *out, - int n -) -{ - return lpc24xx_ssp_read_write(bus, NULL, out, n); -} - -static int lpc24xx_ssp_ioctl(rtems_libi2c_bus_t *bus, int cmd, void *arg) -{ - int rv = -1; - const rtems_libi2c_tfr_mode_t *tm = (const rtems_libi2c_tfr_mode_t *) arg; - rtems_libi2c_read_write_t *rw = (rtems_libi2c_read_write_t *) arg; - rtems_libi2c_read_write_async_t *rwa = - (rtems_libi2c_read_write_async_t *) arg; - - switch (cmd) { - case RTEMS_LIBI2C_IOCTL_READ_WRITE: - rv = lpc24xx_ssp_read_write(bus, rw->rd_buf, rw->wr_buf, rw->byte_cnt); - break; - case RTEMS_LIBI2C_IOCTL_READ_WRITE_ASYNC: - rv = lpc24xx_ssp_read_write_async( - bus, - rwa->rd_buf, - rwa->wr_buf, - rwa->byte_cnt, - rwa->done, - rwa->arg - ); - break; - case RTEMS_LIBI2C_IOCTL_SET_TFRMODE: - rv = lpc24xx_ssp_set_transfer_mode(bus, tm); - break; - default: - rv = -RTEMS_NOT_DEFINED; - break; - } - - return rv; -} - -static const rtems_libi2c_bus_ops_t lpc24xx_ssp_ops = { - .init = lpc24xx_ssp_init, - .send_start = lpc24xx_ssp_send_start, - .send_stop = lpc24xx_ssp_send_stop, - .send_addr = lpc24xx_ssp_send_addr, - .read_bytes = lpc24xx_ssp_read, - .write_bytes = lpc24xx_ssp_write, - .ioctl = lpc24xx_ssp_ioctl -}; - -static lpc24xx_ssp_bus_entry lpc24xx_ssp_bus_table [LPC24XX_SSP_NUMBER] = { - { - /* SSP 0 */ - .bus = { - .ops = &lpc24xx_ssp_ops, - .size = sizeof(lpc24xx_ssp_bus_entry) - }, - .regs = (volatile lpc24xx_ssp *) SSP0_BASE_ADDR, - .clock = 0, - .idle_char = 0xffffffff - }, { - /* SSP 1 */ - .bus = { - .ops = &lpc24xx_ssp_ops, - .size = sizeof(lpc24xx_ssp_bus_entry) - }, - .regs = (volatile lpc24xx_ssp *) SSP1_BASE_ADDR, - .clock = 0, - .idle_char = 0xffffffff - } -}; - -rtems_libi2c_bus_t * const lpc24xx_ssp_0 = - (rtems_libi2c_bus_t *) &lpc24xx_ssp_bus_table [0]; - -rtems_libi2c_bus_t * const lpc24xx_ssp_1 = - (rtems_libi2c_bus_t *) &lpc24xx_ssp_bus_table [1]; -- cgit v1.2.3