diff options
author | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2008-07-11 10:00:41 +0000 |
---|---|---|
committer | Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> | 2008-07-11 10:00:41 +0000 |
commit | 69effbb4e16db7e6c85cd9b2bb8ad648c700b0a6 (patch) | |
tree | 342616a26286d7378fdde5acdafe923003d0aa76 /c/src/lib/libbsp/m68k/gen68360 | |
parent | added mcf548x BSP support (diff) | |
download | rtems-69effbb4e16db7e6c85cd9b2bb8ad648c700b0a6.tar.bz2 |
added variant to gen68360 BSP
added genmcf548x BSP
Diffstat (limited to 'c/src/lib/libbsp/m68k/gen68360')
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68360/ChangeLog | 10 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68360/Makefile.am | 1 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68360/README | 11 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68360/include/bsp.h | 23 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68360/spi/m360_spi.c | 852 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68360/spi/m360_spi.h | 146 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68360/spi/mc68360_spidrv.c | 627 | ||||
-rw-r--r-- | c/src/lib/libbsp/m68k/gen68360/startup/init68360.c | 175 |
8 files changed, 1844 insertions, 1 deletions
diff --git a/c/src/lib/libbsp/m68k/gen68360/ChangeLog b/c/src/lib/libbsp/m68k/gen68360/ChangeLog index 6bcdbed1ee..0853aa3311 100644 --- a/c/src/lib/libbsp/m68k/gen68360/ChangeLog +++ b/c/src/lib/libbsp/m68k/gen68360/ChangeLog @@ -1,3 +1,13 @@ +2008-07-09 Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> + + * Makefile.am, spi/m360_spidrv.c, spi/m360_spidrv.h: + added SPI driver + +2008-07-09 Thomas Doerfler <Thomas.Doerfler@embedded-brains.de> + + * README: + added pgh360 BSP variant + 2008-05-23 Joel Sherrill <joel.sherrill@OARcorp.com> * console/console.c: Eliminate copies of switches to convert termios diff --git a/c/src/lib/libbsp/m68k/gen68360/Makefile.am b/c/src/lib/libbsp/m68k/gen68360/Makefile.am index 93f1ee2061..e2c17fb2f3 100644 --- a/c/src/lib/libbsp/m68k/gen68360/Makefile.am +++ b/c/src/lib/libbsp/m68k/gen68360/Makefile.am @@ -11,7 +11,6 @@ dist_project_lib_DATA = bsp_specs include_HEADERS = include/bsp.h include_HEADERS += include/tm27.h - nodist_include_HEADERS = include/bspopts.h DISTCLEANFILES = include/bspopts.h noinst_PROGRAMS = diff --git a/c/src/lib/libbsp/m68k/gen68360/README b/c/src/lib/libbsp/m68k/gen68360/README index 471e55581f..c48fb20b84 100644 --- a/c/src/lib/libbsp/m68k/gen68360/README +++ b/c/src/lib/libbsp/m68k/gen68360/README @@ -29,6 +29,8 @@ # can be used with the Arnewsh SBC360 card. # - If the preprocessor symbol M68360_ATLAS_HSB is defined, # the BSP is compiled for an Atlas HSB card. +# - If the preprocessor symbol M68360_IMD_PGH is defined, +# the BSP is compiled for an IMD PGH360 card. # - Otherwise, the BSP is compiled for a generic 68360 system # as described in Chapter 9 of the MC68360 User's Manual. This # version works with the Atlas ACE360 card. @@ -39,6 +41,7 @@ BOARD: Generic 68360 as described in Motorola MC68360 User's Manual BOARD: Atlas Computer Equipment Inc. High Speed Bridge (HSB) BOARD: Atlas Computer Equipment Inc. Advanced Communication Engine (ACE) BOARD: Arnewsh SBC360 68040/68360 card +BOARD: IMD PGH Board (custom) BUS: none CPU FAMILY: Motorola CPU32+, Motorola 68040 COPROCESSORS: none @@ -83,6 +86,13 @@ bus width: 8-bit PROM/FLASH, 32-bit DRAM ROM: To 1 MByte, 180 nsec (3 wait states), chip select 0 RAM: 4 or 16 MBytes of 60 nsec parity DRAM (1Mx36) to RAS1*/CAS1* +Board description (IMD PGH) +--------------------------- +clock rate: 25 MHz +bus width: 8-bit PROM/FLASH, 32-bit DRAM +ROM: 512KByte, 180 nsec (3 wait states), chip select 0 +RAM: 16 MBytes of 60 nsec no-parity DRAM (1Mx32) to RAS1*/CAS1* + Host System ----------- OPENSTEP 4.2 (Intel and Motorola), Solaris 2.5, Linux 2.0.29 @@ -292,3 +302,4 @@ The board support package has been tested with: Arnewsh Inc. P.O. Box 270352 Fort Collins, CO 80527-0352 + A custom 68360 board (PGH360) produced by IMD diff --git a/c/src/lib/libbsp/m68k/gen68360/include/bsp.h b/c/src/lib/libbsp/m68k/gen68360/include/bsp.h index 7f84e5b26a..5f30586daa 100644 --- a/c/src/lib/libbsp/m68k/gen68360/include/bsp.h +++ b/c/src/lib/libbsp/m68k/gen68360/include/bsp.h @@ -90,6 +90,8 @@ void *M360AllocateBufferDescriptors( int count ); void *M360AllocateRiscTimers( int count ); extern char M360DefaultWatchdogFeeder; +extern int m360_clock_rate; /* BRG clock rate, defined in console.c */ + m68k_isr_entry set_vector( rtems_isr_entry handler, rtems_vector_number vector, @@ -102,6 +104,7 @@ m68k_isr_entry set_vector( extern char _RamBase[]; extern char _HeapSize[]; + /* * Definitions for Atlas Computer Equipment Inc. High Speed Bridge (HSB) */ @@ -111,6 +114,26 @@ extern char _HeapSize[]; #define ATLASHSB_LED4 0x20010004L #define ATLASHSB_ROM_U6 0xFF080000L /* U6 flash ROM socket */ + + /* + * definitions for PGH360 board + */ +#if defined(PGH360) +/* + * logical SPI addresses of SPI slaves available + */ +#define PGH360_SPI_ADDR_EEPROM 0 +#define PGH360_SPI_ADDR_DISP4_DATA 1 +#define PGH360_SPI_ADDR_DISP4_CTRL 2 + +/* + * Port B bit locations of SPI slave selects + */ +#define PGH360_PB_SPI_DISP4_RS_MSK (1<<15) +#define PGH360_PB_SPI_DISP4_CE_MSK (1<<14) +#define PGH360_PB_SPI_EEP_CE_MSK (1<< 0) +#endif /* defined(PGH360) */ + #ifdef __cplusplus } #endif diff --git a/c/src/lib/libbsp/m68k/gen68360/spi/m360_spi.c b/c/src/lib/libbsp/m68k/gen68360/spi/m360_spi.c new file mode 100644 index 0000000000..38f80a5789 --- /dev/null +++ b/c/src/lib/libbsp/m68k/gen68360/spi/m360_spi.c @@ -0,0 +1,852 @@ +/*===============================================================*\ +| Project: RTEMS support for PGH360 | ++-----------------------------------------------------------------+ +| 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.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the M360 SPI driver | +\*===============================================================*/ +#include <stdlib.h> +#include <bsp.h> +#include <rtems/m68k/m68360.h> +#include <rtems/m68k/m360_spi.h> +#include <rtems/error.h> +#include <rtems/bspIo.h> +#include <errno.h> +#include <rtems/libi2c.h> + +#undef DEBUG +static m360_spi_softc_t *m360_spi_softc_ptr; +/* + * this is a dummy receive buffer for sequences, + * where only send data are available + */ +uint8_t m360_spi_dummy_rxbuf[2]; +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static rtems_status_code m360_spi_baud_to_mode +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| determine proper divider value | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + uint32_t baudrate, /* desired baudrate */ + uint32_t *spimode /* result value */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ + uint32_t divider; + uint16_t tmpmode = 0; + /* + * determine clock divider and DIV16 bit + */ + divider = m360_clock_rate/baudrate; + if (divider > 64) { + tmpmode = M360_SPMODE_DIV16; + divider /= 16; + } + if ((divider < 1) || + (divider > 64)) { + return RTEMS_INVALID_NUMBER; + } + else { + tmpmode |= M360_SPMODE_PM(divider/4-1); + } + *spimode = tmpmode; + return RTEMS_SUCCESSFUL; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static rtems_status_code m360_spi_char_mode +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| determine proper value for character size | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + m360_spi_softc_t *softc_ptr, /* handle */ + uint32_t bits_per_char, /* bits per character */ + boolean lsb_first, /* TRUE: send LSB first */ + uint16_t *spimode /* result value */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ + uint16_t tmpmode; + + /* + * calculate data format + */ + if ((bits_per_char >= 4) && + (bits_per_char <= 16)) { + tmpmode = M360_SPMODE_CLEN( bits_per_char-1); + } + else { + return RTEMS_INVALID_NUMBER; + } + + *spimode = tmpmode; + return 0; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static int m360_spi_wait +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| wait for spi to become idle | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + m360_spi_softc_t *softc_ptr /* handle */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ + uint16_t act_status; + rtems_status_code rc; + uint32_t tout; + +#if defined(DEBUG) + printk("m360_spi_wait called... "); +#endif + if (softc_ptr->initialized) { + /* + * allow interrupts, when receiver is not empty + */ + m360.spim = (M360_SPIE_TXE | M360_SPIE_TXB | + M360_SPIE_BSY | M360_SPIE_MME); + + rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id, + RTEMS_WAIT, + RTEMS_NO_TIMEOUT); + if (rc != RTEMS_SUCCESSFUL) { + return rc; + } + } + else { + tout = 0; + do { + if (tout++ > 1000000) { +#if defined(DEBUG) + printk("... exit with RTEMS_TIMEOUT\r\n"); +#endif + return RTEMS_TIMEOUT; + } + /* + * wait for SPI to terminate + */ + } while (!(m360.spie & M360_SPIE_TXB)); + } + + act_status = m360.spie; + if ((act_status & (M360_SPIE_TXE | M360_SPIE_TXB | + M360_SPIE_BSY | M360_SPIE_MME))!= M360_SPIE_TXB) { +#if defined(DEBUG) + printk("... exit with RTEMS_IO_ERROR," + "act_status=0x%04x,mask=0x%04x,desired_status=0x%04x\r\n", + act_status,status_mask,desired_status); +#endif + return RTEMS_IO_ERROR; + } +#if defined(DEBUG) + printk("... exit OK\r\n"); +#endif + return RTEMS_SUCCESSFUL; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static rtems_isr m360_spi_irq_handler +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| handle interrupts | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_vector_number v /* vector number */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| <none> | +\*=========================================================================*/ +{ + m360_spi_softc_t *softc_ptr = m360_spi_softc_ptr; + + /* + * disable interrupt mask + */ + m360.spim = 0; + if (softc_ptr->initialized) { + rtems_semaphore_release(softc_ptr->irq_sema_id); + } +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static void m360_spi_install_irq_handler +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| (un-)install the interrupt handler | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + m360_spi_softc_t *softc_ptr, /* ptr to control structure */ + int install /* TRUE: install, FALSE: remove */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| <none> | +\*=========================================================================*/ +{ + rtems_status_code rc = RTEMS_SUCCESSFUL; + + /* + * (un-)install handler for SPI device + */ + if (install) { + /* + * create semaphore for IRQ synchronization + */ + rc = rtems_semaphore_create(rtems_build_name('s','p','i','s'), + 0, + RTEMS_FIFO + | RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &softc_ptr->irq_sema_id); + if (rc != RTEMS_SUCCESSFUL) { + rtems_panic("SPI: cannot create semaphore"); + } + if (rc == RTEMS_SUCCESSFUL) { + rc = rtems_interrupt_catch (m360_spi_irq_handler, + (m360.cicr & 0xE0) | 0x05, + &softc_ptr->old_handler); + if (rc != RTEMS_SUCCESSFUL) { + rtems_panic("SPI: cannot install IRQ handler"); + } + } + /* + * enable IRQ in CPIC + */ + if (rc == RTEMS_SUCCESSFUL) { + m360.cimr |= (1 << 5); + } + } + else { + rtems_isr_entry old_handler; + /* + * disable IRQ in CPIC + */ + if (rc == RTEMS_SUCCESSFUL) { + m360.cimr &= ~(1 << 5); + } + rc = rtems_interrupt_catch (softc_ptr->old_handler, + (m360.cicr & 0xE0) | 0x05, + &old_handler); + if (rc != RTEMS_SUCCESSFUL) { + rtems_panic("SPI: cannot uninstall IRQ handler"); + } + /* + * delete sync semaphore + */ + if (softc_ptr->irq_sema_id != 0) { + rc = rtems_semaphore_delete(softc_ptr->irq_sema_id); + if (rc != RTEMS_SUCCESSFUL) { + rtems_panic("SPI: cannot delete semaphore"); + } + } + } +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +rtems_status_code m360_spi_init +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| initialize the driver | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh /* bus specifier structure */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ + m360_spi_softc_t *softc_ptr = &(((m360_spi_desc_t *)(bh))->softc); + rtems_status_code rc = RTEMS_SUCCESSFUL; + +#if defined(DEBUG) + printk("m360_spi_init called... "); +#endif + /* + * init HW registers: + */ + /* + * FIXME: set default mode in SPMODE + */ + + /* + * allocate BDs (1x RX, 1x TX) + */ + if (rc == RTEMS_SUCCESSFUL) { + softc_ptr->rx_bd = M360AllocateBufferDescriptors (1); + softc_ptr->tx_bd = M360AllocateBufferDescriptors (1); + if ((softc_ptr->rx_bd == NULL) || + (softc_ptr->tx_bd == NULL)) { + rc = RTEMS_NO_MEMORY; + } + } + /* + * set parameter RAM + */ + m360.spip.rbase = (char *)softc_ptr->rx_bd - (char *)&m360; + m360.spip.tbase = (char *)softc_ptr->tx_bd - (char *)&m360; + m360.spip.rfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE; + m360.spip.tfcr = M360_RFCR_MOT | M360_RFCR_DMA_SPACE; + m360.spip.mrblr = 2; + + /* + * issue "InitRxTx" Command to CP + */ + M360ExecuteRISC (M360_CR_OP_INIT_RX_TX | M360_CR_CHAN_SPI); + + /* + * init interrupt stuff + */ + if (rc == RTEMS_SUCCESSFUL) { + m360_spi_install_irq_handler(softc_ptr,TRUE); + } + if (rc == RTEMS_SUCCESSFUL) { + /* + * set up ports + * LINE PAR DIR DAT + * ----------------------- + * MOSI 1 1 x + * MISO 1 1 x + * CLK 1 1 x + */ + + /* set Port B Pin Assignment Register... */ + m360.pbpar = + m360.pbpar + | M360_PB_SPI_MISO_MSK + | M360_PB_SPI_MOSI_MSK + | M360_PB_SPI_CLK_MSK; + + /* set Port B Data Direction Register... */ + m360.pbdir = + m360.pbdir + | M360_PB_SPI_MISO_MSK + | M360_PB_SPI_MOSI_MSK + | M360_PB_SPI_CLK_MSK; + } + /* + * mark, that we have initialized + */ + if (rc == RTEMS_SUCCESSFUL) { + softc_ptr->initialized = TRUE; + } +#if defined(DEBUG) + printk("... exit OK\r\n"); +#endif + return rc; +} + + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static int m360_spi_read_write_bytes +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| transmit/receive some bytes from SPI device | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *rbuf, /* buffer to store bytes */ + const unsigned char *tbuf, /* buffer to send bytes */ + int len /* number of bytes to transceive */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| number of bytes received or (negative) error code | +\*=========================================================================*/ +{ + m360_spi_softc_t *softc_ptr = &(((m360_spi_desc_t *)(bh))->softc); + rtems_status_code rc = RTEMS_SUCCESSFUL; + int bc = 0; + +#if defined(DEBUG) + printk("m360_spi_read_write_bytes called... "); +#endif + + /* + * prepare RxBD + */ + if (rc == RTEMS_SUCCESSFUL) { + if (rbuf == NULL) { + /* + * no Tx buffer: receive to dummy buffer + */ + m360.spip.mrblr = sizeof(m360_spi_dummy_rxbuf); + softc_ptr->rx_bd->buffer = m360_spi_dummy_rxbuf; + softc_ptr->rx_bd->length = 0; + softc_ptr->rx_bd->status = (M360_BD_EMPTY | M360_BD_WRAP | + M360_BD_CONTINUOUS); + } + else { + m360.spip.mrblr = len; + softc_ptr->rx_bd->buffer = rbuf; + softc_ptr->rx_bd->length = 0; + softc_ptr->rx_bd->status = (M360_BD_EMPTY | M360_BD_WRAP); + } + } + /* + * prepare TxBD + */ + if (rc == RTEMS_SUCCESSFUL) { + if (tbuf == NULL) { + /* + * FIXME: no Tx buffer: transmit from dummy buffer + */ + softc_ptr->tx_bd->buffer = m360_spi_dummy_rxbuf; + softc_ptr->tx_bd->length = len; + softc_ptr->tx_bd->status = (M360_BD_READY | M360_BD_WRAP | + M360_BD_CONTINUOUS); + } + else { + softc_ptr->tx_bd->buffer = tbuf; + softc_ptr->tx_bd->length = len; + softc_ptr->tx_bd->status = (M360_BD_READY | M360_BD_WRAP); + } + } + + if (rc == RTEMS_SUCCESSFUL) { + /* + * set START command + */ + m360.spcom = M360_SPCOM_STR; + /* + * wait for SPI to finish + */ + rc = m360_spi_wait(softc_ptr); + } +#if defined(DEBUG) + printk("... exit OK, rc=%d\r\n",bc); +#endif + return (rc == RTEMS_SUCCESSFUL) ? bc : -rc; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_read_bytes +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| receive some bytes from SPI device | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to store bytes */ + int len /* number of bytes to receive */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| number of bytes received or (negative) error code | +\*=========================================================================*/ +{ + return m360_spi_read_write_bytes(bh,buf,NULL,len); +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_write_bytes +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| send some bytes to SPI device | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to send */ + int len /* number of bytes to send */ + +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| number of bytes sent or (negative) error code | +\*=========================================================================*/ +{ + return m360_spi_read_write_bytes(bh,NULL,buf,len); +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +rtems_status_code m360_spi_set_tfr_mode +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| set SPI to desired baudrate/clock mode/character mode | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| rtems_status_code | +\*=========================================================================*/ +{ + m360_spi_softc_t *softc_ptr = &(((m360_spi_desc_t *)(bh))->softc); + uint32_t spimode_baud,spimode; + rtems_status_code rc = RTEMS_SUCCESSFUL; + /* + * FIXME: set proper mode + */ + if (rc == RTEMS_SUCCESSFUL) { + rc = m360_spi_baud_to_mode(tfr_mode->baudrate,&spimode_baud); + } + if (rc == RTEMS_SUCCESSFUL) { + rc = m360_spi_char_mode(softc_ptr, + tfr_mode->bits_per_char, + tfr_mode->lsb_first, + &spimode); + } + if (rc == RTEMS_SUCCESSFUL) { + spimode |= spimode_baud; + spimode |= M360_SPMODE_MASTER; /* set master mode */ + if (!tfr_mode->lsb_first) { + spimode |= M360_SPMODE_REV; + } + if (tfr_mode->clock_inv) { + spimode |= M360_SPMODE_CI; + } + if (tfr_mode->clock_phs) { + spimode |= M360_SPMODE_CP; + } + } + + if (rc == RTEMS_SUCCESSFUL) { + /* + * disable SPI + */ + m360.spmode &= ~M360_SPMODE_EN; + /* + * set new mode and reenable SPI + */ + m360.spmode = spimode | M360_SPMODE_EN; + } + return rc; +} + + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_ioctl +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| perform selected ioctl function for SPI | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + int cmd, /* ioctl command code */ + void *arg /* additional argument array */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| rtems_status_code | +\*=========================================================================*/ +{ + int ret_val = -1; + + switch(cmd) { + case RTEMS_LIBI2C_IOCTL_SET_TFRMODE: + ret_val = + -m360_spi_set_tfr_mode(bh, + (const rtems_libi2c_tfr_mode_t *)arg); + break; + case RTEMS_LIBI2C_IOCTL_READ_WRITE: + ret_val = + m360_spi_read_write_bytes(bh, + ((rtems_libi2c_read_write_t *)arg)->rd_buf, + ((rtems_libi2c_read_write_t *)arg)->wr_buf, + ((rtems_libi2c_read_write_t *)arg)->byte_cnt); + break; + default: + ret_val = -RTEMS_NOT_DEFINED; + break; + } + return ret_val; +} + +/*=========================================================================*\ +| Board-specific adaptation functions | +\*=========================================================================*/ + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static rtems_status_code bsp_spi_sel_addr +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| address a slave device on the bus | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + uint32_t addr, /* address to send on bus */ + int rw /* 0=write,1=read */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ +#if defined(PGH360) + /* + * select given device + */ + /* + * GPIO1[24] is SPI_A0 + * GPIO1[25] is SPI_A1 + * GPIO1[26] is SPI_A2 + * set pins to address + */ + switch(addr) { + case PGH360_SPI_ADDR_EEPROM: + m360.pbdat &= ~PGH360_PB_SPI_EEP_CE_MSK; + break; + case PGH360_SPI_ADDR_DISP4_DATA: + m360.pbdat = (m360.pbdat + & ~(PGH360_PB_SPI_DISP4_CE_MSK | + PGH360_PB_SPI_DISP4_RS_MSK)); + break; + case PGH360_SPI_ADDR_DISP4_CTRL: + m360.pbdat = (m360.pbdat + & ~(PGH360_PB_SPI_DISP4_CE_MSK) + | PGH360_PB_SPI_DISP4_RS_MSK); + break; + default: + return RTEMS_INVALID_NUMBER; + } +#endif /* PGH360 */ + return RTEMS_SUCCESSFUL; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static rtems_status_code bsp_spi_send_start_dummy +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| dummy function, SPI has no start condition | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh /* bus specifier structure */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ + return 0; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static rtems_status_code bsp_spi_send_stop +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| deselect SPI | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh /* bus specifier structure */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ +#if defined(DEBUG) + printk("bsp_spi_send_stop called... "); +#endif +#if defined(PGH360) + m360.pbdat = (m360.pbdat + | PGH360_PB_SPI_DISP4_CE_MSK + | PGH360_PB_SPI_EEP_CE_MSK); +#endif +#if defined(DEBUG) + printk("... exit OK\r\n"); +#endif + return 0; +} + +/*=========================================================================*\ +| list of handlers | +\*=========================================================================*/ + +rtems_libi2c_bus_ops_t bsp_spi_ops = { + init: m360_spi_init, + send_start: bsp_spi_send_start_dummy, + send_stop: bsp_spi_send_stop, + send_addr: bsp_spi_sel_addr, + read_bytes: m360_spi_read_bytes, + write_bytes: m360_spi_write_bytes, + ioctl: m360_spi_ioctl +}; + +static m360_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 | +\*=========================================================================*/ + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +rtems_status_code bsp_register_spi +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| register SPI bus and devices | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + void /* <none> */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| 0 or error code | +\*=========================================================================*/ +{ + int ret_code; + int spi_busno; + + /* + * init I2C library (if not already done) + */ + rtems_libi2c_initialize (); + + /* + * init port pins used to address/select SPI devices + */ + +#if defined(PGH360) + + /* + * set up ports + * LINE PAR DIR DAT + * ----------------------- + * EEP_CE 0 1 act-high + * DISP4_CS 0 1 act-high + * DISP4_RS 0 1 active + */ + + /* set Port B Pin Assignment Register... */ + m360.pbpar = + (m360.pbpar + & ~(PGH360_PB_SPI_EEP_CE_MSK + | PGH360_PB_SPI_DISP4_CE_MSK + | PGH360_PB_SPI_DISP4_RS_MSK)); + + /* set Port B Data Direction Register... */ + m360.pbdir = + m360.pbdir + | PGH360_PB_SPI_EEP_CE_MSK + | PGH360_PB_SPI_DISP4_CE_MSK + | PGH360_PB_SPI_DISP4_RS_MSK; + + /* set Port B Data Register to inactive CE state */ + m360.pbdat = + m360.pbdat + | PGH360_PB_SPI_DISP4_CE_MSK + | PGH360_PB_SPI_DISP4_RS_MSK; +#endif + + /* + * register SPI bus + */ + ret_code = rtems_libi2c_register_bus("/dev/spi", + &(bsp_spi_bus_desc.bus_desc)); + if (ret_code < 0) { + return -ret_code; + } + spi_busno = ret_code; +#if defined(PGH360) + /* + * register devices + */ +#if 0 + ret_code = rtems_libi2c_register_drv(RTEMS_BSP_SPI_FLASH_DEVICE_NAME, + spi_flash_m25p40_rw_driver_descriptor, + spi_busno,0x00); + if (ret_code < 0) { + return -ret_code; + } +#endif +#endif /* defined(PGH360) */ + /* + * FIXME: further drivers, when available + */ + return 0; +} + + diff --git a/c/src/lib/libbsp/m68k/gen68360/spi/m360_spi.h b/c/src/lib/libbsp/m68k/gen68360/spi/m360_spi.h new file mode 100644 index 0000000000..6974002364 --- /dev/null +++ b/c/src/lib/libbsp/m68k/gen68360/spi/m360_spi.h @@ -0,0 +1,146 @@ +/*===============================================================*\ +| Project: RTEMS support for MC68360 | ++-----------------------------------------------------------------+ +| 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.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the MC68360 SPI driver declarations | +\*===============================================================*/ +#ifndef _M360_SPIDRV_H +#define _M360_SPIDRV_H + +#include <rtems/m68k/m68360.h> +#include <rtems/libi2c.h> +#include <rtems/irq.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct m360_spi_softc { + int initialized; + rtems_id irq_sema_id; + rtems_isr_entry old_handler; + m360BufferDescriptor_t *rx_bd; + m360BufferDescriptor_t *tx_bd; +} m360_spi_softc_t ; + +typedef struct { + rtems_libi2c_bus_t bus_desc; + m360_spi_softc_t softc; +} m360_spi_desc_t; + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +rtems_status_code m360_spi_init +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| initialize the driver | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh /* bus specifier structure */ + ); +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_read_bytes +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| receive some bytes from SPI device | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to store bytes */ + int len /* number of bytes to receive */ + ); +/*-------------------------------------------------------------------------*\ +| Return Value: | +| number of bytes received or (negative) error code | +\*=========================================================================*/ + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_write_bytes +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| send some bytes to SPI device | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to send */ + int len /* number of bytes to send */ + + ); +/*-------------------------------------------------------------------------*\ +| Return Value: | +| number of bytes sent or (negative) error code | +\*=========================================================================*/ + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +rtems_status_code m360_spi_set_tfr_mode +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| set SPI to desired baudrate/clock mode/character mode | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info */ + ); +/*-------------------------------------------------------------------------*\ +| Return Value: | +| rtems_status_code | +\*=========================================================================*/ + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_ioctl +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| perform selected ioctl function for SPI | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + int cmd, /* ioctl command code */ + void *arg /* additional argument array */ + ); +/*-------------------------------------------------------------------------*\ +| Return Value: | +| rtems_status_code | +\*=========================================================================*/ + +#ifdef __cplusplus +} +#endif + + +#endif /* _M360_SPIDRV_H */ diff --git a/c/src/lib/libbsp/m68k/gen68360/spi/mc68360_spidrv.c b/c/src/lib/libbsp/m68k/gen68360/spi/mc68360_spidrv.c new file mode 100644 index 0000000000..9a6b01ce27 --- /dev/null +++ b/c/src/lib/libbsp/m68k/gen68360/spi/mc68360_spidrv.c @@ -0,0 +1,627 @@ +/*===============================================================*\ +| Project: RTEMS support for PGH360 | ++-----------------------------------------------------------------+ +| 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.com/license/LICENSE. | +| | ++-----------------------------------------------------------------+ +| this file contains the M360 SPI driver | +\*===============================================================*/ +#include <stdlib.h> +#include <bsp.h> +#include <bsp/irq.h> +#include <rtems/m68k/m68360.h> +#include <m360/m360_spidrv.h> +#include <rtems/error.h> +#include <rtems/bspIo.h> +#include <errno.h> +#include <rtems/libi2c.h> + +#undef DEBUG + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static rtems_status_code m360_spi_baud_to_mode +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| determine proper divider value | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + uint32_t baudrate, /* desired baudrate */ + uint32_t *spimode /* result value */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ + uint32_t divider; + uint16_t tmpmode = 0; + /* + * determine clock divider and DIV16 bit + */ + divider = m360_clock_rate/baudrate; + if (divider > 64) { + tmpmode = M360_SPMODE_DIV16; + divider /= 16; + } + if ((divider < 1) || + (divider > 64)) { + return RTEMS_INVALID_NUMBER; + } + else { + tmpmode |= M360_SPMODE_PM(divider/4-1); + } + *spimode = tmpmode; + return RTEMS_SUCCESSFUL; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static rtems_status_code m360_spi_char_mode +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| determine proper value for character size | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + m360_spi_softc_t *softc_ptr, /* handle */ + uint32_t bits_per_char, /* bits per character */ + boolean lsb_first, /* TRUE: send LSB first */ + uint16_t *spimode /* result value */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ + uint32_t tmpmode; + + if (bits_per_char == 32) { + tmpmode = 0; + softc_ptr->bytes_per_char = 4; + softc_ptr->bit_shift = 0; + } + else { + if (lsb_first) { + /* + * non-reversed data (LSB first): 4..16 bits valid + * always aligned to bit 16 of data register + */ + if ((bits_per_char >= 4) && + (bits_per_char <= 16)) { + tmpmode = M360_SPIMODE_LEN( bits_per_char-1); + softc_ptr->bytes_per_char = (bits_per_char > 8) ? 2 : 1; + softc_ptr->bit_shift = 16-bits_per_char; + } + else { + return RTEMS_INVALID_NUMBER; + } + } + else { + /* + * reversed data (MSB first): only 8/16/32 bits valid, + * always in lowest bits of data register + */ + if (bits_per_char == 8) { + tmpmode = M360_SPIMODE_LEN(8-1); + softc_ptr->bytes_per_char = 1; + softc_ptr->bit_shift = 0; + } + else if (bits_per_char == 16) { + tmpmode = M360_SPIMODE_LEN(16-1); + softc_ptr->bytes_per_char = 2; + softc_ptr->bit_shift = 0; + } + else { + return RTEMS_INVALID_NUMBER; + } + } + } + + *spimode = tmpmode; + return 0; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static int m360_spi_wait +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| wait for spi to become idle | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + m360_spi_softc_t *softc_ptr, /* handle */ + uint32_t irq_mask, /* irq mask to use */ + uint32_t desired_status, /* desired status word */ + uint32_t status_mask /* status word mask */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ + uint32_t act_status; + rtems_status_code rc; + uint32_t tout; + +#if defined(DEBUG) + printk("m360_spi_wait called... "); +#endif + if (softc_ptr->initialized) { + /* + * allow interrupts, when receiver is not empty + */ + softc_ptr->reg_ptr->spim = irq_mask; + rc = rtems_semaphore_obtain(softc_ptr->irq_sema_id,RTEMS_WAIT,100); + if (rc != RTEMS_SUCCESSFUL) { + return rc; + } + } + else { + tout = 0; + do { + if (tout++ > 1000000) { +#if defined(DEBUG) + printk("... exit with RTEMS_TIMEOUT\r\n"); +#endif + return RTEMS_TIMEOUT; + } + /* + * wait for SPI to terminate + */ + } while (!(softc_ptr->reg_ptr->spie & M360_SPIE_NE)); + } + + act_status = softc_ptr->reg_ptr->spie; + if ((act_status & status_mask)!= desired_status) { +#if defined(DEBUG) + printk("... exit with RTEMS_IO_ERROR," + "act_status=0x%04x,mask=0x%04x,desired_status=0x%04x\r\n", + act_status,status_mask,desired_status); +#endif + return RTEMS_IO_ERROR; + } +#if defined(DEBUG) + printk("... exit OK\r\n"); +#endif + return RTEMS_SUCCESSFUL; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static void m360_spi_irq_handler +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| handle interrupts | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_irq_hdl_param handle /* handle, is softc_ptr structure */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| <none> | +\*=========================================================================*/ +{ + m360_spi_softc_t *softc_ptr = (m360_spi_softc_t *)handle; + + /* + * disable interrupt mask + */ + softc_ptr->reg_ptr->spim = 0; + if (softc_ptr->initialized) { + rtems_semaphore_release(softc_ptr->irq_sema_id); + } +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +static void m360_spi_install_irq_handler +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| (un-)install the interrupt handler | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + m360_spi_softc_t *softc_ptr, /* ptr to control structure */ + int install /* TRUE: install, FALSE: remove */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| <none> | +\*=========================================================================*/ +{ + rtems_status_code rc = RTEMS_SUCCESSFUL; + + rtems_irq_connect_data irq_conn_data = { + softc_ptr->irq_number, + m360_spi_irq_handler, /* rtems_irq_hdl */ + (rtems_irq_hdl_param)softc_ptr, /* (rtems_irq_hdl_param) */ + m360_spi_irq_on_off, /* (rtems_irq_enable) */ + m360_spi_irq_on_off, /* (rtems_irq_disable) */ + m360_spi_irq_isOn /* (rtems_irq_is_enabled) */ + }; + + /* + * (un-)install handler for SPI device + */ + if (install) { + /* + * create semaphore for IRQ synchronization + */ + rc = rtems_semaphore_create(rtems_build_name('s','p','i','s'), + 0, + RTEMS_FIFO + | RTEMS_SIMPLE_BINARY_SEMAPHORE, + 0, + &softc_ptr->irq_sema_id); + if (rc != RTEMS_SUCCESSFUL) { + rtems_panic("SPI: cannot create semaphore"); + } + if (!BSP_install_rtems_irq_handler (&irq_conn_data)) { + rtems_panic("SPI: cannot install IRQ handler"); + } + } + else { + if (!BSP_remove_rtems_irq_handler (&irq_conn_data)) { + rtems_panic("SPI: cannot uninstall IRQ handler"); + } + /* + * delete sync semaphore + */ + if (softc_ptr->irq_sema_id != 0) { + rc = rtems_semaphore_delete(softc_ptr->irq_sema_id); + if (rc != RTEMS_SUCCESSFUL) { + rtems_panic("SPI: cannot delete semaphore"); + } + } + } +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +rtems_status_code m360_spi_init +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| initialize the driver | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh /* bus specifier structure */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| o = ok or error code | +\*=========================================================================*/ +{ + m360_spi_softc_t *softc_ptr = &(((m360_spi_desc_t *)(bh))->softc); +#if defined(DEBUG) + printk("m360_spi_init called... "); +#endif + /* + * init HW registers: + */ + /* + * FIXME: set default mode in SPIM + */ + + /* + * FIXME: allocate BDs (1x RX, 1x TX) + */ + + /* + * init interrupt stuff + */ + m360_spi_install_irq_handler(softc_ptr,TRUE); + + /* + * mark, that we have initialized + */ + softc_ptr->initialized = TRUE; +#if defined(DEBUG) + printk("... exit OK\r\n"); +#endif + return RTEMS_SUCCESSFUL; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_read_write_bytes +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| transmit/receive some bytes from SPI device | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *rbuf, /* buffer to store bytes */ + const unsigned char *tbuf, /* buffer to send bytes */ + int len /* number of bytes to transceive */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| number of bytes received or (negative) error code | +\*=========================================================================*/ +{ + m360_spi_softc_t *softc_ptr = &(((m360_spi_desc_t *)(bh))->softc); + rtems_status_code rc; + int bc = 0; + int bytes_per_char = softc_ptr->bytes_per_char; + int bit_shift = softc_ptr->bit_shift; + uint32_t spird_val; + +#if defined(DEBUG) + printk("m360_spi_read_write_bytes called... "); +#endif + + while (len > bytes_per_char-1) { + len -= bytes_per_char; + /* + * mark last byte in SPCOM + */ +#if defined(USE_LAST_BIT) + softc_ptr->reg_ptr->spcom = (len < bytes_per_char) ? M360_SPCOM_LST : 0; +#else + softc_ptr->reg_ptr->spcom = 0; +#endif + if (tbuf == NULL) { + /* + * perform dummy write to read byte + */ + softc_ptr->reg_ptr->spitd = 0; + } + else { + switch(bytes_per_char) { + case 1: + softc_ptr->reg_ptr->spitd = (*(uint8_t *)tbuf) << bit_shift; + break; + case 2: + softc_ptr->reg_ptr->spitd = (*(uint16_t *)tbuf) << bit_shift; + break; + case 4: + softc_ptr->reg_ptr->spitd = (*(uint32_t *)tbuf) << bit_shift; + break; + } + tbuf += softc_ptr->bytes_per_char; + } + /* + * wait 'til end of transfer + */ +#if defined(USE_LAST_BIT) + rc = m360_spi_wait(softc_ptr, + ((len == 0) + ? M360_SPIE_LT + : M360_SPIE_NE), + ((len == 0) + ? M360_SPIE_LT + : M360_SPIE_NF) + | M360_SPIE_NE, + M360_SPIE_LT + | M360_SPIE_OV + | M360_SPIE_UN + | M360_SPIE_NE + | M360_SPIE_NF); + if (len == 0) { + /* + * clear the "last transfer complete" event + */ + softc_ptr->reg_ptr->spie = M360_SPIE_LT; + } +#else + rc = m360_spi_wait(softc_ptr, + M360_SPIE_NE, + M360_SPIE_NF + | M360_SPIE_NE, + M360_SPIE_OV + | M360_SPIE_UN + | M360_SPIE_NE + | M360_SPIE_NF); +#endif + if (rc != RTEMS_SUCCESSFUL) { +#if defined(DEBUG) + printk("... exit rc=%d\r\n",-rc); +#endif + return -rc; + } + spird_val = softc_ptr->reg_ptr->spird; + if (rbuf != NULL) { + switch(bytes_per_char) { + case 1: + (*(uint8_t *)rbuf) = spird_val >> bit_shift; + break; + case 2: + (*(uint16_t *)rbuf) = spird_val >> bit_shift; + break; + case 4: + (*(uint32_t *)rbuf) = spird_val >> bit_shift; + break; + } + rbuf += bytes_per_char; + } + bc += bytes_per_char; + } +#if defined(DEBUG) + printk("... exit OK, rc=%d\r\n",bc); +#endif + return bc; +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_read_bytes +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| receive some bytes from SPI device | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to store bytes */ + int len /* number of bytes to receive */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| number of bytes received or (negative) error code | +\*=========================================================================*/ +{ + return m360_spi_read_write_bytes(bh,buf,NULL,len); +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_write_bytes +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| send some bytes to SPI device | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + unsigned char *buf, /* buffer to send */ + int len /* number of bytes to send */ + +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| number of bytes sent or (negative) error code | +\*=========================================================================*/ +{ + return m360_spi_read_write_bytes(bh,NULL,buf,len); +} + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +rtems_status_code m360_spi_set_tfr_mode +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| set SPI to desired baudrate/clock mode/character mode | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + const rtems_libi2c_tfr_mode_t *tfr_mode /* transfer mode info */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| rtems_status_code | +\*=========================================================================*/ +{ + m360_spi_softc_t *softc_ptr = &(((m360_spi_desc_t *)(bh))->softc); + uint32_t spimode_baud,spimode; + rtems_status_code rc = RTEMS_SUCCESSFUL; + /* + * FIXME: set proper mode + */ + if (rc == RTEMS_SUCCESSFUL) { + rc = m360_spi_baud_to_mode(tfr_mode->baudrate,&spimode_baud); + } + if (rc == RTEMS_SUCCESSFUL) { + rc = m360_spi_char_mode(softc_ptr, + tfr_mode->bits_per_char, + tfr_mode->lsb_first, + &spimode); + } + if (rc == RTEMS_SUCCESSFUL) { + spimode |= spimode_baud; + spimode |= M360_SPIMODE_M_S; /* set master mode */ + if (!tfr_mode->lsb_first) { + spimode |= M360_SPIMODE_REV; + } + if (tfr_mode->clock_inv) { + spimode |= M360_SPIMODE_CI; + } + if (tfr_mode->clock_phs) { + spimode |= M360_SPIMODE_CP; + } + } + + if (rc == RTEMS_SUCCESSFUL) { + /* + * disable SPI + */ + softc_ptr->reg_ptr->spmode &= ~M360_SPIMODE_EN; + /* + * set new mode and reenable SPI + */ + softc_ptr->reg_ptr->spmode = spimode | M360_SPIMODE_EN; + } + return rc; +} + + +/*=========================================================================*\ +| Function: | +\*-------------------------------------------------------------------------*/ +int m360_spi_ioctl +( +/*-------------------------------------------------------------------------*\ +| Purpose: | +| perform selected ioctl function for SPI | ++---------------------------------------------------------------------------+ +| Input Parameters: | +\*-------------------------------------------------------------------------*/ + rtems_libi2c_bus_t *bh, /* bus specifier structure */ + int cmd, /* ioctl command code */ + void *arg /* additional argument array */ +) +/*-------------------------------------------------------------------------*\ +| Return Value: | +| rtems_status_code | +\*=========================================================================*/ +{ + int ret_val = -1; + + switch(cmd) { + case RTEMS_LIBI2C_IOCTL_SET_TFRMODE: + ret_val = + -m360_spi_set_tfr_mode(bh, + (const rtems_libi2c_tfr_mode_t *)arg); + break; + case RTEMS_LIBI2C_IOCTL_READ_WRITE: + ret_val = + m360_spi_read_write_bytes(bh, + ((rtems_libi2c_read_write_t *)arg)->rd_buf, + ((rtems_libi2c_read_write_t *)arg)->wr_buf, + ((rtems_libi2c_read_write_t *)arg)->byte_cnt); + break; + default: + ret_val = -RTEMS_NOT_DEFINED; + break; + } + return ret_val; +} + + + diff --git a/c/src/lib/libbsp/m68k/gen68360/startup/init68360.c b/c/src/lib/libbsp/m68k/gen68360/startup/init68360.c index 37fd35f5e2..f1f0f26dce 100644 --- a/c/src/lib/libbsp/m68k/gen68360/startup/init68360.c +++ b/c/src/lib/libbsp/m68k/gen68360/startup/init68360.c @@ -14,6 +14,13 @@ #include <bsp.h> #include <rtems/m68k/m68360.h> + +/* + * Declare the m360 structure here for the benefit of the debugger + */ + +volatile m360_t m360; + /* * Send a command to the CPM RISC processer */ @@ -335,6 +342,174 @@ void _Init68360 (void) * BCLRO* arbitration level 3 */ +#elif defined(PGH360) + /* + * Step 6: Is this a power-up reset? + * For now we just ignore this and do *all* the steps + * Someday we might want to: + * if (Hard, Loss of Clock, Power-up) + * Do all steps + * else if (Double bus fault, watchdog or soft reset) + * Skip to step 12 + * else (must be a CPU32+ reset command) + * Skip to step 14 + */ + + /* + * Step 7: Deal with clock synthesizer + * HARDWARE: + * Change if you're not using an external 25 MHz oscillator. + */ + m360.clkocr = 0x8e; /* No more writes, CLKO1=1/3, CLKO2=off */ + /* + * adjust crystal to average between 4.19 MHz and 4.00 MHz + * reprogram pll + */ + m360.pllcr = 0xA000+(24576000/((4000000+4194304)/2/128))-1; + /* LPSTOP slowdown, PLL /128*??? */ + m360.cdvcr = 0x8000; /* No more writes, no clock division */ + + /* + * Step 8: Initialize system protection + * Enable watchdog + * Watchdog causes system reset + * 128 sec. watchdog timeout + * Enable double bus fault monitor + * Enable bus monitor external + * 128 clocks for external timeout + */ + m360.sypcr = 0xEF; + /* + * also initialize the SWP bit in PITR to 1 + */ + m360.pitr |= 0x0200; + /* + * and trigger SWSR twice to ensure, that interval starts right now + */ + m360.swsr = 0x55; + m360.swsr = 0xAA; + m360.swsr = 0x55; + m360.swsr = 0xAA; + /* + * Step 9: Clear parameter RAM and reset communication processor module + */ + for (i = 0 ; i < 192 ; i += sizeof (long)) { + *((long *)((char *)&m360 + 0xC00 + i)) = 0; + *((long *)((char *)&m360 + 0xD00 + i)) = 0; + *((long *)((char *)&m360 + 0xE00 + i)) = 0; + *((long *)((char *)&m360 + 0xF00 + i)) = 0; + } + M360ExecuteRISC (M360_CR_RST); + + /* + * Step 10: Write PEPAR + * SINTOUT not used (CPU32+ mode) + * CF1MODE=00 (CONFIG1 input) + * IPIPE1 + * WE0-3 + * OE* output + * CAS2* / CAS3* + * CAS0* / CAS1* + * CS7* + * AVEC* + * HARDWARE: + * Change if you are using a different memory configuration + * (static RAM, external address multiplexing, etc). + */ + m360.pepar = 0x0080; + /* + * Step 11: Remap Chip Select 0 (CS0*), set up GMR + * no DRAM support + * HARDWARE: + * Change if you are using a different memory configuration + */ + m360.gmr = M360_GMR_RCNT(23) | M360_GMR_RFEN | M360_GMR_RCYC(0) | + M360_GMR_PGS(6) | M360_GMR_DPS_32BIT | M360_GMR_DWQ | + M360_GMR_GAMX; + + m360.memc[0].br = (unsigned long)&_RomBase | M360_MEMC_BR_WP | + M360_MEMC_BR_V; + m360.memc[0].or = M360_MEMC_OR_WAITS(3) | M360_MEMC_OR_512KB | + M360_MEMC_OR_8BIT; + + /* + * Step 12: Initialize the system RAM + * Set up option/base registers + * 16 MB DRAM + * 1 wait state + * HARDWARE: + * Change if you are using a different memory configuration + * NOTE: no Page mode possible for EDO RAMs (?) + */ + ramSize = 16 * 1024 * 1024; + m360.memc[7].or = M360_MEMC_OR_TCYC(1) | M360_MEMC_OR_16MB | + M360_MEMC_OR_FCMC(0) | /* M360_MEMC_OR_PGME | */ + M360_MEMC_OR_32BIT | M360_MEMC_OR_DRAM; + m360.memc[7].br = (unsigned long)&_RamBase | M360_MEMC_BR_V; + + /* + * FIXME: here we should wait for 8 refresh cycles... + */ + /* + * Step 12a: test the ram, if wanted + * FIXME: when do we call this? + * -> only during firmware execution + * -> perform intesive test only on request + * -> ensure, that results are stored properly + */ +#if 0 /* FIXME: activate RAM tests again */ + { + void *ram_base, *ram_end, *code_loc; + extern char ramtest_start,ramtest_end; + ram_base = &ramtest_start; + ram_end = &ramtest_end; + code_loc = (void *)ramtest_exec; + if ((ram_base < ram_end) && + !((ram_base <= code_loc) && (code_loc < ram_end))) { + ramtest_exec(ram_base,ram_end); + } + } +#endif + /* + * Step 13: Copy the exception vector table to system RAM + */ + m68k_get_vbr (vbr); + for (i = 0; i < 256; ++i) + M68Kvec[i] = vbr[i]; + m68k_set_vbr (M68Kvec); + + /* + * Step 14: More system initialization + * SDCR (Serial DMA configuration register) + * Disable SDMA during FREEZE + * Give SDMA priority over all interrupt handlers + * Set DMA arbiration level to 4 + * CICR (CPM interrupt configuration register): + * SCC1 requests at SCCa position + * SCC2 requests at SCCb position + * SCC3 requests at SCCc position + * SCC4 requests at SCCd position + * Interrupt request level 4 + * Maintain original priority order + * Vector base 128 + * SCCs priority grouped at top of table + */ + m360.sdcr = M360_SDMA_SISM_7 | M360_SDMA_SAID_4; + m360.cicr = (3 << 22) | (2 << 20) | (1 << 18) | (0 << 16) | + (4 << 13) | (0x1F << 8) | (128); + + /* + * Step 15: Set module configuration register + * Disable timers during FREEZE + * Enable bus monitor during FREEZE + * BCLRO* arbitration level 3 + * No show cycles + * User/supervisor access + * Bus clear interupt service level 7 + * SIM60 interrupt sources higher priority than CPM + */ + m360.mcr = 0x4C7F; + #elif (defined (GEN68360_WITH_SRAM)) /* *************************************************** |