diff --git a/board/actel/sf2-dev-kit/Makefile b/board/actel/sf2-dev-kit/Makefile index ae566a0511cd55198fa311f81295fbeedb152128..934808d663ccd7695225a6b3c20ccde1478f11c6 100644 --- a/board/actel/sf2-dev-kit/Makefile +++ b/board/actel/sf2-dev-kit/Makefile @@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk LIB = $(obj)lib$(BOARD).a -COBJS := board.o +COBJS := board.o mss_spi/mss_spi.o zl30362_config.o SRCS := $(COBJS:.o=.c) OBJS := $(addprefix $(obj),$(COBJS)) diff --git a/board/actel/sf2-dev-kit/board.c b/board/actel/sf2-dev-kit/board.c index 0b4a69e02937278027d52ab4e65d9261dbfde761..73d1fb4e2a7c7cfc61b76c4958b639642d7339d6 100644 --- a/board/actel/sf2-dev-kit/board.c +++ b/board/actel/sf2-dev-kit/board.c @@ -36,8 +36,29 @@ void dummy_func(void) return; } +extern void configure_zl30362(void); + +#define SERDES0_LANE3_REGS 0x40029c00 +#define TX_PST_RATIO 0x28 + int board_init(void) { + /* some magic from the Libero design generated source code + to get the PHY working in the SGMII mode */ + *(volatile uint32_t*)(SERDES0_LANE3_REGS + TX_PST_RATIO) = 0x0; + /* configure the ZL30362 Clock Network Synchronizer + (required for Ethernet to function in U-boot and Linux) */ + configure_zl30362(); + CORE_SF2_CFG->config_done = 1u; /* Signal to CoreSF2Reset that peripheral + configuration registers have + been written.*/ +#if 0 /* FIXME: init_done is never signalled after a soft reset + if the DDR has been initialized before the reset. */ + while(!CORE_SF2_CFG->init_done) + { + ; /* Wait for INIT_DONE from CoreSF2Reset. */ + } +#endif return 0; } diff --git a/board/actel/sf2-dev-kit/mss_spi/mss_spi.c b/board/actel/sf2-dev-kit/mss_spi/mss_spi.c new file mode 100644 index 0000000000000000000000000000000000000000..4fb9a722cc15978e8abc3910cfbded4f937ac72c --- /dev/null +++ b/board/actel/sf2-dev-kit/mss_spi/mss_spi.c @@ -0,0 +1,991 @@ +/******************************************************************************* + * (c) Copyright 2008 Actel Corporation. All rights reserved. + * + * SmartFusion microcontroller subsystem SPI bare metal software driver + * implementation. + * + * SVN $Revision: 4566 $ + * SVN $Date: 2012-08-23 17:12:11 +0100 (Thu, 23 Aug 2012) $ + */ +#include <common.h> +#include "mss_spi.h" +/* #include "../../CMSIS/mss_assert.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + MSS SPI can operate as master or slave. + */ +#define MSS_SPI_MODE_SLAVE 0u +#define MSS_SPI_MODE_MASTER 1u + +/***************************************************************************//** + * Mask of transfer protocol and SPO, SPH bits within control register. + */ +#define PROTOCOL_MODE_MASK (uint32_t)0x030000C0 + +/***************************************************************************//** + * Mask of theframe count bits within the SPI control register. + */ +#define TXRXDFCOUNT_MASK (uint32_t)0x00FFFF00 +#define TXRXDFCOUNT_SHIFT (uint32_t)8 + +/***************************************************************************//** + * SPI hardware FIFO depth. + */ +#define RX_FIFO_SIZE 4u +#define BIG_FIFO_SIZE 32u + +/***************************************************************************//** + * + */ +#define RX_IRQ_THRESHOLD (BIG_FIFO_SIZE / 2u) + +/***************************************************************************//** + Marker used to detect that the configuration has not been selected for a + specific slave when operating as a master. + */ +#define NOT_CONFIGURED 0xFFFFFFFF + +/***************************************************************************//** + * CONTROL register bit masks + */ +#define CTRL_ENABLE_MASK 0x00000001u +#define CTRL_MASTER_MASK 0x00000002u + +/***************************************************************************//** + Registers bit masks + */ +/* CONTROL register. */ +#define MASTER_MODE_MASK 0x00000002u +#define CTRL_RX_IRQ_EN_MASK 0x00000010u +#define CTRL_TX_IRQ_EN_MASK 0x00000020u +#define CTRL_REG_RESET_MASK 0x80000000u +#define BIGFIFO_MASK 0x20000000u + +/* CONTROL2 register */ +#define ENABLE_CMD_IRQ_MASK 0x00000010u +#define ENABLE_SSEND_IRQ_MASK 0x00000020u + +/* STATUS register */ +#define TX_DONE_MASK 0x00000001u +#define RX_DATA_READY_MASK 0x00000002u +#define RX_OVERFLOW_MASK 0x00000004u +#define RX_FIFO_EMPTY_MASK 0x00000040u +#define TX_FIFO_FULL_MASK 0x00000100u +#define TX_FIFO_EMPTY_MASK 0x00000400u + +/* MIS register. */ +#define TXDONE_IRQ_MASK 0x00000001u +#define RXDONE_IRQ_MASK 0x00000002u +#define RXOVER_IRQ_MASK 0x00000004u +#define RXUNDER_IRQ_MASK 0x00000008u +#define CMD_IRQ_MASK 0x00000010u +#define SSEND_IRQ_MASK 0x00000020u + +/* COMMAND register */ +#define AUTOFILL_MASK 0x00000001u +#define RX_FIFO_RESET_MASK 0x00000004u +#define TX_FIFO_RESET_MASK 0x00000008u + +/***************************************************************************//** + * SPI instance data structures for SPI0 and SPI1. A pointer to these data + * structures must be used as first parameter to any of the SPI driver functions + * to identify the SPI hardware block that will perform the requested operation. + */ +mss_spi_instance_t g_mss_spi0; +volatile mss_spi_instance_t g_mss_spi1; + +/***************************************************************************//** + SPI0 interrupt service routine + */ +#if defined(__GNUC__) +__attribute__((__interrupt__)) void SPI0_IRQHandler(void); +#else +void SPI0_IRQHandler(void); +#endif + +/***************************************************************************//** + SPI1 interrupt service routine + */ +#if defined(__GNUC__) +__attribute__((__interrupt__)) void SPI1_IRQHandler(void); +#else +void SPI1_IRQHandler(void); +#endif + +/***************************************************************************//** + local functions + */ +static void recover_from_rx_overflow(volatile mss_spi_instance_t * this_spi); +/* static void fill_slave_tx_fifo(mss_spi_instance_t * this_spi); */ +/* static void read_slave_rx_fifo(mss_spi_instance_t * this_spi); */ + +/***************************************************************************//** + * MSS_SPI_init() + * See "mss_spi.h" for details of how to use this function. + */ +void MSS_SPI_init +( + volatile mss_spi_instance_t * this_spi +) +{ + uint16_t i; + + ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); + + if(this_spi == &g_mss_spi0) + { + this_spi->hw_reg = ((SPI_REVB_TypeDef *) SPI0_BASE); + this_spi->irqn = SPI0_IRQn; + + /* reset SPI0 */ + SYSREG->SOFT_RST_CR |= SYSREG_SPI0_SOFTRESET_MASK; + /* Clear any previously pended SPI0 interrupt */ + /* NVIC_ClearPendingIRQ(SPI0_IRQn); */ + /* Take SPI0 out of reset. */ + SYSREG->SOFT_RST_CR &= ~SYSREG_SPI0_SOFTRESET_MASK; + + this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK; + } + else + { + this_spi->hw_reg = ((SPI_REVB_TypeDef *) SPI1_BASE); + this_spi->irqn = SPI1_IRQn; + + /* reset SPI1 */ + SYSREG->SOFT_RST_CR |= SYSREG_SPI1_SOFTRESET_MASK; + /* Clear any previously pended SPI1 interrupt */ + /* NVIC_ClearPendingIRQ(SPI1_IRQn); */ + /* Take SPI1 out of reset. */ + SYSREG->SOFT_RST_CR &= ~SYSREG_SPI1_SOFTRESET_MASK; + + this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK; + } + + this_spi->frame_rx_handler = 0u; + this_spi->slave_tx_frame = 0u; + + this_spi->block_rx_handler = 0u; + + this_spi->slave_tx_buffer = 0u; + this_spi->slave_tx_size = 0u; + this_spi->slave_tx_idx = 0u; + + this_spi->resp_tx_buffer = 0u; + this_spi->resp_buff_size = 0u; + this_spi->resp_buff_tx_idx = 0u; + + for(i = 0u; i < (uint16_t)MSS_SPI_MAX_NB_OF_SLAVES; ++i) + { + this_spi->slaves_cfg[i].ctrl_reg = NOT_CONFIGURED; + } +} + +/***************************************************************************//** + * + * + */ +static void recover_from_rx_overflow +( + volatile mss_spi_instance_t * this_spi +) +{ + uint32_t control_reg; + uint32_t clk_gen; + uint32_t frame_size; + + /* + * Read current SPI hardware block configuration. + */ + control_reg = this_spi->hw_reg->CONTROL; + clk_gen = this_spi->hw_reg->CLK_GEN; + frame_size = this_spi->hw_reg->TXRXDF_SIZE; + + /* + * Reset the SPI hardware block. + */ + if(this_spi == &g_mss_spi0) + { + this_spi->hw_reg = ((SPI_REVB_TypeDef *) SPI0_BASE); + this_spi->irqn = SPI0_IRQn; + + /* reset SPI0 */ + SYSREG->SOFT_RST_CR |= SYSREG_SPI0_SOFTRESET_MASK; + /* Clear any previously pended SPI0 interrupt */ + /* NVIC_ClearPendingIRQ(SPI0_IRQn); */ + /* Take SPI0 out of reset. */ + SYSREG->SOFT_RST_CR &= ~SYSREG_SPI0_SOFTRESET_MASK; + + this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK; + } + else + { + this_spi->hw_reg = ((SPI_REVB_TypeDef *) SPI1_BASE); + this_spi->irqn = SPI1_IRQn; + + /* reset SPI1 */ + SYSREG->SOFT_RST_CR |= SYSREG_SPI1_SOFTRESET_MASK; + /* Clear any previously pended SPI1 interrupt */ + /* NVIC_ClearPendingIRQ(SPI1_IRQn); */ + /* Take SPI1 out of reset. */ + SYSREG->SOFT_RST_CR &= ~SYSREG_SPI1_SOFTRESET_MASK; + + this_spi->hw_reg->CONTROL &= ~CTRL_REG_RESET_MASK; + } + + /* + * Restore SPI hardware block configuration. + */ + this_spi->hw_reg->CONTROL &= ~CTRL_ENABLE_MASK; + this_spi->hw_reg->CONTROL = control_reg; + this_spi->hw_reg->CLK_GEN = clk_gen; + this_spi->hw_reg->TXRXDF_SIZE = frame_size; + this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; +} + +/* /\***************************************************************************\//\** */ +/* * MSS_SPI_configure_slave_mode() */ +/* * See "mss_spi.h" for details of how to use this function. */ +/* *\/ */ +/* void MSS_SPI_configure_slave_mode */ +/* ( */ +/* mss_spi_instance_t * this_spi, */ +/* mss_spi_protocol_mode_t protocol_mode, */ +/* mss_spi_pclk_div_t clk_rate, */ +/* uint8_t frame_bit_length */ +/* ) */ +/* { */ +/* ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); */ +/* ASSERT(frame_bit_length <= 32); */ + +/* /\* Set the mode. *\/ */ +/* this_spi->hw_reg->CONTROL &= ~CTRL_MASTER_MASK; */ + +/* /\* Set the clock rate. *\/ */ +/* this_spi->hw_reg->CONTROL &= ~CTRL_ENABLE_MASK; */ +/* this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~PROTOCOL_MODE_MASK) | */ +/* (uint32_t)protocol_mode | BIGFIFO_MASK; */ + +/* this_spi->hw_reg->CLK_GEN = (uint32_t)clk_rate; */ + +/* /\* Set default frame size to byte size and number of data frames to 1. *\/ */ +/* this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ((uint32_t)1 << TXRXDFCOUNT_SHIFT); */ +/* this_spi->hw_reg->TXRXDF_SIZE = frame_bit_length; */ +/* this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; */ +/* } */ + +/***************************************************************************//** + * MSS_SPI_configure_master_mode() + * See "mss_spi.h" for details of how to use this function. + */ +void MSS_SPI_configure_master_mode +( + volatile mss_spi_instance_t * this_spi, + mss_spi_slave_t slave, + mss_spi_protocol_mode_t protocol_mode, + mss_spi_pclk_div_t clk_rate, + uint8_t frame_bit_length +) +{ + ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); + ASSERT(slave < MSS_SPI_MAX_NB_OF_SLAVES); + ASSERT(frame_bit_length <= 32); + + /* Set the mode. */ + this_spi->hw_reg->CONTROL &= ~CTRL_ENABLE_MASK; + this_spi->hw_reg->CONTROL |= CTRL_MASTER_MASK; + this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; + + /* + * Keep track of the required register configuration for this slave. These + * values will be used by the MSS_SPI_set_slave_select() function to configure + * the master to match the slave being selected. + */ + if(slave < MSS_SPI_MAX_NB_OF_SLAVES) + { + this_spi->slaves_cfg[slave].ctrl_reg = MASTER_MODE_MASK | + BIGFIFO_MASK | + (uint32_t)protocol_mode | + ((uint32_t)1 << TXRXDFCOUNT_SHIFT); + this_spi->slaves_cfg[slave].txrxdf_size_reg = frame_bit_length; + this_spi->slaves_cfg[slave].clk_gen = (uint8_t)clk_rate; + } +} + +/***************************************************************************//** + * MSS_SPI_set_slave_select() + * See "mss_spi.h" for details of how to use this function. + */ +void MSS_SPI_set_slave_select +( + volatile mss_spi_instance_t * this_spi, + mss_spi_slave_t slave +) +{ + uint32_t rx_overflow; + + ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); + + /* This function is only intended to be used with an SPI master. */ + ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) == CTRL_MASTER_MASK); + + ASSERT(this_spi->slaves_cfg[slave].ctrl_reg != NOT_CONFIGURED); + + /* Recover from receive overflow. */ + rx_overflow = this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK; + if(rx_overflow) + { + recover_from_rx_overflow(this_spi); + } + + /* Set the clock rate. */ + this_spi->hw_reg->CONTROL &= ~CTRL_ENABLE_MASK; + this_spi->hw_reg->CONTROL = this_spi->slaves_cfg[slave].ctrl_reg; + this_spi->hw_reg->CLK_GEN = this_spi->slaves_cfg[slave].clk_gen; + this_spi->hw_reg->TXRXDF_SIZE = this_spi->slaves_cfg[slave].txrxdf_size_reg; + this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; + + /* Set slave select */ + this_spi->hw_reg->SLAVE_SELECT |= ((uint32_t)1 << (uint32_t)slave); +} + +/***************************************************************************//** + * MSS_SPI_clear_slave_select() + * See "mss_spi.h" for details of how to use this function. + */ +void MSS_SPI_clear_slave_select +( + mss_spi_instance_t * this_spi, + mss_spi_slave_t slave +) +{ + uint32_t rx_overflow; + + ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); + + /* This function is only intended to be used with an SPI master. */ + ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) == CTRL_MASTER_MASK); + + /* Recover from receive overflow. */ + rx_overflow = this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK; + if(rx_overflow) + { + recover_from_rx_overflow(this_spi); + } + + this_spi->hw_reg->SLAVE_SELECT &= ~((uint32_t)1 << (uint32_t)slave); +} + +/***************************************************************************//** + * MSS_SPI_transfer_frame() + * See "mss_spi.h" for details of how to use this function. + */ +uint32_t MSS_SPI_transfer_frame +( + volatile mss_spi_instance_t * this_spi, + uint32_t tx_bits +) +{ + volatile uint32_t dummy; + uint32_t rx_ready; + uint32_t tx_done; + + ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); + + /* This function is only intended to be used with an SPI master. */ + ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) == CTRL_MASTER_MASK); + + /* printf("%s %d %s %08x\n", __FILE__, __LINE__, __FUNCTION__, this_spi->hw_reg->STATUS); */ + /* Flush Rx FIFO. */ + rx_ready = this_spi->hw_reg->STATUS & RX_DATA_READY_MASK; + while(rx_ready) + { + dummy = this_spi->hw_reg->RX_DATA; + dummy = dummy; /* Prevent Lint warning. */ + rx_ready = this_spi->hw_reg->STATUS & RX_DATA_READY_MASK; + } + + /* printf("%s %d %s %08x\n", __FILE__, __LINE__, __FUNCTION__, this_spi->hw_reg->STATUS); */ + /* Send frame. */ + this_spi->hw_reg->TX_DATA = tx_bits; + + /* Wait for frame Tx to complete. */ + tx_done = this_spi->hw_reg->STATUS & TX_DONE_MASK; + while(!tx_done) + { + tx_done = this_spi->hw_reg->STATUS & TX_DONE_MASK; + /* printf("%s %d %s %08x\n", __FILE__, __LINE__, __FUNCTION__, this_spi->hw_reg->STATUS); */ + } + /* printf("%s %d %s %08x\n", __FILE__, __LINE__, __FUNCTION__, this_spi->hw_reg->STATUS); */ + + /* Read received frame. */ + /* Wait for Rx complete. */ + rx_ready = this_spi->hw_reg->STATUS & RX_DATA_READY_MASK; + while(!rx_ready) + { + rx_ready = this_spi->hw_reg->STATUS & RX_DATA_READY_MASK; + } + /* printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); */ + /* Return Rx data. */ + return( this_spi->hw_reg->RX_DATA ); +} + + +/* /\***************************************************************************\//\** */ +/* * MSS_SPI_transfer_block() */ +/* * See "mss_spi.h" for details of how to use this function. */ +/* *\/ */ +/* void MSS_SPI_transfer_block */ +/* ( */ +/* mss_spi_instance_t * this_spi, */ +/* const uint8_t * cmd_buffer, */ +/* uint16_t cmd_byte_size, */ +/* uint8_t * rd_buffer, */ +/* uint16_t rd_byte_size */ +/* ) */ +/* { */ +/* uint16_t transfer_idx = 0u; */ +/* uint16_t tx_idx; */ +/* uint16_t rx_idx; */ +/* uint32_t frame_count; */ +/* volatile uint32_t rx_raw; */ +/* uint16_t transit = 0u; */ +/* uint32_t tx_fifo_full; */ +/* uint32_t rx_overflow; */ +/* uint32_t rx_fifo_empty; */ + +/* uint16_t transfer_size; /\* Total number of bytes transfered. *\/ */ + +/* ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); */ + +/* /\* This function is only intended to be used with an SPI master. *\/ */ +/* ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) == CTRL_MASTER_MASK); */ + +/* /\* Compute number of bytes to transfer. *\/ */ +/* transfer_size = cmd_byte_size + rd_byte_size; */ + +/* /\* Adjust to 1 byte transfer to cater for DMA transfers. *\/ */ +/* if(transfer_size == 0u) */ +/* { */ +/* frame_count = 1u; */ +/* } */ +/* else */ +/* { */ +/* frame_count = transfer_size; */ +/* } */ + +/* /\* Recover from receive overflow. *\/ */ +/* rx_overflow = this_spi->hw_reg->STATUS & RX_OVERFLOW_MASK; */ +/* if(rx_overflow) */ +/* { */ +/* recover_from_rx_overflow(this_spi); */ +/* } */ + +/* /\* Set frame size to 8 bits and the frame count to the transfer size. *\/ */ +/* this_spi->hw_reg->CONTROL &= ~CTRL_ENABLE_MASK; */ +/* this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | ( (frame_count << TXRXDFCOUNT_SHIFT) & TXRXDFCOUNT_MASK); */ +/* this_spi->hw_reg->TXRXDF_SIZE = 8u; */ +/* this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; */ + +/* /\* Flush the receive FIFO. *\/ */ +/* rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; */ +/* while(!rx_fifo_empty) */ +/* { */ +/* rx_raw = this_spi->hw_reg->RX_DATA; */ +/* rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; */ +/* } */ + +/* tx_idx = 0u; */ +/* rx_idx = 0u; */ +/* if(tx_idx < cmd_byte_size) */ +/* { */ +/* this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx]; */ +/* ++tx_idx; */ +/* ++transit; */ +/* } */ +/* else */ +/* { */ +/* if(tx_idx < transfer_size) */ +/* { */ +/* this_spi->hw_reg->TX_DATA = 0x00u; */ +/* ++tx_idx; */ +/* ++transit; */ +/* } */ +/* } */ +/* /\* Perform the remainder of the transfer by sending a byte every time a byte */ +/* * has been received. This should ensure that no Rx overflow can happen in */ +/* * case of an interrupt occurs during this function. *\/ */ +/* while(transfer_idx < transfer_size) */ +/* { */ +/* rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; */ +/* if(!rx_fifo_empty) */ +/* { */ +/* /\* Process received byte. *\/ */ +/* rx_raw = this_spi->hw_reg->RX_DATA; */ +/* if(transfer_idx >= cmd_byte_size) */ +/* { */ +/* if(rx_idx < rd_byte_size) */ +/* { */ +/* rd_buffer[rx_idx] = (uint8_t)rx_raw; */ +/* } */ +/* ++rx_idx; */ +/* } */ +/* ++transfer_idx; */ +/* --transit; */ +/* } */ + +/* tx_fifo_full = this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK; */ +/* if(!tx_fifo_full) */ +/* { */ +/* if(transit < RX_FIFO_SIZE) */ +/* { */ +/* /\* Send another byte. *\/ */ +/* if(tx_idx < cmd_byte_size) */ +/* { */ +/* this_spi->hw_reg->TX_DATA = cmd_buffer[tx_idx]; */ +/* ++tx_idx; */ +/* ++transit; */ +/* } */ +/* else */ +/* { */ +/* if(tx_idx < transfer_size) */ +/* { */ +/* this_spi->hw_reg->TX_DATA = 0x00u; */ +/* ++tx_idx; */ +/* ++transit; */ +/* } */ +/* } */ +/* } */ +/* } */ +/* } */ +/* } */ + +/* /\***************************************************************************\//\** */ +/* * MSS_SPI_set_frame_rx_handler() */ +/* * See "mss_spi.h" for details of how to use this function. */ +/* *\/ */ +/* void MSS_SPI_set_frame_rx_handler */ +/* ( */ +/* mss_spi_instance_t * this_spi, */ +/* mss_spi_frame_rx_handler_t rx_handler */ +/* ) */ +/* { */ +/* uint32_t tx_fifo_empty; */ + +/* ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); */ + +/* /\* This function is only intended to be used with an SPI slave. *\/ */ +/* ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) != CTRL_MASTER_MASK); */ + +/* /\* Disable block Rx handler as they are mutually exclusive. *\/ */ +/* this_spi->block_rx_handler = 0u; */ + +/* /\* Keep a copy of the pointer to the rx hnadler function. *\/ */ +/* this_spi->frame_rx_handler = rx_handler; */ + +/* /\* Automatically fill the TX FIFO with zeroes if no slave tx frame set.*\/ */ +/* tx_fifo_empty = this_spi->hw_reg->STATUS & TX_FIFO_EMPTY_MASK; */ +/* if(tx_fifo_empty) */ +/* { */ +/* this_spi->hw_reg->COMMAND |= AUTOFILL_MASK; */ +/* } */ + +/* /\* Enable Rx interrupt. *\/ */ +/* this_spi->hw_reg->CONTROL |= CTRL_RX_IRQ_EN_MASK; */ +/* /\* NVIC_EnableIRQ( this_spi->irqn ); *\/ */ +/* } */ + +/* /\***************************************************************************\//\** */ +/* * MSS_SPI_set_slave_tx_frame() */ +/* * See "mss_spi.h" for details of how to use this function. */ +/* *\/ */ +/* void MSS_SPI_set_slave_tx_frame */ +/* ( */ +/* mss_spi_instance_t * this_spi, */ +/* uint32_t frame_value */ +/* ) */ +/* { */ +/* ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); */ + +/* /\* This function is only intended to be used with an SPI slave. *\/ */ +/* ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) != CTRL_MASTER_MASK); */ + +/* /\* Disable slave block tx buffer as it is mutually exclusive with frame */ +/* * level handling. *\/ */ +/* this_spi->slave_tx_buffer = 0u; */ +/* this_spi->slave_tx_size = 0u; */ +/* this_spi->slave_tx_idx = 0u; */ + +/* /\* Keep a copy of the slave tx frame value. *\/ */ +/* this_spi->slave_tx_frame = frame_value; */ + +/* /\* Disable automatic fill of the TX FIFO with zeroes.*\/ */ +/* this_spi->hw_reg->COMMAND &= ~AUTOFILL_MASK; */ +/* this_spi->hw_reg->COMMAND |= TX_FIFO_RESET_MASK; */ + +/* /\* Load frame into Tx data register. *\/ */ +/* this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame; */ + +/* /\* Enable Tx Done interrupt in order to reload the slave Tx frame after each */ +/* * time it has been sent. *\/ */ +/* this_spi->hw_reg->CONTROL |= CTRL_TX_IRQ_EN_MASK; */ +/* /\* NVIC_EnableIRQ( this_spi->irqn ); *\/ */ +/* } */ + +/* /\***************************************************************************\//\** */ +/* * MSS_SPI_set_slave_block_buffers() */ +/* * See "mss_spi.h" for details of how to use this function. */ +/* *\/ */ +/* void MSS_SPI_set_slave_block_buffers */ +/* ( */ +/* mss_spi_instance_t * this_spi, */ +/* const uint8_t * tx_buffer, */ +/* uint32_t tx_buff_size, */ +/* uint8_t * rx_buffer, */ +/* uint32_t rx_buff_size, */ +/* mss_spi_block_rx_handler_t block_rx_handler */ +/* ) */ +/* { */ +/* uint32_t frame_count; */ +/* uint32_t tx_fifo_full; */ + +/* ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); */ + +/* /\* This function is only intended to be used with an SPI slave. *\/ */ +/* ASSERT((this_spi->hw_reg->CONTROL & CTRL_MASTER_MASK) != CTRL_MASTER_MASK); */ + +/* /\* Disable Rx frame handler as it is mutually exclusive with block rx handler. *\/ */ +/* this_spi->frame_rx_handler = 0u; */ + +/* /\* Keep a copy of the pointer to the block rx handler function. *\/ */ +/* this_spi->block_rx_handler = block_rx_handler; */ + +/* this_spi->slave_rx_buffer = rx_buffer; */ +/* this_spi->slave_rx_size = rx_buff_size; */ +/* this_spi->slave_rx_idx = 0u; */ + +/* /\* Initialise the transmit state data. *\/ */ +/* this_spi->slave_tx_buffer = tx_buffer; */ +/* this_spi->slave_tx_size = tx_buff_size; */ +/* this_spi->slave_tx_idx = 0u; */ + +/* /\* Use the frame counter to control how often receive interrupts are generated. *\/ */ +/* frame_count = RX_IRQ_THRESHOLD; */ + +/* /\**\/ */ +/* this_spi->hw_reg->CONTROL &= ~CTRL_ENABLE_MASK; */ +/* this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) | (frame_count << TXRXDFCOUNT_SHIFT); */ +/* this_spi->hw_reg->TXRXDF_SIZE = 8u; */ +/* this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; */ + +/* /\* Load the transmit FIFO. *\/ */ +/* tx_fifo_full = this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK; */ +/* while(!tx_fifo_full && (this_spi->slave_tx_idx < this_spi->slave_tx_size)) */ +/* { */ +/* this_spi->hw_reg->TX_DATA = this_spi->slave_tx_buffer[this_spi->slave_tx_idx]; */ +/* ++this_spi->slave_tx_idx; */ +/* tx_fifo_full = this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK; */ +/* } */ + +/* /\* Enable Rx interrupt. *\/ */ +/* this_spi->hw_reg->CONTROL |= CTRL_RX_IRQ_EN_MASK; */ + + +/* if(tx_buff_size > 0) */ +/* { */ +/* this_spi->hw_reg->COMMAND &= ~AUTOFILL_MASK; */ +/* this_spi->hw_reg->CONTROL |= CTRL_TX_IRQ_EN_MASK; */ +/* } */ +/* else */ +/* { */ +/* this_spi->hw_reg->COMMAND |= AUTOFILL_MASK; */ +/* } */ + +/* /\* */ +/* * Enable slave select release interrupt. The SSEND interrupt is used to */ +/* * complete reading of the recieve FIFO and prepare the transmit FIFO for */ +/* * the next transaction. */ +/* *\/ */ +/* this_spi->hw_reg->CONTROL2 |= ENABLE_SSEND_IRQ_MASK; */ + +/* /\* NVIC_EnableIRQ(this_spi->irqn); *\/ */ +/* } */ + +/* /\***************************************************************************\//\** */ +/* * MSS_SPI_set_cmd_handler() */ +/* * See "mss_spi.h" for details of how to use this function. */ +/* *\/ */ +/* void MSS_SPI_set_cmd_handler */ +/* ( */ +/* mss_spi_instance_t * this_spi, */ +/* mss_spi_block_rx_handler_t cmd_handler, */ +/* uint32_t cmd_size */ +/* ) */ +/* { */ +/* this_spi->cmd_handler = cmd_handler; */ +/* this_spi->hw_reg->CMDSIZE = cmd_size; */ +/* this_spi->hw_reg->CONTROL2 |= ENABLE_CMD_IRQ_MASK; */ +/* } */ + +/* /\***************************************************************************\//\** */ +/* * MSS_SPI_set_cmd_response() */ +/* * See "mss_spi.h" for details of how to use this function. */ +/* *\/ */ +/* void MSS_SPI_set_cmd_response */ +/* ( */ +/* mss_spi_instance_t * this_spi, */ +/* const uint8_t * resp_tx_buffer, */ +/* uint32_t resp_buff_size */ +/* ) */ +/* { */ +/* this_spi->resp_tx_buffer = resp_tx_buffer; */ +/* this_spi->resp_buff_size = resp_buff_size; */ +/* this_spi->resp_buff_tx_idx = 0u; */ + +/* fill_slave_tx_fifo(this_spi); */ +/* } */ + +/***************************************************************************//** + * MSS_SPI_enable() + * See "mss_spi.h" for details of how to use this function. + */ +void MSS_SPI_enable +( + volatile mss_spi_instance_t * this_spi +) +{ + this_spi->hw_reg->CONTROL |= CTRL_ENABLE_MASK; +} + +/***************************************************************************//** + * MSS_SPI_disable() + * See "mss_spi.h" for details of how to use this function. + */ +void MSS_SPI_disable +( + volatile mss_spi_instance_t * this_spi +) +{ + this_spi->hw_reg->CONTROL &= ~CTRL_ENABLE_MASK; +} + +/* /\***************************************************************************\//\** */ +/* * MSS_SPI_set_transfer_byte_count() */ +/* * See "mss_spi.h" for details of how to use this function. */ +/* *\/ */ +/* void MSS_SPI_set_transfer_byte_count */ +/* ( */ +/* volatile mss_spi_instance_t * this_spi, */ +/* uint16_t byte_count */ +/* ) */ +/* { */ +/* this_spi->hw_reg->CONTROL = (this_spi->hw_reg->CONTROL & ~TXRXDFCOUNT_MASK) */ +/* | ((byte_count << TXRXDFCOUNT_SHIFT) & TXRXDFCOUNT_MASK); */ + +/* this_spi->hw_reg->TXRXDF_SIZE = 8u; */ +/* } */ + +/* /\***************************************************************************\//\** */ +/* * MSS_SPI_tx_done() */ +/* * See "mss_spi.h" for details of how to use this function. */ +/* *\/ */ +/* uint32_t MSS_SPI_tx_done */ +/* ( */ +/* mss_spi_instance_t * this_spi */ +/* ) */ +/* { */ +/* uint32_t tx_done; */ + +/* tx_done = this_spi->hw_reg->STATUS & TX_DONE_MASK; */ + +/* return tx_done; */ +/* } */ + +/* /\***************************************************************************\//\** */ +/* * Fill the transmit FIFO (used for slave block transfers). */ +/* *\/ */ +/* static void fill_slave_tx_fifo */ +/* ( */ +/* mss_spi_instance_t * this_spi */ +/* ) */ +/* { */ +/* uint32_t more_data = 1u; */ +/* uint32_t tx_fifo_full; */ + +/* tx_fifo_full = this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK; */ + +/* while(!tx_fifo_full && more_data) */ +/* { */ +/* if(this_spi->slave_tx_idx < this_spi->slave_tx_size) */ +/* { */ +/* this_spi->hw_reg->TX_DATA = this_spi->slave_tx_buffer[this_spi->slave_tx_idx]; */ +/* ++this_spi->slave_tx_idx; */ +/* } */ +/* else if(this_spi->resp_buff_tx_idx < this_spi->resp_buff_size) */ +/* { */ +/* this_spi->hw_reg->TX_DATA = this_spi->resp_tx_buffer[this_spi->resp_buff_tx_idx]; */ +/* ++this_spi->resp_buff_tx_idx; */ +/* } */ +/* else */ +/* { */ +/* more_data = 0u; */ +/* } */ +/* tx_fifo_full = this_spi->hw_reg->STATUS & TX_FIFO_FULL_MASK; */ +/* } */ +/* } */ + +/***************************************************************************//** + * + */ +/* static void read_slave_rx_fifo */ +/* ( */ +/* mss_spi_instance_t * this_spi */ +/* ) */ +/* { */ +/* uint32_t rx_frame; */ +/* uint32_t rx_fifo_empty; */ + +/* if(this_spi->frame_rx_handler != 0u) */ +/* { */ +/* rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; */ + +/* while(!rx_fifo_empty) */ +/* { */ +/* /\* Single frame handling mode. *\/ */ +/* rx_frame = this_spi->hw_reg->RX_DATA; */ +/* this_spi->frame_rx_handler( rx_frame ); */ +/* rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; */ +/* } */ +/* } */ +/* else */ +/* { */ +/* /\* Block handling mode. *\/ */ +/* rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; */ + +/* while((!rx_fifo_empty) && (this_spi->slave_rx_idx < this_spi->slave_rx_size)) */ +/* { */ +/* rx_frame = this_spi->hw_reg->RX_DATA; */ +/* this_spi->slave_rx_buffer[this_spi->slave_rx_idx] = (uint8_t)rx_frame; */ +/* ++this_spi->slave_rx_idx; */ +/* rx_fifo_empty = this_spi->hw_reg->STATUS & RX_FIFO_EMPTY_MASK; */ +/* } */ +/* } */ +/* } */ + +/***************************************************************************//** + * SPI interrupt service routine. + */ +/* static void mss_spi_isr */ +/* ( */ +/* mss_spi_instance_t * this_spi */ +/* ) */ +/* { */ +/* uint32_t tx_done; */ + +/* ASSERT((this_spi == &g_mss_spi0) || (this_spi == &g_mss_spi1)); */ + +/* /\* Handle receive. *\/ */ +/* if(this_spi->hw_reg->MIS & RXDONE_IRQ_MASK) */ +/* { */ +/* read_slave_rx_fifo(this_spi); */ +/* this_spi->hw_reg->IRQ_CLEAR = RXDONE_IRQ_MASK; */ +/* } */ + +/* /\* Handle transmit. *\/ */ +/* tx_done = this_spi->hw_reg->MIS & TXDONE_IRQ_MASK; */ +/* if(tx_done) */ +/* { */ +/* if(0u == this_spi->slave_tx_buffer) */ +/* { */ +/* /\* Reload slave tx frame into Tx data register. *\/ */ +/* this_spi->hw_reg->TX_DATA = this_spi->slave_tx_frame; */ +/* } */ +/* this_spi->hw_reg->IRQ_CLEAR = TXDONE_IRQ_MASK; */ +/* } */ + +/* /\* Handle command interrupt. *\/ */ +/* if(this_spi->hw_reg->MIS & CMD_IRQ_MASK) */ +/* { */ +/* read_slave_rx_fifo(this_spi); */ + +/* /\* */ +/* * Call the command handler if one exists. */ +/* *\/ */ +/* if(this_spi->cmd_handler != 0u) */ +/* { */ +/* (*this_spi->cmd_handler)(this_spi->slave_rx_buffer, this_spi->slave_rx_idx); */ +/* } */ + +/* this_spi->hw_reg->IRQ_CLEAR = CMD_IRQ_MASK; */ +/* } */ + +/* /\* Handle slave select becoming de-asserted. *\/ */ +/* if(this_spi->hw_reg->MIS & SSEND_IRQ_MASK) */ +/* { */ +/* uint32_t rx_size; */ + +/* read_slave_rx_fifo(this_spi); */ +/* rx_size = this_spi->slave_rx_idx; */ + +/* /\* */ +/* * Reset the transmit index to 0 to restart transmit at the start of the */ +/* * transmit buffer in the next transaction. This also requires flushing */ +/* * the Tx FIFO and refilling it with the start of Tx data buffer. */ +/* *\/ */ +/* this_spi->slave_tx_idx = 0u; */ +/* this_spi->hw_reg->COMMAND |= TX_FIFO_RESET_MASK; */ +/* fill_slave_tx_fifo(this_spi); */ + +/* /\* Prepare to receive next packet. *\/ */ +/* this_spi->slave_rx_idx = 0u; */ + +/* /\* */ +/* * Call the receive handler if one exists. */ +/* *\/ */ +/* if(this_spi->block_rx_handler != 0u) */ +/* { */ +/* (*this_spi->block_rx_handler)(this_spi->slave_rx_buffer, rx_size); */ +/* } */ + +/* this_spi->hw_reg->IRQ_CLEAR = SSEND_IRQ_MASK; */ +/* } */ +/* } */ + + +/***************************************************************************//** + * SPIO interrupt service routine. + * Please note that the name of this ISR is defined as part of the SmartFusion + * CMSIS startup code. + */ +#if defined(__GNUC__) +__attribute__((__interrupt__)) void SPI0_IRQHandler(void) +#else +void SPI0_IRQHandler( void ) +#endif +{ + /* mss_spi_isr(&g_mss_spi0); */ + /* NVIC_ClearPendingIRQ(SPI0_IRQn); */ +} + +/***************************************************************************//** + * SPI1 interrupt service routine. + * Please note that the name of this ISR is defined as part of the SmartFusion + * CMSIS startup code. + */ +#if defined(__GNUC__) +__attribute__((__interrupt__)) void SPI1_IRQHandler(void) +#else +void SPI1_IRQHandler(void) +#endif +{ + /* mss_spi_isr(&g_mss_spi1); */ + /* NVIC_ClearPendingIRQ(SPI1_IRQn); */ +} + +#ifdef __cplusplus +} +#endif + diff --git a/board/actel/sf2-dev-kit/mss_spi/mss_spi.h b/board/actel/sf2-dev-kit/mss_spi/mss_spi.h new file mode 100644 index 0000000000000000000000000000000000000000..8ed4ee630e7d9a5b714f7e6c52e13ded9c09098e --- /dev/null +++ b/board/actel/sf2-dev-kit/mss_spi/mss_spi.h @@ -0,0 +1,1663 @@ +/***************************************************************************//** + * (c) Copyright 2008 Actel Corporation. All rights reserved. + * + * SmartFusion microcontroller subsystem SPI bare metal software driver public API. + * + * The microcontroller subsystem SPI driver provides functions for implementing + * SPI master or SPI slave operations. These operations can be one of two + * classes: SPI frame operation or block transfer operations. + * Frame operations allow transferring SPI frames from 4 to 32 bits long. Block + * operations allow transferring blocks of data organized as 8 bit bytes. + * + * SVN $Revision: 4566 $ + * SVN $Date: 2012-08-23 17:12:11 +0100 (Thu, 23 Aug 2012) $ + */ +#define SPI0_BASE 0x40001000u +#define SPI1_BASE 0x40011000u +#define SYSREG_BASE 0x40038000u + +#define SPI0_IRQn 0 +#define SPI1_IRQn 0 + + +#define SYSREG ((SYSREG_TypeDef *) SYSREG_BASE) + +/*=========================================================================*//** + @mainpage SmartFusion MSS SPI Bare Metal Driver. + + @section intro_sec Introduction + The SmartFusion™ microcontroller subsystem (MSS) includes two serial + peripheral interface SPI peripherals for serial communication. This driver + provides a set of functions for controlling the MSS SPIs as part of a bare + metal system where no operating system is available. These drivers can be + adapted for use as part of an operating system, but the implementation of the + adaptation layer between this driver and the operating system's driver model + is outside the scope of this driver. + + @section hw_dependencies Hardware Flow Dependencies + The configuration of all features of the MSS SPIs is covered by this driver + with the exception of the SmartFusion IOMUX configuration. SmartFusion allows + multiple non-concurrent uses of some external pins through IOMUX configuration. + This feature allows optimization of external pin usage by assigning external + pins for use by either the microcontroller subsystem or the FPGA fabric. The + MSS SPIs serial signals are routed through IOMUXes to the SmartFusion device + external pins. These IOMUXes are automatically configured correctly by the MSS + configurator tool in the hardware flow when the MSS SPIs are enabled in that + tool. You must ensure that the MSS SPIs are enabled by the MSS configurator + tool in the hardware flow; otherwise the serial inputs and outputs will not be + connected to the chip's external pins. For more information on IOMUX, refer to + the IOMUX section of the SmartFusion Datasheet. + The base address, register addresses and interrupt number assignment for the + MSS SPI blocks are defined as constants in the SmartFusion CMSIS-PAL. You must + ensure that the SmartFusion CMSIS-PAL is either included in the software tool + chain used to build your project or is included in your project. + + @section theory_op Theory of Operation + The MSS SPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + • DMA block transfer + Frame transfers allow the MSS SPI to write or read up to 32 bits of data in a + SPI transaction. For example, a frame transfer of 12 bits might be used to + read the result of an ADC conversion from a SPI analog to digital converter. + Block transfers allow the MSS SPI to write or read a number of bytes in a SPI + transaction. Block transfer transactions allow data transfers in multiples of + 8 bits (8, 16, 24, 32, 40…). Block transfers are typically used with byte + oriented devices like SPI FLASH devices. + + Initialization + The MSS SPI driver is initialized through a call to the MSS_SPI_init() + function. The MSS_SPI_init() function takes only one parameter, a pointer + to one of two global data structures used by the driver to store state + information for each MSS SPI. A pointer to these data structures is also + used as first parameter to any of the driver functions to identify which MSS + SPI will be used by the called function. The names of these two data + structures are g_mss_spi0 and g_mss_spi1. Therefore any call to an MSS SPI + driver function should be of the form MSS_SPI_function_name( &g_mss_spi0, ... ) + or MSS_SPI_function_name( &g_mss_spi1, ... ). + The MSS_SPI_init() function resets the specified MSS SPI hardware block and + clears any pending interrupts from that MSS SPI in the Cortex-M3 NVIC. + The MSS_SPI_init() function must be called before any other MSS SPI driver + functions can be called. + + Configuration + A MSS SPI block can operate either as a master or slave SPI device. There + are two distinct functions for configuring a MSS SPI block for master or + slave operations. + + Master configuration + The MSS_SPI_configure_master_mode() function configures the specified MSS + SPI block for operations as a SPI master. It must be called once for each + remote SPI slave device the MSS SPI block will communicate with. It is used + to provide the following information about each SPI slave’s communication + characteristics: + • The SPI protocol mode + • The SPI clock speed + • The frame bit length + This information is held by the driver and will be used to alter the + configuration of the MSS SPI block each time a slave is selected through a + call to MSS_SPI_set_slave_select(). The SPI protocol mode defines the + initial state of the clock signal at the start of a transaction and which + clock edge will be used to sample the data signal, or it defines whether the + SPI block will operate in TI synchronous serial mode or in NSC MICROWIRE mode. + + Slave configuration + The MSS_SPI_configure_slave_mode() function configures the specified MSS SPI + block for operations as a SPI slave. It configures the following SPI + communication characteristics: + • The SPI protocol mode + • The SPI clock speed + • The frame bit length + The SPI protocol mode defines the initial state of the clock signal at the + start of a transaction and which clock edge will be used to sample the data + signal, or it defines whether the SPI block will operate in TI synchronous + serial mode or in NSC MICROWIRE mode. + + SPI master frame transfer control + The following functions are used as part of SPI master frame transfers: + • MSS_SPI_set_slave_select() + • MSS_SPI_transfer_frame() + • MSS_SPI_clear_slave_select() + The master must first select the target slave through a call to + MSS_SPI_set_slave_select(). This causes the relevant slave select line to + become asserted while data is clocked out onto the SPI data line. + A call to is then made to function MSS_SPI_transfer_frame() specifying and + the value of the data frame to be sent. + The function MSS_SPI_clear_slave_select() can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if the + master is communicating with multiple slave devices. + + SPI master block transfer control + The following functions are used as part of SPI master block transfers: + • MSS_SPI_set_slave_select() + • MSS_SPI_clear_slave_select() + • MSS_SPI_transfer_block() + The master must first select the target slave through a call to + MSS_SPI_set_slave_select(). This causes the relevant slave select line to + become asserted while data is clocked out onto the SPI data line. + Alternatively a GPIO can be used to control the state of the target slave + device’s chip select signal. + A call to is then made to function MSS_SPI_transfer_block (). The + parameters of this function specify: + • the number of bytes to be transmitted + • a pointer to the buffer containing the data to be transmitted + • the number of bytes to be received + • a pointer to the buffer where received data will be stored + The number of bytes to be transmitted can be set to zero to indicate that + the transfer is purely a block read transfer. The number of bytes to be + received can be set to zero to specify that the transfer is purely a block + write transfer. + The function MSS_SPI_clear_slave_select() can be used after the transfer is + complete to prevent this slave select line from being asserted during + subsequent SPI transactions. A call to this function is only required if the + master is communicating with multiple slave devices. + + SPI slave frame transfer control + The following functions are used as part of SPI slave frame transfers: + • MSS_SPI_set_slave_tx_frame() + • MSS_SPI_set_frame_rx_handler() + The MSS_SPI_set_slave_tx_frame() function specifies the frame data that will + be returned to the SPI master. The frame data specified through this + function is the value that will be read over the SPI bus by the remote SPI + master when it initiates a transaction. A call to MSS_SPI_set_slave_tx_frame() + is only required if the MSS SPI slave is the target of SPI read transactions, + i.e. if data is meant to be read from the SmartFusion device over SPI. + The MSS_SPI_set_frame_rx_handler() function specifies the receive handler + function that will called when a frame of data has been received by the MSS + SPI when it is configured as a slave. The receive handler function specified + through this call will process the frame data written, over the SPI bus, to + the MSS SPI slave by the remote SPI master. The receive handler function must + be implemented as part of the application. It is only required if the MSS SPI + slave is the target of SPI frame write transactions. + + SPI slave block transfer control + The following functions are used as part of SPI slave block transfers: + • MSS_SPI_set_slave_block_buffers() + The MSS_SPI_set_slave_block_buffers() function is used to configure a MSS SPI + slave for block transfer operations. It specifies: + • The buffer containing the data that will be returned to the remote SPI master + • The buffer where data received from the remote SPI master will be stored + • The handler function that will be called after the receive buffer is filled + + DMA block transfer control + The following functions are used as part of MSS SPI DMA transfers: + • MSS_SPI_disable() + • MSS_SPI_set_transfer_byte_count() + • MSS_SPI_enable() + • MSS_SPI_tx_done() + The MSS SPI must first be disabled through a call to function MSS_SPI_disable(). + The number of bytes to be transferred is then set through a call to function + MSS_SPI_set_transfer_byte_count(). The DMA transfer is then initiated by a call + to the MSS_PDMA_start() function provided by the MSS PDMA driver. The actual + DMA transfer will only start once the MSS SPI block has been re-enabled through + a call to MSS_SPI_enable(). The completion of the DMA driven SPI transfer can + be detected through a call to MSS_SPI_tx_done(). The direction of the SPI + transfer, write or read, depends on the DMA channel configuration. A SPI write + transfer occurs when the DMA channel is configured to write data to the MSS SPI + block. A SPI read transfer occurs when the DMA channel is configured to read data + from the MSS SPI block. + + *//*=========================================================================*/ +#ifndef MSS_SPI_H_ +#define MSS_SPI_H_ + +/* #include "../../CMSIS/m2sxxx.h" */ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + This defines the function prototype that must be followed by MSS SPI slave + frame receive handler functions. These functions are registered with the MSS + SPI driver through the MSS_SPI_set_frame_rx_handler () function. + + Declaring and Implementing Slave Frame Receive Handler Functions: + Slave frame receive handler functions should follow the following prototype: + void slave_frame_receive_handler ( uint32_t rx_frame ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_frame parameter will + contain the value of the received frame. + */ +typedef void (*mss_spi_frame_rx_handler_t)( uint32_t rx_frame ); + +/***************************************************************************//** + This defines the function prototype that must be followed by MSS SPI slave + block receive handler functions. These functions are registered with the MSS + SPI driver through the MSS_SPI_set_slave_block_buffers() function. + + Declaring and Implementing Slave Block Receive Handler Functions + Slave block receive handler functions should follow the following prototype: + void mss_spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + The actual name of the receive handler is unimportant. You can use any name + of your choice for the receive frame handler. The rx_buff parameter will + contain a pointer to the start of the received block. The rx_size parameter + will contain the number of bytes of the received block. + + */ +typedef void (*mss_spi_block_rx_handler_t)( uint8_t * rx_buff, uint32_t rx_size ); + +/***************************************************************************//** + This enumeration is used to define the settings for the SPI protocol mode + bits, CPHA and CPOL. It is used as a parameter to the MSS_SPI_configure_master_mode() + and MSS_SPI_configure_slave_mode() functions. + + - MSS_SPI_MODE0: + Clock starts low, data read on clock's rising edge, data changes on + falling edge. + + - MSS_SPI_MODE1: + Clock starts low, data read on clock's falling edge, data changes on + rising edge. + + - MSS_SPI_MODE2: + Clock starts high, data read on clock's falling edge, data changes on + rising edge. + + - MSS_SPI_MODE3: + Clock starts high, data read on clock's rising edge, data changes on + falling edge. + + - MSS_TI_MODE: + TI syncronous serial mode. Slave select is pulsed at start of transfer. + + - MSS_NSC_MODE: + NSC Microwire mode. + */ +typedef enum __mss_spi_protocol_mode_t +{ + MSS_SPI_MODE0 = 0x00000000, + MSS_SPI_TI_MODE = 0x01000004, + MSS_SPI_NSC_MODE = 0x00000008, + MSS_SPI_MODE2 = 0x01000000, + MSS_SPI_MODE1 = 0x02000000, + MSS_SPI_MODE3 = 0x03000000 +} mss_spi_protocol_mode_t; + +/***************************************************************************//** + This enumeration specifies the divider to be applied to the the APB bus clock + in order to generate the SPI clock. It is used as parameter to the + MSS_SPI_configure_master_mode() and MSS_SPI_configure_slave_mode()functions. + */ + typedef enum __mss_spi_pclk_div_t + { + MSS_SPI_PCLK_DIV_2 = 0, + MSS_SPI_PCLK_DIV_4 = 1, + MSS_SPI_PCLK_DIV_8 = 2, + MSS_SPI_PCLK_DIV_16 = 3, + MSS_SPI_PCLK_DIV_32 = 4, + MSS_SPI_PCLK_DIV_64 = 5, + MSS_SPI_PCLK_DIV_128 = 6, + MSS_SPI_PCLK_DIV_256 = 7 +} mss_spi_pclk_div_t; + +/***************************************************************************//** + This enumeration is used to select a specific SPI slave device (0 to 7). It is + used as a parameter to the MSS_SPI_configure_master_mode(), + MSS_SPI_set_slave_select() and MSS_SPI_clear_slave_select () functions. + */ + typedef enum __mss_spi_slave_t + { + MSS_SPI_SLAVE_0 = 0, + MSS_SPI_SLAVE_1 = 1, + MSS_SPI_SLAVE_2 = 2, + MSS_SPI_SLAVE_3 = 3, + MSS_SPI_SLAVE_4 = 4, + MSS_SPI_SLAVE_5 = 5, + MSS_SPI_SLAVE_6 = 6, + MSS_SPI_SLAVE_7 = 7, + MSS_SPI_MAX_NB_OF_SLAVES = 8 +} mss_spi_slave_t; + +/***************************************************************************//** + This constant defines a frame size of 8 bits when configuring an MSS SPI to + perform block transfer data transactions. + It must be used as the value for the frame_bit_length parameter of function + MSS_SPI_configure_master_mode() when performing block transfers between the + MSS SPI master and the target SPI slave. + It must also be used as the value for the frame_bit_length parameter of + function MSS_SPI_configure_slave_mode() when performing block transfers + between the MSS SPI slave and the remote SPI master. + */ +#define MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE 8 + +/***************************************************************************//** + The mss_spi_slave_cfg_t holds the MSS SPI configuration that must be used to + communicate with a specific SPI slave. + */ +typedef struct __mss_spi_slave_cfg_t +{ + uint32_t ctrl_reg; + uint8_t txrxdf_size_reg; + uint8_t clk_gen; +} mss_spi_slave_cfg_t; + +#define __IO +#define __I +#define __O + +/***************************************************************************//** + + */ +typedef struct +{ + __IO uint32_t CONTROL; + __IO uint32_t TXRXDF_SIZE; + __I uint32_t STATUS; + __O uint32_t IRQ_CLEAR; + __I uint32_t RX_DATA; + __O uint32_t TX_DATA; + __IO uint32_t CLK_GEN; + __IO uint32_t SLAVE_SELECT; + __I uint32_t MIS; + __I uint32_t RIS; + __IO uint32_t CONTROL2; + __IO uint32_t COMMAND; + __IO uint32_t _PKTSIZE; + __IO uint32_t CMDSIZE; + __IO uint32_t HWSTATUS; + __IO uint32_t STAT8; + __IO uint32_t CTRL0; + __IO uint32_t CTRL1; + __IO uint32_t CTRL2; + __IO uint32_t CTRL3; +} SPI_REVB_TypeDef; + + +typedef struct +{ + __IO uint32_t ESRAM_CR; /*0X0 */ + __IO uint32_t ESRAM_MAX_LAT_CR; /*0X4 */ + __IO uint32_t DDR_CR; /*0X8 */ + __IO uint32_t ENVM_CR; /*0XC */ + __IO uint32_t ENVM_REMAP_BASE_CR; /*0X10 */ + __IO uint32_t ENVM_REMAP_FAB_CR; /*0X14 */ + __IO uint32_t CC_CR; /*0X18 */ + __IO uint32_t CC_REGION_CR; /*0X1C */ + __IO uint32_t CC_LOCK_BASE_ADDR_CR; /*0X20 */ + __IO uint32_t CC_FLUSH_INDX_CR; /*0X24 */ + __IO uint32_t DDRB_BUF_TIMER_CR; /*0X28 */ + __IO uint32_t DDRB_NB_ADDR_CR; /*0X2C */ + __IO uint32_t DDRB_NB_SIZE_CR; /*0X30 */ + __IO uint32_t DDRB_CR; /*0X34 */ + __IO uint32_t EDAC_CR; /*0X38 */ + __IO uint32_t MASTER_WEIGHT0_CR; /*0X3C */ + __IO uint32_t MASTER_WEIGHT1_CR; /*0X40 */ + __IO uint32_t SOFT_IRQ_CR; /*0X44 */ + __IO uint32_t SOFT_RST_CR; /*0X48 */ + __IO uint32_t M3_CR; /*0X4C */ + __IO uint32_t FAB_IF_CR; /*0X50 */ + __IO uint32_t LOOPBACK_CR; /*0X54 */ + __IO uint32_t GPIO_SYSRESET_SEL_CR; /*0X58 */ + __IO uint32_t GPIN_SRC_SEL_CR; /*0X5C */ + __IO uint32_t MDDR_CR; /*0X60 */ + __IO uint32_t USB_IO_INPUT_SEL_CR; /*0X64 */ + __IO uint32_t PERIPH_CLK_MUX_SEL_CR; /*0X68 */ + __IO uint32_t WDOG_CR; /*0X6C */ + __IO uint32_t MDDR_IO_CALIB_CR; /*0X70 */ + __IO uint32_t SPARE_OUT_CR; /*0X74 */ + __IO uint32_t EDAC_IRQ_ENABLE_CR; /*0X78 */ + __IO uint32_t USB_CR; /*0X7C */ + __IO uint32_t ESRAM_PIPELINE_CR; /*0X80 */ + __IO uint32_t MSS_IRQ_ENABLE_CR; /*0X84 */ + __IO uint32_t RTC_WAKEUP_CR; /*0X88 */ + __IO uint32_t MAC_CR; /*0X8C */ + __IO uint32_t MSSDDR_PLL_STATUS_LOW_CR; /*0X90 */ + __IO uint32_t MSSDDR_PLL_STATUS_HIGH_CR; /*0X94 */ + __IO uint32_t MSSDDR_FACC1_CR; /*0X98 */ + __IO uint32_t MSSDDR_FACC2_CR; /*0X9C */ + __IO uint32_t PLL_LOCK_EN_CR; /*0XA0 */ + __IO uint32_t MSSDDR_CLK_CALIB_CR; /*0XA4 */ + __IO uint32_t PLL_DELAY_LINE_SEL_CR; /*0XA8 */ + __IO uint32_t MAC_STAT_CLRONRD_CR; /*0XAC */ + __IO uint32_t RESET_SOURCE_CR; /*0XB0 */ + __I uint32_t CC_DC_ERR_ADDR_SR; /*0XB4 */ + __I uint32_t CC_IC_ERR_ADDR_SR; /*0XB8 */ + __I uint32_t CC_SB_ERR_ADDR_SR; /*0XBC */ + __I uint32_t CC_DECC_ERR_ADDR_SR; /*0XC0 */ + __I uint32_t CC_IC_MISS_CNT_SR; /*0XC4 */ + __I uint32_t CC_IC_HIT_CNT_SR; /*0XC8 */ + __I uint32_t CC_DC_MISS_CNT_SR; /*0XCC */ + __I uint32_t CC_DC_HIT_CNT_SR; /*0XD0 */ + __I uint32_t CC_IC_TRANS_CNT_SR; /*0XD4 */ + __I uint32_t CC_DC_TRANS_CNT_SR; /*0XD8 */ + __I uint32_t DDRB_DS_ERR_ADR_SR; /*0XDC */ + __I uint32_t DDRB_HPD_ERR_ADR_SR; /*0XE0 */ + __I uint32_t DDRB_SW_ERR_ADR_SR; /*0XE4 */ + __I uint32_t DDRB_BUF_EMPTY_SR; /*0XE8 */ + __I uint32_t DDRB_DSBL_DN_SR; /*0XEC */ + __I uint32_t ESRAM0_EDAC_CNT; /*0XF0 */ + __I uint32_t ESRAM1_EDAC_CNT; /*0XF4 */ + __I uint32_t CC_EDAC_CNT; /*0XF8 */ + __I uint32_t MAC_EDAC_TX_CNT; /*0XFC */ + __I uint32_t MAC_EDAC_RX_CNT; /*0X100 */ + __I uint32_t USB_EDAC_CNT; /*0X104 */ + __I uint32_t CAN_EDAC_CNT; /*0X108 */ + __I uint32_t ESRAM0_EDAC_ADR; /*0X10C */ + __I uint32_t ESRAM1_EDAC_ADR; /*0X110 */ + __I uint32_t MAC_EDAC_RX_ADR; /*0X114 */ + __I uint32_t MAC_EDAC_TX_ADR; /*0X118 */ + __I uint32_t CAN_EDAC_ADR; /*0X11C */ + __I uint32_t USB_EDAC_ADR; /*0X120 */ + __I uint32_t MM0_1_2_SECURITY; /*0X124 */ + __I uint32_t MM4_5_FIC64_SECURITY; /*0X128 */ + __I uint32_t MM3_6_7_8_SECURITY; /*0X12C */ + __I uint32_t MM9_SECURITY; /*0X130 */ + __I uint32_t M3_SR; /*0X134 */ + __I uint32_t ETM_COUNT_LOW; /*0X138 */ + __I uint32_t ETM_COUNT_HIGH; /*0X13C */ + __I uint32_t DEVICE_SR; /*0X140 */ + __I uint32_t ENVM_PROTECT_USER; /*0X144 */ + __I uint32_t G4C_ENVM_STATUS; /*0X148 */ + __I uint32_t DEVICE_VERSION; /*0X14C */ + __I uint32_t MSSDDR_PLL_STATUS; /*0X150 */ + __I uint32_t USB_SR; /*0X154 */ + __I uint32_t ENVM_SR; /*0X158 */ + __I uint32_t SPARE_IN; /*0X15C */ + __I uint32_t DDRB_STATUS; /*0X160 */ + __I uint32_t MDDR_IO_CALIB_STATUS; /*0X164 */ + __I uint32_t MSSDDR_CLK_CALIB_STATUS; /*0X168 */ + __I uint32_t WDOGLOAD; /*0X16C */ + __I uint32_t WDOGMVRP; /*0X170 */ + __I uint32_t USERCONFIG0; /*0X174 */ + __I uint32_t USERCONFIG1; /*0X178 */ + __I uint32_t USERCONFIG2; /*0X17C */ + __I uint32_t USERCONFIG3; /*0X180 */ + __I uint32_t FAB_PROT_SIZE; /*0X184 */ + __I uint32_t FAB_PROT_BASE; /*0X188 */ + __I uint32_t MSS_GPIO_DEF; /*0X18C */ + __IO uint32_t EDAC_SR; /*0X190 */ + __IO uint32_t MSS_INTERNAL_SR; /*0X194 */ + __IO uint32_t MSS_EXTERNAL_SR; /*0X198 */ + __IO uint32_t WDOGTIMEOUTEVENT; /*0X19C */ + __IO uint32_t CLR_MSS_COUNTERS; /*0X1A0 */ + __IO uint32_t CLR_EDAC_COUNTERS; /*0X1A4 */ + __IO uint32_t FLUSH_CR; /*0X1A8 */ + __IO uint32_t MAC_STAT_CLR_CR; /*0X1AC */ + __IO uint32_t IOMUXCELL_CONFIG[57]; /*0X1B0 */ + __I uint32_t NVM_PROTECT_FACTORY; /*0X294 */ + __I uint32_t DEVICE_STATUS_FIXED; /*0X298 */ + __I uint32_t MBIST_ES0; /*0X29C */ + __I uint32_t MBIST_ES1; /*0X2A0 */ + __IO uint32_t MSDDR_PLL_STAUS_1; /*0X2A4 */ + __I uint32_t REDUNDANCY_ESRAM0; /*0X2A8 */ + __I uint32_t REDUNDANCY_ESRAM1; /*0X2AC */ + __I uint32_t SERDESIF; /*0X2B0 */ + +} SYSREG_TypeDef; + +#define SYSREG_SPI0_SOFTRESET_MASK ( (uint32_t)( 0x01 << 9) ) +#define SYSREG_SPI1_SOFTRESET_MASK ( (uint32_t)( 0x01 << 10) ) + + +typedef int IRQn_Type; +#define ASSERT(x) + +/***************************************************************************//** + There is one instance of this structure for each of the microcontroller + subsystem's SPIs. Instances of this structure are used to identify a specific + SPI. A pointer to an instance of the mss_spi_instance_t structure is passed as + the first parameter to MSS SPI driver functions to identify which SPI should + perform the requested operation. + */ +typedef struct __mss_spi_instance_t +{ + /* CMSIS related defines identifying the SPI hardware. */ + SPI_REVB_TypeDef * hw_reg; /*!< Pointer to SPI registers. */ + IRQn_Type irqn; /*!< SPI's Cortex-M3 NVIC interrupt number. */ + + /* Internal transmit state: */ + const uint8_t * slave_tx_buffer; /*!< Pointer to slave transmit buffer. */ + uint32_t slave_tx_size; /*!< Size of slave transmit buffer. */ + uint32_t slave_tx_idx; /*!< Current index into slave transmit buffer. */ + + /* Slave command response buffer: */ + const uint8_t * resp_tx_buffer; + uint32_t resp_buff_size; + uint32_t resp_buff_tx_idx; + mss_spi_block_rx_handler_t cmd_handler; + + /* Internal receive state: */ + uint8_t * slave_rx_buffer; /*!< Pointer to buffer where data received by a slave will be stored. */ + uint32_t slave_rx_size; /*!< Slave receive buffer size. */ + uint32_t slave_rx_idx; /*!< Current index into slave receive buffer. */ + + /* Configuration for each target slave. */ + mss_spi_slave_cfg_t slaves_cfg[MSS_SPI_MAX_NB_OF_SLAVES]; + + /** Slave received frame handler: */ + mss_spi_frame_rx_handler_t frame_rx_handler; /*!< Pointer to function that will be called when a frame is received when the SPI block is configured as slave. */ + + uint32_t slave_tx_frame; /*!< Value of the data frame that will be transmited when the SPI block is configured as slave. */ + + /* Slave block rx handler: */ + mss_spi_block_rx_handler_t block_rx_handler; /*!< Pointer to the function that will be called when a data block has been received. */ + +} mss_spi_instance_t; + +/***************************************************************************//** + This instance of mss_spi_instance_t holds all data related to the operations + performed by MSS SPI 0. A pointer to g_mss_spi0 is passed as the first + parameter to MSS SPI driver functions to indicate that MSS SPI 0 should + perform the requested operation. + */ +extern mss_spi_instance_t g_mss_spi0; + +/***************************************************************************//** + This instance of mss_spi_instance_t holds all data related to the operations + performed by MSS SPI 1. A pointer to g_mss_spi1 is passed as the first + parameter to MSS SPI driver functions to indicate that MSS SPI 1 should + perform the requested operation. + */ +extern volatile mss_spi_instance_t g_mss_spi1; + +/***************************************************************************//** + The MSS_SPI_init() function initializes and hardware and data structures of + one of the SmartFusion MSS SPIs. The MSS_SPI_init() function must be called + before any other MSS SPI driver functions can be called. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + Example: + @code + MSS_SPI_init( &g_mss_spi0 ); + @endcode + */ +void MSS_SPI_init +( + volatile mss_spi_instance_t * this_spi +); + +/***************************************************************************//** + The MSS_SPI_configure_slave_mode() function configure a MSS SPI block for + operations as a slave SPI device. It configures the SPI hardware with the + selected SPI protocol mode and clock speed. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + @param protocol_mode + Serial peripheral interface operating mode. Allowed values are: + - MSS_SPI_MODE0 + - MSS_SPI_MODE1 + - MSS_SPI_MODE2 + - MSS_SPI_MODE3 + - MSS_TI_MODE + - MSS_NSC_MODE + + @param clk_rate + Divider value used to generate serial interface clock signal from PCLK. + Allowed values are: + - MSS_SPI_PCLK_DIV_2 + - MSS_SPI_PCLK_DIV_4 + - MSS_SPI_PCLK_DIV_8 + - MSS_SPI_PCLK_DIV_16 + - MSS_SPI_PCLK_DIV_32 + - MSS_SPI_PCLK_DIV_64 + - MSS_SPI_PCLK_DIV_128 + - MSS_SPI_PCLK_DIV_256 + + @param frame_bit_length + Number of bits making up the frame. The maximum frame length is 32 bits. You + must use the MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE constant as the value for + frame_bit_length when configuring the MSS SPI master for block transfer + transactions with the target SPI slave. + + Example: + @code + MSS_SPI_init( &g_mss_spi0 ); + MSS_SPI_configure_slave_mode + ( + &g_mss_spi0, + MSS_SPI_MODE2, + MSS_SPI_PCLK_DIV_64, + MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE + ); + @endcode + + */ +void MSS_SPI_configure_slave_mode +( + mss_spi_instance_t * this_spi, + mss_spi_protocol_mode_t protocol_mode, + mss_spi_pclk_div_t clk_rate, + uint8_t frame_bit_length +); + +/***************************************************************************//** + The MSS_SPI_configure_master_mode() function configures the protocol mode, + serial clock speed and frame size for a specific target SPI slave device. It + is used when the MSS SPI hardware block is used as a SPI master. This function + must be called once for each target SPI slave the SPI master is going to + communicate with. The SPI master hardware will be configured with the + configuration specified by this function during calls to + MSS_SPI_set_slave_select(). + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + + @param slave + The slave parameter is used to identify a target SPI slave. The driver will + hold the MSS SPI master configuration required to communicate with this + slave, as specified by the other function parameters. Allowed values are: + • MSS_SPI_SLAVE_0 + • MSS_SPI_SLAVE_1 + • MSS_SPI_SLAVE_2 + • MSS_SPI_SLAVE_3 + • MSS_SPI_SLAVE_4 + • MSS_SPI_SLAVE_5 + • MSS_SPI_SLAVE_6 + • MSS_SPI_SLAVE_7 + + @param protocol_mode + Serial peripheral interface operating mode. Allowed values are: + • MSS_SPI_MODE0 + • MSS_SPI_MODE1 + • MSS_SPI_MODE2 + • MSS_SPI_MODE3 + • MSS_SPI_TI_MODE + • MSS_SPI_NSC_MODE + + @param clk_rate + Divider value used to generate serial interface clock signal from PCLK. + Allowed values are: + • MSS_SPI_PCLK_DIV_2 + • MSS_SPI_PCLK_DIV_4 + • MSS_SPI_PCLK_DIV_8 + • MSS_SPI_PCLK_DIV_16 + • MSS_SPI_PCLK_DIV_32 + • MSS_SPI_PCLK_DIV_64 + • MSS_SPI_PCLK_DIV_128 + • MSS_SPI_PCLK_DIV_256 + + @param frame_bit_length + Number of bits making up the frame. The maximum frame length is 32 bits. You + must use the MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE constant as the value for + frame_bit_length when configuring the MSS SPI master for block transfer + transactions with the target SPI slave. + + Example: + @code + MSS_SPI_init( &g_mss_spi0 ); + + MSS_SPI_configure_master_mode + ( + &g_mss_spi0, + MSS_SPI_SLAVE_0, + MSS_SPI_MODE2, + MSS_SPI_PCLK_DIV_64, + 12 + ); + + MSS_SPI_configure_master_mode + ( + &g_mss_spi0, + MSS_SPI_SLAVE_1, + MSS_SPI_TI_MODE, + MSS_SPI_PCLK_DIV_128, + MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE + ); + @endcode + */ +void MSS_SPI_configure_master_mode +( + volatile mss_spi_instance_t * this_spi, + mss_spi_slave_t slave, + mss_spi_protocol_mode_t protocol_mode, + mss_spi_pclk_div_t clk_rate, + uint8_t frame_bit_length +); + +/*============================================================================== + * Master functions + *============================================================================*/ + +/***************************************************************************//** + The MSS_SPI_slave_select() function is used by a MSS SPI master to select a + specific slave. This function causes the relevant slave select signal to be + asserted. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + + @param slave + The slave parameter is one of mss_spi_slave_t enumerated constants + identifying a slave. + + Example: + @code + const uint8_t frame_size = 25; + const uint32_t master_tx_frame = 0x0100A0E1; + + MSS_SPI_init( &g_mss_spi0 ); + MSS_SPI_configure_master_mode + ( + &g_mss_spi0, + MSS_SPI_SLAVE_0, + MSS_SPI_MODE1, + MSS_SPI_PCLK_DIV_256, + frame_size + ); + + MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + MSS_SPI_transfer_frame( &g_mss_spi0, master_tx_frame ); + MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + @endcode + */ +void MSS_SPI_set_slave_select +( + volatile mss_spi_instance_t * this_spi, + mss_spi_slave_t slave +); + +/***************************************************************************//** + The MSS_SPI_clear_slave_select() function is used by a MSS SPI Master to + deselect a specific slave. This function causes the relevant slave select + signal to be de-asserted. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + + @param slave + The slave parameter is one of mss_spi_slave_t enumerated constants + identifying a slave. + + Example: + @code + const uint8_t frame_size = 25; + const uint32_t master_tx_frame = 0x0100A0E1; + + MSS_SPI_init( &g_mss_spi0 ); + MSS_SPI_configure_master_mode + ( + &g_mss_spi0, + MSS_SPI_SLAVE_0, + MSS_SPI_MODE1, + MSS_SPI_PCLK_DIV_256, + frame_size + ); + MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + MSS_SPI_transfer_frame( &g_mss_spi0, master_tx_frame ); + MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + @endcode + */ +void MSS_SPI_clear_slave_select +( + mss_spi_instance_t * this_spi, + mss_spi_slave_t slave +); + +/***************************************************************************//** + The MSS_SPI_disable() function is used to temporarily disable a MSS SPI + hardware block. This function is typically used in conjunction with the + SPI_set_transfer_byte_count() function to setup a DMA controlled SPI transmit + transaction as the SPI_set_transfer_byte_count() function must only be used + when the MSS SPI hardware is disabled. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + Example: + @code + uint32_t transfer_size; + uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + transfer_size = sizeof(tx_buffer); + + MSS_SPI_disable( &g_mss_spi0 ); + MSS_SPI_set_transfer_byte_count( &g_mss_spi0, transfer_size ); + PDMA_start + ( + PDMA_CHANNEL_0, + (uint32_t)tx_buffer, + PDMA_SPI1_TX_REGISTER, + transfer_size + ); + MSS_SPI_enable( &g_mss_spi0 ); + + while ( !MSS_SPI_tx_done( &g_mss_spi0 ) ) + { + ; + } + @endcode + */ +void MSS_SPI_disable +( + volatile mss_spi_instance_t * this_spi +); + +/***************************************************************************//** + The MSS_SPI_enable() function is used to re-enable a MSS SPI hardware block + after it was disabled using the SPI_disable() function. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + Example: + @code + uint32_t transfer_size; + uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + transfer_size = sizeof(tx_buffer); + + MSS_SPI_disable( &g_mss_spi0 ); + MSS_SPI_set_transfer_byte_count( &g_mss_spi0, transfer_size ); + PDMA_start + ( + PDMA_CHANNEL_0, + (uint32_t)tx_buffer, + PDMA_SPI1_TX_REGISTER, + transfer_size + ); + MSS_SPI_enable( &g_mss_spi0 ); + + while ( !MSS_SPI_tx_done( &g_mss_spi0 ) ) + { + ; + } + @endcode + */ +void MSS_SPI_enable +( + volatile mss_spi_instance_t * this_spi +); + +/***************************************************************************//** + The MSS_SPI_set_transfer_byte_count() function is used as part of setting up + a SPI transfer using DMA. It specifies the number of bytes that must be + transferred before MSS_SPI_tx_done() indicates that the transfer is complete. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + + @param byte_count + The byte_count parameter specifies the number of bytes that must be + transferred by the SPI hardware block considering that a transaction has + been completed. + + Example: + @code + uint32_t transfer_size; + uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + transfer_size = sizeof(tx_buffer); + + MSS_SPI_disable( &g_mss_spi0 ); + + MSS_SPI_set_transfer_byte_count( &g_mss_spi0, transfer_size ); + + PDMA_start( PDMA_CHANNEL_0, (uint32_t)tx_buffer, 0x40011014, transfer_size ); + + MSS_SPI_enable( &g_mss_spi0 ); + + while ( !MSS_SPI_tx_done( &g_mss_spi0) ) + { + ; + } + @endcode + */ +void MSS_SPI_set_transfer_byte_count +( + mss_spi_instance_t * this_spi, + uint16_t byte_count +); + +/***************************************************************************//** + The MSS_SPI_tx_done() function is used to find out if a DMA controlled transfer + has completed. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + Example: + @code + uint32_t transfer_size; + uint8_t tx_buffer[8] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + transfer_size = sizeof(tx_buffer); + + MSS_SPI_disable( &g_mss_spi0 ); + + MSS_SPI_set_transfer_byte_count( &g_mss_spi0, transfer_size ); + + PDMA_start + ( + PDMA_CHANNEL_0, + (uint32_t)tx_buffer, + PDMA_SPI1_TX_REGISTER, + transfer_size + ); + + MSS_SPI_enable( &g_mss_spi0 ); + + while ( !MSS_SPI_tx_done(&g_mss_spi0) ) + { + ; + } + @endcode + */ +uint32_t MSS_SPI_tx_done +( + mss_spi_instance_t * this_spi +); + +/***************************************************************************//** + The MSS_SPI_transfer_frame() function is used by a MSS SPI master to transmit + and receive a frame up to 32 bits long. This function is typically used for + transactions with a SPI slave where the number of transmit and receive bits is + not divisible by 8. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + + @param tx_bits + The tx_bits parameter is a 32 bits word containing the value that will be + transmitted. + Note: The bit length of the value to be transmitted to the slave must be + specified as the frame_bit_length parameter in a previous call to + the MSS_SPI_configure_master() function. + + @return + This function returns a 32 bits word containing the value that is received + from the slave. + + Example: + @code + const uint8_t frame_size = 25; + const uint32_t master_tx_frame = 0x0100A0E1; + uint32_t master_rx; + + MSS_SPI_init( &g_mss_spi0 ); + MSS_SPI_configure_master_mode + ( + &g_mss_spi0, + MSS_SPI_SLAVE_0, + MSS_SPI_MODE1, + MSS_SPI_PCLK_DIV_256, + frame_size + ); + + MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + master_rx = MSS_SPI_transfer_frame( &g_mss_spi0, master_tx_frame ); + MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + @endcode + */ +uint32_t MSS_SPI_transfer_frame +( + volatile mss_spi_instance_t * this_spi, + uint32_t tx_bits +); + +/***************************************************************************//** + The MSS_SPI_transfer_block() function is used by MSS SPI masters to transmit + and receive blocks of data organized as a specified number of bytes. It can be + used for: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of the + command in a single SPI transaction. This function can be used alongside + Peripheral DMA functions to perform the actual moving to and from the SPI + hardware block using Peripheral DMA. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer containing the data that + will be sent by the master from the beginning of the transfer. This pointer + can be null (0) if the master does not need to send a command before reading + data or if the command part of the transfer is written to the SPI hardware + block using DMA. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value of 0 indicates that no data needs to + be sent to the slave. A non-zero value while the cmd_buffer pointer is 0 is + used to indicate that the command data will be written to the SPI hardware + block using DMA. + + @param rd_buffer + The rd_buffer parameter is a pointer to the buffer where the data received + from the slave after the command has been sent will be stored. + + @param rd_byte_size + The rd_byte_size parameter specifies the number of bytes to be received from + the slave and stored in the rd_buffer. A value of 0 indicates that no data + is to be read from the slave. A non-zero value while the rd_buffer pointer + is null (0) is used to specify the receive size when using DMA to read from + the slave. + Note: All bytes received from the slave, including the bytes received + while the command is sent, will be read through DMA. + + Polled write transfer example: + @code + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + MSS_SPI_init( &g_mss_spi0 ); + MSS_SPI_configure_master_mode + ( + &g_mss_spi0, + MSS_SPI_SLAVE_0, + MSS_SPI_MODE1, + MSS_SPI_PCLK_DIV_256, + MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE + ); + + MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + MSS_SPI_transfer_block + ( + &g_mss_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0 + ); + MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + @endcode + + DMA transfer example: + In this example the transmit and receive buffers are not specified as part of + the call to MSS_SPI_transfer_block(). MSS_SPI_transfer_block() will only + prepare the MSS SPI hardware for a transfer. The MSS SPI transmit hardware + FIFO is filled using one DMA channel and a second DMA channel is used to read + the content of the MSS SPI receive hardware FIFO. The transmit and receive + buffers are specified by two separate calls to PDMA_start() to initiate DMA + transfers on the channel used for transmit data and the channel used for + receive data. + @code + uint8_t master_tx_buffer[MASTER_RX_BUFFER] = + { + 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA + }; + uint8_t slave_rx_buffer[MASTER_RX_BUFFER] = + { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A + }; + MSS_SPI_init( &g_mss_spi0 ); + + MSS_SPI_configure_master_mode + ( + &g_mss_spi0, + MSS_SPI_SLAVE_0, + MSS_SPI_MODE1, + MSS_SPI_PCLK_DIV_256, + MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE + ); + MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + MSS_SPI_transfer_block( &g_mss_spi0, 0, 0, 0, 0 ); + PDMA_start + ( + PDMA_CHANNEL_1, + PDMA_SPI0_RX_REGISTER, + (uint32_t)master_rx_buffer, + sizeof(master_rx_buffer) + ); + PDMA_start + ( + PDMA_CHANNEL_2, + (uint32_t)master_tx_buffer, + PDMA_SPI0_TX_REGISTER, + sizeof(master_tx_buffer) + ); + while( PDMA_status(PDMA_CHANNEL_1) == 0 ) + { + ; + } + MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 ); + @endcode + */ +void MSS_SPI_transfer_block +( + mss_spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rd_buffer, + uint16_t rd_byte_size +); + +/*============================================================================== + * Slave functions + *============================================================================*/ + +/***************************************************************************//** + The MSS_SPI_set_frame_rx_handler() function is used by MSS SPI slaves to + specify the receive handler function that will be called by the MSS SPI driver + interrupt handler when a a frame of data is received by the MSS SPI slave. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + + @param rx_handler + The rx_handler parameter is a pointer to the frame receive handler that must + be called when a frame is received by the MSS SPI slave. + + Example: + @code + uint32_t g_slave_rx_frame = 0; + + void slave_frame_handler( uint32_t rx_frame ) + { + g_slave_rx_frame = rx_frame; + } + + int setup_slave( void ) + { + const uint16_t frame_size = 25; + MSS_SPI_init( &g_mss_spi1 ); + MSS_SPI_configure_slave_mode + ( + &g_mss_spi0, + MSS_SPI_MODE2, + MSS_SPI_PCLK_DIV_64, + frame_size + ); + MSS_SPI_set_frame_rx_handler( &g_mss_spi1, slave_frame_handler ); + } + @endcode + */ +void MSS_SPI_set_frame_rx_handler +( + mss_spi_instance_t * this_spi, + mss_spi_frame_rx_handler_t rx_handler +); + +/***************************************************************************//** + The MSS_SPI_set_slave_tx_frame() function is used by MSS SPI slaves to specify + the frame that will be transmitted when a transaction is initiated by the SPI + master. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + + @param frame_value + The frame_value parameter contains the value of the frame to be sent to the + master. + Note: The bit length of the value to be transmitted to the master must be + specified as the frame_bit_length parameter in a previous call to + the MSS_SPI_configure_slave() function. + + Example: + @code + const uint16_t frame_size = 25; + const uint32_t slave_tx_frame = 0x0110F761; + uint32_t master_rx; + + MSS_SPI_init( &g_mss_spi1 ); + MSS_SPI_configure_slave_mode + ( + &g_mss_spi0, + MSS_SPI_MODE2, + MSS_SPI_PCLK_DIV_64, + frame_size + ); + MSS_SPI_set_slave_tx_frame( &g_mss_spi1, slave_tx_frame ); + @endcode + */ +void MSS_SPI_set_slave_tx_frame +( + mss_spi_instance_t * this_spi, + uint32_t frame_value +); + +/***************************************************************************//** + The MSS_SPI_set_slave_block_buffers() function is used to configure an MSS + SPI slave for block transfer operations. It specifies one or more of the + following: + - The data that will be transmitted when accessed by a master. + - The buffer where data received from a master will be stored. + - The handler function that must be called after the receive buffer has been + filled. + - The number of bytes that must be received from the master before the receive + handler function is called. + These parameters allow the following use cases: + - Slave performing an action after receiving a block of data from a master + containing a command. The action will be performed by the receive handler + based on the content of the receive data buffer. + - Slave returning a block of data to the master. The type of information is + always the same but the actual values change over time. For example, + returning the voltage of a predefined set of analog inputs. + - Slave returning data based on a command contained in the first part of the + SPI transaction. For example, reading the voltage of the analog input + specified by the first data byte by the master. This is achieved by using + the MSS_SPI_set_slave_block_buffers() function in conjunction with + functions MSS_SPI_set_cmd_handler() and MSS_SPI_set_cmd_response(). Please + refer to the MSS_SPI_set_cmd_handler() function description for details of + this use case. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block to be initialized. There are two such + data structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and + MSS SPI 1 respectively. This parameter must point to either the g_mss_spi0 + or g_mss_spi1 global data structure defined within the SPI driver. + + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data that + will be sent to the master. This parameter can be set to 0 if the MSS SPI + slave is not intended to be the target of SPI read transactions. + + @param tx_buff_size + The tx_buff_size parameter specifies the number of bytes contained in the + tx_buffer. This parameter can be set to 0 if the MSS SPI slave is not + intended to be the target of SPI read transactions. + + @param rx_buffer + The rx_buffer parameter is a pointer to the buffer where data received from + the master will be stored. This parameter can be set to 0 if the MSS SPI + slave is not intended to be the target of SPI write or write-read + transactions. + + @param rx_buff_size + The rx_buff_size parameter specifies the size of the receive buffer. It is + also the number of bytes that must be received before the receive handler + is called, if a receive handler is specified using the block_rx_handler + parameter. This parameter can be set to 0 if the MSS SPI slave is not + intended to be the target of SPI write or write-read transactions. + + @param block_rx_handler + The block_rx_handler parameter is a pointer to a function that will be + called when the receive buffer has been filled. This parameter can be set + to 0 if the MSS SPI slave is not intended to be the target of SPI write or + write-read transactions. + + Slave performing operation based on master command: + In this example the SPI slave is configured to receive 10 bytes of data or + command from the SPI slave and process the data received from the master. + @code + uint32_t nb_of_rx_handler_calls = 0; + + void spi1_block_rx_handler_b + ( + uint8_t * rx_buff, + uint16_t rx_size + ) + { + ++nb_of_rx_handler_calls; + } + + void setup_slave( void ) + { + uint8_t slave_rx_buffer[10] = + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + + MSS_SPI_init( &g_mss_spi1 ); + MSS_SPI_configure_slave_mode + ( + &g_mss_spi0, + MSS_SPI_MODE2, + MSS_SPI_PCLK_DIV_64, + MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE + ); + + MSS_SPI_set_slave_block_buffers + ( + &g_mss_spi1, + 0, + 0, + slave_rx_buffer, + sizeof(master_tx_buffer), + spi1_block_rx_handler_b + ); + } + @endcode + + Slave responding to command example: + In this example the slave will return data based on a command sent by the + master. The first part of the transaction is handled using polled mode where + each byte returned to the master is written as part of the interrupt service + routine. The second part of the transaction, where the slave returns data + based on the command value, is sent using a DMA transfer initiated by the + receive handler. + The MSS_SPI_set_slave_block_buffers() function specifies that five bytes of + preamble data will be transmitted before the actual response is sent by the + slave. These five bytes will be transmitted while the one byte command, + followed by four turnaround bytes, is received. The turnaround bytes give + time to the slave to call the command handler and setup the PDMA transfer + that will return the response data. + + @code + #define SLAVE_NB_OF_COMMANDS 4 + #define SLAVE_PACKET_LENGTH 8 + + const uint8_t g_slave_data_array[SLAVE_NB_OF_COMMANDS][SLAVE_PACKET_LENGTH] = + { + {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, + {0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}, + {0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28}, + {0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38} + }; + + void spi1_rx_handler_d + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t index; + const uint8_t * p_response; + + index = rx_buff[0]; + + if(index < 4) + { + p_response = &g_slave_data_array[index][0]; + } + else + { + p_response = &g_slave_data_array[0][0]; + } + + PDMA_start + ( + PDMA_CHANNEL_0, + (uint32_t)p_response, + PDMA_SPI1_TX_REGISTER, + SLAVE_PACKET_LENGTH + ); + } + + void setup_slave( void ) + { + uint8_t slave_tx_buffer[16] = { 0x12, 0x34, 0x56, 0x78, 0x9A }; + + PDMA_init(); + PDMA->RATIO_HIGH_LOW = 0xFF; + PDMA_configure + ( + PDMA_CHANNEL_0, + PDMA_TO_SPI_1, + PDMA_LOW_PRIORITY | PDMA_BYTE_TRANSFER | PDMA_INC_SRC_ONE_BYTE, + PDMA_DEFAULT_WRITE_ADJ + ); + + MSS_SPI_init( &g_mss_spi1 ); + + MSS_SPI_configure_slave_mode + ( + &g_mss_spi1, + MSS_SPI_MODE1, + MSS_SPI_PCLK_DIV_256, + MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE + ); + + MSS_SPI_set_slave_block_buffers + ( + &g_mss_spi1, + slave_tx_buffer, + 5, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi1_rx_handler_d + ); + + MSS_SPI_set_cmd_handler + ( + &g_mss_spi1, + spi1_slave_cmd_handler, + 1 + ); + } + @endcode + */ +void MSS_SPI_set_slave_block_buffers +( + mss_spi_instance_t * this_spi, + const uint8_t * tx_buffer, + uint32_t tx_buff_size, + uint8_t * rx_buffer, + uint32_t rx_buff_size, + mss_spi_block_rx_handler_t block_rx_handler +); + + +/***************************************************************************//** + The MSS_SPI_set_cmd_handler() function specifies a command handler function + that will be called when the number of bytes received reaches the command size + specified as parameter. + This function is used by SPI slaves performing block transfers. Its purpose is + to allow a SPI slave to decide the data that will be returned to the master + while a SPI transaction is taking place. Typically, one of more command bytes + are sent by the master to request some specific data. The slave interprets the + command byte(s) while one or more turn-around bytes are transmitted. The + slave adjusts its transmit data buffer based on the command during the + turnaround time. + The diagram below provides an example of the use of this function where the + SPI slave returns data bytes D0 to D6 based on the value of a command. The + 3 bytes long command is made up of a command opcode byte followed by an address + byte followed by a size byte. The cmd_handler() function specified through an + earlier call to MSS_SPI_set_cmd_handler() is called by the SPI driver once the + third byte is received. The cmd_handler() function interprets the command bytes + and calls MSS_SPI_set_cmd_response() to set the SPI slave's response transmit + buffer with the data to be transmitted after the turnaround bytes (T0 to T3). + The number of turnaround bytes must be sufficient to give enough time for the + cmd_handler() to execute. The number of turnaround bytes is specified by the + protocol used on top of the SPI transport layer so that master and slave agree + on the number of turn around bytes. + + t0 t1 t2 t3 t4 + | | | | | + |------------------------------------------------------------------| + | COMMAND | TURN-AROUND | DATA | + |------------------------------------------------------------------| + | C | A | S | T0 | T1 | T2 | T4 | D0 | D1 | D2 | D3 | D4 | D5 | D6 | + |------------------------------------------------------------------| + | + | + --> cmd_handler() called here. + | + | + --> MSS_SPI_set_cmd_response() called here by + implementation of cmd_handler() to set the data + that will be transmitted by the SPI slave. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block used. There are two such data + structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI + 1 respectively. This parameter must point to either the g_mss_spi0 or + g_mss_spi1 global data structure defined within the SPI driver. + + @param cmd_handler + The cmd_handler parameter is a pointer to a function with prototype: + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + It specifies the function that will be called when the number of bytes + specified by parameter cmd_size has been received. + + @param cmd_size + The cmd_size parameter specifies the number of bytes that must be received + before the command handler function specified by cmd_handler is called. + + The example below demonstrates how to configure SPI1 to implement the protocol + given as example in the diagram above. + The configure_slave() function configures SPI1. It sets the receive and transmit + buffers. The transmit buffer specified through the call to + MSS_SPI_set_slave_block_buffers() specifies the data that will be returned to + the master in bytes between t0 and t3. These are the bytes that will be sent + to the master while the master transmits the command and dummy bytes. + The spi1_slave_cmd_handler() function will be called by the driver at time t1 + after the 3 command bytes have been received. + The spi1_block_rx_handler() function will be called by the driver at time t4 + when the transaction completes when the slave select signal becomes de-asserted. + + @code + #define COMMAND_SIZE 3 + #define NB_OF_DUMMY_BYTES 4 + #define MAX_TRANSACTION_SIZE 16 + + uint8_t slave_tx_buffer[COMMAND_SIZE + NB_OF_DUMMY_BYTES]; + uint8_t slave_rx_buffer[MAX_TRANSACTION_SIZE]; + + void configure_slave(void) + { + MSS_SPI_init( &g_mss_spi1 ); + + MSS_SPI_configure_slave_mode + ( + &g_mss_spi1, + MSS_SPI_MODE1, + MSS_SPI_PCLK_DIV_256, + MSS_SPI_BLOCK_TRANSFER_FRAME_SIZE + ); + + MSS_SPI_set_slave_block_buffers + ( + &g_mss_spi1, + slave_tx_buffer, + COMMAND_SIZE + NB_OF_DUMMY_BYTES, + slave_rx_buffer, + sizeof(slave_rx_buffer), + spi1_block_rx_handler + ); + + + MSS_SPI_set_cmd_handler + ( + &g_mss_spi1, + spi1_slave_cmd_handler, + COMMAND_SIZE + ); + } + + void spi1_slave_cmd_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + uint8_t command; + uint8_t address; + uint8_t size; + + uint8_t * p_response; + uint32_t response_size; + + command = rx_buff[0]; + address = rx_buff[1]; + size = rx_buff[2]; + + p_response = get_response_data(command, address, size, &response_size); + + MSS_SPI_set_cmd_response(&g_mss_spi1, p_response, response_size); + } + + void spi1_block_rx_handler + ( + uint8_t * rx_buff, + uint32_t rx_size + ) + { + process_rx_data(rx_buff, rx_size); + } + @endcode + */ +void MSS_SPI_set_cmd_handler +( + mss_spi_instance_t * this_spi, + mss_spi_block_rx_handler_t cmd_handler, + uint32_t cmd_size +); + +/***************************************************************************//** + The MSS_SPI_set_cmd_response() function specifies the data that will be + returned to the master. See the description of MSS_SPI_set_cmd_handler() for + details. + + @param this_spi + The this_spi parameter is a pointer to an mss_spi_instance_t structure + identifying the MSS SPI hardware block used. There are two such data + structures, g_mss_spi0 and g_mss_spi1, associated with MSS SPI 0 and MSS SPI + 1 respectively. This parameter must point to either the g_mss_spi0 or + g_mss_spi1 global data structure defined within the SPI driver. + + @param resp_tx_buffer + The resp_tx_buffer parameter is a pointer to the buffer containing the data + that must be returned to the host in the data phase of a SPI transaction. + + @param resp_buff_size + The resp_buff_size parameter specifies the size of the buffer pointed to by + the resp_tx_buffer parameter. + */ +void MSS_SPI_set_cmd_response +( + mss_spi_instance_t * this_spi, + const uint8_t * resp_tx_buffer, + uint32_t resp_buff_size +); + + +#ifdef __cplusplus +} +#endif + +#endif /* MSS_SPI_H_*/ diff --git a/board/actel/sf2-dev-kit/zl30362_config.c b/board/actel/sf2-dev-kit/zl30362_config.c new file mode 100644 index 0000000000000000000000000000000000000000..8589737f3f38b4b3a0fd86765d8ae0e13a8f3cdb --- /dev/null +++ b/board/actel/sf2-dev-kit/zl30362_config.c @@ -0,0 +1,856 @@ +/******************************************************************************* + * (c) Copyright 2012 Microsemi Corporation. All rights reserved. + * + * Configure ZL30363 device. + * + * SVN $Revision: $ + * SVN $Date: $ + */ + +#include <common.h> +#include "mss_spi/mss_spi.h" + +/*============================================================================== + * ZL30362 configuration. + * The values for this configuration were created using the ZL30362 GUI. + */ +const uint8_t g_zl30362_config[] = +{ + // ClockCenter Register Configuration File + // Exported from GUI Ver. 2.1.0, 11:39:15, Nov 26, 2012 + // Product family ZL30362 + 0x9F, // Register address 0x0: Ready indicator + 0x3E, // Register address 0x1: ID_Register + 0x02, // Register address 0x2: HW Revision + 0x00, // Register address 0x3: Reserved + 0x00, // Register address 0x4: Reserved + 0x05, // Register address 0x5: Reserved + 0xF6, // Register address 0x6: Reserved + 0xFF, // Register address 0x7: Customer identification [31:24] + 0xFF, // Register address 0x8: Customer identification [23:16] + 0xFF, // Register address 0x9: Customer identification [15:8] + 0xFF, // Register address 0xA: Customer identification [7:0] + 0x04, // Register address 0xB: Central Freq Offset [31:24] + 0x6A, // Register address 0xC: Central Freq Offset [23:16] + 0xAA, // Register address 0xD: Central Freq Offset [15:8] + 0xAB, // Register address 0xE: Central Freq Offset [7:0] + 0x00, // Register address 0xF: Reserved + 0x00, // Register address 0x10: APLL Frequency Offset + 0x00, // Register address 0x11: Sticky Lock Register + 0x00, // Register address 0x12: Reserved + 0x00, // Register address 0x13: Reserved + 0x00, // Register address 0x14: Reserved + 0x00, // Register address 0x15: Reserved + 0x00, // Register address 0x16: Reserved + 0x00, // Register address 0x17: Reserved + 0x01, // Register address 0x18: Reset Status + 0xF7, // Register address 0x19: GPIO at Startup [15:8] + 0x00, // Register address 0x1A: GPIO at Startup [7:0] + 0x00, // Register address 0x1B: Reserved + 0x00, // Register address 0x1C: Reserved + 0x00, // Register address 0x1D: Reserved + 0x00, // Register address 0x1E: Reserved + 0x00, // Register address 0x1F: Reserved + 0x00, // Register address 0x20: Reference Fail 7-0 + 0x00, // Register address 0x21: Reference Fail 10-8 + 0x00, // Register address 0x22: DPLL Status + 0x00, // Register address 0x23: Ref Fail Mask 7-0 + 0x00, // Register address 0x24: Ref Fail Mask 10-8 + 0x00, // Register address 0x25: DPLL Fail Mask + 0x1E, // Register address 0x26: Reference Monitor Fail 0 + 0x1E, // Register address 0x27: Reference Monitor Fail 1 + 0x1E, // Register address 0x28: Reference Monitor Fail 2 + 0x1E, // Register address 0x29: Reference Monitor Fail 3 + 0x1E, // Register address 0x2A: Reference Monitor Fail 4 + 0x1E, // Register address 0x2B: Reference Monitor Fail 5 + 0x1E, // Register address 0x2C: Reference Monitor Fail 6 + 0x1E, // Register address 0x2D: Reference Monitor Fail 7 + 0x1E, // Register address 0x2E: Reference Monitor Fail 8 + 0x1E, // Register address 0x2F: Reference Monitor Fail 9 + 0x1E, // Register address 0x30: Reference Monitor Fail 10 + 0x00, // Register address 0x31: Reserved + 0x00, // Register address 0x32: Reserved + 0x00, // Register address 0x33: Reserved + 0x00, // Register address 0x34: Reserved + 0x00, // Register address 0x35: Reserved + 0x16, // Register address 0x36: Reference Monitor Mask 0 + 0x16, // Register address 0x37: Reference Monitor Mask 1 + 0x16, // Register address 0x38: Reference Monitor Mask 2 + 0x16, // Register address 0x39: Reference Monitor Mask 3 + 0x16, // Register address 0x3A: Reference Monitor Mask 4 + 0x16, // Register address 0x3B: Reference Monitor Mask 5 + 0x16, // Register address 0x3C: Reference Monitor Mask 6 + 0x16, // Register address 0x3D: Reference Monitor Mask 7 + 0x16, // Register address 0x3E: Reference Monitor Mask 8 + 0x16, // Register address 0x3F: Reference Monitor Mask 9 + 0x16, // Register address 0x40: Reference Monitor Mask 10 + 0x00, // Register address 0x41: Reserved + 0x00, // Register address 0x42: Reserved + 0x00, // Register address 0x43: Reserved + 0x00, // Register address 0x44: Reserved + 0x00, // Register address 0x45: Reserved + 0xAA, // Register address 0x46: GST Disqualify Time 3-0 + 0xAA, // Register address 0x47: GST Disqualify Time 7-4 + 0x2A, // Register address 0x48: GST Disqualify Time 10-8 + 0x00, // Register address 0x49: Reserved + 0x55, // Register address 0x4A: GST Qualify Time 3-0 + 0x55, // Register address 0x4B: GST Qualify Time 7-4 + 0x15, // Register address 0x4C: GST Qualify Time 10-8 + 0x00, // Register address 0x4D: Reserved + 0x00, // Register address 0x4E: Reserved + 0x00, // Register address 0x4F: Reserved + 0x55, // Register address 0x50: SCM/CFM Limit 0 + 0x55, // Register address 0x51: SCM/CFM Limit 1 + 0x55, // Register address 0x52: SCM/CFM Limit 2 + 0x55, // Register address 0x53: SCM/CFM Limit 3 + 0x55, // Register address 0x54: SCM/CFM Limit 4 + 0x55, // Register address 0x55: SCM/CFM Limit 5 + 0x55, // Register address 0x56: SCM/CFM Limit 6 + 0x55, // Register address 0x57: SCM/CFM Limit 7 + 0x55, // Register address 0x58: SCM/CFM Limit 8 + 0x55, // Register address 0x59: SCM/CFM Limit 9 + 0x55, // Register address 0x5A: SCM/CFM Limit 10 + 0x00, // Register address 0x5B: Reserved + 0x00, // Register address 0x5C: Reserved + 0x00, // Register address 0x5D: Reserved + 0x00, // Register address 0x5E: Reserved + 0x00, // Register address 0x5F: Reserved + 0x33, // Register address 0x60: PFM Limit 1-0 + 0x33, // Register address 0x61: PFM Limit 3-2 + 0x33, // Register address 0x62: PFM Limit 5-4 + 0x33, // Register address 0x63: PFM Limit 7-6 + 0x33, // Register address 0x64: PFM Limit 9-8 + 0x03, // Register address 0x65: PFM Limit 10 + 0x00, // Register address 0x66: Reserved + 0x00, // Register address 0x67: Reserved + 0xFF, // Register address 0x68: Phase Acquisition Enable 7-0 + 0x07, // Register address 0x69: Phase Acquisition Enable 10-8 + 0x0A, // Register address 0x6A: Phase Memory Limit 0 + 0x0A, // Register address 0x6B: Phase Memory Limit 1 + 0x0A, // Register address 0x6C: Phase Memory Limit 2 + 0x0A, // Register address 0x6D: Phase Memory Limit 3 + 0x0A, // Register address 0x6E: Phase Memory Limit 4 + 0x0A, // Register address 0x6F: Phase Memory Limit 5 + 0x0A, // Register address 0x70: Phase Memory Limit 6 + 0x0A, // Register address 0x71: Phase Memory Limit 7 + 0x0A, // Register address 0x72: Phase Memory Limit 8 + 0x0A, // Register address 0x73: Phase Memory Limit 9 + 0x0A, // Register address 0x74: Phase Memory Limit 10 + 0x00, // Register address 0x75: Reserved + 0x00, // Register address 0x76: Reserved + 0x00, // Register address 0x77: Reserved + 0x00, // Register address 0x78: Reserved + 0x00, // Register address 0x79: Reserved + 0x00, // Register address 0x7A: Reference Config 7-0 + 0x00, // Register address 0x7B: Reference Config 8 + 0x00, // Register address 0x7C: Reference Pre-divide 7-0 + 0x00, // Register address 0x7D: Reference Pre-divide 10-8 + 0x00, // Register address 0x7E: Microport Status + 0x01, // Register address 0x7F: Page Select + 0x9C, // Register address 0x80: Ref0 Base Freq Br [15:8] + 0x40, // Register address 0x81: Ref0 Base Freq Br [7:0] + 0x0F, // Register address 0x82: Ref0 Frequency Multiple Kr [15:8] + 0x30, // Register address 0x83: Ref0 Frequency Multiple Kr [7:0] + 0x00, // Register address 0x84: Ref0 Numerator Mr [15:8] + 0x01, // Register address 0x85: Ref0 Numerator Mr [7:0] + 0x00, // Register address 0x86: Ref0 Denominator Nr [15:8] + 0x01, // Register address 0x87: Ref0 Denominator Nr [7:0] + 0x9C, // Register address 0x88: Ref1 Base Freq Br [15:8] + 0x40, // Register address 0x89: Ref1 Base Freq Br [7:0] + 0x01, // Register address 0x8A: Ref1 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0x8B: Ref1 Frequency Multiple Kr [7:0] + 0x00, // Register address 0x8C: Ref1 Numerator Mr [15:8] + 0x01, // Register address 0x8D: Ref1 Numerator Mr [7:0] + 0x00, // Register address 0x8E: Ref1 Denominator Nr [15:8] + 0x01, // Register address 0x8F: Ref1 Denominator Nr [7:0] + 0x9C, // Register address 0x90: Ref2 Base Freq Br [15:8] + 0x40, // Register address 0x91: Ref2 Base Freq Br [7:0] + 0x01, // Register address 0x92: Ref2 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0x93: Ref2 Frequency Multiple Kr [7:0] + 0x00, // Register address 0x94: Ref2 Numerator Mr [15:8] + 0x01, // Register address 0x95: Ref2 Numerator Mr [7:0] + 0x00, // Register address 0x96: Ref2 Denominator Nr [15:8] + 0x01, // Register address 0x97: Ref2 Denominator Nr [7:0] + 0x9C, // Register address 0x98: Ref3 Base Freq Br [15:8] + 0x40, // Register address 0x99: Ref3 Base Freq Br [7:0] + 0x01, // Register address 0x9A: Ref3 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0x9B: Ref3 Frequency Multiple Kr [7:0] + 0x00, // Register address 0x9C: Ref3 Numerator Mr [15:8] + 0x01, // Register address 0x9D: Ref3 Numerator Mr [7:0] + 0x00, // Register address 0x9E: Ref3 Denominator Nr [15:8] + 0x01, // Register address 0x9F: Ref3 Denominator Nr [7:0] + 0x9C, // Register address 0xA0: Ref4 Base Freq Br [15:8] + 0x40, // Register address 0xA1: Ref4 Base Freq Br [7:0] + 0x01, // Register address 0xA2: Ref4 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0xA3: Ref4 Frequency Multiple Kr [7:0] + 0x00, // Register address 0xA4: Ref4 Numerator Mr [15:8] + 0x01, // Register address 0xA5: Ref4 Numerator Mr [7:0] + 0x00, // Register address 0xA6: Ref4 Denominator Nr [15:8] + 0x01, // Register address 0xA7: Ref4 Denominator Nr [7:0] + 0x9C, // Register address 0xA8: Ref5 Base Freq Br [15:8] + 0x40, // Register address 0xA9: Ref5 Base Freq Br [7:0] + 0x01, // Register address 0xAA: Ref5 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0xAB: Ref5 Frequency Multiple Kr [7:0] + 0x00, // Register address 0xAC: Ref5 Numerator Mr [15:8] + 0x01, // Register address 0xAD: Ref5 Numerator Mr [7:0] + 0x00, // Register address 0xAE: Ref5 Denominator Nr [15:8] + 0x01, // Register address 0xAF: Ref5 Denominator Nr [7:0] + 0x9C, // Register address 0xB0: Ref6 Base Freq Br [15:8] + 0x40, // Register address 0xB1: Ref6 Base Freq Br [7:0] + 0x01, // Register address 0xB2: Ref6 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0xB3: Ref6 Frequency Multiple Kr [7:0] + 0x00, // Register address 0xB4: Ref6 Numerator Mr [15:8] + 0x01, // Register address 0xB5: Ref6 Numerator Mr [7:0] + 0x00, // Register address 0xB6: Ref6 Denominator Nr [15:8] + 0x01, // Register address 0xB7: Ref6 Denominator Nr [7:0] + 0x9C, // Register address 0xB8: Ref7 Base Freq Br [15:8] + 0x40, // Register address 0xB9: Ref7 Base Freq Br [7:0] + 0x01, // Register address 0xBA: Ref7 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0xBB: Ref7 Frequency Multiple Kr [7:0] + 0x00, // Register address 0xBC: Ref7 Numerator Mr [15:8] + 0x01, // Register address 0xBD: Ref7 Numerator Mr [7:0] + 0x00, // Register address 0xBE: Ref7 Denominator Nr [15:8] + 0x01, // Register address 0xBF: Ref7 Denominator Nr [7:0] + 0x9C, // Register address 0xC0: Ref8 Base Freq Br [15:8] + 0x40, // Register address 0xC1: Ref8 Base Freq Br [7:0] + 0x01, // Register address 0xC2: Ref8 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0xC3: Ref8 Frequency Multiple Kr [7:0] + 0x00, // Register address 0xC4: Ref8 Numerator Mr [15:8] + 0x01, // Register address 0xC5: Ref8 Numerator Mr [7:0] + 0x00, // Register address 0xC6: Ref8 Denominator Nr [15:8] + 0x01, // Register address 0xC7: Ref8 Denominator Nr [7:0] + 0x9C, // Register address 0xC8: Ref9 Base Freq Br [15:8] + 0x40, // Register address 0xC9: Ref9 Base Freq Br [7:0] + 0x01, // Register address 0xCA: Ref9 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0xCB: Ref9 Frequency Multiple Kr [7:0] + 0x00, // Register address 0xCC: Ref9 Numerator Mr [15:8] + 0x01, // Register address 0xCD: Ref9 Numerator Mr [7:0] + 0x00, // Register address 0xCE: Ref9 Denominator Nr [15:8] + 0x01, // Register address 0xCF: Ref9 Denominator Nr [7:0] + 0x9C, // Register address 0xD0: Ref10 Base Freq Br [15:8] + 0x40, // Register address 0xD1: Ref10 Base Freq Br [7:0] + 0x01, // Register address 0xD2: Ref10 Frequency Multiple Kr [15:8] + 0xE6, // Register address 0xD3: Ref10 Frequency Multiple Kr [7:0] + 0x00, // Register address 0xD4: Ref10 Numerator Mr [15:8] + 0x01, // Register address 0xD5: Ref10 Numerator Mr [7:0] + 0x00, // Register address 0xD6: Ref10 Denominator Nr [15:8] + 0x01, // Register address 0xD7: Ref10 Denominator Nr [7:0] + 0x00, // Register address 0xD8: Reserved + 0x00, // Register address 0xD9: Reserved + 0x00, // Register address 0xDA: Reserved + 0x00, // Register address 0xDB: Reserved + 0x00, // Register address 0xDC: Reserved + 0x00, // Register address 0xDD: Reserved + 0x00, // Register address 0xDE: Reserved + 0x00, // Register address 0xDF: Reserved + 0x00, // Register address 0xE0: Reserved + 0x00, // Register address 0xE1: Reserved + 0x00, // Register address 0xE2: Reserved + 0x00, // Register address 0xE3: Reserved + 0x00, // Register address 0xE4: Reserved + 0x00, // Register address 0xE5: Reserved + 0x00, // Register address 0xE6: Reserved + 0x00, // Register address 0xE7: Reserved + 0x00, // Register address 0xE8: Reserved + 0x00, // Register address 0xE9: Reserved + 0x00, // Register address 0xEA: Reserved + 0x00, // Register address 0xEB: Reserved + 0x10, // Register address 0xEC: Clock Sync Pulse 1-0 + 0x32, // Register address 0xED: Clock Sync Pulse 3-2 + 0x54, // Register address 0xEE: Clock Sync Pulse 5-4 + 0x76, // Register address 0xEF: Clock Sync Pulse 7-6 + 0x98, // Register address 0xF0: Clock Sync Pulse 9-8 + 0x0A, // Register address 0xF1: Clock Sync Pulse 10 + 0x00, // Register address 0xF2: Reserved + 0x00, // Register address 0xF3: Reserved + 0x00, // Register address 0xF4: Reserved + 0x00, // Register address 0xF5: Reserved + 0x00, // Register address 0xF6: Reserved + 0x00, // Register address 0xF7: Reserved + 0x00, // Register address 0xF8: Reserved + 0x00, // Register address 0xF9: Reserved + 0x00, // Register address 0xFA: Reserved + 0x00, // Register address 0xFB: Reserved + 0x00, // Register address 0xFC: Reserved + 0x00, // Register address 0xFD: Reserved + 0x00, // Register address 0xFE: Reserved + 0x02, // Register address 0xFF: Page Select + 0x0C, // Register address 0x100: DPLL0 Control + 0x00, // Register address 0x101: DPLL0 Bandwidth Select + 0x00, // Register address 0x102: DPLL0 Pull-in/Hold-in Select + 0x00, // Register address 0x103: DPLL0 Mode/Reference Select + 0x00, // Register address 0x104: DPLL0 Reference Select Status + 0x10, // Register address 0x105: DPLL0 Ref Priority 1-0 + 0x32, // Register address 0x106: DPLL0 Ref Priority 3-2 + 0x54, // Register address 0x107: DPLL0 Ref Priority 5-4 + 0x76, // Register address 0x108: DPLL0 Ref Priority 7-6 + 0x98, // Register address 0x109: DPLL0 Ref Priority 9-8 + 0x0A, // Register address 0x10A: DPLL0 Ref Priority 10 + 0x00, // Register address 0x10B: Reserved + 0x00, // Register address 0x10C: Reserved + 0x87, // Register address 0x10D: DPLL0 Ref Fail Mask + 0x01, // Register address 0x10E: DPLL0 PFM Fail Mask + 0x0B, // Register address 0x10F: DPLL0 Holdover Delay/Edge Sel + 0x00, // Register address 0x110: DPLL0 Phase Buildout Control + 0x23, // Register address 0x111: DPLL0 PBO Phase Error Threshold + 0x70, // Register address 0x112: DPLL0 PBO Min Phase Slope + 0x20, // Register address 0x113: DPLL0 PBO End Interval + 0x64, // Register address 0x114: DPLL0 PBO Timeout + 0x00, // Register address 0x115: DPLL0 PBO Counter + 0x00, // Register address 0x116: DPLL0 PBO Error Count [23:16] + 0x00, // Register address 0x117: DPLL0 PBO Error Count [15:8] + 0x00, // Register address 0x118: DPLL0 PBO Error Count [7:0] + 0x05, // Register address 0x119: Reserved + 0x05, // Register address 0x11A: Reserved + 0x00, // Register address 0x11B: Reserved + 0x00, // Register address 0x11C: Reserved + 0x00, // Register address 0x11D: Reserved + 0x00, // Register address 0x11E: Reserved + 0x00, // Register address 0x11F: Reserved + 0x0C, // Register address 0x120: DPLL1 Control + 0x00, // Register address 0x121: DPLL1 Bandwidth Select + 0x00, // Register address 0x122: DPLL1 Pull-in/Hold-in Select + 0x03, // Register address 0x123: DPLL1 Mode/Reference Select + 0x00, // Register address 0x124: DPLL1 Reference Select Status + 0x10, // Register address 0x125: DPLL1 Ref Priority 1-0 + 0x32, // Register address 0x126: DPLL1 Ref Priority 3-2 + 0x54, // Register address 0x127: DPLL1 Ref Priority 5-4 + 0x76, // Register address 0x128: DPLL1 Ref Priority 7-6 + 0x98, // Register address 0x129: DPLL1 Ref Priority 9-8 + 0x0A, // Register address 0x12A: DPLL1 Ref Priority 10 + 0x00, // Register address 0x12B: Reserved + 0x00, // Register address 0x12C: Reserved + 0x87, // Register address 0x12D: DPLL1 Ref Fail Mask + 0x01, // Register address 0x12E: DPLL1 PFM Fail Mask + 0x0B, // Register address 0x12F: DPLL1 Holdover Delay/Edge Sel + 0x00, // Register address 0x130: DPLL1 Phase Buildout Control + 0x23, // Register address 0x131: DPLL1 PBO Jitter Threshold + 0x70, // Register address 0x132: DPLL1 PBO Min Phase Slope + 0x20, // Register address 0x133: DPLL1 PBO End Interval + 0x64, // Register address 0x134: DPLL1 PBO Timeout + 0x00, // Register address 0x135: DPLL1 PBO Counter + 0x00, // Register address 0x136: DPLL1 PBO Error Count [23:16] + 0x00, // Register address 0x137: DPLL1 PBO Error Count [15:8] + 0x00, // Register address 0x138: DPLL1 PBO Error Count [7:0] + 0x05, // Register address 0x139: Reserved + 0x05, // Register address 0x13A: Reserved + 0x00, // Register address 0x13B: Reserved + 0x00, // Register address 0x13C: Reserved + 0x00, // Register address 0x13D: Reserved + 0x00, // Register address 0x13E: Reserved + 0x00, // Register address 0x13F: Reserved + 0x0C, // Register address 0x140: DPLL2 Control + 0x00, // Register address 0x141: DPLL2 Bandwidth Select + 0x00, // Register address 0x142: DPLL2 Pull-in/Hold-in Select + 0x03, // Register address 0x143: DPLL2 Mode/Reference Select + 0x00, // Register address 0x144: DPLL2 Reference Select Status + 0x10, // Register address 0x145: DPLL2 Ref Priority 1-0 + 0x32, // Register address 0x146: DPLL2 Ref Priority 3-2 + 0x54, // Register address 0x147: DPLL2 Ref Priority 5-4 + 0x76, // Register address 0x148: DPLL2 Ref Priority 7-6 + 0x98, // Register address 0x149: DPLL2 Ref Priority 9-8 + 0x0A, // Register address 0x14A: DPLL2 Ref Priority 10 + 0x00, // Register address 0x14B: Reserved + 0x00, // Register address 0x14C: Reserved + 0x87, // Register address 0x14D: DPLL2 Ref Fail Mask + 0x01, // Register address 0x14E: DPLL2 PFM Fail Mask + 0x0B, // Register address 0x14F: DPLL2 Holdover Delay/Edge Sel + 0x00, // Register address 0x150: DPLL2 Phase Buildout Control + 0x23, // Register address 0x151: DPLL2 PBO Jitter Threshold + 0x70, // Register address 0x152: DPLL2 PBO Min Phase Slope + 0x20, // Register address 0x153: DPLL2 PBO End Interval + 0x64, // Register address 0x154: DPLL2 PBO Timeout + 0x00, // Register address 0x155: DPLL2 PBO Counter + 0x00, // Register address 0x156: DPLL2 PBO Error Count [23:16] + 0x00, // Register address 0x157: DPLL2 PBO Error Count [15:8] + 0x00, // Register address 0x158: DPLL2 PBO Error Count [7:0] + 0x05, // Register address 0x159: Reserved + 0x05, // Register address 0x15A: Reserved + 0x00, // Register address 0x15B: Reserved + 0x00, // Register address 0x15C: Reserved + 0x00, // Register address 0x15D: Reserved + 0x00, // Register address 0x15E: Reserved + 0x00, // Register address 0x15F: Reserved + 0x0C, // Register address 0x160: DPLL3 Control + 0x00, // Register address 0x161: DPLL3 Bandwidth Select + 0x00, // Register address 0x162: DPLL3 Pull-in/Hold-in Select + 0x00, // Register address 0x163: DPLL3 Mode/Reference Select + 0x00, // Register address 0x164: DPLL3 Reference Select Status + 0x10, // Register address 0x165: DPLL3 Ref Priority 1-0 + 0x32, // Register address 0x166: DPLL3 Ref Priority 3-2 + 0x54, // Register address 0x167: DPLL3 Ref Priority 5-4 + 0x76, // Register address 0x168: DPLL3 Ref Priority 7-6 + 0x98, // Register address 0x169: DPLL3 Ref Priority 9-8 + 0x0A, // Register address 0x16A: DPLL3 Ref Priority 10 + 0x00, // Register address 0x16B: Reserved + 0x00, // Register address 0x16C: Reserved + 0x87, // Register address 0x16D: DPLL3 Ref Fail Mask + 0x01, // Register address 0x16E: DPLL3 PFM Fail Mask + 0x0B, // Register address 0x16F: DPLL3 Holdover Delay/Edge Sel + 0x00, // Register address 0x170: DPLL3 Phase Buildout Control + 0x23, // Register address 0x171: DPLL3 PBO Jitter Threshold + 0x70, // Register address 0x172: DPLL3 PBO Min Phase Slope + 0x20, // Register address 0x173: DPLL3 PBO End Interval + 0x64, // Register address 0x174: DPLL3 PBO Timeout + 0x00, // Register address 0x175: DPLL3 PBO Counter + 0x00, // Register address 0x176: DPLL3 PBO Error Count [23:16] + 0x00, // Register address 0x177: DPLL3 PBO Error Count [15:8] + 0x00, // Register address 0x178: DPLL3 PBO Error Count [7:0] + 0x05, // Register address 0x179: Reserved + 0x05, // Register address 0x17A: Reserved + 0x00, // Register address 0x17B: Reserved + 0x00, // Register address 0x17C: Reserved + 0x00, // Register address 0x17D: Reserved + 0x00, // Register address 0x17E: Reserved + 0x03, // Register address 0x17F: Page Select + 0x14, // Register address 0x180: DPLL Hold/Lock Status + 0x00, // Register address 0x181: External Feedback Control + 0x04, // Register address 0x182: DPLL Configuration + 0x00, // Register address 0x183: DPLL Lock Selection + 0x00, // Register address 0x184: DPLL 1pps Alignment + 0x00, // Register address 0x185: Reserved + 0x00, // Register address 0x186: Reserved + 0x00, // Register address 0x187: Reserved + 0x00, // Register address 0x188: Reserved + 0x00, // Register address 0x189: Reserved + 0x00, // Register address 0x18A: Reserved + 0x00, // Register address 0x18B: Reserved + 0x00, // Register address 0x18C: Reserved + 0x00, // Register address 0x18D: DPLL0 Delta Freq Offset [39:32] + 0x00, // Register address 0x18E: DPLL0 Delta Freq Offset [31:24] + 0x00, // Register address 0x18F: DPLL0 Delta Freq Offset [23:16] + 0x00, // Register address 0x190: DPLL0 Delta Freq Offset [15:8] + 0x00, // Register address 0x191: DPLL0 Delta Freq Offset [7:0] + 0x00, // Register address 0x192: DPLL1 Delta Freq Offset [39:32] + 0x00, // Register address 0x193: DPLL1 Delta Freq Offset [31:24] + 0x00, // Register address 0x194: DPLL1 Delta Freq Offset [23:16] + 0x00, // Register address 0x195: DPLL1 Delta Freq Offset [15:8] + 0x00, // Register address 0x196: DPLL1 Delta Freq Offset [7:0] + 0x00, // Register address 0x197: DPLL2 Delta Freq Offset [39:32] + 0x00, // Register address 0x198: DPLL2 Delta Freq Offset [31:24] + 0x00, // Register address 0x199: DPLL2 Delta Freq Offset [23:16] + 0x00, // Register address 0x19A: DPLL2 Delta Freq Offset [15:8] + 0x00, // Register address 0x19B: DPLL2 Delta Freq Offset [7:0] + 0x00, // Register address 0x19C: DPLL3 Delta Freq Offset [39:32] + 0x00, // Register address 0x19D: DPLL3 Delta Freq Offset [31:24] + 0x00, // Register address 0x19E: DPLL3 Delta Freq Offset [23:16] + 0x00, // Register address 0x19F: DPLL3 Delta Freq Offset [15:8] + 0x00, // Register address 0x1A0: DPLL3 Delta Freq Offset [7:0] + 0x00, // Register address 0x1A1: Reserved + 0x00, // Register address 0x1A2: Reserved + 0x00, // Register address 0x1A3: Reserved + 0x00, // Register address 0x1A4: Reserved + 0x00, // Register address 0x1A5: Reserved + 0x00, // Register address 0x1A6: Reserved + 0x00, // Register address 0x1A7: Reserved + 0x00, // Register address 0x1A8: Reserved + 0x00, // Register address 0x1A9: Reserved + 0x00, // Register address 0x1AA: Reserved + 0x00, // Register address 0x1AB: Reserved + 0x00, // Register address 0x1AC: Reserved + 0x00, // Register address 0x1AD: Reserved + 0x00, // Register address 0x1AE: Reserved + 0x00, // Register address 0x1AF: Reserved + 0xE4, // Register address 0x1B0: DPLL->Synth Drive Select + 0x0B, // Register address 0x1B1: Synthesizer Enable + 0x00, // Register address 0x1B2: Synthesizer Filter Select + 0x00, // Register address 0x1B3: Reserved + 0x00, // Register address 0x1B4: Reserved + 0x00, // Register address 0x1B5: Synth Prescale Select + 0x02, // Register address 0x1B6: Synth fail Status + 0x00, // Register address 0x1B7: Synth Clear Fail Flag + 0x61, // Register address 0x1B8: Synth0 Base Frequency Bs [15:8] + 0xA8, // Register address 0x1B9: Synth0 Base Frequency Bs [7:0] + 0x09, // Register address 0x1BA: Synth0 Freq Multiple Ks [15:8] + 0xC4, // Register address 0x1BB: Synth0 Freq Multiple Ks [7:0] + 0x00, // Register address 0x1BC: Synth0 Numerator Ms [15:8] + 0x01, // Register address 0x1BD: Synth0 Numerator Ms [7:0] + 0x00, // Register address 0x1BE: Synth0 Denominator Ns [15:8] + 0x01, // Register address 0x1BF: Synth0 Denominator Ns [7:0] + 0x61, // Register address 0x1C0: Synth1 Base Frequency [15:8] + 0xA8, // Register address 0x1C1: Synth1 Base Frequency [7:0] + 0x0C, // Register address 0x1C2: Synth1 Freq Multiple Ks [15:8] + 0x35, // Register address 0x1C3: Synth1 Freq Multiple Ks [7:0] + 0x00, // Register address 0x1C4: Synth1 Numerator Ms [15:8] + 0x01, // Register address 0x1C5: Synth1 Numerator Ms [7:0] + 0x00, // Register address 0x1C6: Synth1 Denominator Ns [15:8] + 0x01, // Register address 0x1C7: Synth1 Denominator Ns [7:0] + 0x9C, // Register address 0x1C8: Synth2 Base Frequency [15:8] + 0x40, // Register address 0x1C9: Synth2 Base Frequency [7:0] + 0x07, // Register address 0x1CA: Synth2 Freq Multiple Ks [15:8] + 0x98, // Register address 0x1CB: Synth2 Freq Multiple Ks [7:0] + 0x00, // Register address 0x1CC: Synth2 Numerator Ms [15:8] + 0x01, // Register address 0x1CD: Synth2 Numerator Ms [7:0] + 0x00, // Register address 0x1CE: Synth2 Denominator Ns [15:8] + 0x01, // Register address 0x1CF: Synth2 Denominator Ns [7:0] + 0x61, // Register address 0x1D0: Synth3 Base Frequency [15:8] + 0xA8, // Register address 0x1D1: Synth3 Base Frequency [7:0] + 0x09, // Register address 0x1D2: Synth3 Freq Multiple Ks [15:8] + 0xC4, // Register address 0x1D3: Synth3 Freq Multiple Ks [7:0] + 0x00, // Register address 0x1D4: Synth3 Numerator Ms [15:8] + 0x01, // Register address 0x1D5: Synth3 Numerator Ms [7:0] + 0x00, // Register address 0x1D6: Synth3 Denominator Ns [15:8] + 0x01, // Register address 0x1D7: Synth3 Denominator Ns [7:0] + 0x00, // Register address 0x1D8: Reserved + 0x00, // Register address 0x1D9: Reserved + 0x00, // Register address 0x1DA: Reserved + 0x00, // Register address 0x1DB: Reserved + 0x00, // Register address 0x1DC: Reserved + 0x00, // Register address 0x1DD: Reserved + 0x00, // Register address 0x1DE: Reserved + 0x00, // Register address 0x1DF: Reserved + 0x00, // Register address 0x1E0: Reserved + 0x00, // Register address 0x1E1: Reserved + 0x00, // Register address 0x1E2: Reserved + 0x00, // Register address 0x1E3: Reserved + 0x00, // Register address 0x1E4: Reserved + 0x00, // Register address 0x1E5: Reserved + 0x00, // Register address 0x1E6: Reserved + 0x00, // Register address 0x1E7: Reserved + 0x00, // Register address 0x1E8: Reserved + 0x00, // Register address 0x1E9: Reserved + 0x00, // Register address 0x1EA: Reserved + 0x00, // Register address 0x1EB: Reserved + 0x00, // Register address 0x1EC: Reserved + 0x00, // Register address 0x1ED: Reserved + 0x00, // Register address 0x1EE: Reserved + 0x00, // Register address 0x1EF: Reserved + 0x00, // Register address 0x1F0: Reserved + 0x00, // Register address 0x1F1: Reserved + 0x00, // Register address 0x1F2: Reserved + 0x00, // Register address 0x1F3: Reserved + 0x00, // Register address 0x1F4: Reserved + 0x00, // Register address 0x1F5: Reserved + 0x00, // Register address 0x1F6: Reserved + 0x00, // Register address 0x1F7: Reserved + 0x00, // Register address 0x1F8: Reserved + 0x00, // Register address 0x1F9: Reserved + 0x00, // Register address 0x1FA: Reserved + 0x00, // Register address 0x1FB: Reserved + 0x00, // Register address 0x1FC: Reserved + 0x00, // Register address 0x1FD: Reserved + 0x00, // Register address 0x1FE: Reserved + 0x04, // Register address 0x1FF: Page Select + 0x00, // Register address 0x200: Synth 0A Post Divide [23:16] + 0x00, // Register address 0x201: Synth 0A Post Divide [15:8] + 0x08, // Register address 0x202: Synth 0A Post Divide [7:0] + 0x00, // Register address 0x203: Synth 0B Post Divide [23:16] + 0x00, // Register address 0x204: Synth 0B Post Divide [15:8] + 0x08, // Register address 0x205: Synth 0B Post Divide [7:0] + 0x00, // Register address 0x206: Synth 0C Post Divide [23:16] + 0x00, // Register address 0x207: Synth 0C Post Divide [15:8] + 0x28, // Register address 0x208: Synth 0C Post Divide [7:0] + 0x00, // Register address 0x209: Synth 0D Post Divide [23:16] + 0x00, // Register address 0x20A: Synth 0D Post Divide [15:8] + 0x08, // Register address 0x20B: Synth 0D Post Divide [7:0] + 0x00, // Register address 0x20C: Synth 1A Post Divide [23:16] + 0x00, // Register address 0x20D: Synth 1A Post Divide [15:8] + 0x02, // Register address 0x20E: Synth 1A Post Divide [7:0] + 0x00, // Register address 0x20F: Synth 1B Post Divide [23:16] + 0x00, // Register address 0x210: Synth 1B Post Divide [15:8] + 0x02, // Register address 0x211: Synth 1B Post Divide [7:0] + 0x00, // Register address 0x212: Synth 1C Post Divide [23:16] + 0x00, // Register address 0x213: Synth 1C Post Divide [15:8] + 0x32, // Register address 0x214: Synth 1C Post Divide [7:0] + 0x00, // Register address 0x215: Synth 1D Post Divide [23:16] + 0x00, // Register address 0x216: Synth 1D Post Divide [15:8] + 0x32, // Register address 0x217: Synth 1D Post Divide [7:0] + 0x00, // Register address 0x218: Synth 2A Post Divide [23:16] + 0x00, // Register address 0x219: Synth 2A Post Divide [15:8] + 0x00, // Register address 0x21A: Synth 2A Post Divide [7:0] + 0x00, // Register address 0x21B: Synth 2B Post Divide [23:16] + 0x00, // Register address 0x21C: Synth 2B Post Divide [15:8] + 0x00, // Register address 0x21D: Synth 2B Post Divide [7:0] + 0x00, // Register address 0x21E: Synth 2C Post Divide [23:16] + 0x00, // Register address 0x21F: Synth 2C Post Divide [15:8] + 0x00, // Register address 0x220: Synth 2C Post Divide [7:0] + 0x00, // Register address 0x221: Synth 2D Post Divide [23:16] + 0x00, // Register address 0x222: Synth 2D Post Divide [15:8] + 0x00, // Register address 0x223: Synth 2D Post Divide [7:0] + 0x00, // Register address 0x224: Synth 3A Post Divide [23:16] + 0x00, // Register address 0x225: Synth 3A Post Divide [15:8] + 0x08, // Register address 0x226: Synth 3A Post Divide [7:0] + 0x00, // Register address 0x227: Synth 3B Post Divide [23:16] + 0x00, // Register address 0x228: Synth 3B Post Divide [15:8] + 0x08, // Register address 0x229: Synth 3B Post Divide [7:0] + 0x00, // Register address 0x22A: Synth 3C Post Divide [23:16] + 0x00, // Register address 0x22B: Synth 3C Post Divide [15:8] + 0x28, // Register address 0x22C: Synth 3C Post Divide [7:0] + 0x00, // Register address 0x22D: Synth 3D Post Divide [23:16] + 0x00, // Register address 0x22E: Synth 3D Post Divide [15:8] + 0x08, // Register address 0x22F: Synth 3D Post Divide [7:0] + 0x00, // Register address 0x230: Reserved + 0x00, // Register address 0x231: Reserved + 0x00, // Register address 0x232: Reserved + 0x00, // Register address 0x233: Reserved + 0x00, // Register address 0x234: Synth 0C Post Div Phase [15:8] + 0x00, // Register address 0x235: Synth 0C Post Div Phase [7:0] + 0x00, // Register address 0x236: Synth 0D Post Div Phase [15:8] + 0x00, // Register address 0x237: Synth 0D Post Div Phase [7:0] + 0x00, // Register address 0x238: Reserved + 0x00, // Register address 0x239: Reserved + 0x00, // Register address 0x23A: Reserved + 0x00, // Register address 0x23B: Reserved + 0x00, // Register address 0x23C: Synth 1C Post Div Phase [15:8] + 0x00, // Register address 0x23D: Synth 1C Post Div Phase [7:0] + 0x00, // Register address 0x23E: Synth 1D Post Div Phase [15:8] + 0x00, // Register address 0x23F: Synth 1D Post Div Phase [7:0] + 0x00, // Register address 0x240: Reserved + 0x00, // Register address 0x241: Reserved + 0x00, // Register address 0x242: Reserved + 0x00, // Register address 0x243: Reserved + 0x00, // Register address 0x244: Synth 2C Post Div Phase [15:8] + 0x00, // Register address 0x245: Synth 2C Post Div Phase [7:0] + 0x00, // Register address 0x246: Synth 2D Post Div Phase [15:8] + 0x00, // Register address 0x247: Synth 2D Post Div Phase [7:0] + 0x00, // Register address 0x248: Reserved + 0x00, // Register address 0x249: Reserved + 0x00, // Register address 0x24A: Reserved + 0x00, // Register address 0x24B: Reserved + 0x00, // Register address 0x24C: Synth 3C Post Div Phase [15:8] + 0x00, // Register address 0x24D: Synth 3C Post Div Phase [7:0] + 0x00, // Register address 0x24E: Synth 3D Post Div Phase [15:8] + 0x00, // Register address 0x24F: Synth 3D Post Div Phase [7:0] + 0x00, // Register address 0x250: Synth0 Skew + 0x00, // Register address 0x251: Synth1 Skew + 0x00, // Register address 0x252: Synth2 Skew + 0x00, // Register address 0x253: Synth3 Skew + 0x00, // Register address 0x254: Synth Stop Clock 1-0 + 0x00, // Register address 0x255: Synth Stop Clock 3-2 + 0x00, // Register address 0x256: Reserved + 0x00, // Register address 0x257: Reserved + 0x00, // Register address 0x258: Reserved + 0x00, // Register address 0x259: Reserved + 0x00, // Register address 0x25A: Reserved + 0x00, // Register address 0x25B: Reserved + 0x00, // Register address 0x25C: Reserved + 0x00, // Register address 0x25D: Reserved + 0x00, // Register address 0x25E: Reserved + 0x00, // Register address 0x25F: Reserved + 0x00, // Register address 0x260: Reserved + 0xC3, // Register address 0x261: HP Diff Output Enable + 0x03, // Register address 0x262: HP CMOS Output Enable + 0xFF, // Register address 0x263: HP Ouput Reduced Drive + 0xFF, // Register address 0x264: HP CMOS Drive 3-0 + 0xFF, // Register address 0x265: HP CMOS Drive 7-4 + 0x00, // Register address 0x266: GPIO-0 Select/Status + 0x00, // Register address 0x267: GPIO-1 Select/Status + 0x60, // Register address 0x268: GPIO-2 Select/Status + 0x00, // Register address 0x269: GPIO-3 Select/Status + 0x00, // Register address 0x26A: GPIO-4 Select/Status + 0x00, // Register address 0x26B: GPIO-5 Select/Status + 0x00, // Register address 0x26C: GPIO-6 Select/Status + 0x00, // Register address 0x26D: Reserved + 0x00, // Register address 0x26E: Reserved + 0x00, // Register address 0x26F: Reserved + 0x00, // Register address 0x270: Reserved + 0x00, // Register address 0x271: Reserved + 0x00, // Register address 0x272: Reserved + 0x00, // Register address 0x273: Reserved + 0x00, // Register address 0x274: Reserved + 0x00, // Register address 0x275: Reserved + 0x00, // Register address 0x276: GPIO Input 7-0 + 0xF7, // Register address 0x277: Reserved + 0x00, // Register address 0x278: GPIO Output 7-0 + 0x00, // Register address 0x279: Reserved + 0x00, // Register address 0x27A: GPIO Output Enable 7-0 + 0x00, // Register address 0x27B: Reserved + 0x00, // Register address 0x27C: GPIO Freeze 7-0 + 0x00, // Register address 0x27D: Reserved + 0x00, // Register address 0x27E: Reserved + 0x05, // Register address 0x27F: Page Select + 0x00, // Register address 0x280: Reserved + 0x00, // Register address 0x281: Reserved + 0x00, // Register address 0x282: Reserved + 0x00, // Register address 0x283: Reserved + 0x00, // Register address 0x284: Reserved + 0x00, // Register address 0x285: Reserved + 0x00, // Register address 0x286: Reserved + 0x00, // Register address 0x287: Reserved + 0x00, // Register address 0x288: Reserved + 0x00, // Register address 0x289: Reserved + 0x00, // Register address 0x28A: Reserved + 0x00, // Register address 0x28B: Reserved + 0x00, // Register address 0x28C: Reserved + 0x00, // Register address 0x28D: Reserved + 0x00, // Register address 0x28E: Reserved + 0x00, // Register address 0x28F: Reserved + 0x00, // Register address 0x290: Reserved + 0x00, // Register address 0x291: Reserved + 0x00, // Register address 0x292: Reserved + 0x00, // Register address 0x293: Reserved + 0x00, // Register address 0x294: Reserved + 0x00, // Register address 0x295: Reserved + 0x00, // Register address 0x296: Reserved + 0x00, // Register address 0x297: Reserved + 0x00, // Register address 0x298: Reserved + 0x00, // Register address 0x299: Reserved + 0x00, // Register address 0x29A: Reserved + 0x00, // Register address 0x29B: Reserved + 0x00, // Register address 0x29C: Reserved + 0x00, // Register address 0x29D: Reserved + 0x00, // Register address 0x29E: Reserved + 0x00, // Register address 0x29F: Reserved + 0x00, // Register address 0x2A0: Reserved + 0x00, // Register address 0x2A1: Reserved + 0x00, // Register address 0x2A2: Reserved + 0x00, // Register address 0x2A3: Reserved + 0x00, // Register address 0x2A4: Reserved + 0x00, // Register address 0x2A5: Reserved + 0x00, // Register address 0x2A6: Reserved + 0x00, // Register address 0x2A7: Reserved + 0x00, // Register address 0x2A8: Reserved + 0x00, // Register address 0x2A9: Reserved + 0x00, // Register address 0x2AA: Reserved + 0x00, // Register address 0x2AB: Reserved + 0x00, // Register address 0x2AC: Reserved + 0x00, // Register address 0x2AD: Reserved + 0x00, // Register address 0x2AE: Reserved + 0x00, // Register address 0x2AF: Reserved + 0x00, // Register address 0x2B0: Reserved + 0x00, // Register address 0x2B1: Reserved + 0x00, // Register address 0x2B2: Reserved + 0x00, // Register address 0x2B3: Reserved + 0x00, // Register address 0x2B4: Reserved + 0x00, // Register address 0x2B5: Reserved + 0x00, // Register address 0x2B6: Reserved + 0x00, // Register address 0x2B7: Reserved + 0x00, // Register address 0x2B8: Reserved + 0x00, // Register address 0x2B9: Reserved + 0x00, // Register address 0x2BA: Reserved + 0x00, // Register address 0x2BB: Reserved + 0x00, // Register address 0x2BC: Reserved + 0x00, // Register address 0x2BD: Reserved + 0x00, // Register address 0x2BE: Reserved + 0x00, // Register address 0x2BF: Reserved + 0x00, // Register address 0x2C0: Reserved + 0x00, // Register address 0x2C1: Reserved + 0x00, // Register address 0x2C2: Reserved + 0x00, // Register address 0x2C3: Reserved + 0x00, // Register address 0x2C4: Reserved + 0x00, // Register address 0x2C5: Reserved + 0x00, // Register address 0x2C6: Reserved + 0x00, // Register address 0x2C7: Reserved + 0x00, // Register address 0x2C8: Reserved + 0x00, // Register address 0x2C9: Reserved + 0x00, // Register address 0x2CA: Reserved + 0x00, // Register address 0x2CB: Reserved + 0x00, // Register address 0x2CC: Reserved + 0x00, // Register address 0x2CD: Reserved + 0x00, // Register address 0x2CE: Reserved + 0x00, // Register address 0x2CF: Reserved + 0x00, // Register address 0x2D0: Reserved + 0x00, // Register address 0x2D1: Reserved + 0x00, // Register address 0x2D2: Reserved + 0x00, // Register address 0x2D3: Reserved + 0x00, // Register address 0x2D4: Reserved + 0x00, // Register address 0x2D5: Reserved + 0x00, // Register address 0x2D6: Reserved + 0x00, // Register address 0x2D7: Reserved + 0x00, // Register address 0x2D8: Reserved + 0x00, // Register address 0x2D9: Reserved + 0x00, // Register address 0x2DA: Reserved + 0x00, // Register address 0x2DB: Reserved + 0x00, // Register address 0x2DC: Reserved + 0x00, // Register address 0x2DD: Reserved + 0x00, // Register address 0x2DE: Reserved + 0x00, // Register address 0x2DF: Reserved + 0x00, // Register address 0x2E0: Reserved + 0x00, // Register address 0x2E1: Reserved + 0x00, // Register address 0x2E2: Reserved + 0x00, // Register address 0x2E3: Reserved + 0x00, // Register address 0x2E4: Reserved + 0x00, // Register address 0x2E5: Reserved + 0x00, // Register address 0x2E6: Reserved + 0x00, // Register address 0x2E7: Reserved + 0x00, // Register address 0x2E8: Reserved + 0x00, // Register address 0x2E9: Reserved + 0x00, // Register address 0x2EA: Reserved + 0x00, // Register address 0x2EB: Reserved + 0x00, // Register address 0x2EC: Reserved + 0x00, // Register address 0x2ED: Reserved + 0x00, // Register address 0x2EE: Reserved + 0x00, // Register address 0x2EF: Reserved + 0x00, // Register address 0x2F0: Reserved + 0x00, // Register address 0x2F1: Reserved + 0x00, // Register address 0x2F2: Reserved + 0x00, // Register address 0x2F3: Reserved + 0x00, // Register address 0x2F4: Reserved + 0x00, // Register address 0x2F5: Reserved + 0x00, // Register address 0x2F6: Reserved + 0x00, // Register address 0x2F7: Reserved + 0x00, // Register address 0x2F8: Reserved + 0x00, // Register address 0x2F9: Reserved + 0x00, // Register address 0x2FA: Reserved + 0x00, // Register address 0x2FB: Reserved + 0x00, // Register address 0x2FC: Reserved + 0x00, // Register address 0x2FD: Reserved + 0x00, // Register address 0x2FE: Reserved + 0x00 // Register address 0x2FF: Reserved +}; + +/*============================================================================== + * ZL30362 registers are 8-bit registers. + */ +#define ZL_ADDRESS_BITS_MASK 0x0000007Fu +#define ZL_REG_BITS_MASK 0x000000FFu +#define ZL_READY_CODE 0x0000009Fu + +#define READ_ZL_READY_REG_CMD 0x00008000u +#define SELECT_ZL_PAGE0_CMD 0x00007F00u + +/*============================================================================== + * Configure the ZL30362 device through its SPI interface. + */ +void configure_zl30362(void) +{ + uint32_t inc; + uint32_t zl_register; + uint32_t zl_ready; + const uint8_t frame_size = 16u; + + int count = 0; + + /*-------------------------------------------------------------------------- + * Configure SPI interface. + */ + MSS_SPI_init(&g_mss_spi1); + + MSS_SPI_configure_master_mode(&g_mss_spi1, + MSS_SPI_SLAVE_0, + MSS_SPI_MODE0, + MSS_SPI_PCLK_DIV_256, + frame_size); + + /* printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); */ + MSS_SPI_set_slave_select(&g_mss_spi1, MSS_SPI_SLAVE_0); + + /*-------------------------------------------------------------------------- + * Wait for ZL30362 to become ready. + * Compare against full ready register value instead of simply polling the + * ready bit. This avoids false ready bit detection when the ZL device has + * not fully come out of reset and does not respond to SPI transactions yet. + * The SPI transfer would typically return all 1's when there is no SPI + * device responding to the transaction. + */ + MSS_SPI_transfer_frame(&g_mss_spi1, SELECT_ZL_PAGE0_CMD); + do { + zl_register = MSS_SPI_transfer_frame(&g_mss_spi1, READ_ZL_READY_REG_CMD); + zl_ready = zl_register & ZL_REG_BITS_MASK; + /* if (count++ > 1000) { */ + /* printf ("finish timeout\n"); */ + /* return; */ + /* } */ + } while(zl_ready != ZL_READY_CODE); + + /*-------------------------------------------------------------------------- + * Transfer ZL30362 configuration via SPI. + */ + for(inc = 0; inc < sizeof(g_zl30362_config); ++inc) + { + uint32_t tx_bits; + + tx_bits = ((inc & ZL_ADDRESS_BITS_MASK) << 8u) | g_zl30362_config[inc]; + MSS_SPI_transfer_frame(&g_mss_spi1, tx_bits); + } +} diff --git a/drivers/net/m2s_eth.c b/drivers/net/m2s_eth.c index bf90e7641dc65b244ad293e0becd74835cc95554..6634aa14bc62094e11f228ff7563283cf18d2eba 100644 --- a/drivers/net/m2s_eth.c +++ b/drivers/net/m2s_eth.c @@ -91,17 +91,45 @@ * CFG1 register fields */ #define M2S_MAC_CFG1_RST (1 << 31) /* PE-MCXMAC full reset */ +#define M2S_MAC_CFG1_RXCTL_RST (1 << 19) +#define M2S_MAC_CFG1_TXCTL_RST (1 << 18) +#define M2S_MAC_CFG1_RX_RST (1 << 17) +#define M2S_MAC_CFG1_TX_RST (1 << 16) #define M2S_MAC_CFG1_RX_ENA (1 << 2) /* MAC receive enable */ #define M2S_MAC_CFG1_TX_ENA (1 << 0) /* MAC transmit enable */ /* * CFG2 register fields */ -#define M2S_MAC_CFG2_MODE_BIT 8 /* MAC interface mode */ -#define M2S_MAC_CFG2_MODE_MSK 0x3 -#define M2S_MAC_CFG2_MODE_MII 0x1 /* Nibble mode */ -#define M2S_MAC_CFG2_PAD_CRC (1 << 2) /* PAD&CRC appending enable */ -#define M2S_MAC_CFG2_FULL_DUP (1 << 0) /* PE-MCXMAC Full duplex */ +#define M2S_MAC_CFG2_PREAM_LEN_BIT 12 +#define M2S_MAC_CFG2_PREAM_LEN_MSK 0xf +#define M2S_MAC_CFG2_MODE_BIT 8 /* MAC interface mode */ +#define M2S_MAC_CFG2_MODE_MSK 0x3 +#define M2S_MAC_CFG2_MODE_BYTE 0x2 /* Byte mode */ +#define M2S_MAC_CFG2_MODE_MII 0x1 /* Nibble mode */ +#define M2S_MAC_CFG2_HUGE_FRAME_EN (1 << 5) +#define M2S_MAC_CFG2_LEN_CHECK (1 << 4) +#define M2S_MAC_CFG2_PAD_CRC (1 << 2) /* PAD&CRC appending enable */ +#define M2S_MAC_CFG2_CRC_EN (1 << 1) +#define M2S_MAC_CFG2_FULL_DUP (1 << 0) /* PE-MCXMAC Full duplex */ + +/* + * IPG/IFG register + */ +#define M2S_MAC_IFG_BTBIPG_BIT 0 +#define M2S_MAC_IFG_MINIFGENF_BIT 8 +#define M2S_MAC_IFG_NONBTBIPG_BIT 16 + +/* + * half-duplex register + */ +#define M2S_MAC_HALF_DUPLEX_ABEB_TUNC_BIT 20 +#define M2S_MAC_HALF_DUPLEX_ABEB_ENABLE (1 << 19) +#define M2S_MAC_HALF_DUPLEX_BACKPRES_NOBACKOFF (1 << 18) +#define M2S_MAC_HALF_DUPLEX_NO_BACKOFF (1 << 17) +#define M2S_MAC_HALF_DUPLEX_EXCS_DEFER (1 << 16) +#define M2S_MAC_HALF_DUPLEX_RETX_MAX_BIT 12 +#define M2S_MAC_HALF_DUPLEX_SLOTTIME_BIT 0 /* * MII_COMMAND register fields @@ -125,6 +153,12 @@ */ #define M2S_MAC_DMA_CTRL_ENA (1 << 0) /* Enable Tx/Rx DMA xfers */ +/* + * Interface Control register fields + */ +#define M2S_MAC_INTF_RESET (1 << 31) /* Reset interface module */ +#define M2S_MAC_INTF_SPEED_100 (1 << 4) /* MII PHY speed 100Mbit */ + /* * FIFO_CFG0 register fields */ @@ -164,12 +198,15 @@ /* * MAC Configuration Register in Sysreg block fields */ -#define M2S_SYS_MAC_CR_PM_BIT 2 /* PHY mode */ +#define M2S_SYS_MAC_CR_PM_BIT 2 /* PHY mode */ #define M2S_SYS_MAC_CR_PM_MSK 0x7 +#define M2S_SYS_MAC_CR_PM_TBI 0x2 /* Use TBI mode */ #define M2S_SYS_MAC_CR_PM_MII 0x3 /* Use MII mode */ #define M2S_SYS_MAC_CR_LS_BIT 0 /* Line speed */ #define M2S_SYS_MAC_CR_LS_MSK 0x3 +#define M2S_SYS_MAC_CR_LS_10 0x0 /* 10 Mbps */ #define M2S_SYS_MAC_CR_LS_100 0x1 /* 100 Mbps */ +#define M2S_SYS_MAC_CR_LS_1000 0x2 /* 1000 Mbps */ /* * Software Reset Control Register fields @@ -255,8 +292,10 @@ static void m2s_eth_halt(struct eth_device *dev); static int m2s_mii_read(char *devname, u8 addr, u8 reg, u16 *val); static int m2s_mii_write(char *devname, u8 addr, u8 reg, u16 val); +#ifndef CONFIG_M2S_ETH_MODE_SGMII static int m2s_phy_probe(void); static int m2s_phy_link_setup(void); +#endif static void m2s_mac_dump_regs(char *who); @@ -277,7 +316,10 @@ static struct eth_device m2s_eth_dev = { /* * PHY address */ +#ifndef CONFIG_M2S_ETH_MODE_SGMII static u8 m2s_phy_addr = 0xFF; +#endif +static u8 m2s_mii_speed = M2S_SYS_MAC_CR_LS_100; /* * Current indexes within m2s_bd_Xx[] (idx of BT to process next) @@ -295,6 +337,238 @@ static volatile struct m2s_eth_dma_bd m2s_bd_rx[M2S_RX_BD_NUM]; */ static u8 m2s_buf_rx[M2S_RX_BD_NUM][M2S_FRM_MAX_LEN]; +#define M88E1340_PHY_ADDR 0 +#define SF2_MSGMII_PHY_ADDR 0x1e + +/* M88E1340 PHY registers */ + +/* Advertisement control register. */ +#define MII_ADVERTISE 0x04 /* Advertisement control reg */ + +#define ADVERTISE_SLCT 0x001f /* Selector bits */ +#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ +#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ +#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ +#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ +#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ +#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ +#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ +#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ +#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ +#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ +#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ +#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ +#define ADVERTISE_RESV 0x1000 /* Unused... */ +#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ +#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ +#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ + +/* 1000BASE-T Control register */ +#define MII_CTRL1000 0x09 /* 1000BASE-T control */ + +#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ +#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ + +#define M88E1340_EXT_ADDR_PAGE_CR 0x16 +#define PAGE_0 0x00 + +#define M88E1340_PHY_STATUS 0x11 +#define M88E1340_PHY_STATUS_1000 0x8000 +#define M88E1340_PHY_STATUS_100 0x4000 +#define M88E1340_PHY_STATUS_SPD_MASK 0xc000 +#define M88E1340_PHY_STATUS_FULLDUPLEX 0x2000 +#define M88E1340_PHY_STATUS_RESOLVED 0x0800 +#define M88E1340_PHY_STATUS_LINK 0x0400 + +#ifdef CONFIG_M2S_ETH_MODE_SGMII + +static int msgmii_phy_init(void) +{ + u16 val; + int rv; + + /* Reset M-SGMII. */ + rv = miiphy_write(M2S_MII_NAME, SF2_MSGMII_PHY_ADDR, 0x00, 0x9000u); + if (rv != 0) { + return -1; + } + /* Register 0x04 of M-SGMII must be always be set to 0x0001. */ + rv = miiphy_write(M2S_MII_NAME, SF2_MSGMII_PHY_ADDR, 0x04, 0x0001); + if (rv != 0) { + return -1; + } + /* + * Enable auto-negotiation inside SmartFusion2 SGMII block. + */ + rv = miiphy_read(M2S_MII_NAME, SF2_MSGMII_PHY_ADDR, 0, &val); + if (rv != 0) { + return -1; + } + val |= 0x1000; + rv = miiphy_write(M2S_MII_NAME, SF2_MSGMII_PHY_ADDR, 0x0, val); + if (rv != 0) { + return -1; + } + + return 0; +} + +static int m881340_phy_set_link_speed(void) +{ + u16 val; + int rv; + /* Set auto-negotiation advertisement. */ + /* Set 10Mbps and 100Mbps advertisement. */ + rv = miiphy_read(M2S_MII_NAME, M88E1340_PHY_ADDR, MII_ADVERTISE, &val); + if (rv != 0) { + goto out; + } + val |= (ADVERTISE_10HALF | ADVERTISE_10FULL + | ADVERTISE_100HALF | ADVERTISE_100FULL); + rv = miiphy_write(M2S_MII_NAME, M88E1340_PHY_ADDR, MII_ADVERTISE, val); + if (rv != 0) { + goto out; + } + + /* Set 1000Mbps advertisement. */ + rv = miiphy_read(M2S_MII_NAME, M88E1340_PHY_ADDR, MII_CTRL1000, &val); + if (rv != 0) { + goto out; + } + + val |= (ADVERTISE_1000FULL | ADVERTISE_1000HALF); + rv = miiphy_write(M2S_MII_NAME, M88E1340_PHY_ADDR, MII_CTRL1000, val); + if (rv != 0) { + goto out; + } + out: + if (rv) { + printf("%s %d %s return %d\n", __FILE__, __LINE__, + __func__, rv); + } + return rv; +} + +static int msgmii_phy_autonegotiate(void) +{ + int rv; + u16 val; + int timeout; + + /* Enable auto-negotiation. */ + rv = miiphy_write(M2S_MII_NAME, M88E1340_PHY_ADDR, + M88E1340_EXT_ADDR_PAGE_CR, PAGE_0); + if (rv != 0) { + goto out; + } + val = 0x9340 | PHY_BMCR_100_MBPS; + rv = miiphy_write(M2S_MII_NAME, M88E1340_PHY_ADDR, PHY_BMCR, val); + if (rv != 0) { + goto out; + } + + /* Wait for copper auto-negotiation to complete. */ + timeout = M2S_AUTONEG_TOUT/1000; + while (timeout--) { + rv = miiphy_read(M2S_MII_NAME, M88E1340_PHY_ADDR, + PHY_BMSR, &val); + if (rv != 0) { + printf("mii err %d.\n", rv); + goto out; + } + if (!(val & PHY_BMSR_AUTN_COMP)) { + int i; + for (i = 0; i < 1000; i++) + udelay(1000); + continue; + } + rv = miiphy_read(M2S_MII_NAME, M88E1340_PHY_ADDR, + M88E1340_PHY_STATUS, &val); + if (rv != 0) { + printf("mii err %d.\n", rv); + goto out; + } + if ((val & M88E1340_PHY_STATUS_SPD_MASK) == + M88E1340_PHY_STATUS_100) { + m2s_mii_speed = M2S_SYS_MAC_CR_LS_100; + } else if ((val & M88E1340_PHY_STATUS_SPD_MASK) == + M88E1340_PHY_STATUS_1000) { + m2s_mii_speed = M2S_SYS_MAC_CR_LS_1000; + } else { + m2s_mii_speed = M2S_SYS_MAC_CR_LS_10; + } + break; + } + + if (timeout <= 0) { + printf("%s %d %s marvel autoneg failed by timeout %02x\n", + __FILE__, __LINE__, __func__, val); + return -1; + } + + rv = miiphy_read(M2S_MII_NAME, SF2_MSGMII_PHY_ADDR, PHY_BMSR, &val); + if (rv != 0) { + goto out; + } + + if (val & PHY_BMSR_AUTN_COMP) { + /* no need to start auto-negotiation if it is already done */ + goto out; + } + + rv = miiphy_read(M2S_MII_NAME, SF2_MSGMII_PHY_ADDR, PHY_BMCR, &val); + if (rv != 0) { + goto out; + } + + rv = miiphy_write(M2S_MII_NAME, SF2_MSGMII_PHY_ADDR, PHY_BMCR, + val | PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); + if (rv != 0) { + goto out; + } + + /* + * Wait until auto-negotiation completes + */ + timeout = M2S_AUTONEG_TOUT/10; + while (timeout--) { + rv = miiphy_read(M2S_MII_NAME, SF2_MSGMII_PHY_ADDR, + PHY_BMSR, &val); + + if (rv != 0) { + printf("mii err %d.\n", rv); + goto out; + } + if (!(val & PHY_BMSR_AUTN_COMP)) { + if (timeout % 100 != 0) { + udelay(10000); + continue; + } + + /* restart auto-negotiation if it is not complete + in a second */ + rv = miiphy_write(M2S_MII_NAME, SF2_MSGMII_PHY_ADDR, + PHY_BMCR, + PHY_BMCR_AUTON | PHY_BMCR_RST_NEG); + if (rv != 0) { + goto out; + } + + continue; + } + break; + } + if (timeout <= 0) + printf("MSGMII PHY auto-negotiaiton timed out!\n"); + + out: + return rv; + + +} + +#endif + /****************************************************************************** * Functions exported from the module ******************************************************************************/ @@ -334,7 +608,7 @@ out: static int m2s_eth_init(struct eth_device *dev, bd_t *bd_unused) { volatile struct m2s_eth_dma_bd *bd; - int i, rv, timeout; + int i, rv = 0, timeout; /* * Release the Ethernet MAC from reset @@ -343,23 +617,55 @@ static int m2s_eth_init(struct eth_device *dev, bd_t *bd_unused) /* * Set-up CR - * FIXME: set line-speed according to val get from PHY? */ M2S_SYSREG->mac_cr &= ~(M2S_SYS_MAC_CR_PM_MSK << M2S_SYS_MAC_CR_PM_BIT); M2S_SYSREG->mac_cr &= ~(M2S_SYS_MAC_CR_LS_MSK << M2S_SYS_MAC_CR_LS_BIT); +#ifndef CONFIG_M2S_ETH_MODE_SGMII M2S_SYSREG->mac_cr |= M2S_SYS_MAC_CR_PM_MII << M2S_SYS_MAC_CR_PM_BIT; - M2S_SYSREG->mac_cr |= M2S_SYS_MAC_CR_LS_100 << M2S_SYS_MAC_CR_LS_BIT; +#else + /* Interface type: TBI */ + M2S_SYSREG->mac_cr = M2S_SYS_MAC_CR_PM_TBI << M2S_SYS_MAC_CR_PM_BIT; +#endif + + M2S_MAC_CFG->mii_config = 7; /* * Reset all PE-MCXMAC modules, and configure */ M2S_MAC_CFG->cfg1 |= M2S_MAC_CFG1_RST; M2S_MAC_CFG->cfg1 &= ~M2S_MAC_CFG1_RST; + /* Clear all reset bits */ + /* Clear MCXMAC TX reset */ + M2S_MAC_CFG->cfg1 &= ~M2S_MAC_CFG1_TX_RST; + /* Clear MCXMAC RX reset */ + M2S_MAC_CFG->cfg1 &= ~M2S_MAC_CFG1_RX_RST; + /* Clear MCXMAC TX reset */ + M2S_MAC_CFG->cfg1 &= ~M2S_MAC_CFG1_TXCTL_RST; + /* Clear MCXMAC RX reset */ + M2S_MAC_CFG->cfg1 &= ~M2S_MAC_CFG1_RXCTL_RST; + /* Clear MCXMAC interface reset */ + M2S_MAC_CFG->if_ctrl &= ~M2S_MAC_INTF_RESET; + /* Clear FIFO watermark reset */ + /* Clear FIFO Rx system reset */ + /* Clear FIFO Rx fab reset */ + /* Clear FIFO Tx system reset */ + /* Clear FIFO Tx system reset */ + M2S_MAC_CFG->fifo_cfg[0] &= ~M2S_MAC_FIFO_CFG0_ALL_RST; + + M2S_MAC_CFG->cfg1 = 0; M2S_MAC_CFG->cfg2 &= ~(M2S_MAC_CFG2_MODE_MSK << M2S_MAC_CFG2_MODE_BIT); +#ifndef CONFIG_M2S_ETH_MODE_SGMII M2S_MAC_CFG->cfg2 |= (M2S_MAC_CFG2_MODE_MII << M2S_MAC_CFG2_MODE_BIT) | M2S_MAC_CFG2_FULL_DUP | M2S_MAC_CFG2_PAD_CRC; - +#else + M2S_MAC_CFG->cfg2 = + M2S_MAC_CFG2_FULL_DUP | M2S_MAC_CFG2_CRC_EN + | M2S_MAC_CFG2_PAD_CRC + | M2S_MAC_CFG2_LEN_CHECK + | (M2S_MAC_CFG2_MODE_BYTE << M2S_MAC_CFG2_MODE_BIT) + | (0x7 << M2S_MAC_CFG2_PREAM_LEN_BIT); +#endif M2S_MAC_CFG->max_frame_length = M2S_FRM_MAX_LEN; M2S_MAC_CFG->station_addr[0] = (dev->enetaddr[0] << 24) | @@ -402,11 +708,6 @@ static int m2s_eth_init(struct eth_device *dev, bd_t *bd_unused) M2S_MAC_DMA->rx_desc = (u32)m2s_bd_rx; M2S_MAC_DMA->rx_ctrl = M2S_MAC_DMA_CTRL_ENA; - /* - * Enable MAC Rx and Tx - */ - M2S_MAC_CFG->cfg1 = M2S_MAC_CFG1_RX_ENA | M2S_MAC_CFG1_TX_ENA; - /* * Reset and enable FIFOs */ @@ -427,13 +728,37 @@ static int m2s_eth_init(struct eth_device *dev, bd_t *bd_unused) goto out; } +#ifdef CONFIG_M2S_ETH_MODE_SGMII + if (msgmii_phy_init() < 0) + goto out; + if (m881340_phy_set_link_speed() < 0) + goto out; + if (msgmii_phy_autonegotiate() < 0) + goto out; +#else /* * Probe for PHY, and get LINK status */ rv = m2s_phy_probe(); if (rv != 0) goto out; - m2s_phy_link_setup(); + if (rv != 0) + goto out; +#endif + + if (m2s_mii_speed == M2S_SYS_MAC_CR_LS_100) { + M2S_MAC_CFG->if_ctrl |= M2S_MAC_INTF_SPEED_100; + } else { + M2S_MAC_CFG->if_ctrl &= ~M2S_MAC_INTF_SPEED_100; + } + M2S_SYSREG->mac_cr = (M2S_SYSREG->mac_cr & ~M2S_SYS_MAC_CR_LS_MSK) | + m2s_mii_speed; + M2S_MAC_CFG->cfg2 |= M2S_MAC_CFG2_FULL_DUP; + + /* + * Enable MAC Rx and Tx + */ + M2S_MAC_CFG->cfg1 = M2S_MAC_CFG1_RX_ENA | M2S_MAC_CFG1_TX_ENA; rv = 0; out: @@ -581,7 +906,7 @@ static int m2s_mii_read(char *devname, u8 adr, u8 reg, u16 *val) { int timeout, rv; - if (adr == 0 || adr > 31 || reg > 31 || !val) { + if (adr > 31 || reg > 31 || !val) { printf("%s: bad params %x/%x/%p\n", __func__, adr, reg, val); rv = -EINVAL; goto out; @@ -617,7 +942,7 @@ static int m2s_mii_write(char *devname, u8 adr, u8 reg, u16 val) { int timeout, rv; - if (adr == 0 || adr > 31 || reg > 31) { + if (adr > 31 || reg > 31) { printf("%s: bad params %x/%x\n", __func__, adr, reg); rv = -EINVAL; goto out; @@ -641,6 +966,8 @@ out: return rv; } +#ifndef CONFIG_M2S_ETH_MODE_SGMII + /****************************************************************************** * PHY routines ******************************************************************************/ @@ -741,6 +1068,8 @@ out: return rv; } +#endif + /****************************************************************************** * Debug stuff ******************************************************************************/ diff --git a/include/asm-arm/arch-m2s/m2s.h b/include/asm-arm/arch-m2s/m2s.h index 40dea65a29fdeef950b0f7e73322aeee864640e8..8e19fc5b6dae5806be06c4709db8cb6b1c5b7f2c 100644 --- a/include/asm-arm/arch-m2s/m2s.h +++ b/include/asm-arm/arch-m2s/m2s.h @@ -79,6 +79,15 @@ struct m2s_sysreg { #define M2S_SYSREG ((volatile struct m2s_sysreg *)\ (M2S_SYSREG_BASE)) +struct m2s_coresf2config { + unsigned int config_done; + unsigned int init_done; + unsigned int clr_init_done; +}; + +#define CORE_SF2_CFG_BASE 0x40022000u +#define CORE_SF2_CFG \ + ((volatile struct m2s_coresf2config *)CORE_SF2_CFG_BASE) /* * Reference clocks enumeration diff --git a/include/configs/sf2-dev-kit.h b/include/configs/sf2-dev-kit.h index 27406decfdf85a003d7ba1e606715c17eee4ac0a..29ce1d7273f674d7c0dbf72992b016283d2dadb6 100644 --- a/include/configs/sf2-dev-kit.h +++ b/include/configs/sf2-dev-kit.h @@ -141,6 +141,21 @@ #define CONFIG_SYS_RAM_BASE 0xA0000000 #define CONFIG_SYS_RAM_SIZE (256 * 1024 * 1024) +/* + * Ethernet driver configuration + */ +#define CONFIG_NET_MULTI +#define CONFIG_M2S_ETH +#define CONFIG_M2S_ETH_MODE_SGMII + +#define CONFIG_SYS_RX_ETH_BUFFER 2 + +/* + * Use standard MII PHY API + */ +#define CONFIG_MII +#define CONFIG_SYS_FAULT_ECHO_LINK_DOWN + /* * Configuration of the external Flash * No NOR Flash @@ -241,8 +256,8 @@ #undef CONFIG_CMD_IMLS #define CONFIG_CMD_LOADS #undef CONFIG_CMD_MISC -/* #define CONFIG_CMD_NET */ -#undef CONFIG_CMD_NET +#define CONFIG_CMD_NET +#define CONFIG_CMD_PING #undef CONFIG_CMD_NETBOOT #undef CONFIG_CMD_NFS #undef CONFIG_CMD_SOURCE