--- bsps/arm/beagle/headers.am | 1 + bsps/arm/beagle/include/bsp.h | 4 +- bsps/arm/beagle/include/bsp/spi.h | 144 +++++++ bsps/arm/beagle/spi/spi.c | 535 ++++++++++++++++++++++++ bsps/arm/include/libcpu/am335x.h | 93 +++- c/src/lib/libbsp/arm/beagle/Makefile.am | 3 + 6 files changed, 778 insertions(+), 2 deletions(-) create mode 100644 bsps/arm/beagle/include/bsp/spi.h create mode 100644 bsps/arm/beagle/spi/spi.c
diff --git a/bsps/arm/beagle/headers.am b/bsps/arm/beagle/headers.am index 6692d0b69c..4dc35f2e2a 100644 --- a/bsps/arm/beagle/headers.am +++ b/bsps/arm/beagle/headers.am @@ -12,3 +12,4 @@ include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/bbb-pwm.h include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/beagleboneblack.h include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/i2c.h include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/irq.h +include_bsp_HEADERS += ../../../../../../bsps/arm/beagle/include/bsp/spi.h diff --git a/bsps/arm/beagle/include/bsp.h b/bsps/arm/beagle/include/bsp.h index f394c84157..7767456a8e 100644 --- a/bsps/arm/beagle/include/bsp.h +++ b/bsps/arm/beagle/include/bsp.h @@ -52,7 +52,9 @@ #define REG16(x)(*((volatile uint16_t *)(x))) #define REG(x)(*((volatile uint32_t *)(x))) -#define BIT(x)(0x1 << x) +#define BIT(x)(0x1 << (x)) +// Start and End included +#define BITS(Start, End) (((1 << (End+1)) - 1) & ~((1 << (Start)) - 1)) #define udelay(u) rtems_task_wake_after(1 + ((u)/rtems_configuration_get_microseconds_per_tick())) diff --git a/bsps/arm/beagle/include/bsp/spi.h b/bsps/arm/beagle/include/bsp/spi.h new file mode 100644 index 0000000000..ffda7edf60 --- /dev/null +++ b/bsps/arm/beagle/include/bsp/spi.h @@ -0,0 +1,144 @@ +/** + * @file + * + * @ingroup arm_beagle + * + * @brief SPI support API. + * + * Based on bsps/m68k/gen68360/spi/m360_spi.h + */ + +/* + * Copyright (c) 2018 Pierre-Louis Garnier <garni...@epita.fr> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef LIBBSP_ARM_BEAGLE_SPI_H +#define LIBBSP_ARM_BEAGLE_SPI_H + +#include <bsp.h> +#include <rtems/libi2c.h> +#include <rtems/irq.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define BBB_SPI_TIMEOUT 1000 + +#define BBB_SPI_0_BUS_PATH "/dev/spi-0" + +#define BBB_SPI_0_IRQ AM335X_INT_SPI0INT + +typedef enum { + SPI0, + SPI1, + SPI_COUNT +} bbb_spi_id_t; + + + +typedef struct BEAGLE_SPI_BufferDescriptor_ { + unsigned short status; + unsigned short length; + volatile void *buffer; +} BEAGLE_SPI_BufferDescriptor_t; + +typedef struct beagle_spi_softc { + int initialized; + rtems_id task_id; + uintptr_t regs_base; + rtems_vector_number irq; +} beagle_spi_softc_t; + +typedef struct { + rtems_libi2c_bus_t bus_desc; + beagle_spi_softc_t softc; +} beagle_spi_desc_t; + +/* + * Initialize the driver + * + * Returns: o = ok or error code + */ +rtems_status_code beagle_spi_init +( + rtems_libi2c_bus_t *bh /* bus specifier structure */ +); + +/* + * Receive some bytes from SPI device + * + * Returns: number of bytes received or (negative) error code + */ +int beagle_spi_read_bytes +( + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to store bytes */ + int len /* number of bytes to receive */ +); + +/* + * Send some bytes to SPI device + * + * Returns: number of bytes sent or (negative) error code + */ +int beagle_spi_write_bytes +( + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to send */ + int len /* number of bytes to send */ +); + +/* + * Set SPI to desired baudrate/clock mode/character mode + * + * Returns: rtems_status_code + */ +rtems_status_code beagle_spi_set_tfr_mode +( + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info */ +); + +/* + * Perform selected ioctl function for SPI + * + * Returns: rtems_status_code + */ +int beagle_spi_ioctl +( + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + int cmd, /* ioctl command code */ + void *arg /* additional argument array */ +); + +/* + * Register SPI bus and devices + * + * Returns: Bus number or error code + */ +rtems_status_code bsp_register_spi +( + const char *bus_path, + uintptr_t register_base, + rtems_vector_number irq +); + +static inline rtems_status_code bbb_register_spi_0(void) +{ + return bsp_register_spi( + BBB_SPI_0_BUS_PATH, + AM335X_SPI0_BASE, + BBB_SPI_0_IRQ + ); +} + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* LIBBSP_ARM_BEAGLE_SPI_H */ diff --git a/bsps/arm/beagle/spi/spi.c b/bsps/arm/beagle/spi/spi.c new file mode 100644 index 0000000000..38c0a503e0 --- /dev/null +++ b/bsps/arm/beagle/spi/spi.c @@ -0,0 +1,535 @@ +/** + * @file + * + * @ingroup arm_beagle + * + * @brief BeagleBoard SPI bus initialization and API Support. + * + * Based on bsps/m68k/gen68360/spi/m360_spi.c + */ + +/* + * Copyright (c) 2018 Pierre-Louis Garnier <garni...@epita.fr> + * + * 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 <bsp.h> +#include <bsp/bbb-gpio.h> +#include <bsp/spi.h> +#include <errno.h> +#include <rtems/bspIo.h> +#include <rtems/error.h> +#include <rtems/libi2c.h> +#include <stdio.h> +#include <stdlib.h> + +// #define DEBUG +// #define TRACE + +#define EVENT_TXEMPTY RTEMS_EVENT_0 +#define EVENT_RXFULL RTEMS_EVENT_1 + +static void SPI0ModuleClkConfig(void) +{ + /* Writing to MODULEMODE field of AM335X_CM_PER_SPI0_CLKCTRL register. */ + REG( AM335X_CM_PER_ADDR + AM335X_CM_PER_SPI0_CLKCTRL ) |= + AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE; + + /* Waiting for MODULEMODE field to reflect the written value. */ + while ( AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE != + ( REG( AM335X_CM_PER_ADDR + AM335X_CM_PER_SPI0_CLKCTRL ) & + AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE ) ) + continue; + + /* + * Waiting for IDLEST field in AM335X_CM_PER_SPI0_CLKCTRL + * register to attain desired value. + */ + while ( ( AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_FUNC << + AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_SHIFT ) != + ( REG( AM335X_CM_PER_ADDR + AM335X_CM_PER_SPI0_CLKCTRL ) & + AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST ) ) + continue; +} + +static inline void am335x_spi_clear_irqstatus(uint32_t reg_base, uint32_t irqs) +{ + REG(reg_base + AM335X_SPI_SYST) &= ~AM335X_SPI_SYST_SSB; + REG(reg_base + AM335X_SPI_IRQSTATUS) = irqs; +} + +static void am335x_spi0_pinmux(void) +{ + REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_SCLK) = + (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN); + + REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D0) = + (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN); + + REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_D1) = + (BBB_RXACTIVE | BBB_SLEWCTRL | BBB_PU_EN); + + REG(AM335X_PADCONF_BASE + AM335X_CONF_SPI0_CS0) = + (BBB_RXACTIVE | BBB_PU_EN); +} + +static void am335x_spi_reset(uint32_t reg_base) +{ + int timeout = BBB_SPI_TIMEOUT; + + REG(reg_base + AM335X_SPI_SYSCONFIG) |= AM335X_SPI_SYSCONFIG_SOFTRESET; + + while ((REG(reg_base + AM335X_SPI_SYSSTATUS) & AM335X_SPI_SYSSTATUS_RESETDONE) == 0 && timeout--) { + if (timeout <= 0) { + puts("ERROR: Timeout in soft-reset\n"); + + return; + } + + udelay(1000); + } +} + +static void beagle_spi_irq_handler(void *arg) +{ + const uint32_t handled_irqs = AM335X_SPI_IRQSTATUS_TX0_EMPTY | AM335X_SPI_IRQSTATUS_RX0_FULL; + + beagle_spi_softc_t *softc_ptr = arg; + + rtems_status_code sc = -1; + + uint32_t irq = 0; + uint32_t events = 0; + + uint32_t tmp; + while ((tmp = (REG(softc_ptr->regs_base + AM335X_SPI_IRQSTATUS)) & handled_irqs) != 0) { + irq |= tmp; + am335x_spi_clear_irqstatus(softc_ptr->regs_base, tmp); + } + +#if defined(TRACE) + printk("beagle_spi_irq_handler: AM335X_SPI_IRQSTATUS = 0x%04lx\r\n", irq); +#endif + + if (irq & AM335X_SPI_IRQSTATUS_TX0_EMPTY) { +#if defined(TRACE) + printk("beagle_spi_irq_handler: sending event TXEMPTY to task_id = %ld\r\n", softc_ptr->task_id); +#endif + + events |= EVENT_TXEMPTY; + } + + if (irq & AM335X_SPI_IRQSTATUS_RX0_FULL) { +#if defined(TRACE) + printk("beagle_spi_irq_handler: sending event RXFULL to task_id = %ld\r\n", softc_ptr->task_id); +#endif + + events |= EVENT_RXFULL; + } + + sc = rtems_event_send(softc_ptr->task_id, events); + _Assert(sc == RTEMS_SUCCESSFUL); + (void)sc; +} + +/* Initialize the driver + * + * Returns: o = ok or error code + */ +rtems_status_code beagle_spi_init +( + rtems_libi2c_bus_t *bh /* bus specifier structure */ +) +{ + beagle_spi_softc_t *softc_ptr = &(((beagle_spi_desc_t *)(bh))->softc); + + rtems_status_code rc = RTEMS_SUCCESSFUL; + +#if defined(DEBUG) + printk("beagle_spi_init called...\r\n"); +#endif + + SPI0ModuleClkConfig(); + am335x_spi0_pinmux(); + am335x_spi_reset(softc_ptr->regs_base); + + REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) &= ~AM335X_SPI_MODULCTRL_PIN34; + REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) &= ~AM335X_SPI_MODULCTRL_MS; // Master mode + REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) |= AM335X_SPI_MODULCTRL_SINGLE; // Single channel + REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) &= ~AM335X_SPI_MODULCTRL_PIN34; // SPIEN is usedas a chip select + // REG(softc_ptr->regs_base + AM335X_SPI_MODULCTRL) |= (1 << 3); // Test mode + + // REG(softc_ptr->regs_base + AM335X_SPI_SYST) |= AM335X_SPI_SYST_SPIEN_0; // Not sure about this + // REG(softc_ptr->regs_base + AM335X_SPI_SYST) |= AM335X_SPI_SYST_SPIDATDIR0; // Input + // REG(softc_ptr->regs_base + AM335X_SPI_SYST) &= ~AM335X_SPI_SYST_SPIDATDIR1; // Output + + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_TRM_MASK; + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_DPE0; + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_DPE1; + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_IS; + + // REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_FFEW; + // REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_FFER; + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_WL(8 - 1); + + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_PHA; + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_POL; + + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_EPOL; + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_CLKD(0x1); + + + // Setup interrupt + rc = rtems_interrupt_handler_install( + softc_ptr->irq, + NULL, + RTEMS_INTERRUPT_UNIQUE, + (rtems_interrupt_handler)beagle_spi_irq_handler, + softc_ptr + ); + +#if defined(DEBUG) + printk("beagle_spi_init done\r\n"); +#endif + + if (rc == RTEMS_SUCCESSFUL) { + softc_ptr->initialized = TRUE; + } + + return rc; +} + +static int beagle_spi_read_write_bytes( + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *rx_buf, /* buffer to store bytes */ + unsigned char *tx_buf, /* buffer to send */ + int len /* number of bytes to send */ +) +{ + beagle_spi_softc_t *softc_ptr = &(((beagle_spi_desc_t *)(bh))->softc); + + rtems_status_code sc; + rtems_event_set received_events; + +#if defined(TRACE) + printk("beagle_spi_read_write_bytes called...\r\n"); +#endif + + softc_ptr->task_id = rtems_task_self(); + + // Enable IRQs + + if (rx_buf) { + am335x_spi_clear_irqstatus(softc_ptr->regs_base, AM335X_SPI_IRQSTATUS_RX0_FULL); + REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) |= AM335X_SPI_IRQENABLE_RX0_FULL; + } + + if (tx_buf) { + am335x_spi_clear_irqstatus(softc_ptr->regs_base, AM335X_SPI_IRQSTATUS_TX0_EMPTY); + REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) |= AM335X_SPI_IRQENABLE_TX0_EMPTY; + } + + // Enable Channel + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) |= AM335X_SPI_CH0CONF_FORCE; + REG(softc_ptr->regs_base + AM335X_SPI_CH0CTRL) |= AM335X_SPI_CH0CTRL_EN; + + // Main loop + for (int i = 0; i < len; i++) { + received_events = 0; + + if (tx_buf) { + // Wait for IRQ to wake us up (room in TX FIFO) +#if defined(TRACE) + printk("beagle_spi_read_write_bytes: waiting (task_id = %ld)\r\n", softc_ptr->task_id); +#endif + + sc = rtems_event_receive(EVENT_TXEMPTY, RTEMS_WAIT, BBB_SPI_TIMEOUT, &received_events); + if (sc != RTEMS_SUCCESSFUL) { + printk("ERROR: beagle_spi_read_write_bytes timed out on tx byte number %d\n", i); + return i > 0 ? i : -RTEMS_TIMEOUT; + } + + _Assert(received_events == EVENT_TXEMPTY); + +#if defined(TRACE) + printk("beagle_spi_read_write_bytes: sending byte: i = %d, tx_buf[i] = 0x%x\r\n", i, tx_buf[i]); +#endif + + REG(softc_ptr->regs_base + AM335X_SPI_TX0) = tx_buf[i]; + } + + if (rx_buf) { + // Wait for IRQ to wake us up (data in RX FIFO) + if ((received_events & EVENT_RXFULL) == 0) { + sc = rtems_event_receive(EVENT_RXFULL, RTEMS_WAIT, BBB_SPI_TIMEOUT, &received_events); + if (sc != RTEMS_SUCCESSFUL) { + printk("ERROR: beagle_spi_read_write_bytes timed out on rx byte number %d\n", i); + return i > 0 ? i : -RTEMS_TIMEOUT; + } + + _Assert(received_events == EVENT_RXFULL); + } + + rx_buf[i] = REG(softc_ptr->regs_base + AM335X_SPI_RX0); + +#if defined(TRACE) + printk("beagle_spi_read_write_bytes: received byte: i = %d, rx_buf[i] = 0x%x\r\n", i, rx_buf[i]); +#endif + } + } + + // REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) &= ~AM335X_SPI_IRQENABLE_RX0_FULL; + // REG(softc_ptr->regs_base + AM335X_SPI_IRQENABLE) &= ~AM335X_SPI_IRQENABLE_TX0_EMPTY; + + REG(softc_ptr->regs_base + AM335X_SPI_CH0CTRL) &= ~AM335X_SPI_CH0CTRL_EN; + REG(softc_ptr->regs_base + AM335X_SPI_CH0CONF) &= ~AM335X_SPI_CH0CONF_FORCE; + +#if defined(TRACE) + printk("beagle_spi_read_write_bytes done\r\n"); +#endif + + return len; +} + +/* + * Receive some bytes from SPI device + * + * Returns: number of bytes received or (negative) error code + */ +int beagle_spi_read_bytes +( + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to store bytes */ + int len /* number of bytes to receive */ +) +{ + // FIXME +#if defined(DEBUG) + printk("beagle_spi_read_bytes called...\r\n"); +#endif + + int n = beagle_spi_read_write_bytes(bh, buf, NULL, len); + +#if defined(DEBUG) + printk("beagle_spi_read_bytes done\r\n"); +#endif + + return n; +} + +/* + * Send some bytes to SPI device + * + * Returns: number of bytes sent or (negative) error code + */ +int beagle_spi_write_bytes +( + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to send */ + int len /* number of bytes to send */ +) +{ +#if defined(DEBUG) + printk("beagle_spi_write_bytes called...\r\n"); +#endif + + int n = beagle_spi_read_write_bytes(bh, NULL, buf, len); + +#if defined(DEBUG) + printk("beagle_spi_write_bytes done\r\n"); +#endif + + return n; +} + +/* + * Perform selected ioctl function for SPI + * + * Returns: rtems_status_code + */ +int beagle_spi_ioctl +( + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + int cmd, /* ioctl command code */ + void *arg /* additional argument array */ +) +{ + int ret_val = -1; + +#if defined(DEBUG) + printk("beagle_spi_ioctl called...\r\n"); +#endif + + switch(cmd) { // FIXME: other ioctls + case RTEMS_LIBI2C_IOCTL_SET_TFRMODE: +#if defined(TRACE) + printk("cmd == RTEMS_LIBI2C_IOCTL_SET_TFRMODE\r\n"); +#endif + // FIXME + // ret_val = + // -m360_spi_set_tfr_mode(bh, + // (const rtems_libi2c_tfr_mode_t *)arg); + break; + case RTEMS_LIBI2C_IOCTL_READ_WRITE: { +#if defined(TRACE) + printk("cmd == RTEMS_LIBI2C_IOCTL_READ_WRITE\r\n"); +#endif + const rtems_libi2c_read_write_t *cmd = (const rtems_libi2c_read_write_t *)arg; + + ret_val = beagle_spi_read_write_bytes( + bh, + (unsigned char *)cmd->rd_buf, + (unsigned char *)cmd->wr_buf, + cmd->byte_cnt + ); + break; + } + default: + ret_val = -RTEMS_NOT_DEFINED; + break; + } + +#if defined(DEBUG) + printk("beagle_spi_ioctl done\r\n"); +#endif + + return ret_val; +} + +/*=========================================================================*\ +| Board-specific adaptation functions | +\*=========================================================================*/ + +/* + * Address a slave device on the bus + * + * Returns: o = ok or error code + */ +static rtems_status_code bsp_spi_sel_addr +( + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + uint32_t addr, /* address to send on bus */ + int rw /* 0=write,1=read */ +) +{ + if (addr != 0) + return RTEMS_NOT_IMPLEMENTED; + + return RTEMS_SUCCESSFUL; +} + +/* + * Dummy function, SPI has no start condition + * + * Returns: o = ok or error code + */ +static rtems_status_code bsp_spi_send_start_dummy +( + rtems_libi2c_bus_t *bh /* bus specifier structure */ +) +{ +#if defined(DEBUG) + printk("bsp_spi_send_start_dummy OK\r\n"); +#endif + + return 0; +} + +/* + * Deselect SPI + * + * Returns: o = ok or error code + */ +static rtems_status_code bsp_spi_send_stop +( + rtems_libi2c_bus_t *bh /* bus specifier structure */ +) +{ +#if defined(DEBUG) + printk("bsp_spi_send_stop called... "); +#endif + + // FIXME + +#if defined(DEBUG) + printk("... exit OK\r\n"); +#endif + return 0; +} + +/*=========================================================================*\ +| list of handlers | +\*=========================================================================*/ + +rtems_libi2c_bus_ops_t bsp_spi_ops = { + init: beagle_spi_init, + send_start: bsp_spi_send_start_dummy, + send_stop: bsp_spi_send_stop, + send_addr: bsp_spi_sel_addr, + read_bytes: beagle_spi_read_bytes, + write_bytes: beagle_spi_write_bytes, + ioctl: beagle_spi_ioctl +}; + +static beagle_spi_desc_t bsp_spi_bus_desc = { + {/* public fields */ + ops: &bsp_spi_ops, + size: sizeof(bsp_spi_bus_desc) + }, + { /* our private fields */ + initialized: FALSE, + } +}; + +/*=========================================================================*\ +| initialization | +\*=========================================================================*/ + +/* + * Register SPI bus and devices + * + * Returns: Bus number or error code + */ +rtems_status_code bsp_register_spi +( + const char *bus_path, + uintptr_t register_base, + rtems_vector_number irq +) +{ + int ret_code; + int spi_busno; + + beagle_spi_softc_t *softc_ptr = &bsp_spi_bus_desc.softc; + + if (softc_ptr->initialized) { + printk("ERROR: Only one SPI bus at a time is supported\n"); + return -RTEMS_RESOURCE_IN_USE; + } + + softc_ptr->regs_base = register_base; + softc_ptr->irq = irq; + + /* + * init I2C library (if not already done) + */ + rtems_libi2c_initialize(); + + /* + * register SPI bus + */ + ret_code = rtems_libi2c_register_bus(bus_path, + &(bsp_spi_bus_desc.bus_desc)); + if (ret_code < 0) { + return -ret_code; + } + spi_busno = ret_code; + +#if IS_AM335X + // TODO: register board devices +#endif + + return spi_busno; +} diff --git a/bsps/arm/include/libcpu/am335x.h b/bsps/arm/include/libcpu/am335x.h index 367e97cae9..a78cbd028d 100644 --- a/bsps/arm/include/libcpu/am335x.h +++ b/bsps/arm/include/libcpu/am335x.h @@ -19,6 +19,9 @@ #if !defined(_AM335X_H_) #define _AM335X_H_ +#define AM335X_MASK(Shift, Width) (((1 << (Width)) - 1) << (Shift)) + + /* Interrupt controller memory map */ #define OMAP3_DM37XX_INTR_BASE 0x48200000 /* INTCPS physical address */ @@ -649,6 +652,9 @@ #define AM335X_CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_L4LS_GCLK (0x00000100u) #define AM335X_CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_I2C_FCLK (0x01000000u) #define AM335X_CM_PER_I2C1_CLKCTRL_MODULEMODE (0x00000003u) +#define AM335X_CM_PER_SPI0_CLKCTRL (0x4c) +#define AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE_ENABLE (0x2u) +#define AM335X_CM_PER_SPI0_CLKCTRL_MODULEMODE (0x00000003u) #define AM335X_I2C_CON_XSA (0x00000100u) #define AM335X_I2C_CFG_10BIT_SLAVE_ADDR AM335X_I2C_CON_XSA #define AM335X_I2C_CON_XSA_SHIFT (0x00000008u) @@ -660,7 +666,6 @@ #define AM335X_I2C_SYSC_AUTOIDLE (0x00000001u) /*I2C0 module clock registers*/ - #define AM335X_CM_WKUP_CONTROL_CLKCTRL (0x4) #define AM335X_CM_WKUP_CLKSTCTRL (0x0) #define AM335X_CM_WKUP_I2C0_CLKCTRL (0xb8) @@ -675,6 +680,12 @@ #define AM335X_CM_WKUP_I2C0_CLKCTRL_IDLEST (0x00030000u) #define AM335X_SOC_CM_WKUP_REGS (AM335X_CM_PER_ADDR + 0x400) +/* SPI0 module clock registers */ +#define AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_FUNC (0x0u) +#define AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST_SHIFT (0x00000010u) +#define AM335X_CM_PER_CONTROL_CLKCTRL_IDLEST (0x00030000u) + + /* I2C status Register */ #define AM335X_I2C_IRQSTATUS_NACK (1 << 1) #define AM335X_I2C_IRQSTATUS_ROVR (1 << 11) @@ -701,4 +712,84 @@ #define AM335X_CM_PER_OCPWP_L3_CLKSTCTRL_CLKACTIVITY_OCPWP_L4_GCLK (0x00000020u) #define AM335X_I2C_INT_STOP_CONDITION AM335X_I2C_IRQSTATUS_BF + +/* SPI registers */ +#define AM335X_SPI0_BASE 0x48030000 + /* SPI0 base address */ +#define AM335X_SPI1_BASE 0x481A0000 + /* SPI1 base address */ + +#define AM335X_SPI_REVISION 0x000 +#define AM335X_SPI_SYSCONFIG 0x110 +#define AM335X_SPI_SYSSTATUS 0x114 +#define AM335X_SPI_IRQSTATUS 0x118 +#define AM335X_SPI_IRQENABLE 0x11c +#define AM335X_SPI_WAKEUPENABLE 0x120 +#define AM335X_SPI_SYST 0x124 +#define AM335X_SPI_MODULCTRL 0x128 +#define AM335X_SPI_CH0CONF 0x12c +#define AM335X_SPI_CH0STAT 0x130 +#define AM335X_SPI_CH0CTRL 0x134 +#define AM335X_SPI_TX0 0x138 +#define AM335X_SPI_RX0 0x13C +#define AM335X_SPI_XFERLEVEL 0x17c + +/* SPI sysconfig Register */ +#define AM335X_SPI_SYSCONFIG_SOFTRESET (1 << 1) + +/* SPI sysstatus Register */ +#define AM335X_SPI_SYSSTATUS_RESETDONE (1 << 0) + +/* SPI interrupt status Register */ +#define AM335X_SPI_IRQSTATUS_TX0_EMPTY (1 << 0) +#define AM335X_SPI_IRQSTATUS_RX0_FULL (1 << 2) + +/* SPI interrupt enable Register */ +#define AM335X_SPI_IRQENABLE_TX0_EMPTY (1 << 0) +#define AM335X_SPI_IRQENABLE_RX0_FULL (1 << 2) + +/* SPI system Register */ +#define AM335X_SPI_SYST_SPIEN_0 (1 << 0) +#define AM335X_SPI_SYST_SPIDAT_0 (1 << 4) +#define AM335X_SPI_SYST_SPIDAT_1 (1 << 5) +#define AM335X_SPI_SYST_SPIDATDIR0 (1 << 8) +#define AM335X_SPI_SYST_SPIDATDIR1 (1 << 9) +#define AM335X_SPI_SYST_SSB (1 << 11) + +/* SPI modulctrl Register */ +#define AM335X_SPI_MODULCTRL_SINGLE (1 << 0) +#define AM335X_SPI_MODULCTRL_PIN34 (1 << 1) +#define AM335X_SPI_MODULCTRL_MS (1 << 2) + +/* SPI Channel 0 Configuration Register */ +#define AM335X_SPI_CH0CONF_PHA (1 << 0) +#define AM335X_SPI_CH0CONF_POL (1 << 1) +#define AM335X_SPI_CH0CONF_CLKD_SHIFT 2 +#define AM335X_SPI_CH0CONF_CLKD_WIDTH 4 +#define AM335X_SPI_CH0CONF_CLKD_MASK AM335X_MASK(AM335X_SPI_CH0CONF_CLKD_SHIFT, AM335X_SPI_CH0CONF_CLKD_WIDTH) +#define AM335X_SPI_CH0CONF_CLKD(X) (((X) << AM335X_SPI_CH0CONF_CLKD_SHIFT) & AM335X_SPI_CH0CONF_CLKD_MASK) +#define AM335X_SPI_CH0CONF_EPOL (1 << 6) +#define AM335X_SPI_CH0CONF_WL_SHIFT 7 +#define AM335X_SPI_CH0CONF_WL_WIDTH 5 +#define AM335X_SPI_CH0CONF_WL_MASK AM335X_MASK(AM335X_SPI_CH0CONF_WL_SHIFT, AM335X_SPI_CH0CONF_WL_WIDTH) +#define AM335X_SPI_CH0CONF_WL(X) (((X) << AM335X_SPI_CH0CONF_WL_SHIFT) & AM335X_SPI_CH0CONF_WL_MASK) +#define AM335X_SPI_CH0CONF_TRM_SHIFT 12 +#define AM335X_SPI_CH0CONF_TRM_WIDTH 2 +#define AM335X_SPI_CH0CONF_TRM_MASK AM335X_MASK(AM335X_SPI_CH0CONF_TRM_SHIFT, AM335X_SPI_CH0CONF_TRM_WIDTH) +#define AM335X_SPI_CH0CONF_TRM(X) (((X) << AM335X_SPI_CH0CONF_TRM_SHIFT) & AM335X_SPI_CH0CONF_TRM_MASK) +#define AM335X_SPI_CH0CONF_DPE0 (1 << 16) +#define AM335X_SPI_CH0CONF_DPE1 (1 << 17) +#define AM335X_SPI_CH0CONF_IS (1 << 18) +#define AM335X_SPI_CH0CONF_FORCE (1 << 20) +#define AM335X_SPI_CH0CONF_SBPOL (1 << 27) +#define AM335X_SPI_CH0CONF_FFEW (1 << 27) +#define AM335X_SPI_CH0CONF_FFER (1 << 28) + +/* SPI Channel 0 Status Register */ +#define AM335X_SPI_CH0STAT_RXS (1 << 0) +#define AM335X_SPI_CH0STAT_TXS (1 << 1) + +/* SPI Channel 0 Control Register */ +#define AM335X_SPI_CH0CTRL_EN (1 << 0) + #endif diff --git a/c/src/lib/libbsp/arm/beagle/Makefile.am b/c/src/lib/libbsp/arm/beagle/Makefile.am index acab25c52f..332536c428 100644 --- a/c/src/lib/libbsp/arm/beagle/Makefile.am +++ b/c/src/lib/libbsp/arm/beagle/Makefile.am @@ -70,6 +70,9 @@ librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/console/console-confi # I2C librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/i2c/bbb-i2c.c +# SPI +librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/spi/spi.c + # GPIO librtemsbsp_a_SOURCES += ../../../../../../bsps/arm/beagle/gpio/bbb-gpio.c -- 2.17.2 (Apple Git-113) _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel