diff options
| author | whik <[email protected]> | 2020-06-05 21:56:40 +0800 |
|---|---|---|
| committer | whik <[email protected]> | 2020-06-05 21:56:40 +0800 |
| commit | 02c6c92a19976b5b5269e23026bae99a82c8fab0 (patch) | |
| tree | f3cfb0f2d1746ccff433d50a84a8e334385fb51b /bsp/smartfusion2/libraries | |
| parent | 695a58648ad49397c106d7d1f508eb27d3bc94a7 (diff) | |
add support for SmartFusion2 family FPGA
Diffstat (limited to 'bsp/smartfusion2/libraries')
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_gpio/mss_gpio.c | 298 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_gpio/mss_gpio.h | 507 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_sys_services/mss_comblk.c | 752 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_sys_services/mss_comblk.h | 90 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_sys_services/mss_comblk_page_handler.h | 66 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_sys_services/mss_sys_services.c | 2452 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_sys_services/mss_sys_services.h | 2500 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_uart/mss_uart.c | 1762 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_uart/mss_uart.h | 2639 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/mss_uart/mss_uart_regs.h | 83 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/sys_config/sys_config.c | 385 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/sys_config/sys_config.h | 66 | ||||
| -rw-r--r-- | bsp/smartfusion2/libraries/sys_config/sys_config_mss_clocks.h | 21 |
13 files changed, 11621 insertions, 0 deletions
diff --git a/bsp/smartfusion2/libraries/mss_gpio/mss_gpio.c b/bsp/smartfusion2/libraries/mss_gpio/mss_gpio.c new file mode 100644 index 0000000000..11dbc21fee --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_gpio/mss_gpio.c @@ -0,0 +1,298 @@ +/******************************************************************************* + * (c) Copyright 2008-2015 Microsemi SoC Products Group. All rights reserved. + * + * SmartFusion2 microcontroller subsystem GPIO bare metal driver implementation. + * + * SVN $Revision: 7749 $ + * SVN $Date: 2015-09-04 14:32:09 +0530 (Fri, 04 Sep 2015) $ + */ +#include "mss_gpio.h" +#include "../../CMSIS/mss_assert.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + * Defines. + */ +#define GPIO_INT_ENABLE_MASK ((uint32_t)0x00000008uL) +#define OUTPUT_BUFFER_ENABLE_MASK 0x00000004u + +#define NB_OF_GPIO ((uint32_t)32) + +/*-------------------------------------------------------------------------*//** + * Lookup table of GPIO configuration registers address indexed on GPIO ID. + */ +static uint32_t volatile * const g_config_reg_lut[NB_OF_GPIO] = +{ + &(GPIO->GPIO_0_CFG), + &(GPIO->GPIO_1_CFG), + &(GPIO->GPIO_2_CFG), + &(GPIO->GPIO_3_CFG), + &(GPIO->GPIO_4_CFG), + &(GPIO->GPIO_5_CFG), + &(GPIO->GPIO_6_CFG), + &(GPIO->GPIO_7_CFG), + &(GPIO->GPIO_8_CFG), + &(GPIO->GPIO_9_CFG), + &(GPIO->GPIO_10_CFG), + &(GPIO->GPIO_11_CFG), + &(GPIO->GPIO_12_CFG), + &(GPIO->GPIO_13_CFG), + &(GPIO->GPIO_14_CFG), + &(GPIO->GPIO_15_CFG), + &(GPIO->GPIO_16_CFG), + &(GPIO->GPIO_17_CFG), + &(GPIO->GPIO_18_CFG), + &(GPIO->GPIO_19_CFG), + &(GPIO->GPIO_20_CFG), + &(GPIO->GPIO_21_CFG), + &(GPIO->GPIO_22_CFG), + &(GPIO->GPIO_23_CFG), + &(GPIO->GPIO_24_CFG), + &(GPIO->GPIO_25_CFG), + &(GPIO->GPIO_26_CFG), + &(GPIO->GPIO_27_CFG), + &(GPIO->GPIO_28_CFG), + &(GPIO->GPIO_29_CFG), + &(GPIO->GPIO_30_CFG), + &(GPIO->GPIO_31_CFG) +}; + +/*-------------------------------------------------------------------------*//** + * Lookup table of Cortex-M3 GPIO interrupt number indexed on GPIO ID. + */ +static const IRQn_Type g_gpio_irqn_lut[NB_OF_GPIO] = +{ + GPIO0_IRQn, + GPIO1_IRQn, + GPIO2_IRQn, + GPIO3_IRQn, + GPIO4_IRQn, + GPIO5_IRQn, + GPIO6_IRQn, + GPIO7_IRQn, + GPIO8_IRQn, + GPIO9_IRQn, + GPIO10_IRQn, + GPIO11_IRQn, + GPIO12_IRQn, + GPIO13_IRQn, + GPIO14_IRQn, + GPIO15_IRQn, + GPIO16_IRQn, + GPIO17_IRQn, + GPIO18_IRQn, + GPIO19_IRQn, + GPIO20_IRQn, + GPIO21_IRQn, + GPIO22_IRQn, + GPIO23_IRQn, + GPIO24_IRQn, + GPIO25_IRQn, + GPIO26_IRQn, + GPIO27_IRQn, + GPIO28_IRQn, + GPIO29_IRQn, + GPIO30_IRQn, + GPIO31_IRQn +}; + +/*-------------------------------------------------------------------------*//** + * MSS_GPIO_init + * See "mss_gpio.h" for details of how to use this function. + */ +void MSS_GPIO_init( void ) +{ + uint32_t inc; + + /* reset MSS GPIO hardware */ + SYSREG->SOFT_RST_CR |= SYSREG_GPIO_SOFTRESET_MASK; + SYSREG->SOFT_RST_CR |= (SYSREG_GPIO_7_0_SOFTRESET_MASK | + SYSREG_GPIO_15_8_SOFTRESET_MASK | + SYSREG_GPIO_23_16_SOFTRESET_MASK | + SYSREG_GPIO_31_24_SOFTRESET_MASK); + + /* Clear any previously pended MSS GPIO interrupt */ + for(inc = 0U; inc < NB_OF_GPIO; ++inc) + { + NVIC_DisableIRQ(g_gpio_irqn_lut[inc]); + NVIC_ClearPendingIRQ(g_gpio_irqn_lut[inc]); + } + /* Take MSS GPIO hardware out of reset. */ + SYSREG->SOFT_RST_CR &= ~(SYSREG_GPIO_7_0_SOFTRESET_MASK | + SYSREG_GPIO_15_8_SOFTRESET_MASK | + SYSREG_GPIO_23_16_SOFTRESET_MASK | + SYSREG_GPIO_31_24_SOFTRESET_MASK); + SYSREG->SOFT_RST_CR &= ~SYSREG_GPIO_SOFTRESET_MASK; +} + +/*-------------------------------------------------------------------------*//** + * MSS_GPIO_config + * See "mss_gpio.h" for details of how to use this function. + */ +void MSS_GPIO_config +( + mss_gpio_id_t port_id, + uint32_t config +) +{ + uint32_t gpio_idx = (uint32_t)port_id; + + ASSERT(gpio_idx < NB_OF_GPIO); + + if(gpio_idx < NB_OF_GPIO) + { + *(g_config_reg_lut[gpio_idx]) = config; + } +} + +/*-------------------------------------------------------------------------*//** + * MSS_GPIO_set_output + * See "mss_gpio.h" for details of how to use this function. + */ +void MSS_GPIO_set_output +( + mss_gpio_id_t port_id, + uint8_t value +) +{ + uint32_t gpio_setting; + uint32_t gpio_idx = (uint32_t)port_id; + + ASSERT(gpio_idx < NB_OF_GPIO); + + if(gpio_idx < NB_OF_GPIO) + { + gpio_setting = GPIO->GPIO_OUT; + gpio_setting &= ~((uint32_t)0x01u << gpio_idx); + gpio_setting |= ((uint32_t)value & 0x01u) << gpio_idx; + GPIO->GPIO_OUT = gpio_setting; + } +} + +/*-------------------------------------------------------------------------*//** + * MSS_GPIO_drive_inout + * See "mss_gpio.h" for details of how to use this function. + */ +void MSS_GPIO_drive_inout +( + mss_gpio_id_t port_id, + mss_gpio_inout_state_t inout_state +) +{ + uint32_t outputs_state; + uint32_t config; + uint32_t gpio_idx = (uint32_t)port_id; + + ASSERT(gpio_idx < NB_OF_GPIO); + + if(gpio_idx < NB_OF_GPIO) + { + switch(inout_state) + { + case MSS_GPIO_DRIVE_HIGH: + /* Set output high */ + outputs_state = GPIO->GPIO_OUT; + outputs_state |= (uint32_t)1 << gpio_idx; + GPIO->GPIO_OUT = outputs_state; + /* Enable output buffer */ + config = *(g_config_reg_lut[gpio_idx]); + config |= OUTPUT_BUFFER_ENABLE_MASK; + *(g_config_reg_lut[gpio_idx]) = config; + break; + + case MSS_GPIO_DRIVE_LOW: + /* Set output low */ + outputs_state = GPIO->GPIO_OUT; + outputs_state &= ~((uint32_t)((uint32_t)1 << gpio_idx)); + GPIO->GPIO_OUT = outputs_state; + /* Enable output buffer */ + config = *(g_config_reg_lut[gpio_idx]); + config |= OUTPUT_BUFFER_ENABLE_MASK; + *(g_config_reg_lut[gpio_idx]) = config; + break; + + case MSS_GPIO_HIGH_Z: + /* Disable output buffer */ + config = *(g_config_reg_lut[gpio_idx]); + config &= ~OUTPUT_BUFFER_ENABLE_MASK; + *(g_config_reg_lut[gpio_idx]) = config; + break; + + default: + ASSERT(0); + break; + } + } +} + +/*-------------------------------------------------------------------------*//** + * MSS_GPIO_enable_irq + * See "mss_gpio.h" for details of how to use this function. + */ +void MSS_GPIO_enable_irq +( + mss_gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t gpio_idx = (uint32_t)port_id; + + ASSERT(gpio_idx < NB_OF_GPIO); + + if(gpio_idx < NB_OF_GPIO) + { + cfg_value = *(g_config_reg_lut[gpio_idx]); + *(g_config_reg_lut[gpio_idx]) = (cfg_value | GPIO_INT_ENABLE_MASK); + NVIC_EnableIRQ(g_gpio_irqn_lut[gpio_idx]); + } +} + +/*-------------------------------------------------------------------------*//** + * MSS_GPIO_disable_irq + * See "mss_gpio.h" for details of how to use this function. + */ +void MSS_GPIO_disable_irq +( + mss_gpio_id_t port_id +) +{ + uint32_t cfg_value; + uint32_t gpio_idx = (uint32_t)port_id; + + ASSERT(gpio_idx < NB_OF_GPIO); + + if(gpio_idx < NB_OF_GPIO) + { + cfg_value = *(g_config_reg_lut[gpio_idx]); + *(g_config_reg_lut[gpio_idx]) = (cfg_value & ~GPIO_INT_ENABLE_MASK); + } +} + +/*-------------------------------------------------------------------------*//** + * MSS_GPIO_clear_irq + * See "mss_gpio.h" for details of how to use this function. + */ +void MSS_GPIO_clear_irq +( + mss_gpio_id_t port_id +) +{ + uint32_t gpio_idx = (uint32_t)port_id; + + ASSERT(gpio_idx < NB_OF_GPIO); + + if(gpio_idx < NB_OF_GPIO) + { + GPIO->GPIO_IRQ = ((uint32_t)1) << gpio_idx; + } + __ASM volatile ("dsb"); + +} + +#ifdef __cplusplus +} +#endif + diff --git a/bsp/smartfusion2/libraries/mss_gpio/mss_gpio.h b/bsp/smartfusion2/libraries/mss_gpio/mss_gpio.h new file mode 100644 index 0000000000..58c98f8556 --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_gpio/mss_gpio.h @@ -0,0 +1,507 @@ +/******************************************************************************* + * (c) Copyright 2008-2015 Microsemi SoC Products Group. All rights reserved. + * + * SmartFusion2 Microcontroller Subsystem GPIO bare metal software driver public + * API. + * + * SVN $Revision: 7748 $ + * SVN $Date: 2015-09-04 11:36:30 +0530 (Fri, 04 Sep 2015) $ + */ + +/*=========================================================================*//** + @mainpage SmartFusion2 MSS GPIO Bare Metal Driver. + + @section intro_sec Introduction + The SmartFusion2 Microcontroller Subsystem (MSS) includes a block of 32 general + purpose input/outputs (GPIO). + This software driver provides a set of functions for controlling the MSS GPIO + block as part of a bare metal system where no operating system is available. + This driver 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 GPIOs is covered by this driver + with the exception of the SmartFusion2 IOMUX configuration. SmartFusion2 + 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 GPIOs share SmartFusion2 device external pins with the + FPGA fabric and with other MSS peripherals via an IOMUX. The MSS GPIO ports + can alternatively be routed to the FPGA fabric through an IOMUX. + The IOMUXs are configured using the SmartFusion2 MSS configurator tool. You + must ensure that the MSS GPIOs are enabled and configured in the SmartFusion2 + MSS configurator if you wish to use them. For more information on IOMUXs, + refer to the IOMUX section of the SmartFusion2 Microcontroller Subsystem (MSS) + User’s Guide. + The base address, register addresses and interrupt number assignment for the + MSS GPIO block are defined as constants in the SmartFusion2 CMSIS HAL. You + must ensure that the latest SmartFusion2 CMSIS HAL is included in the project + settings of the software tool chain used to build your project and that it is + generated into your project. + + @section theory_op Theory of Operation + The MSS GPIO driver functions are grouped into the following categories: + - Initialization + - Configuration + - Reading and setting GPIO state + - Interrupt control + + Initialization + The MSS GPIO driver is initialized through a call to the MSS_GPIO_init() + function. The MSS_GPIO_init() function must be called before any other MSS + GPIO driver functions can be called. + + Configuration + Each GPIO port is individually configured through a call to the + MSS_GPIO_config() function. Configuration includes deciding if a GPIO port + will be used as an input, an output or both. GPIO ports configured as inputs + can be further configured to generate interrupts based on the input's state. + Interrupts can be level or edge sensitive. + + Reading and Setting GPIO State + The state of the GPIO ports can be read and set using the following functions: + - MSS_GPIO_get_inputs() + - MSS_GPIO_get_outputs() + - MSS_GPIO_set_outputs() + - MSS_GPIO_set_output() + - MSS_GPIO_drive_inout() + + Interrupt Control + Interrupts generated by GPIO ports configured as inputs are controlled using + the following functions: + - MSS_GPIO_enable_irq() + - MSS_GPIO_disable_irq() + - MSS_GPIO_clear_irq() + + *//*=========================================================================*/ +#ifndef MSS_GPIO_H_ +#define MSS_GPIO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "../../CMSIS/m2sxxx.h" + +/*-------------------------------------------------------------------------*//** + The mss_gpio_id_t enumeration is used to identify individual GPIO ports as an + argument to functions: + - MSS_GPIO_config() + - MSS_GPIO_set_output() and MSS_GPIO_drive_inout() + - MSS_GPIO_enable_irq(), MSS_GPIO_disable_irq() and MSS_GPIO_clear_irq() + */ +typedef enum __mss_gpio_id_t +{ + MSS_GPIO_0 = 0, + MSS_GPIO_1 = 1, + MSS_GPIO_2 = 2, + MSS_GPIO_3 = 3, + MSS_GPIO_4 = 4, + MSS_GPIO_5 = 5, + MSS_GPIO_6 = 6, + MSS_GPIO_7 = 7, + MSS_GPIO_8 = 8, + MSS_GPIO_9 = 9, + MSS_GPIO_10 = 10, + MSS_GPIO_11 = 11, + MSS_GPIO_12 = 12, + MSS_GPIO_13 = 13, + MSS_GPIO_14 = 14, + MSS_GPIO_15 = 15, + MSS_GPIO_16 = 16, + MSS_GPIO_17 = 17, + MSS_GPIO_18 = 18, + MSS_GPIO_19 = 19, + MSS_GPIO_20 = 20, + MSS_GPIO_21 = 21, + MSS_GPIO_22 = 22, + MSS_GPIO_23 = 23, + MSS_GPIO_24 = 24, + MSS_GPIO_25 = 25, + MSS_GPIO_26 = 26, + MSS_GPIO_27 = 27, + MSS_GPIO_28 = 28, + MSS_GPIO_29 = 29, + MSS_GPIO_30 = 30, + MSS_GPIO_31 = 31 +} mss_gpio_id_t; + +/*-------------------------------------------------------------------------*//** + These constant definitions are used as an argument to the + MSS_GPIO_set_outputs() function to identify GPIO ports. A logical OR of these + constants can be used to specify multiple GPIO ports. + These definitions can also be used to identify GPIO ports through logical + operations on the return value of the MSS_GPIO_get_inputs() function. + */ +#define MSS_GPIO_0_MASK 0x00000001uL +#define MSS_GPIO_1_MASK 0x00000002uL +#define MSS_GPIO_2_MASK 0x00000004uL +#define MSS_GPIO_3_MASK 0x00000008uL +#define MSS_GPIO_4_MASK 0x00000010uL +#define MSS_GPIO_5_MASK 0x00000020uL +#define MSS_GPIO_6_MASK 0x00000040uL +#define MSS_GPIO_7_MASK 0x00000080uL +#define MSS_GPIO_8_MASK 0x00000100uL +#define MSS_GPIO_9_MASK 0x00000200uL +#define MSS_GPIO_10_MASK 0x00000400uL +#define MSS_GPIO_11_MASK 0x00000800uL +#define MSS_GPIO_12_MASK 0x00001000uL +#define MSS_GPIO_13_MASK 0x00002000uL +#define MSS_GPIO_14_MASK 0x00004000uL +#define MSS_GPIO_15_MASK 0x00008000uL +#define MSS_GPIO_16_MASK 0x00010000uL +#define MSS_GPIO_17_MASK 0x00020000uL +#define MSS_GPIO_18_MASK 0x00040000uL +#define MSS_GPIO_19_MASK 0x00080000uL +#define MSS_GPIO_20_MASK 0x00100000uL +#define MSS_GPIO_21_MASK 0x00200000uL +#define MSS_GPIO_22_MASK 0x00400000uL +#define MSS_GPIO_23_MASK 0x00800000uL +#define MSS_GPIO_24_MASK 0x01000000uL +#define MSS_GPIO_25_MASK 0x02000000uL +#define MSS_GPIO_26_MASK 0x04000000uL +#define MSS_GPIO_27_MASK 0x08000000uL +#define MSS_GPIO_28_MASK 0x10000000uL +#define MSS_GPIO_29_MASK 0x20000000uL +#define MSS_GPIO_30_MASK 0x40000000uL +#define MSS_GPIO_31_MASK 0x80000000uL + +/*-------------------------------------------------------------------------*//** + These constant definitions are used as an argument to the MSS_GPIO_config() + function to specify the I/O mode of each GPIO port. + */ +#define MSS_GPIO_INPUT_MODE 0x0000000002uL +#define MSS_GPIO_OUTPUT_MODE 0x0000000005uL +#define MSS_GPIO_INOUT_MODE 0x0000000003uL + +/*-------------------------------------------------------------------------*//** + These constant definitions are used as an argument to the MSS_GPIO_config() + function to specify the interrupt mode of each GPIO port. + */ +#define MSS_GPIO_IRQ_LEVEL_HIGH 0x0000000000uL +#define MSS_GPIO_IRQ_LEVEL_LOW 0x0000000020uL +#define MSS_GPIO_IRQ_EDGE_POSITIVE 0x0000000040uL +#define MSS_GPIO_IRQ_EDGE_NEGATIVE 0x0000000060uL +#define MSS_GPIO_IRQ_EDGE_BOTH 0x0000000080uL + +/*-------------------------------------------------------------------------*//** + The mss_gpio_inout_state_t enumeration is used to specify the output state of + an INOUT GPIO port as an argument to the MSS_GPIO_drive_inout() function. + */ +typedef enum mss_gpio_inout_state +{ + MSS_GPIO_DRIVE_LOW = 0, + MSS_GPIO_DRIVE_HIGH, + MSS_GPIO_HIGH_Z +} mss_gpio_inout_state_t; + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_init() function initializes the SmartFusion2 MSS GPIO block. It + resets the MSS GPIO hardware block and it also clears any pending MSS GPIO + interrupts in the ARM Cortex-M3 interrupt controller. When the function exits, + it takes the MSS GPIO block out of reset. + + @param + This function has no parameters. + + @return + This function does not return a value. + */ +void MSS_GPIO_init( void ); + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_config() function is used to configure an individual GPIO port. + + @param port_id + The port_id parameter identifies the GPIO port to be configured. An + enumeration item of the form MSS_GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, MSS_GPIO_0 identifies + the first GPIO port and MSS_GPIO_31 is the last one. + + @param config + The config parameter specifies the configuration to be applied to the GPIO + port identified by the port_id parameter. It is a logical OR of the required + I/O mode and the required interrupt mode. The interrupt mode is not relevant + if the GPIO is configured as an output only. + These I/O mode constants are allowed: + - MSS_GPIO_INPUT_MODE + - MSS_GPIO_OUTPUT_MODE + - MSS_GPIO_INOUT_MODE + These interrupt mode constants are allowed: + - MSS_GPIO_IRQ_LEVEL_HIGH + - MSS_GPIO_IRQ_LEVEL_LOW + - MSS_GPIO_IRQ_EDGE_POSITIVE + - MSS_GPIO_IRQ_EDGE_NEGATIVE + - MSS_GPIO_IRQ_EDGE_BOTH + + @return + none. + + Example: + The following call will configure GPIO 4 as an input generating interrupts on + a Low to High transition of the input: + @code + MSS_GPIO_config( MSS_GPIO_4, MSS_GPIO_INPUT_MODE | MSS_GPIO_IRQ_EDGE_POSITIVE ); + @endcode + */ +void MSS_GPIO_config +( + mss_gpio_id_t port_id, + uint32_t config +); + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_set_outputs() function is used to set the state of all GPIO ports + configured as outputs. + + @param value + The value parameter specifies the state of the GPIO ports configured as + outputs. It is a bit mask of the form (MSS_GPIO_n_MASK | MSS_GPIO_m_MASK) + where n and m are numbers identifying GPIOs. For example, (MSS_GPIO_0_MASK | + MSS_GPIO_1_MASK | MSS_GPIO_2_MASK ) specifies that the first, second and + third GPIO outputs must be set High and all other GPIO outputs set Low. The + driver provides 32 mask constants, MSS_GPIO_0_MASK to MSS_GPIO_31_MASK + inclusive, for this purpose. + + @return + none. + + Example 1: + Set GPIOs outputs 0 and 8 high and all other GPIO outputs low. + @code + MSS_GPIO_set_outputs( MSS_GPIO_0_MASK | MSS_GPIO_8_MASK ); + @endcode + + Example 2: + Set GPIOs outputs 2 and 4 low without affecting other GPIO outputs. + @code + uint32_t gpio_outputs; + gpio_outputs = MSS_GPIO_get_outputs(); + gpio_outputs &= ~( MSS_GPIO_2_MASK | MSS_GPIO_4_MASK ); + MSS_GPIO_set_outputs( gpio_outputs ); + @endcode + + @see MSS_GPIO_get_outputs() + */ +static __INLINE void +MSS_GPIO_set_outputs +( + uint32_t value +) +{ + GPIO->GPIO_OUT = value; +} + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_set_output() function is used to set the state of a single GPIO + port configured as an output. + Note: Using bit-band writes might be a better option than this function for + performance critical applications where the application code is not + intended to be ported to a processor other than the ARM Cortex-M3 in + SmartFusion2. The bit-band write equivalent to this function would be: + GPIO_BITBAND->GPIO_OUT[port_id] = (uint32_t)value; + + @param port_id + The port_id parameter identifies the GPIO port that is to have its output + set. An enumeration item of the form MSS_GPIO_n, where n is the number of + the GPIO port, is used to identify the GPIO port. For example, MSS_GPIO_0 + identifies the first GPIO port and MSS_GPIO_31 is the last one. + + @param value + The value parameter specifies the desired state for the GPIO output. A value + of 0 will set the output Low and a value of 1 will set the output High. + + @return + This function does not return a value. + + Example: + The following call will set GPIO output 12 High, leaving all other GPIO + outputs unaffected: + @code + _GPIO_set_output(MSS_GPIO_12, 1); + @endcode + */ +void MSS_GPIO_set_output +( + mss_gpio_id_t port_id, + uint8_t value +); + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_get_inputs() function is used to read the current state all GPIO + ports configured as inputs. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of a GPIO input. The least significant bit represents the state of + GPIO input 0 and the most significant bit the state of GPIO input 31. + + Example: + Read and assign the current state of the GPIO outputs to a variable. + @code + uint32_t gpio_inputs; + gpio_inputs = MSS_GPIO_get_inputs(); + @endcode + */ +static __INLINE uint32_t +MSS_GPIO_get_inputs( void ) +{ + return GPIO->GPIO_IN; +} + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_get_outputs() function is used to read the current state all GPIO + ports configured as outputs. + + @return + This function returns a 32-bit unsigned integer where each bit represents + the state of a GPIO output. The least significant bit represents the state + of GPIO output 0 and the most significant bit the state of GPIO output 31. + + Example: + Read and assign the current state of the GPIO outputs to a variable. + @code + uint32_t gpio_outputs; + gpio_outputs = MSS_GPIO_get_outputs(); + @endcode + */ +static __INLINE uint32_t +MSS_GPIO_get_outputs( void ) +{ + return GPIO->GPIO_OUT; +} + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_drive_inout() function is used to set the output state of a + single GPIO port configured as an INOUT. An INOUT GPIO can be in one of three + states: + - High + - Low + - High impedance + An INOUT output would typically be used where several devices can drive the + state of a shared signal line. The High and Low states are equivalent to the + High and Low states of a GPIO configured as an output. The High impedance + state is used to prevent the GPIO from driving its output state onto the + signal line, while at the same time allowing the input state of the GPIO to + be read. + + @param port_id + The port_id parameter identifies the GPIO port for which you want to change + the output state. An enumeration item of the form MSS_GPIO_n, where n is the + number of the GPIO port, is used to identify the GPIO port. For example, + MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one. + + @param inout_state + The inout_state parameter specifies the state of the GPIO port identified by + the port_id parameter. Allowed values of type mss_gpio_inout_state_t are as + follows: + - MSS_GPIO_DRIVE_HIGH + - MSS_GPIO_DRIVE_LOW + - MSS_GPIO_HIGH_Z (High impedance) + + @return + This function does not return a value. + + Example: + The call to MSS_GPIO_drive_inout() below will set the GPIO 7 output to the + high impedance state. + @code + MSS_GPIO_drive_inout( MSS_GPIO_7, MSS_GPIO_HIGH_Z ); + @endcode + */ +void MSS_GPIO_drive_inout +( + mss_gpio_id_t port_id, + mss_gpio_inout_state_t inout_state +); + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_enable_irq() function is used to enable interrupt generation for + the specified GPIO input. Interrupts are generated based on the state of the + GPIO input and the interrupt mode configured for it by MSS_GPIO_config(). + + @param port_id + The port_id parameter identifies the GPIO port for which you want to enable + interrupt generation. An enumeration item of the form MSS_GPIO_n, where n is + the number of the GPIO port, is used to identify the GPIO port. For example, + MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one. + + @return + This function does not return a value. + + Example: + The call to MSS_GPIO_enable_irq() below will allow GPIO 8 to generate + interrupts. + @code + MSS_GPIO_enable_irq( MSS_GPIO_8 ); + @endcode + */ +void MSS_GPIO_enable_irq +( + mss_gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_disable_irq() function is used to disable interrupt generation + for the specified GPIO input. + + @param port_id + The port_id parameter identifies the GPIO port for which you want to disable + interrupt generation. An enumeration item of the form MSS_GPIO_n, where n is + the number of the GPIO port, is used to identify the GPIO port. For example, + MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one. + + @return + This function does not return a value. + + Example: + The call to MSS_GPIO_disable_irq() below will prevent GPIO 8 from generating + interrupts. + @code + MSS_GPIO_disable_irq( MSS_GPIO_8 ); + @endcode + */ +void MSS_GPIO_disable_irq +( + mss_gpio_id_t port_id +); + +/*-------------------------------------------------------------------------*//** + The MSS_GPIO_clear_irq() function is used to clear a pending interrupt from + the specified GPIO input. + Note: The MSS_GPIO_clear_irq() function must be called as part of any GPIO + interrupt service routine (ISR) in order to prevent the same interrupt + event retriggering a call to the GPIO ISR. + + @param port_id + The port_id parameter identifies the GPIO port for which you want to clear + the interrupt. An enumeration item of the form MSS_GPIO_n, where n is the + number of the GPIO port, is used to identify the GPIO port. For example, + MSS_GPIO_0 identifies the first GPIO port and MSS_GPIO_31 is the last one. + + @return + none. + + Example: + The example below demonstrates the use of the MSS_GPIO_clear_irq() function + as part of the GPIO 9 interrupt service routine. + @code + void GPIO9_IRQHandler( void ) + { + do_interrupt_processing(); + + MSS_GPIO_clear_irq( MSS_GPIO_9 ); + } + @endcode + */ +void MSS_GPIO_clear_irq +( + mss_gpio_id_t port_id +); + +#ifdef __cplusplus +} +#endif + +#endif /* MSS_GPIO_H_ */ diff --git a/bsp/smartfusion2/libraries/mss_sys_services/mss_comblk.c b/bsp/smartfusion2/libraries/mss_sys_services/mss_comblk.c new file mode 100644 index 0000000000..ebd9805ca2 --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_sys_services/mss_comblk.c @@ -0,0 +1,752 @@ +/******************************************************************************* + * (c) Copyright 2012-2016 Microsemi SoC Products Group. All rights reserved. + * + * SmartFusion2 COMBLK access functions. + * + * SVN $Revision: 8345 $ + * SVN $Date: 2016-03-23 11:53:04 +0530 (Wed, 23 Mar 2016) $ + */ + +#include "mss_comblk.h" +#include "../../CMSIS/mss_assert.h" + +/*============================================================================== + * + */ +/*------------------------------------------------------------------------------ + * Control register bit masks. + */ +#define CR_FLUSHOUT_MASK 0x01u +#define CR_FLUSHIN_MASK 0x02u +#define CR_SIZETX_MASK 0x04u +#define CR_ENABLE_MASK 0x10u +#define CR_LOOPBACK_MASK 0x20u + +/*------------------------------------------------------------------------------ + * Status and interrupt enable registers bit masks. + */ +#define TXTOKAY_MASK 0x01u +#define RCVOKAY_MASK 0x02u +#define TXOVERFLOW_MASK 0x04u +#define RXUNDERFLOW_MASK 0x08u +/*------------------------------------------------------------------------------ + * DATA8 register bit masks. + */ +#define DATA8_COMMAND_MASK 0x8000u + +/*------------------------------------------------------------------------------ + * COMBLK driver states. + */ +#define COMBLK_IDLE 0u +#define COMBLK_TX_CMD 1u +#define COMBLK_TX_DATA 2u +#define COMBLK_WAIT_RESPONSE 3u +#define COMBLK_RX_RESPONSE 4u +#define COMBLK_TX_PAGED_DATA 5u + +#define POR_DIGEST_ERROR_OPCODE 0xF1u + +/*============================================================================== + * COMBLK interrupt service routine. + */ +void ComBlk_IRQHandler(void); + +/*============================================================================== + * Local functions. + */ +static void abort_current_cmd(void); +static void send_cmd_opcode(uint8_t opcode); +static uint32_t fill_tx_fifo(const uint8_t * p_cmd, uint32_t cmd_size); +static void handle_tx_okay_irq(void); +static void handle_rx_okay_irq(void); +static void complete_request(uint16_t response_length); +static void process_sys_ctrl_command(uint8_t cmd_opcode); + +/*============================================================================== + * Global variables: + */ +static volatile uint8_t g_comblk_cmd_opcode = 0u; +static const uint8_t * g_comblk_p_cmd = 0u; +static volatile uint16_t g_comblk_cmd_size = 0u; +static const uint8_t * g_comblk_p_data = 0u; +static volatile uint32_t g_comblk_data_size = 0u; +static uint8_t * g_comblk_p_response = 0u; +static uint16_t g_comblk_response_size = 0u; +static volatile uint16_t g_comblk_response_idx = 0u; +static comblk_completion_handler_t g_comblk_completion_handler = 0; +static uint32_t (*g_comblk_page_handler)(uint8_t const ** pp_next_page) = 0; +static volatile uint8_t g_request_in_progress = 0u; +static uint8_t g_comblk_state = COMBLK_IDLE; +static volatile comblk_async_event_handler_t g_async_event_handler = 0; + +/*============================================================================== + * + */ +void MSS_COMBLK_init +( + comblk_async_event_handler_t async_event_handler, + uint8_t* p_response +) +{ + /* + * Disable and clear previous interrupts. + */ + NVIC_DisableIRQ(ComBlk_IRQn); + COMBLK->INT_ENABLE = 0u; + NVIC_ClearPendingIRQ(ComBlk_IRQn); + + g_async_event_handler = async_event_handler; + + /* + * Initialize COMBLK driver state variables: + */ + g_request_in_progress = 0u; + g_comblk_cmd_opcode = 0u; + g_comblk_p_cmd = 0u; + g_comblk_cmd_size = 0u; + g_comblk_p_data = 0u; + g_comblk_data_size = 0u; + g_comblk_p_response = p_response; + g_comblk_response_size = 0u; + g_comblk_response_idx = 0u; + g_comblk_completion_handler = 0; + + g_comblk_state = COMBLK_IDLE; + + /* + * Disable loopback before enabling the MSS COMM_BLK to ensure that any + * codes waiting in the TX FIFO of the System Controller�s COMM_BLK are + * not lost. + */ + COMBLK->CONTROL &= ~CR_LOOPBACK_MASK; + COMBLK->CONTROL |= CR_ENABLE_MASK; + + /*-------------------------------------------------------------------------- + * Enable receive interrupt to receive asynchronous events from the system + * controller. + */ + COMBLK->INT_ENABLE &= ~TXTOKAY_MASK; + COMBLK->INT_ENABLE |= RCVOKAY_MASK; + NVIC_EnableIRQ(ComBlk_IRQn); +} + +/*============================================================================== + * + */ +void MSS_COMBLK_send_cmd_with_ptr +( + uint8_t cmd_opcode, + uint32_t cmd_params_ptr, + uint8_t * p_response, + uint16_t response_size, + comblk_completion_handler_t completion_handler +) +{ + uint32_t tx_okay; + + /*-------------------------------------------------------------------------- + * Disable and clear previous interrupts. + */ + NVIC_DisableIRQ(ComBlk_IRQn); + COMBLK->INT_ENABLE = 0u; + NVIC_ClearPendingIRQ(ComBlk_IRQn); + + /*-------------------------------------------------------------------------- + * Abort current command if any. + */ + abort_current_cmd(); + + /*-------------------------------------------------------------------------- + * Initialize COMBLK driver state variables. + */ + g_request_in_progress = 1u; + g_comblk_cmd_opcode = cmd_opcode; + g_comblk_p_cmd = 0u; + g_comblk_cmd_size = 0u; + g_comblk_p_data = 0u; + g_comblk_data_size = 0u; + g_comblk_p_response = p_response; + g_comblk_response_size = response_size; + g_comblk_response_idx = 0u; + g_comblk_page_handler = 0u; + g_comblk_completion_handler = completion_handler; + + /*-------------------------------------------------------------------------- + * Send command opcode as a single byte write to the Tx FIFO. + */ + send_cmd_opcode(g_comblk_cmd_opcode); + + /*-------------------------------------------------------------------------- + * Send the command parameters pointer to the Tx FIFO as a single 4 bytes + * write to the Tx FIFO. + */ + COMBLK->CONTROL |= CR_SIZETX_MASK; + + /* Wait for space to become available in Tx FIFO. */ + do { + tx_okay = COMBLK->STATUS & TXTOKAY_MASK; + } while(0u == tx_okay); + + /* Send command opcode. */ + COMBLK->DATA32 = cmd_params_ptr; + + COMBLK->CONTROL &= ~CR_SIZETX_MASK; + + g_comblk_state = COMBLK_WAIT_RESPONSE; + + /*-------------------------------------------------------------------------- + * Enable interrupt. + */ + COMBLK->INT_ENABLE |= RCVOKAY_MASK; + NVIC_EnableIRQ(ComBlk_IRQn); +} + +/*============================================================================== + * + */ +void MSS_COMBLK_send_cmd +( + const uint8_t * p_cmd, + uint16_t cmd_size, + const uint8_t * p_data, + uint32_t data_size, + uint8_t * p_response, + uint16_t response_size, + comblk_completion_handler_t completion_handler +) +{ + uint32_t size_sent; + + ASSERT(cmd_size > 0); + + /* + * Disable and clear previous interrupts. + */ + NVIC_DisableIRQ(ComBlk_IRQn); + COMBLK->INT_ENABLE = 0u; + NVIC_ClearPendingIRQ(ComBlk_IRQn); + + /* + * Abort current command if any. + */ + abort_current_cmd(); + + /* + * Initialize COMBLK driver state variables: + */ + g_request_in_progress = 1u; + g_comblk_cmd_opcode = p_cmd[0]; + g_comblk_p_cmd = p_cmd; + g_comblk_cmd_size = cmd_size; + g_comblk_p_data = p_data; + g_comblk_data_size = data_size; + g_comblk_p_response = p_response; + g_comblk_response_size = response_size; + g_comblk_response_idx = 0u; + g_comblk_page_handler = 0u; + g_comblk_completion_handler = completion_handler; + + COMBLK->INT_ENABLE |= RCVOKAY_MASK; + + /* + * Fill FIFO with command. + */ + send_cmd_opcode(g_comblk_cmd_opcode); + size_sent = fill_tx_fifo(&p_cmd[1], cmd_size - 1u); + ++size_sent; /* Adjust for opcode byte sent. */ + if(size_sent < cmd_size) + { + g_comblk_cmd_size = g_comblk_cmd_size - (uint16_t)size_sent; + g_comblk_p_cmd = &g_comblk_p_cmd[size_sent]; + + g_comblk_state = COMBLK_TX_CMD; + } + else + { + g_comblk_cmd_size = 0u; + if(g_comblk_data_size > 0u) + { + g_comblk_state = COMBLK_TX_DATA; + } + else + { + g_comblk_state = COMBLK_WAIT_RESPONSE; + } + } + + /* + * Enable interrupt. + */ + NVIC_EnableIRQ(ComBlk_IRQn); +} + +/*============================================================================== + * + */ +void MSS_COMBLK_send_paged_cmd +( + const uint8_t * p_cmd, + uint16_t cmd_size, + uint8_t * p_response, + uint16_t response_size, + comblk_page_handler_t page_read_handler, + comblk_completion_handler_t completion_handler +) +{ + uint32_t size_sent; + uint8_t irq_enable = 0u; + + ASSERT(cmd_size > 0u); + + /* + * Disable and clear previous interrupts. + */ + NVIC_DisableIRQ(ComBlk_IRQn); + COMBLK->INT_ENABLE = 0u; + NVIC_ClearPendingIRQ(ComBlk_IRQn); + + /* + * Abort current command if any. + */ + abort_current_cmd(); + + /* + * Initialize COMBLK driver state variables: + */ + g_request_in_progress = 1u; + g_comblk_cmd_opcode = p_cmd[0]; + g_comblk_p_cmd = p_cmd; + g_comblk_cmd_size = cmd_size; + g_comblk_p_data = 0; + g_comblk_data_size = 0u; + g_comblk_p_response = p_response; + g_comblk_response_size = response_size; + g_comblk_response_idx = 0u; + g_comblk_page_handler = page_read_handler; + g_comblk_completion_handler = completion_handler; + + /* + * Fill FIFO with command. + */ + send_cmd_opcode(g_comblk_cmd_opcode); + size_sent = fill_tx_fifo(&p_cmd[1], cmd_size - 1u); + ++size_sent; /* Adjust for opcode byte sent. */ + if(size_sent < cmd_size) + { + g_comblk_cmd_size = g_comblk_cmd_size - (uint16_t)size_sent; + g_comblk_p_cmd = &g_comblk_p_cmd[size_sent]; + + g_comblk_state = COMBLK_TX_CMD; + irq_enable = TXTOKAY_MASK | RCVOKAY_MASK; + } + else + { + g_comblk_cmd_size = 0u; + g_comblk_state = COMBLK_TX_PAGED_DATA; + irq_enable = TXTOKAY_MASK | RCVOKAY_MASK; + } + + /* + * Enable interrupt. + */ + COMBLK->INT_ENABLE |= irq_enable; + NVIC_EnableIRQ(ComBlk_IRQn); +} + +/*============================================================================== + * COMBLK interrupt handler. + */ +void ComBlk_IRQHandler(void) +{ + uint8_t status; + uint8_t tx_okay; + uint8_t rcv_okay; + + status = (uint8_t)COMBLK->STATUS; + + /* Mask off interrupt that are not enabled.*/ + status &= COMBLK->INT_ENABLE; + + rcv_okay = status & RCVOKAY_MASK; + + if(rcv_okay) + { + handle_rx_okay_irq(); + } + + tx_okay = status & TXTOKAY_MASK; + if(tx_okay) + { + handle_tx_okay_irq(); + } +} + +/*============================================================================== + * + */ +static void handle_tx_okay_irq(void) +{ + switch(g_comblk_state) + { + /*---------------------------------------------------------------------- + * The TX_OKAY interrupt should only be enabled for states COMBLK_TX_CMD + * and COMBLK_TX_DATA. + */ + case COMBLK_TX_CMD: + if(g_comblk_cmd_size > 0u) + { + uint32_t size_sent; + size_sent = fill_tx_fifo(g_comblk_p_cmd, g_comblk_cmd_size); + if(size_sent < g_comblk_cmd_size) + { + g_comblk_cmd_size = g_comblk_cmd_size - (uint16_t)size_sent; + g_comblk_p_cmd = &g_comblk_p_cmd[size_sent]; + } + else + { + g_comblk_cmd_size = 0u; + if(g_comblk_data_size > 0u) + { + g_comblk_state = COMBLK_TX_DATA; + } + else + { + g_comblk_state = COMBLK_WAIT_RESPONSE; + } + } + } + else + { + /* + * This is an invalid situation indicating a bug in the driver + * or corrupted memory. + */ + ASSERT(0); + abort_current_cmd(); + } + break; + + case COMBLK_TX_DATA: + if(g_comblk_data_size > 0u) + { + uint32_t size_sent; + size_sent = fill_tx_fifo(g_comblk_p_data, g_comblk_data_size); + if(size_sent < g_comblk_data_size) + { + g_comblk_data_size = g_comblk_data_size - size_sent; + g_comblk_p_data = &g_comblk_p_data[size_sent]; + } + else + { + COMBLK->INT_ENABLE &= ~TXTOKAY_MASK; + g_comblk_state = COMBLK_WAIT_RESPONSE; + } + } + else + { + /* + * This is an invalid situation indicating a bug in the driver + * or corrupted memory. + */ + ASSERT(0); + abort_current_cmd(); + } + break; + + case COMBLK_TX_PAGED_DATA: + /* + * Read a page of data if required. + */ + if(0u == g_comblk_data_size) + { + if(g_comblk_page_handler != 0) + { + g_comblk_data_size = g_comblk_page_handler(&g_comblk_p_data); + if(0u == g_comblk_data_size) + { + COMBLK->INT_ENABLE &= ~TXTOKAY_MASK; + g_comblk_state = COMBLK_WAIT_RESPONSE; + } + } + else + { + ASSERT(0); + abort_current_cmd(); + } + } + + /* + * Transmit the page data or move to COMBLK_WAIT_RESPONSE state if + * no further page data could be obtained by the call to the page + * handler above. + */ + if(0u == g_comblk_data_size) + { + COMBLK->INT_ENABLE &= ~TXTOKAY_MASK; + g_comblk_state = COMBLK_WAIT_RESPONSE; + } + else + { + uint32_t size_sent; + size_sent = fill_tx_fifo(g_comblk_p_data, g_comblk_data_size); + g_comblk_data_size = g_comblk_data_size - size_sent; + g_comblk_p_data = &g_comblk_p_data[size_sent]; + } + break; + + /*---------------------------------------------------------------------- + * The TX_OKAY interrupt should NOT be enabled for states COMBLK_IDLE, + * COMBLK_WAIT_RESPONSE and COMBLK_RX_RESPONSE. + */ + case COMBLK_IDLE: + /* Fall through */ + case COMBLK_WAIT_RESPONSE: + /* Fall through */ + case COMBLK_RX_RESPONSE: + /* Fall through */ + default: + COMBLK->INT_ENABLE &= ~TXTOKAY_MASK; + complete_request(0u); + g_comblk_state = COMBLK_IDLE; + break; + } +} + +/*============================================================================== + * + */ +static void handle_rx_okay_irq(void) +{ + uint16_t data16; + uint16_t is_command; + uint8_t data8; + + data16 = (uint16_t)COMBLK->DATA8; + is_command = data16 & DATA8_COMMAND_MASK; + data8 = (uint8_t)data16; + + switch(g_comblk_state) + { + /*---------------------------------------------------------------------- + * MSS_COMBLK_init() enables the RCV_OKAY interrupt for the COMBLK_IDLE + * state to receive the asynchronous power-on-reset from the system + * controller. + */ + case COMBLK_IDLE: + if(is_command) + { + if(data8 != POR_DIGEST_ERROR_OPCODE) + { + uint8_t rxed_opcode; + rxed_opcode = data8; + process_sys_ctrl_command(rxed_opcode); + } + else + { + g_comblk_response_idx = 0; + g_comblk_p_response[g_comblk_response_idx] = data8; + g_comblk_response_idx++; + g_comblk_p_response[g_comblk_response_idx] = 0x00u; + g_comblk_state = COMBLK_RX_RESPONSE; + } + } + break; + + /*---------------------------------------------------------------------- + * The RCV_OKAY interrupt should only be enabled for states + * COMBLK_WAIT_RESPONSE and COMBLK_RX_RESPONSE. + */ + case COMBLK_WAIT_RESPONSE: + if(is_command) + { + uint8_t rxed_opcode; + rxed_opcode = data8; + if(rxed_opcode == g_comblk_cmd_opcode) + { + g_comblk_response_idx = 0u; + g_comblk_p_response[g_comblk_response_idx] = rxed_opcode; + ++g_comblk_response_idx; + g_comblk_state = COMBLK_RX_RESPONSE; + } + else + { + process_sys_ctrl_command(rxed_opcode); + } + } + break; + + case COMBLK_RX_RESPONSE: + if(is_command) + { + uint8_t rxed_opcode; + rxed_opcode = data8; + process_sys_ctrl_command(rxed_opcode); + } + else + { + if( g_comblk_p_response[g_comblk_response_idx-1] == POR_DIGEST_ERROR_OPCODE) + { + g_comblk_p_response[g_comblk_response_idx] = data8; + process_sys_ctrl_command(g_comblk_p_response[g_comblk_response_idx-1]); + g_comblk_state = COMBLK_IDLE; + } + else + { + if(g_comblk_response_idx < g_comblk_response_size) + { + uint8_t rxed_data; + + rxed_data = data8; + g_comblk_p_response[g_comblk_response_idx] = rxed_data; + ++g_comblk_response_idx; + } + + if(g_comblk_response_idx == g_comblk_response_size) + { + complete_request(g_comblk_response_idx); + g_comblk_state = COMBLK_IDLE; + } + } + } + break; + + /*---------------------------------------------------------------------- + * The RCV_OKAY interrupt should NOT be enabled for states + * COMBLK_IDLE, COMBLK_TX_CMD and COMBLK_TX_DATA. + */ + case COMBLK_TX_PAGED_DATA: + /* This is needed because when there is an error, we need to terminate loading the data */ + if(!is_command) + { + g_comblk_p_response[1] = data8; + complete_request(2u); + g_comblk_state = COMBLK_IDLE; + } + else + { + uint8_t rxed_opcode; + rxed_opcode = data8; + process_sys_ctrl_command(rxed_opcode); + } + break; + + case COMBLK_TX_CMD: + /* Fall through */ + case COMBLK_TX_DATA: + /* Fall through */ + if(is_command) + { + uint8_t rxed_opcode; + rxed_opcode = data8; + process_sys_ctrl_command(rxed_opcode); + } + break; + + default: + complete_request(0u); + g_comblk_state = COMBLK_IDLE; + break; + } +} + +/*============================================================================== + * + */ +static void complete_request +( + uint16_t response_length +) +{ + if(g_comblk_completion_handler != 0) + { + g_comblk_completion_handler(g_comblk_p_response, response_length); + g_comblk_completion_handler = 0; + g_request_in_progress = 0u; + } +} + +/*============================================================================== + * + */ +static void abort_current_cmd(void) +{ + if(g_request_in_progress) + { + uint32_t flush_in_progress; + + /* + * Call completion handler just in case we are in a multi threaded system + * to avoid a task lockup. + */ + complete_request(g_comblk_response_idx); + + /* + * Flush the FIFOs + */ + COMBLK->CONTROL |= CR_FLUSHOUT_MASK; + do { + flush_in_progress = COMBLK->CONTROL & CR_FLUSHOUT_MASK; + } while(flush_in_progress); + } +} + +/*============================================================================== + * + */ +static void send_cmd_opcode +( + uint8_t opcode +) +{ + uint32_t tx_okay; + + /* Set transmit FIFO to transfer bytes. */ + COMBLK->CONTROL &= ~CR_SIZETX_MASK; + + /* Wait for space to become available in Tx FIFO. */ + do { + tx_okay = COMBLK->STATUS & TXTOKAY_MASK; + } while(0u == tx_okay); + + /* Send command opcode. */ + COMBLK->FRAME_START8 = opcode; +} + +/*============================================================================== + * + */ +static uint32_t fill_tx_fifo +( + const uint8_t * p_cmd, + uint32_t cmd_size +) +{ + volatile uint32_t tx_okay; + uint32_t size_sent; + + /* Set transmit FIFO to transfer bytes. */ + COMBLK->CONTROL &= ~CR_SIZETX_MASK; + + size_sent = 0u; + tx_okay = COMBLK->STATUS & TXTOKAY_MASK; + while((tx_okay != 0u) && (size_sent < cmd_size)) + { + COMBLK->DATA8 = p_cmd[size_sent]; + ++size_sent; + tx_okay = COMBLK->STATUS & TXTOKAY_MASK; + } + + return size_sent; +} + +/*============================================================================== + * + */ +static void process_sys_ctrl_command(uint8_t cmd_opcode) +{ + if(g_async_event_handler != 0) + { + g_async_event_handler(cmd_opcode); + } +} + diff --git a/bsp/smartfusion2/libraries/mss_sys_services/mss_comblk.h b/bsp/smartfusion2/libraries/mss_sys_services/mss_comblk.h new file mode 100644 index 0000000000..96d3af5518 --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_sys_services/mss_comblk.h @@ -0,0 +1,90 @@ +/******************************************************************************* + * (c) Copyright 2012-2016 Microsemi SoC Products Group. All rights reserved. + * + * SmartFusion2 COMBLK access functions. + * + * SVN $Revision: 8345 $ + * SVN $Date: 2016-03-23 11:53:04 +0530 (Wed, 23 Mar 2016) $ + */ +#ifndef __MSS_COMBLK_H_ +#define __MSS_COMBLK_H_ 1 + +#include "../../CMSIS/m2sxxx.h" +#include "mss_comblk_page_handler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * + */ +typedef void(*comblk_completion_handler_t)(uint8_t * p_response, uint16_t response_size); + +typedef void (*comblk_async_event_handler_t)(uint8_t event_opcode); + +/*------------------------------------------------------------------------------ + * + */ +void MSS_COMBLK_init +( + comblk_async_event_handler_t async_event_handler, + uint8_t* p_response +); + +/*------------------------------------------------------------------------------ + * + */ +void MSS_COMBLK_send_cmd_with_ptr +( + uint8_t cmd_opcode, + uint32_t cmd_params_ptr, + uint8_t * p_response, + uint16_t response_size, + comblk_completion_handler_t completion_handler +); + +/*------------------------------------------------------------------------------ + * + */ +void MSS_COMBLK_send_cmd +( + const uint8_t * p_cmd, + uint16_t cmd_size, + const uint8_t * p_data, + uint32_t data_size, + uint8_t * p_response, + uint16_t response_size, + comblk_completion_handler_t completion_handler +); + +/*------------------------------------------------------------------------------ + * + */ +void MSS_COMBLK_read +( + const uint8_t * p_data, + uint16_t cmd_size, + uint8_t * p_response, + uint16_t response_size, + comblk_completion_handler_t completion_handler +); + +/*------------------------------------------------------------------------------ + * + */ +void MSS_COMBLK_send_paged_cmd +( + const uint8_t * p_cmd, + uint16_t cmd_size, + uint8_t * p_response, + uint16_t response_size, + comblk_page_handler_t page_read_handler, + comblk_completion_handler_t completion_handler +); + +#ifdef __cplusplus +} +#endif + +#endif /* __MSS_COMBLK_H_ */ diff --git a/bsp/smartfusion2/libraries/mss_sys_services/mss_comblk_page_handler.h b/bsp/smartfusion2/libraries/mss_sys_services/mss_comblk_page_handler.h new file mode 100644 index 0000000000..1c363df54e --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_sys_services/mss_comblk_page_handler.h @@ -0,0 +1,66 @@ +/******************************************************************************* + * (c) Copyright 2012-2016 Microsemi SoC Products Group. All rights reserved. + * + * SmartFusion2 MSS COM block driver, page handler callback function prototype. + * + * SVN $Revision: 8345 $ + * SVN $Date: 2016-03-23 11:53:04 +0530 (Wed, 23 Mar 2016) $ + */ + +#ifndef __MSS_COMBLK_PAGE_HANDLER_H_ +#define __MSS_COMBLK_PAGE_HANDLER_H_ 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + The comblk_page_handler_t typedef specifies the function prototype of a COMBLK + page handler callback function. This callback is used by the system services + and COMBLK drivers as part of in-system programming (ISP) to retrieve the next + page of programming information to send to the SmartFusion2 System Controller + via the COMBLK. + The COMBLK page handler must be implemented by the application layer to return + the address of the next page of programming data to be sent to the + SmartFusion2 system controller. It must return the number of bytes contained + in the next page. Returning a value of zero indicates that all programming + data has been passed to the system services/COMBLK drivers. + + @code + #define PAGE_LENGTH 512 + + uint8_t programming_data[PROG_DATA_LENGTH]; + uint32_t prog_data_index = 0; + + uint32_t page_read_handler + ( + uint8_t const ** pp_next_page + ) + { + uint32_t returned_page_length; + uint32_t remaining_length; + + *pp_next_page = &programming_data[prog_data_index]; + remaining_length = PROG_DATA_LENGTH - prog_data_index + if(remaining_length > PAGE_LENGTH) + { + returned_page_length = PAGE_LENGTH; + } + else + { + returned_page_length = remaining_length; + prog_data_index = PROG_DATA_LENGTH; + } + + return returned_page_length; + } + + @endcode + */ +typedef uint32_t (*comblk_page_handler_t)(uint8_t const ** pp_next_page); + +#ifdef __cplusplus +} +#endif + +#endif /* __MSS_COMBLK_PAGE_HANDLER_H_ */ diff --git a/bsp/smartfusion2/libraries/mss_sys_services/mss_sys_services.c b/bsp/smartfusion2/libraries/mss_sys_services/mss_sys_services.c new file mode 100644 index 0000000000..982b9d088b --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_sys_services/mss_sys_services.c @@ -0,0 +1,2452 @@ +/******************************************************************************* + * (c) Copyright 2012-2016 Microsemi SoC Products Group. All rights reserved. + * + * SmartFusion2 system services. + * + * SVN $Revision: 8688 $ + * SVN $Date: 2016-11-27 17:46:49 +0530 (Sun, 27 Nov 2016) $ + */ +#include "mss_sys_services.h" +#include "mss_comblk.h" +#include "../../CMSIS/mss_assert.h" +#include <string.h> + +/*============================================================================== + * + */ +/* + * Service request command opcodes: + */ +#define DEVICE_CERTIFICATE_REQUEST_CMD 0u +#define SERIAL_NUMBER_REQUEST_CMD 1u +#define FLASH_FREEZE_REQUEST_CMD 2u +#define AES128_REQUEST_CMD 3u +#define USERCODE_REQUEST_CMD 4u +#define DESIGNVER_REQUEST_CMD 5u +#define AES256_REQUEST_CMD 6u +#define KEYTREE_REQUEST_CMD 9u +#define SHA256_REQUEST_CMD 10u +#define HMAC_REQUEST_CMD 12u +#define PPUF_CHALLENGE_RESP_REQUEST_CMD 14u +#define POINT_MULTIPLICATION_REQUEST_CMD 16u +#define POINT_ADDITION_REQUEST_CMD 17u +#define IAP_PROGRAMMING_REQUEST_CMD 20u +#define ISP_PROGRAMMING_REQUEST_CMD 21u +#define DIGEST_CHECK_REQUEST_CMD 23u +#define PUF_ACTIVATION_CODE_REQUEST_CMD 25u +#define PUF_USER_KEY_CODE_REQUEST_CMD 26u +#define PUF_FETCH_KEY_REQUEST_CMD 27u +#define PUF_ECC_PUBLIC_KEY_REQUEST_CMD 28u +#define PUF_SEED_REQUEST_CMD 29u +#define SECONDARY_DEVICE_CERTIFICATE_REQUEST_CMD 30u +#define TAMPER_CONTROL_REQUEST_CMD 31u +#define NRBG_SELF_TEST_REQUEST_CMD 40u +#define NRBG_INSTANTIATE_REQUEST_CMD 41u +#define NRBG_GENERATE_REQUEST_CMD 42u +#define NRBG_RESEED_REQUEST_CMD 43u +#define NRBG_UNINSTANTIATE_REQUEST_CMD 44u +#define NRBG_RESET_REQUEST_CMD 45u +#define FLASHFREEZE_SHUTDOWN_CMD 224u +#define ZEROIZATION_REQUEST_CMD 240u +#define POWER_ON_RESET_DIGEST_ERROR_CMD 241u + +/* + * System Services requests length: + */ +#define FLASH_FREEZE_REQUEST_LENGTH 2u + +/* + * Service response lengths: + */ +#define STANDARD_SERV_RESP_LENGTH 6u +#define SERIAL_NUMBER_SERV_RESP_LENGTH 6u +#define USERCODE_SERV_RESP_LENGTH 6u +#define DESIGNVER_SERV_RESP_LENGTH 6u +#define DEVICE_CERT_SERV_RESP_LENGTH 6u +#define SECONDARY_DEVICE_CERT_SERV_RESP_LENGTH 6u +#define ISP_PROG_SERV_RESP_LENGTH 2u +#define IAP_PROG_SERV_RESP_LENGTH 2u +#define NRBG_RESET_SERV_RESP_LENGTH 2u +#define NRBG_SELF_TEST_SERV_RESP_LENGTH 2u +#define NRBG_UNINST_SERV_RESP_LENGTH 3u +#define DRBG_RESET_SERV_RESP_LENGTH 2u +#define DIGEST_CHECK_SERV_RESP_LENGTH 2u +#define FLASH_FREEZE_SERV_RESP_LENGTH 2u +#define PORDIGEST_CHECK_SERV_RESP_LENGTH 2u +#define TAMPER_CONTROL_SERV_RESP_LENGTH 2u +#define PUF_USER_ACTIVATION_CODE_RESP_LENGTH 2u +#define PUF_GET_NUMBER_OF_KEYS_RESP_LENGTH 6u +#define PUF_ENROLL_KEYS_RESP_LENGTH 6u +#define PUF_EXPORT_ALL_KEYCODES_RESP_LENGTH 6u +#define PUF_IMPORT_ALL_KEYCODES_RESP_LENGTH 6u +#define FACC_STANDBY_SEL 0u +#define MSS_25_50MHZ_EN 1u +#define MSS_1MHZ_EN 1u +#define FACC_STANDBY_SHIFT 6u +#define MSS_25_50MHZ_EN_SHIFT 9u +#define MSS_1MHZ_EN_SHIFT 10u +#define FACC_STANDBY_SEL_MASK 0x000001C0u +#define MSS_25_50MHZ_EN_MASK 0x00000200u +#define MSS_1MHZ_EN_MASK 0x00000400u + +/* + * Non Deterministic Random Bit Generator defines: + */ +#define INVALID_NRBG_HANDLE 0xFFu + +/* + * RTC_WAKEUP_CR system register bit masks: + */ +#define RTC_WAKEUP_G4C_EN_MASK 0x00000004u +#define RTC_WAKEUP_FAB_EN_MASK 0x00000002u + +/* + * PUF user activation code sub command + */ +#define PUF_CREATE_USER_ACTIVATION_CODE 0u +#define PUF_DELETE_USER_ACTIVATION_CODE 1u + +/* + * Sub Command for PUF service + */ +#define PUF_GET_NUMBER_OF_KC_SUBCOMMAND 0u +#define PUF_CREATE_EXT_KC_SUBCOMMAND 1u +#define PUF_CREATE_INT_KC_SUBCOMMAND 2u +#define PUF_EXPORT_ALL_KC_SUBCOMMAND 3u +#define PUF_IMPORT_ALL_KC_SUBCOMMAND 4u +#define PUF_DELETE_KC_SUBCOMMAND 5u + +/*============================================================================== + * Local functions. + */ +static void request_completion_handler(uint8_t * p_response, uint16_t response_size); +static void signal_request_start(void); +static uint16_t wait_for_request_completion(void); +static uint8_t execute_service +( + uint8_t cmd_opcode, + uint8_t * cmd_params_ptr, + uint8_t * response, + uint16_t response_length +); + +static void asynchronous_event_handler(uint8_t event_opcode); + +static void write_ptr_value_into_array +( + const uint8_t * pointer, + uint8_t target_array[], + uint32_t array_index +); + +static void write_array_into_ptr_value +( + uint8_t** pointer, + uint8_t target_array[], + uint32_t array_index +); +static void revert_clk_config(void); +static uint8_t clk_switching_fix(void); +static uint8_t* determine_seq(uint8_t val, uint8_t* len); + +/*============================================================================== + * Global variables + */ +static volatile uint8_t g_request_in_progress = 0u; +static volatile uint16_t g_last_response_length = 0u; +static sys_serv_async_event_handler_t g_event_handler = 0; +static uint8_t g_response[PORDIGEST_CHECK_SERV_RESP_LENGTH] = {0u}; +static uint32_t g_initial_mssddr_facc1_cr = 0U; + +/*============================================================================== + * See mss_sys_services.h for details. + */ +void MSS_SYS_init(sys_serv_async_event_handler_t event_handler) +{ + g_event_handler = event_handler; + g_last_response_length = 0u; + g_request_in_progress = 0u; + + /* + * Set a default good value for g_initial_mssddr_facc1_cr used to control + * the clock dividers coming in and out of Flash*Freeze. + */ + g_initial_mssddr_facc1_cr = SYSREG->MSSDDR_FACC1_CR; + + /* + * Initialize the COMBLK used to communicate with the System Controller. + */ + MSS_COMBLK_init(asynchronous_event_handler, g_response); +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +/* Tamper attempt/failure range */ +#define TAMPER_ATTEMPT_DETECT_OPCODE_RANGE_MIN 0x80u +#define TAMPER_ATTEMPT_DETECT_OPCODE_RANGE_MAX 0x8Fu +#define TAMPER_FAILURE_DETECT_OPCODE_RANGE_MIN 0x90u +#define TAMPER_FAILURE_DETECT_OPCODE_RANGE_MAX 0x9Fu +#define TAMPER_CLOCK_MONITOR_ERROR_OPCODE 0xA0u +#define TAMPER_HARDWARE_MONITOR_ERROR_OPCODE_RANGE_MIN 0xB1u +#define TAMPER_HARDWARE_MONITOR_ERROR_OPCODE_RANGE_MAX 0xB7u + +#define FACC_GLMUX_SEL_MASK 0x00001000u +#define DELAY_MORE_THAN_10US 5000U +static void asynchronous_event_handler(uint8_t event_opcode) +{ + if (event_opcode == FLASH_FREEZE_SHUTDOWN_OPCODE) + { + uint32_t running_on_standby_clock; + volatile uint32_t timeout; + + /* + * Wait for the System Controller to switch the system's clock + * from the main clock to the standby clock. This should take place + * within 10us of receiving the shut-down event. + */ + timeout = DELAY_MORE_THAN_10US; + do + { + running_on_standby_clock = SYSREG->MSSDDR_FACC1_CR & FACC_GLMUX_SEL_MASK; + --timeout; + } + while ((running_on_standby_clock == 0U) && (timeout != 0U)); + + /* Call the user's event handler. */ + if(g_event_handler != 0) + { + g_event_handler(event_opcode, g_response[1]); + } + } + else if (event_opcode == FLASH_FREEZE_EXIT_OPCODE) + { + uint32_t running_on_standby_clock; + volatile uint32_t timeout; + + /* + * Wait for the System Controller to switch the system's clock + * from the standby clock to the main clock. This should take place + * within 10us of receiving the shut-down event. + */ + timeout = DELAY_MORE_THAN_10US; + do + { + running_on_standby_clock = SYSREG->MSSDDR_FACC1_CR & FACC_GLMUX_SEL_MASK; + --timeout; + } + while ((running_on_standby_clock != 0U) && (timeout != 0U)); + + /* Restore the clock dividers values of FACC1 register. */ + revert_clk_config(); + + if(g_event_handler != 0) + { + /* Call the user's event handler. */ + g_event_handler(event_opcode, g_response[1]); + } + } + else + { + if ((event_opcode == POR_DIGEST_ERROR_OPCODE) || \ + ((event_opcode >= TAMPER_ATTEMPT_DETECT_OPCODE_RANGE_MIN) && \ + (event_opcode <= TAMPER_FAILURE_DETECT_OPCODE_RANGE_MAX)) || \ + (event_opcode == TAMPER_CLOCK_MONITOR_ERROR_OPCODE) || \ + ((event_opcode >= TAMPER_HARDWARE_MONITOR_ERROR_OPCODE_RANGE_MIN) && \ + (event_opcode <= TAMPER_HARDWARE_MONITOR_ERROR_OPCODE_RANGE_MAX))) + { + /* + * Inform to the application that new asynchronous message is received, + * only if application call-back function is registered during + * initialization. + */ + if(g_event_handler != 0) + { + /* Call the user's event handler. */ + g_event_handler(event_opcode, g_response[1]); + } + } + } +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_get_serial_number +( + uint8_t * p_serial_number +) +{ + uint8_t response[SERIAL_NUMBER_SERV_RESP_LENGTH]; + uint8_t status; + + status = execute_service(SERIAL_NUMBER_REQUEST_CMD, + p_serial_number, + response, + SERIAL_NUMBER_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_get_user_code +( + uint8_t * p_user_code +) +{ + uint8_t response[USERCODE_SERV_RESP_LENGTH]; + uint8_t status; + + status = execute_service(USERCODE_REQUEST_CMD, + p_user_code, + response, + USERCODE_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_get_design_version +( + uint8_t * p_design_version +) +{ + uint8_t response[DESIGNVER_SERV_RESP_LENGTH]; + uint8_t status; + + status = execute_service(DESIGNVER_REQUEST_CMD, + p_design_version, + response, + DESIGNVER_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_get_device_certificate +( + uint8_t * p_device_certificate +) +{ + uint8_t response[DEVICE_CERT_SERV_RESP_LENGTH]; + uint8_t status; + + status = execute_service(DEVICE_CERTIFICATE_REQUEST_CMD, + p_device_certificate, + response, + DEVICE_CERT_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_get_secondary_device_certificate +( + uint8_t * p_secondary_device_certificate +) +{ + uint8_t response[SECONDARY_DEVICE_CERT_SERV_RESP_LENGTH]; + uint8_t status; + + /* + * The get secondary device certificate system service is not available on + * M2S050 rev A, rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + status = execute_service(SECONDARY_DEVICE_CERTIFICATE_REQUEST_CMD, + p_secondary_device_certificate, + response, + SECONDARY_DEVICE_CERT_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +#define CONFIG_CLOCK_DIV_MASK 0xFFC7F103u +#define CONFIG_CLOCK_DIV_32_RATIO 0x00301CD8u + +/* Sequence array for divisor */ +uint8_t div1_seq[]={ 0x00, 0x01, 0x05, 0x07}; +uint8_t div2_seq[]={ 0x01, 0x05, 0x07}; +uint8_t div4_seq[]={ 0x02, 0x03, 0x01, 0x05, 0x07}; +uint8_t div8_seq[]={ 0x04, 0x06, 0x07}; +uint8_t div16_seq[]={ 0x05, 0x07}; +uint8_t div32_seq[]={ 0x06, 0x07 }; + +/* Divisor array is used to store the values of APB0_DIVISOR, APB1_DIVISOR, + * M3_CLK_DIVISOR and FIC64_DIVISOR bit-fields before entering flash freeze. + * This value will be used to revert back the value of FACC1 register after + * exiting from Flash Freeze/IAP/Fabric digest check. + */ +uint32_t divisor[4] = {0x00}; +volatile uint8_t ind = 0; + +static uint8_t* determine_seq(uint8_t val, uint8_t* len) +{ + uint8_t*seq; + + switch(val) + { + case 0: + seq = &div1_seq[0]; + *len = 4; + break; + + case 1: + seq = &div2_seq[0]; + *len = 3; + break; + + case 2: + seq = &div4_seq[0]; + *len = 5; + break; + + case 4: + seq = &div8_seq[0]; + *len = 3; + break; + + case 5: + seq = &div16_seq[0]; + *len = 2; + break; + + case 6: + seq = &div32_seq[0]; + *len = 2; + break; + + default: + *len = 0; + seq = NULL; + break; + } + + return seq; +} + +#define CLOCK_SWITCHING_SUCCESS 0x00u +#define CLOCK_SWITCHING_ERROR 0x01u + +/* SAR 80563 - Workaround for Glitchless Clock Multiplexer Switching Issue + * If user has requested for fabric digest check/IAP/Flash Freeze service, then + * the firmware will change the clock divisor values of FACC1 register based on + * device version to avoid Glitchless Clock Multiplexer Switching Issue. + * If the device is 010/025/050/090/150 device, Cortex-M3 firmware + * dynamically divides down fclk, pclk0, pclk1 and clk_fic64 to the divided + * by 32 versions. If the device is 05 device, firmware will load the + * divisor values in sequenced from the start setting to the divide by 32 + * setting. If the device is 060 device, then firmware will compare the + * divisor values of fclk, pclk0, pclk1 and clk_fic64, and if the divisor + * values are equal to each other, then firmware will send requested command to + * system controller otherwise return CLOCK_SWITCHING_ERROR error. + */ +static uint8_t clk_switching_fix(void) +{ + uint8_t* sequence; + uint8_t len; + volatile uint32_t g_mssddr_facc1_cr = SYSREG->MSSDDR_FACC1_CR; + uint32_t var = 0; + uint32_t temp = 0; + uint32_t device_version; + uint8_t status = CLOCK_SWITCHING_SUCCESS; + + device_version = (SYSREG->DEVICE_VERSION & 0xFFFFu); + + /* For 10/25/50/90/150 devices */ + if((0xF802u == device_version) || \ + (0xF803u == device_version) || \ + (0xF804u == device_version)|| \ + (0xF807u == device_version) || \ + (0xF806u == device_version)) + { + /* Dynamically divides down fclk, pclk0, pclk1 and clk_fic64 + * to the divided by 32 versions and M3_CLK, PCLK0, PCLK1, + * CLK_FIC64 all driven from CLK_STANDBY clock. + */ + SYSREG->MSSDDR_FACC1_CR = (SYSREG->MSSDDR_FACC1_CR & CONFIG_CLOCK_DIV_MASK) | \ + CONFIG_CLOCK_DIV_32_RATIO; + status = CLOCK_SWITCHING_SUCCESS; + } + + /* For 05 devices + * When modifying clock divisor settings on M2S005, it is necessary to + * sequence them, depending on the starting configuration. + */ + else if(0xF805u == device_version) + { + /* For APB0_DIVISOR setting */ + divisor[0] = ((g_mssddr_facc1_cr >> 2) & 0x00000007); + sequence = determine_seq(divisor[0], &len); + + for(var = 1; var < len; var++) + { + temp = SYSREG->MSSDDR_FACC1_CR; + temp &= 0xFFFFFFE3u; + temp |= ((uint32_t)(sequence[var]) << 2); + SYSREG->MSSDDR_FACC1_CR = temp; + } + + /* For APB1_DIVISOR setting */ + divisor[1] = ((g_mssddr_facc1_cr >> 5) & 0x00000007); + sequence = determine_seq(divisor[1], &len); + + for(var = 1; var < len; var++) + { + temp = SYSREG->MSSDDR_FACC1_CR; + temp &= 0xFFFFFF1Fu; + temp |= ((uint32_t)(sequence[var]) << 5); + SYSREG->MSSDDR_FACC1_CR = temp; + } + + /* For M3_CLK_DIVISOR setting */ + divisor[2] = ((g_mssddr_facc1_cr >> 9) & 0x00000007); + sequence = determine_seq(divisor[2], &len); + + for(var = 1; var < len; var++) + { + temp = SYSREG->MSSDDR_FACC1_CR; + temp &= 0xFFFFF1FFu; + temp |= ((uint32_t)(sequence[var]) << 9); + SYSREG->MSSDDR_FACC1_CR = temp; + } + + /* For FIC64_DIVISOR setting */ + divisor[3] = ((g_mssddr_facc1_cr >> 19) & 0x00000007); + sequence = determine_seq(divisor[3], &len); + for(var = 1; var < len; var++) + { + temp = SYSREG->MSSDDR_FACC1_CR; + temp &= 0xFFC7FFFFu; + temp |= ((uint32_t)(sequence[var]) << 19); + SYSREG->MSSDDR_FACC1_CR = temp; + } + + /* Set the value of FACC_GLMUX_SEL bitfield of FACC1 register to 1 so + * that M3_CLK, PCLK0, PCLK1, CLK_FIC64 all driven from CLK_STANDBY + * clock. + */ + SYSREG->MSSDDR_FACC1_CR = SYSREG->MSSDDR_FACC1_CR | 0x00001000u; + + status = CLOCK_SWITCHING_SUCCESS; + } + /* For 060 devices */ + else if(0xF808u == device_version) + { + /* The divisor setting should be such that all the divisor should be + * equal to each other and set to divide by 1,2,4,8, and 16 (but not 32) + */ + divisor[0] = ((g_mssddr_facc1_cr >> 2) & 0x00000007); + divisor[1] = ((g_mssddr_facc1_cr >> 5) & 0x00000007); + divisor[2] = ((g_mssddr_facc1_cr >> 9) & 0x00000007); + divisor[3] = ((g_mssddr_facc1_cr >> 19) & 0x00000007); + + for(var = 1; var < 4; var++) + { + if((divisor[var] != divisor[0]) || \ + (divisor[0] > 5) || (divisor[var] > 5)) + { + /* If the divisor value does meet the criteria, log the clock + * switching error. + */ + status = CLOCK_SWITCHING_ERROR; + break; + } + } + } + else + { + /* Do Nothing. */ + } + + return status; +} + +/* SAR 80563 - Workaround for Glitchless Clock Multiplexer Switching Issue + * Revert back original values of various divisor in FACC1 register after + * completing the fabric digest check/IAP/Flash Freeze service. + */ +static void revert_clk_config(void) +{ + uint8_t* sequence; + uint8_t len; + uint8_t var = 0; + uint32_t temp = 0; + uint32_t device_version; + + device_version = (SYSREG->DEVICE_VERSION & 0xFFFFu); + + /* Revert back values for 10/25/50/90/150 devices */ + if((0xF802u == device_version) || (0xF803u == device_version) || \ + (0xF804u == device_version)||(0xF807u == device_version) || \ + (0xF806u == device_version)) + { + /* Restore the MSS clock dividers to their normal operations value. */ + SYSREG->MSSDDR_FACC1_CR = g_initial_mssddr_facc1_cr; + } + + /* Revert back values for 05 devices in reverse sequence. */ + else if(0xF805u == device_version) + { + sequence = determine_seq(divisor[0], &len); + for(var = len; var > 0; var--) + { + temp = SYSREG->MSSDDR_FACC1_CR; + temp &= 0xFFFFFFE3u; + temp |= ((uint32_t)(sequence[var - 1]) << 2); + SYSREG->MSSDDR_FACC1_CR = temp; + } + + /* For APB1_DIVISOR setting */ + sequence = determine_seq(divisor[1], &len); + for(var = len; var > 0; var--) + { + temp = SYSREG->MSSDDR_FACC1_CR; + temp &= 0xFFFFFF1Fu; + temp |= ((uint32_t)(sequence[var - 1]) << 5); + SYSREG->MSSDDR_FACC1_CR = temp; + } + + /* For M3_CLK_DIVISOR setting */ + sequence = determine_seq(divisor[2], &len); + for(var = len; var > 0; var--) + { + temp = SYSREG->MSSDDR_FACC1_CR; + temp &= 0xFFFFF1FFu; + temp |= ((uint32_t)(sequence[var - 1]) << 9); + SYSREG->MSSDDR_FACC1_CR = temp; + } + + /* For FIC64_DIVISOR setting */ + sequence = determine_seq(divisor[3], &len); + for(var = len; var > 0; var--) + { + temp = SYSREG->MSSDDR_FACC1_CR; + temp &= 0xFFC7FFFFu; + temp |= ((uint32_t)(sequence[var - 1]) << 19); + SYSREG->MSSDDR_FACC1_CR = temp; + } + + /* Set the value of FACC_GLMUX_SEL bitfield of FACC1 register to 0 so + * that M3_CLK, PCLK0, PCLK1, CLK_FIC64 all driven from stage 2 + * dividers (from CLK_SRC). + */ + SYSREG->MSSDDR_FACC1_CR = SYSREG->MSSDDR_FACC1_CR & 0xFFFFEFFFu; + } + else + { + /* Do Nothing. */ + } +} + +uint8_t MSS_SYS_flash_freeze(uint8_t options) +{ + uint8_t status; + uint8_t clk_switch_status = CLOCK_SWITCHING_SUCCESS; + uint16_t actual_response_length; + uint8_t flash_freeze_req[FLASH_FREEZE_REQUEST_LENGTH]; + uint8_t response[FLASH_FREEZE_SERV_RESP_LENGTH]; + + /* + * The Flash Freeze system service is not available on M2S050 rev A and rev B. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + + /* + * Keep track of the clocks configuration before entering Flash*Freeze so + * that it can be restored on Flash*Freeze exit. + */ + g_initial_mssddr_facc1_cr = SYSREG->MSSDDR_FACC1_CR; + + /* SAR 80563 + * Cortex-M3 firmware dynamically divides down fclk, pclk0, pclk1 and + * clk_fic64 to the divided by 32 versions based on device version. + */ + clk_switch_status = clk_switching_fix(); + + if(clk_switch_status == CLOCK_SWITCHING_SUCCESS) + { + /* + * Enable RTC wake-up interrupt to System Controller and FPGA fabric. + */ + SYSREG->RTC_WAKEUP_CR |= (RTC_WAKEUP_G4C_EN_MASK | RTC_WAKEUP_FAB_EN_MASK); + + signal_request_start(); + + flash_freeze_req[0] = FLASH_FREEZE_REQUEST_CMD; + flash_freeze_req[1] = options; + + MSS_COMBLK_send_cmd(flash_freeze_req, /* p_cmd */ + FLASH_FREEZE_REQUEST_LENGTH, /* cmd_size */ + 0, /* p_data */ + 0u, /* data_size */ + response, /* p_response */ + FLASH_FREEZE_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((FLASH_FREEZE_SERV_RESP_LENGTH == actual_response_length) && + (FLASH_FREEZE_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + } + else + { + /* SAR 80563 + * CLK Divisor error occurs on 060 device. The user should make sure + * that the all divisor i.e fclk, pclk0, pclk1 and clk_fic64 divisor + * must be equal to each other and set to to divide by 1,2, 4, 8, 16(but + * not 32). If the divisor value does not meet the above criteria, the + * function will not send Flash Freeze command to system controller and + * will return CLK divisor error. + */ + status = MSS_SYS_CLK_DIVISOR_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +#define AES128_KEY_LENGTH 16u +#define IV_LENGTH 16u + +#define AES256_KEY_LENGTH 32u + +#define HMAC_KEY_LENGTH 32u + +uint8_t MSS_SYS_128bit_aes +( + const uint8_t * key, + const uint8_t * iv, + uint16_t nb_blocks, + uint8_t mode, + uint8_t * dest_addr, + const uint8_t * src_addr) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[44]; + uint8_t status; + + memcpy(¶ms[0], key, AES128_KEY_LENGTH); + memcpy(¶ms[16], iv, IV_LENGTH); + + params[32] = (uint8_t)nb_blocks; + params[33] = (uint8_t)(nb_blocks >> 8u); + params[34] = mode; + params[35] = 0u; + + write_ptr_value_into_array(dest_addr, params, 36u); + write_ptr_value_into_array(src_addr, params, 40u); + + status = execute_service(AES128_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_256bit_aes +( + const uint8_t * key, + const uint8_t * iv, + uint16_t nb_blocks, + uint8_t mode, + uint8_t * dest_addr, + const uint8_t * src_addr +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[60]; + uint8_t status; + + memcpy(¶ms[0], key, AES256_KEY_LENGTH); + memcpy(¶ms[32], iv, IV_LENGTH); + + params[48] = (uint8_t)nb_blocks; + params[49] = (uint8_t)(nb_blocks >> 8u); + params[50] = mode; + params[51] = 0u; + + write_ptr_value_into_array(dest_addr, params, 52u); + write_ptr_value_into_array(src_addr, params, 56u); + + status = execute_service(AES256_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_sha256 +( + const uint8_t * p_data_in, + uint32_t length, + uint8_t * result +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[12]; + uint8_t status; + + params[0] = (uint8_t)((uint32_t)length); + params[1] = (uint8_t)((uint32_t)length >> 8u); + params[2] = (uint8_t)((uint32_t)length >> 16u); + params[3] = (uint8_t)((uint32_t)length >> 24u); + + write_ptr_value_into_array(result, params, 4u); + write_ptr_value_into_array(p_data_in, params, 8u); + + status = execute_service(SHA256_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_hmac +( + const uint8_t * key, + const uint8_t * p_data_in, + uint32_t length, + uint8_t * p_result +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[58]; + uint8_t status; + + memcpy(¶ms[0], key, HMAC_KEY_LENGTH); + + params[32] = (uint8_t)((uint32_t)length); + params[33] = (uint8_t)((uint32_t)length >> 8u); + params[34] = (uint8_t)((uint32_t)length >> 16u); + params[35] = (uint8_t)((uint32_t)length >> 24u); + + write_ptr_value_into_array(p_data_in, params, 36u); + write_ptr_value_into_array(p_result, params, 40u); + + status = execute_service(HMAC_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +#define KEYTREE_KEY_LENGTH 32 +#define KEYTREE_PATH_LENGTH 16 + +uint8_t MSS_SYS_key_tree +( + uint8_t* p_key, + uint8_t op_type, + const uint8_t* path +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[49]; + uint8_t status; + + memcpy(¶ms[0], p_key, KEYTREE_KEY_LENGTH); + + params[32] = op_type; + + memcpy(¶ms[33], path, KEYTREE_PATH_LENGTH); + + status = execute_service(KEYTREE_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + if(status == MSS_SYS_SUCCESS) + { + memcpy(p_key, ¶ms[0], KEYTREE_KEY_LENGTH); + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_challenge_response +( + uint8_t* p_key, + uint8_t op_type, + const uint8_t* path +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[21]; + uint8_t status; + + params[0] = (uint8_t)((uint32_t)p_key); + params[1] = (uint8_t)((uint32_t)p_key >> 8u); + params[2] = (uint8_t)((uint32_t)p_key >> 16u); + params[3] = (uint8_t)((uint32_t)p_key >> 24u); + + params[4] = op_type; + + memcpy(¶ms[5], path, KEYTREE_PATH_LENGTH); + + status = execute_service(PPUF_CHALLENGE_RESP_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_nrbg_reset(void) +{ + uint8_t status; + uint16_t actual_response_length; + uint8_t reset_cmd[4]; + uint8_t response[NRBG_RESET_SERV_RESP_LENGTH]; + + signal_request_start(); + + reset_cmd[0] = NRBG_RESET_REQUEST_CMD; + reset_cmd[1] = 0u; + reset_cmd[2] = 0u; + reset_cmd[3] = 0u; + + MSS_COMBLK_send_cmd(reset_cmd, /* p_cmd */ + sizeof(reset_cmd), /* cmd_size */ + 0, /* p_data */ + 0, /* data_size */ + response, /* p_response */ + DRBG_RESET_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((NRBG_RESET_SERV_RESP_LENGTH == actual_response_length) && + (NRBG_RESET_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_nrbg_self_test(void) +{ + uint8_t status; + uint16_t actual_response_length; + uint8_t self_test; + uint8_t response[NRBG_SELF_TEST_SERV_RESP_LENGTH]; + + signal_request_start(); + + self_test = NRBG_SELF_TEST_REQUEST_CMD; + + MSS_COMBLK_send_cmd(&self_test, /* p_cmd */ + sizeof(self_test), /* cmd_size */ + 0, /* p_data */ + 0, /* data_size */ + response, /* p_response */ + NRBG_SELF_TEST_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((NRBG_SELF_TEST_SERV_RESP_LENGTH == actual_response_length) && + (NRBG_SELF_TEST_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_nrbg_instantiate +( + const uint8_t * personalization_str, + uint16_t personalization_str_length, + uint8_t * p_nrbg_handle +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t instantiate_params[7]; + uint8_t status; + + write_ptr_value_into_array(personalization_str, instantiate_params, 0u); + + instantiate_params[4] = (uint8_t)personalization_str_length; + instantiate_params[5] = (uint8_t)(personalization_str_length >> 8u); + instantiate_params[6] = INVALID_NRBG_HANDLE; + + status = execute_service(NRBG_INSTANTIATE_REQUEST_CMD, + instantiate_params, + response, + STANDARD_SERV_RESP_LENGTH); + + if(MSS_SYS_SUCCESS == status) + { + *p_nrbg_handle = instantiate_params[6]; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_nrbg_generate +( + const uint8_t * p_requested_data, + const uint8_t * p_additional_input, + uint8_t requested_length, + uint8_t additional_input_length, + uint8_t pr_req, + uint8_t nrbg_handle +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t generate_params[12]; + uint8_t status; + + write_ptr_value_into_array(p_requested_data, generate_params, 0u); + write_ptr_value_into_array(p_additional_input, generate_params, 4u); + + generate_params[8] = requested_length; + generate_params[9] = additional_input_length; + generate_params[10] = pr_req; + generate_params[11] = nrbg_handle; + + status = execute_service(NRBG_GENERATE_REQUEST_CMD, + generate_params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_nrbg_reseed +( + const uint8_t * p_additional_input, + uint8_t additional_input_length, + uint8_t nrbg_handle +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[6]; + uint8_t status; + + write_ptr_value_into_array(p_additional_input, params, 0u); + + params[4] = (uint8_t)additional_input_length; + params[5] = nrbg_handle; + + status = execute_service(NRBG_RESEED_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_nrbg_uninstantiate +( + uint8_t nrbg_handle +) +{ + uint8_t status; + uint16_t actual_response_length; + uint8_t uninstantiate_req[2]; + uint8_t response[NRBG_UNINST_SERV_RESP_LENGTH]; + + signal_request_start(); + + uninstantiate_req[0] = NRBG_UNINSTANTIATE_REQUEST_CMD; + uninstantiate_req[1] = nrbg_handle; + + MSS_COMBLK_send_cmd(uninstantiate_req, /* p_cmd */ + sizeof(uninstantiate_req), /* cmd_size */ + 0, /* p_data */ + 0, /* data_size */ + response, /* p_response */ + NRBG_UNINST_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((NRBG_UNINST_SERV_RESP_LENGTH == actual_response_length) && + (NRBG_UNINSTANTIATE_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +void MSS_SYS_zeroize_device(void) +{ + /* + * We only need to send one command byte to initiate zeroization. + * The zeroization process should result in the Cortex-M3 being reset. This + * means we should never reach the end of this function if zeroization is + * actually performed. + */ + uint8_t zeroization_req = ZEROIZATION_REQUEST_CMD; + + /* + * The Zeroization system service is not available on M2S050 rev A, rev B + * and rev C. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + + signal_request_start(); + + MSS_COMBLK_send_cmd(&zeroization_req, /* p_cmd */ + sizeof(zeroization_req), /* cmd_size */ + 0, /* p_data */ + 0, /* data_size */ + 0, /* p_response */ + 0, /* response_size */ + request_completion_handler); /* completion_handler */ + + /* SAR 74647 + * Zeroization is only performed if the user has instantiated the tamper + * macro (from the Libero Catalog) in the hardware design, configured the + * tamper macro to enable zeroization and set the required zeroization + * options. If program execution idles here, or in the + * wait_for_request_completion() function that follows, you should verify + * that zeroization is properly enabled in the hardware design. + */ + ASSERT(g_request_in_progress == 0u); + + /* + * Handle case where Zeroization is not enabled in the device in Release + * mode. + */ + wait_for_request_completion(); +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +#define NVM_FREQRNG_MASK 0x00001FE0U +#define NVM_FREQRNG_MAX ((uint32_t)0xFFU << 5U) + +static uint8_t g_isp_response[ISP_PROG_SERV_RESP_LENGTH]; +sys_serv_isp_complete_handler_t g_isp_completion_handler = 0; +comblk_page_handler_t g_isp_page_read_handler = 0; + +/* + * g_initial_envm_cr contains the hardware design's original eNVM configuration + * set through the ENVM_CR system register. This global variable is used to + * store the eNVM's configuration while the ISP/IAP is executing with an eNVM + * configuration ensuring successful eNVM programming on all SamrtFusion2 + * devices. It is then used to restore the eNVM's configuration once ISP/IAP has + * completed. SAR 57545. + */ +static uint32_t g_initial_envm_cr = 0x00001FF1U; +/* + * g_initial_mssddr_facc2_cr contains the hardware design's original MSS DDR + * Fabric Alignment Clock Controller (FACC) 2 configuration set through the + * MSSDDR_FACC2_CR system register. This global variable is used to + * store the FACC2's configuration while the ISP/IAP is executing on all + * SamrtFusion2 devices. It is then used to restore the Fabric alignment clock + * configuration once ISP/IAP has completed. + */ +static uint32_t g_initial_mssddr_facc2_cr = 0x00; +static uint8_t g_mode = 0; +static uint8_t wait_for_clock_switch = 1; + +static uint32_t isp_page_read_handler +( + uint8_t const ** pp_next_page +) +{ + uint32_t remaining_length = 0; + uint32_t running_on_standby_clock; + volatile uint32_t timeout; + + if((g_mode != MSS_SYS_PROG_AUTHENTICATE) & (wait_for_clock_switch == 1)) + { + timeout = DELAY_MORE_THAN_10US; + do + { + running_on_standby_clock = SYSREG->MSSDDR_FACC1_CR & FACC_GLMUX_SEL_MASK; + --timeout; + } + while ((running_on_standby_clock == 0U) && (timeout != 0U)); + wait_for_clock_switch = 0; + } + + if(g_isp_page_read_handler != 0) + { + remaining_length = g_isp_page_read_handler(pp_next_page); + } + + return remaining_length; +} + +static void isp_sys_completion_handler +( + uint8_t * p_response, + uint16_t length +) +{ + if(g_mode != MSS_SYS_PROG_AUTHENTICATE) + { + /* + * Restore the eNVM's frequency range to the values used before ISP was + * started. + */ + SYSREG->ENVM_CR = g_initial_envm_cr; + + /* + * Restore the MSS DDR FACC 2 configuration to the values used before ISP + * was started. + */ + SYSREG->MSSDDR_FACC2_CR = g_initial_mssddr_facc2_cr; + } + + if(g_isp_completion_handler != 0) + { + g_isp_completion_handler(p_response[1]); + } +} + +uint8_t MSS_SYS_start_isp +( + uint8_t mode, + comblk_page_handler_t page_read_handler, + sys_serv_isp_complete_handler_t isp_completion_handler +) +{ + uint8_t isp_prog_request[2]; + uint8_t clk_switch_status = CLOCK_SWITCHING_SUCCESS; + uint8_t status = MSS_SYS_SUCCESS; + + if(mode == MSS_SYS_PROG_VERIFY) + { + /* + * Check fabric digest before performing ISP verify + */ + MSS_SYS_check_digest(MSS_SYS_DIGEST_CHECK_FABRIC); + } + + g_mode = mode; + + if(mode != MSS_SYS_PROG_AUTHENTICATE) + { + /* + * Keep a copy of the initial eNVM configuration used before ISP was + * initiated. The eNVM configuration will be restored, as part of the ISP + * completion handler, when ISP completes. + */ + g_initial_envm_cr = SYSREG->ENVM_CR; + + /* Store the MSS DDR FACC 2 register value so that its can be restored back + * when the ISP operation is completed in asynchronous_event_handler. */ + g_initial_mssddr_facc2_cr = SYSREG->MSSDDR_FACC2_CR; + + /* + * Set the eNVM's frequency range to its maximum. This is required to ensure + * successful eNVM programming on all devices. + */ + SYSREG->ENVM_CR = (g_initial_envm_cr & ~NVM_FREQRNG_MASK) | NVM_FREQRNG_MAX; + + /* Select output of MUX 0, MUX 1 and MUX 2 during standby */ + SYSREG->MSSDDR_FACC2_CR = SYSREG->MSSDDR_FACC2_CR & ((uint32_t)(FACC_STANDBY_SEL << FACC_STANDBY_SHIFT) | ~FACC_STANDBY_SEL_MASK); + + /* Enable the signal for the 50 MHz RC oscillator */ + SYSREG->MSSDDR_FACC2_CR = SYSREG->MSSDDR_FACC2_CR | ((uint32_t)(MSS_25_50MHZ_EN << MSS_25_50MHZ_EN_SHIFT) & MSS_25_50MHZ_EN_MASK); + + /* Enable the signal for the 1 MHz RC oscillator */ + SYSREG->MSSDDR_FACC2_CR = SYSREG->MSSDDR_FACC2_CR | ((uint32_t)(MSS_1MHZ_EN << MSS_1MHZ_EN_SHIFT) & MSS_1MHZ_EN_MASK); + + /* SAR 80563 + * Cortex-M3 firmware dynamically divides down fclk, pclk0, pclk1 and + * clk_fic64 to the divided by 32 versions based on device version. + */ + clk_switch_status = clk_switching_fix(); + + wait_for_clock_switch = 1; + } + + if(clk_switch_status == CLOCK_SWITCHING_SUCCESS) + { + signal_request_start(); + + isp_prog_request[0] = ISP_PROGRAMMING_REQUEST_CMD; + isp_prog_request[1] = mode; + + g_isp_completion_handler = isp_completion_handler; + + g_isp_page_read_handler = page_read_handler; + + MSS_COMBLK_send_paged_cmd(isp_prog_request, /* p_cmd */ + sizeof(isp_prog_request), /* cmd_size */ + g_isp_response, /* p_response */ + ISP_PROG_SERV_RESP_LENGTH, /* response_size */ + isp_page_read_handler, /* page_handler */ + isp_sys_completion_handler); /* completion_handler */ + } + else + { + /* SAR 80563 + * On 060 device. The user should make sure that the all divisor i.e + * fclk, pclk0, pclk1 and clk_fic64 divisor must be equal to each other + * and set to to divide by 1,2, 4, 8, 16(but not 32). + */ + status = MSS_SYS_CLK_DIVISOR_ERROR; + } + + return status; +} + + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_initiate_iap +( + uint8_t mode, + uint32_t bitstream_spi_addr +) +{ + uint8_t status = MSS_SYS_SUCCESS; + uint8_t clk_switch_status = CLOCK_SWITCHING_SUCCESS; + uint16_t actual_response_length; + uint8_t iap_prog_req[6]; + uint8_t response[IAP_PROG_SERV_RESP_LENGTH]; + + if(mode == MSS_SYS_PROG_VERIFY) + { + /* + * Check fabric digest before performing IAP verify + */ + MSS_SYS_check_digest(MSS_SYS_DIGEST_CHECK_FABRIC); + } + + if(mode != MSS_SYS_PROG_AUTHENTICATE) + { + /* + * Keep a copy of the initial eNVM configuration used before IAP was + * initiated. The eNVM configuration will be restored, as part of the IAP + * completion handler, when IAP completes. + */ + g_initial_envm_cr = SYSREG->ENVM_CR; + + /* Store the MSS DDR FACC 2 register value so that its can be restored back + * when the IAP operation is completed.asynchronous_event_handler. */ + g_initial_mssddr_facc2_cr = SYSREG->MSSDDR_FACC2_CR; + + /* + * Set the eNVM's frequency range to its maximum. This is required to ensure + * successful eNVM programming on all devices. + */ + SYSREG->ENVM_CR = (g_initial_envm_cr & ~NVM_FREQRNG_MASK) | NVM_FREQRNG_MAX; + + /* Select output of MUX 0, MUX 1 and MUX 2 during standby */ + SYSREG->MSSDDR_FACC2_CR = SYSREG->MSSDDR_FACC2_CR & ((uint32_t)(FACC_STANDBY_SEL << FACC_STANDBY_SHIFT) | ~FACC_STANDBY_SEL_MASK); + + /* Enable the signal for the 50 MHz RC oscillator */ + SYSREG->MSSDDR_FACC2_CR = SYSREG->MSSDDR_FACC2_CR | ((uint32_t)(MSS_25_50MHZ_EN << MSS_25_50MHZ_EN_SHIFT) & MSS_25_50MHZ_EN_MASK); + + /* Enable the signal for the 1 MHz RC oscillator */ + SYSREG->MSSDDR_FACC2_CR = SYSREG->MSSDDR_FACC2_CR | ((uint32_t)(MSS_1MHZ_EN << MSS_1MHZ_EN_SHIFT) & MSS_1MHZ_EN_MASK); + + /* SAR 80563 + * Cortex-M3 firmware dynamically divides down fclk, pclk0, pclk1 and + * clk_fic64 to the divided by 32 versions based on device version. + */ + clk_switch_status = clk_switching_fix(); + } + + if(clk_switch_status == CLOCK_SWITCHING_SUCCESS) + { + /* + * There is no response for Program mode because the Cortex-M3 will + * get reset on completion of the system service. + */ + iap_prog_req[0] = IAP_PROGRAMMING_REQUEST_CMD; + iap_prog_req[1] = mode; + + iap_prog_req[2] = (uint8_t)(bitstream_spi_addr); + iap_prog_req[3] = (uint8_t)(bitstream_spi_addr >> 8u); + iap_prog_req[4] = (uint8_t)(bitstream_spi_addr >> 16u); + iap_prog_req[5] = (uint8_t)(bitstream_spi_addr >> 24u); + + signal_request_start(); + + MSS_COMBLK_send_cmd(iap_prog_req, /* p_cmd */ + sizeof(iap_prog_req), /* cmd_size */ + 0, /* p_data */ + 0, /* data_size */ + response, /* p_response */ + IAP_PROG_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + /* + * Handle case where service is not implemented/enabled in the device. + */ + actual_response_length = wait_for_request_completion(); + + if((IAP_PROG_SERV_RESP_LENGTH == actual_response_length) && + (IAP_PROGRAMMING_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + if(mode != MSS_SYS_PROG_AUTHENTICATE) + { + /* Restore back to original value. */ + SYSREG->ENVM_CR = g_initial_envm_cr; + SYSREG->MSSDDR_FACC2_CR = g_initial_mssddr_facc2_cr; + } + } + else + { + /* SAR 80563 + * On 060 device. The user should make sure that the all divisor i.e + * fclk, pclk0, pclk1 and clk_fic64 divisor must be equal to each other + * and set to to divide by 1,2, 4, 8, 16(but not 32). + */ + status = MSS_SYS_CLK_DIVISOR_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_check_digest +( + uint8_t options +) +{ + uint8_t status; + uint8_t clk_switch_status = CLOCK_SWITCHING_SUCCESS; + uint16_t actual_response_length; + uint8_t digest_check_req[2]; + uint8_t response[DIGEST_CHECK_SERV_RESP_LENGTH]; + + /* + * The Digest Check system service is not available on M2S050 rev A, rev B and rev C. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + + /* + * Private ENVM factory digest and user digest is available only on G4X + * devices + */ + if((options & 0x30u) != 0x00) + { + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + } + + /* SAR 80563 + * Cortex-M3 firmware dynamically divides down fclk, pclk0, pclk1 and + * clk_fic64 to the divided by 32 versions based on device version. + */ + if(MSS_SYS_DIGEST_CHECK_FABRIC == (options & 0x01u)) + { + clk_switch_status = clk_switching_fix(); + } + + if(clk_switch_status == CLOCK_SWITCHING_SUCCESS) + { + + signal_request_start(); + + digest_check_req[0] = DIGEST_CHECK_REQUEST_CMD; + digest_check_req[1] = options; + + MSS_COMBLK_send_cmd(digest_check_req, /* p_cmd */ + sizeof(digest_check_req), /* cmd_size */ + 0, /* p_data */ + 0u, /* data_size */ + response, /* p_response */ + DIGEST_CHECK_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((DIGEST_CHECK_SERV_RESP_LENGTH == actual_response_length) && + (DIGEST_CHECK_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + } + else + { + /* SAR 80563 + * On 060 device. The user should make sure that the all divisor i.e + * fclk, pclk0, pclk1 and clk_fic64 divisor must be equal to each other + * and set to to divide by 1,2, 4, 8, 16(but not 32). + */ + status = MSS_SYS_CLK_DIVISOR_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_create_activation_code +( + void +) +{ + uint8_t response[PUF_USER_ACTIVATION_CODE_RESP_LENGTH]; + uint8_t status; + uint8_t params; + uint8_t key_numbers = 0u; + + /* + * The user activation code system service is not available on M2S050 rev A, + * rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + params = PUF_CREATE_USER_ACTIVATION_CODE; + + status = execute_service(PUF_ACTIVATION_CODE_REQUEST_CMD, + ¶ms, + response, + PUF_USER_ACTIVATION_CODE_RESP_LENGTH); + + /* + * System controller is locking eNVM-1 while executing create activation + * code service, but system controller is not releasing back after + * completing the operation. In order to unlock eNVM-1, call get number of + * key service. PUF get number of key service will release the eNVM-1 lock + * after reading the number of keys enrolled. + */ + MSS_SYS_puf_get_number_of_keys(&key_numbers); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_delete_activation_code +( + void +) +{ + uint8_t response[PUF_USER_ACTIVATION_CODE_RESP_LENGTH]; + uint8_t status; + uint8_t params; + uint8_t key_numbers = 0u; + + /* + * The user activation code system service is not available on M2S050 rev A, + * rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + params = PUF_DELETE_USER_ACTIVATION_CODE; + + status = execute_service(PUF_ACTIVATION_CODE_REQUEST_CMD, + ¶ms, + response, + PUF_USER_ACTIVATION_CODE_RESP_LENGTH); + /* + * System controller is locking eNVM-1 while executing delete activation + * code service, but system controller is not releasing back after + * completing the operation. In order to unlock eNVM-1, call get number of + * key service. PUF get number of key service will release the eNVM-1 lock + * after reading the number of keys enrolled. + */ + MSS_SYS_puf_get_number_of_keys(&key_numbers); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_get_number_of_keys +( + uint8_t* p_number_of_keys +) +{ + uint8_t response[6u] = { 0x00 }; + uint8_t params[11u] = { 0x00 }; + uint8_t status; + + /* + * The user key code system service is not available on M2S050 rev A, + * rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + params[0] = PUF_GET_NUMBER_OF_KC_SUBCOMMAND; + + status = execute_service(PUF_USER_KEY_CODE_REQUEST_CMD, + params, + response, + PUF_GET_NUMBER_OF_KEYS_RESP_LENGTH); + + *p_number_of_keys = params[9]; + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_enroll_key +( + uint8_t key_number, + uint16_t key_size, + uint8_t* p_key_value, + uint8_t* p_key_location +) +{ + uint8_t response[6u]; + uint8_t params[11u]; + uint8_t status; + uint8_t key_numbers = 0u; + + /* + * The PUF enroll key system service is not available on M2S050 rev A, + * rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + if(p_key_value == 0) + { + params[0] = PUF_CREATE_INT_KC_SUBCOMMAND; + } + else + { + params[0] = PUF_CREATE_EXT_KC_SUBCOMMAND; + } + + write_ptr_value_into_array(p_key_location, params, 1u); + write_ptr_value_into_array(p_key_value, params, 5u); + + params[9] = key_number; + params[10] = key_size; + + status = execute_service(PUF_USER_KEY_CODE_REQUEST_CMD, + params, + response, + PUF_ENROLL_KEYS_RESP_LENGTH); + + /* + * System controller is locking eNVM-1 while executing create key code + * service, but system controller is not releasing back after completing the + * operation. In order to unlock eNVM-1, call get number of key service. PUF + * get number of key service will release the eNVM-1 lock after reading the + * number of keys enrolled. + */ + MSS_SYS_puf_get_number_of_keys(&key_numbers); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_delete_key +( + uint8_t key_number +) +{ + uint8_t response[6u]; + uint8_t params[11u]; + uint8_t status; + uint8_t key_numbers = 0u; + + /* + * The delete PUF key system service is not available on M2S050 rev A, + * rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + params[0] = PUF_DELETE_KC_SUBCOMMAND; + params[9] = key_number; + + status = execute_service(PUF_USER_KEY_CODE_REQUEST_CMD, + params, + response, + PUF_ENROLL_KEYS_RESP_LENGTH); + + /* + * System controller is locking eNVM-1 while executing delete key code + * service, but system controller is not releasing back after completing the + * operation. In order to unlock eNVM-1, call get number of key service. PUF + * get number of key service will release the eNVM-1 lock after reading the + * number of keys enrolled. + */ + MSS_SYS_puf_get_number_of_keys(&key_numbers); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_fetch_key +( + uint8_t key_number, + uint8_t ** pp_key +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[5]; + uint8_t status; + + /* + * The fetch user key system service is not available on M2S050 rev A, + * rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + write_ptr_value_into_array(*pp_key, params, 0u); + + params[4] = key_number; + + status = execute_service(PUF_FETCH_KEY_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + if(pp_key != NULL) + { + write_array_into_ptr_value(&(*pp_key), params, 0); + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_export_keycodes +( + uint8_t * p_keycodes +) +{ + uint8_t response[PUF_EXPORT_ALL_KEYCODES_RESP_LENGTH]; + uint8_t params[11u]; + uint8_t status; + + /* + * The export all user key system service is not available on M2S050 rev A, + * rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + params[0] = PUF_EXPORT_ALL_KC_SUBCOMMAND; + + write_ptr_value_into_array(p_keycodes, params, 1u); + + status = execute_service(PUF_USER_KEY_CODE_REQUEST_CMD, + params, + response, + PUF_EXPORT_ALL_KEYCODES_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_import_keycodes +( + uint8_t * p_keycodes +) +{ + uint8_t response[PUF_IMPORT_ALL_KEYCODES_RESP_LENGTH]; + uint8_t params[11u]; + uint8_t status; + + /* + * The import all key code system service is not available on M2S050 rev A, + * rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + params[0] = PUF_IMPORT_ALL_KC_SUBCOMMAND; + + write_ptr_value_into_array(p_keycodes, params, 1u); + + status = execute_service(PUF_USER_KEY_CODE_REQUEST_CMD, + params, + response, + PUF_IMPORT_ALL_KEYCODES_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_fetch_ecc_public_key +( + uint8_t* p_puf_public_key +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[4]; + uint8_t status; + + /* + * The fetch puf ecc public key system service is not available on M2S050 + * rev A, rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + write_ptr_value_into_array(p_puf_public_key, params, 0u); + + status = execute_service(PUF_ECC_PUBLIC_KEY_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_puf_get_random_seed +( + uint8_t* p_puf_seed +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[4]; + uint8_t status; + + /* + * The get puf seed system service is not available on M2S050 rev A, rev B, + * rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + write_ptr_value_into_array(p_puf_seed, params, 0u); + + status = execute_service(PUF_SEED_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_ecc_point_multiplication +( + uint8_t* p_scalar_d, + uint8_t* p_point_p, + uint8_t* p_point_q +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[12]; + uint8_t status; + + /* + * The ECC point multiplication system service is not available on M2S050 + * rev A, rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + write_ptr_value_into_array(p_scalar_d, params, 0u); + write_ptr_value_into_array(p_point_p, params, 4u); + write_ptr_value_into_array(p_point_q, params, 8u); + + status = execute_service(POINT_MULTIPLICATION_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_ecc_point_addition +( + uint8_t* p_point_p, + uint8_t* p_point_q, + uint8_t* p_point_r +) +{ + uint8_t response[STANDARD_SERV_RESP_LENGTH]; + uint8_t params[12]; + uint8_t status; + + /* + * The ECC point addition system service is not available on M2S050 + * rev A, rev B, rev C and rev D. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + write_ptr_value_into_array(p_point_p, params, 0u); + write_ptr_value_into_array(p_point_q, params, 4u); + write_ptr_value_into_array(p_point_r, params, 8u); + + status = execute_service(POINT_ADDITION_REQUEST_CMD, + params, + response, + STANDARD_SERV_RESP_LENGTH); + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +void MSS_SYS_ecc_get_base_point +( + uint8_t* p_point_g +) +{ + const uint8_t base_point_g[] = + { + 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, + 0xf3, 0x20, 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, + 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xB7, + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, + 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, + 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5F + }; + + memcpy(p_point_g, &base_point_g[0], sizeof(base_point_g)); +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_start_clock_monitor +( + void +) +{ + uint8_t status; + uint8_t tamper_control_req[2]; + uint8_t response[TAMPER_CONTROL_SERV_RESP_LENGTH]; + uint16_t actual_response_length; + + /* + * The Start clock monitoring tamper Control service is available only on + * G4X device. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + signal_request_start(); + + tamper_control_req[0] = TAMPER_CONTROL_REQUEST_CMD; + tamper_control_req[1] = 0x01u; + + MSS_COMBLK_send_cmd(tamper_control_req, /* p_cmd */ + sizeof(tamper_control_req), /* cmd_size */ + 0, /* p_data */ + 0u, /* data_size */ + response, /* p_response */ + TAMPER_CONTROL_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((TAMPER_CONTROL_SERV_RESP_LENGTH == actual_response_length) && + (TAMPER_CONTROL_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_stop_clock_monitor +( + void +) +{ + uint8_t status; + uint8_t tamper_control_req[2]; + uint8_t response[TAMPER_CONTROL_SERV_RESP_LENGTH]; + uint16_t actual_response_length; + + /* + * The Stop clock monitoring tamper Control service is available only on + * G4X device. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + signal_request_start(); + + tamper_control_req[0] = TAMPER_CONTROL_REQUEST_CMD; + tamper_control_req[1] = 0x02u; + + MSS_COMBLK_send_cmd(tamper_control_req, /* p_cmd */ + sizeof(tamper_control_req), /* cmd_size */ + 0, /* p_data */ + 0u, /* data_size */ + response, /* p_response */ + TAMPER_CONTROL_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((TAMPER_CONTROL_SERV_RESP_LENGTH == actual_response_length) && + (TAMPER_CONTROL_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_enable_puf_power_down +( + void +) +{ + uint8_t status; + uint8_t tamper_control_req[2]; + uint8_t response[TAMPER_CONTROL_SERV_RESP_LENGTH]; + uint16_t actual_response_length; + + /* + * The Enable PUF power down service is available only on G4X device. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + signal_request_start(); + + tamper_control_req[0] = TAMPER_CONTROL_REQUEST_CMD; + tamper_control_req[1] = 0x04u; + + MSS_COMBLK_send_cmd(tamper_control_req, /* p_cmd */ + sizeof(tamper_control_req), /* cmd_size */ + 0, /* p_data */ + 0u, /* data_size */ + response, /* p_response */ + TAMPER_CONTROL_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((TAMPER_CONTROL_SERV_RESP_LENGTH == actual_response_length) && + (TAMPER_CONTROL_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_disable_puf_power_down +( + void +) +{ + uint8_t status; + uint8_t tamper_control_req[2]; + uint8_t response[TAMPER_CONTROL_SERV_RESP_LENGTH]; + uint16_t actual_response_length; + + /* + * Disable PUF power down is available only on G4X device. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + signal_request_start(); + + tamper_control_req[0] = TAMPER_CONTROL_REQUEST_CMD; + tamper_control_req[1] = 0x08u; + + MSS_COMBLK_send_cmd(tamper_control_req, /* p_cmd */ + sizeof(tamper_control_req), /* cmd_size */ + 0, /* p_data */ + 0u, /* data_size */ + response, /* p_response */ + TAMPER_CONTROL_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((TAMPER_CONTROL_SERV_RESP_LENGTH == actual_response_length) && + (TAMPER_CONTROL_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_clear_lock_parity +( + void +) +{ + uint8_t status; + uint8_t tamper_control_req[2]; + uint8_t response[TAMPER_CONTROL_SERV_RESP_LENGTH]; + uint16_t actual_response_length; + + /* + * The Clear Lock parity is available only on G4X device. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + signal_request_start(); + + tamper_control_req[0] = TAMPER_CONTROL_REQUEST_CMD; + tamper_control_req[1] = 0x10u; + + MSS_COMBLK_send_cmd(tamper_control_req, /* p_cmd */ + sizeof(tamper_control_req), /* cmd_size */ + 0, /* p_data */ + 0u, /* data_size */ + response, /* p_response */ + TAMPER_CONTROL_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((TAMPER_CONTROL_SERV_RESP_LENGTH == actual_response_length) && + (TAMPER_CONTROL_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * See mss_sys_services.h for details. + */ +uint8_t MSS_SYS_clear_mesh_short +( + void +) +{ + uint8_t status; + uint8_t tamper_control_req[2]; + uint8_t response[TAMPER_CONTROL_SERV_RESP_LENGTH]; + uint16_t actual_response_length; + + /* + * The Clear mesh short service is available only on G4X device. + */ + ASSERT(0x0000F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0001F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0002F802u != SYSREG->DEVICE_VERSION); + ASSERT(0x0003F802u != SYSREG->DEVICE_VERSION); + + signal_request_start(); + + tamper_control_req[0] = TAMPER_CONTROL_REQUEST_CMD; + tamper_control_req[1] = 0x20u; + + MSS_COMBLK_send_cmd(tamper_control_req, /* p_cmd */ + sizeof(tamper_control_req), /* cmd_size */ + 0, /* p_data */ + 0u, /* data_size */ + response, /* p_response */ + TAMPER_CONTROL_SERV_RESP_LENGTH, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((TAMPER_CONTROL_SERV_RESP_LENGTH == actual_response_length) && + (TAMPER_CONTROL_REQUEST_CMD == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * + */ +static uint8_t execute_service +( + uint8_t cmd_opcode, + uint8_t * cmd_params_ptr, + uint8_t * response, + uint16_t response_length +) +{ + uint8_t status; + uint16_t actual_response_length; + + signal_request_start(); + + MSS_COMBLK_send_cmd_with_ptr(cmd_opcode, /* cmd_opcode */ + (uint32_t)cmd_params_ptr, /* cmd_params_ptr */ + response, /* p_response */ + response_length, /* response_size */ + request_completion_handler); /* completion_handler */ + + actual_response_length = wait_for_request_completion(); + + if((response_length == actual_response_length) && (cmd_opcode == response[0])) + { + status = response[1]; + } + else + { + status = MSS_SYS_UNEXPECTED_ERROR; + } + + return status; +} + +/*============================================================================== + * + */ +static void request_completion_handler +( + uint8_t * p_response, + uint16_t response_size +) +{ + g_request_in_progress = 0u; + g_last_response_length = response_size; +} + +/*============================================================================== + * + */ +static void signal_request_start(void) +{ + /* Wait for current request to complete. */ + while(g_request_in_progress) + { + ; + } + + g_request_in_progress = 1u; + g_last_response_length = 0u; +} + +/*============================================================================== + * + */ +static uint16_t wait_for_request_completion(void) +{ + while(g_request_in_progress) + { + ; + } + + return g_last_response_length; +} + +/*============================================================================== + * + */ +static void write_ptr_value_into_array +( + const uint8_t * pointer, + uint8_t target_array[], + uint32_t array_index +) +{ + target_array[array_index] = (uint8_t)((uint32_t)pointer); + target_array[array_index + 1] = (uint8_t)((uint32_t)pointer >> 8u); + target_array[array_index + 2] = (uint8_t)((uint32_t)pointer >> 16u); + target_array[array_index + 3] = (uint8_t)((uint32_t)pointer >> 24u); +} + +/*============================================================================== + Function to write array address to pointer location. + */ +static void write_array_into_ptr_value +( + uint8_t** pointer, + uint8_t target_array[], + uint32_t array_index +) +{ + uint32_t var; + + var = (uint32_t)target_array[array_index + 3]; + var = ((var << 8u) & 0xFFFFFF00) | target_array[array_index + 2]; + var = ((var << 8u) & 0xFFFFFF00) | target_array[array_index + 1]; + var = ((var << 8u) & 0xFFFFFF00) | target_array[array_index]; + + *pointer = (uint8_t*)var; +} + diff --git a/bsp/smartfusion2/libraries/mss_sys_services/mss_sys_services.h b/bsp/smartfusion2/libraries/mss_sys_services/mss_sys_services.h new file mode 100644 index 0000000000..b2586e0e5b --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_sys_services/mss_sys_services.h @@ -0,0 +1,2500 @@ +/******************************************************************************* + * (c) Copyright 2012-2016 Microsemi SoC Products Group. All rights reserved. + * + * SmartFusion2 MSS System Services bare metal software driver public API. + * + * SVN $Revision: 8680 $ + * SVN $Date: 2016-11-25 14:18:13 +0530 (Fri, 25 Nov 2016) $ + */ + +/*=========================================================================*//** + @mainpage SmartFusion2 MSS System Services Bare Metal Driver. + + @section intro_sec Introduction + The SmartFusion2 microcontroller subsystem (MSS) includes a communication + block (COMM_BLK) allowing it to communicate with the SmartFusion2 System + Controller. The SmartFusion2 System Controller performs a variety of system + wide services. This software driver provides a set of functions to access + these System Services. The driver can be adapted for use as part of an + operating system, but the implementation of the adaptation layer between the + driver and the operating system's driver model is outside the scope of the + driver. + + @section hw_dependencies Hardware Flow Dependencies + The MSS System Services driver does not require any configuration. It relies + on the SmartFusion2 communication block (MSS_COMM_BLK) to communicate with the + System Controller. The MSS_COMM_BLK is always enabled. + The base address, register addresses and interrupt number assignment for the + MSS_COMM_BLK are defined as constants in the SmartFusion2 CMSIS HAL. You must + ensure that the latest SmartFusion2 CMSIS HAL is included in the project + settings of the software tool chain used to build your project and that it is + generated into your project. + + @section theory_op Theory of Operation + The System Services driver provides access to the SmartFusion2 System + Controller services. These system services are loosely grouped into the + following features: + - Reading system information + - Cryptography + - Non-deterministic random bit generator + - Flash*Freeze + - Zeroization + - Asynchronous Messages + - Programming Services + - Digest Check Service + Note: Refer to the function descriptions for further details about the + features of each individual service. + + Reading System Information + The System Services driver can be used to read information about the + SmartFusion2 device and the design programmed into it using the following + functions: + - MSS_SYS_get_serial_number() + - MSS_SYS_get_user_code() + - MSS_SYS_get_design_version() + - MSS_SYS_get_device_certificate() + - MSS_SYS_get_secondary_device_certificate() + + Cryptography Services + The System Services driver provides cryptographic services using the following + functions: + - MSS_SYS_128bit_aes() + - MSS_SYS_256bit_aes() + - MSS_SYS_sha256() + - MSS_SYS_hmac() + - MSS_SYS_challenge_response() + - MSS_SYS_key_tree() + + Non-Deterministic Random Bit Generator + The System Services driver provides random number generation services using + the following functions: + - MSS_SYS_nrbg_instantiate() + - MSS_SYS_nrbg_self_test() + - MSS_SYS_nrbg_generate() + - MSS_SYS_nrbg_reseed() + - MSS_SYS_nrbg_uninstantiate() + - MSS_SYS_nrbg_reset() + + Flash*Freeze + The System Services driver can be used to request the system to enter + Flash*Freeze mode using the following function: + - MSS_SYS_flash_freeze() + The System Controller sends an asynchronous message to the MSS COMM_BLK when + the device is either about to enter or has exited Flash*Freeze mode. The + MSS_SYS_init() function can register a callback function with the System + Services driver to handle these asynchronous messages. + + Zeroization + The System Service driver can be used to destroy sensitive information on the + SmartFusion2 device using the following function. + - MSS_SYS_zeroize_device() + The zeroization system service erases all user configuration data, user keys, + user security settings, NVM, SRAM, FPGA flip-flops, System Controller memory, + and crypto-engine registers. The zeroization system service is enabled and + configured in the Libero hardware flow. + Note: The zeroization system service can render the SmartFusion2 device + permanently and irrevocably disabled depending on the configuration + selected in the Libero hardware flow. + + Asynchronous Messages + The System Controller sends asynchronous messages to the MSS COMM_BLK when + certain events are detected during the execution of the following system + services: + �Flash*Freeze + �Power-on-reset (POR) digest check + �Tamper detect events + The MSS_SYS_init() function can register a callback function with the System + Services driver to handle these asynchronous messages allowing the user + application code to take remedial or defensive action. If the application + code does not provide an asynchronous event handler function then the driver + simply reads and discards these asynchronous messages. + Flash*Freeze Entry and Exit + The System Controller sends a Flash*Freeze entry or exit message to the MSS + COMM_BLK when the SmartFusion2 device is either about to enter or has exited + Flash*Freeze mode. The driver passes the entry/exit message opcode as a + parameter to the event handler callback function. + Power-on Reset (POR) Digest Error + The POR digest check service is enabled in the Libero hardware flow and if + enabled is automatically performed as part of the device�s power up sequence. + The System Controller sends a POR digest check error message to the MSS + COMM_BLK when the result of the POR digest check is a mismatch between the + original stored digest and the current digest. The driver passes the command + byte and the error flags byte from the error message as parameters to the + event handler callback function. + Tamper detect events + The System Controller sends tamper message to the MSS COMM_BLK when the + tamper event is detected. This tamper message is of one byte contain only + command opcode. The driver pass the tamper message opcode as a parameter + to the event handler callback function. + + Programming Service + The In-System Programming (ISP) system service can be used for field upgrades + of the hardware design programmed in the FPGA fabric. The application program + running on the Cortex-M3 controls the ISP operations, it must retrieve the + programming file from memory or from a communication port and feed it to + the System Controller through the ISP system service. The System Controller + performs the actual programming of the FPGA (fabric and eNVM) using the + programming data it receives from the Cortex-M3 as part of the ISP system + service. + Programming files are large and cannot always be entirely retrieved by the + application before starting the ISP operation. The ISP system service is + designed to work around this issue by handling programming one page at a + time. The application initiates the ISP operation through a call to + MSS_SYS_start_isp(), passing two function pointers as parameters. These two + function pointers point to a page read handler function and an ISP completion + handler function that must be implemented as part of the application. The + system services driver will call the application�s page read handler + function every time it is ready to program the FPGA with a new page of + programming data. The page read handler function is responsible for splitting + the programming file into suitably sized pages. The page size is not fixed + and can be chosen to suit the application. The system services driver will + call the ISP completion handler function once the last page has been + programmed. + The application must keep track of the pages of programming data is has + passed to the ISP system service. It must provide the location of the next + programming page by writing the address of the page into the location + pointed to by the pp_next_page pointer passed as parameter to the page read + handler function. The page read handler must return the size of the page or + zero if the last page has already been given to the ISP system service. + + The In-Application Programming (IAP) system service provides another field + upgrade method of the hardware design programmed in FPGA fabric. Using this + method, the user application first writes the FPGA fabric design into the SPI + Flash connected to MSS SPI-0 before invoking the IAP system service. The FPGA + fabric is then programmed under control of the SmartFusion2 system controller + without intervention of the Cortex-M3 processor. The application must + configure the SPI peripheral and provide exclusive access to the IAP service + before invoking the IAP system service. + When the IAP service is invoked, the system controller will send the SPI + command 0Bh i.e. single read operation command to the SPI flash to retrieve + the FPGA fabric design. The system controller will perform one of the + following operations based on the mode selected when invoking the service: + a) Authenticate the fabric design. + b) Program the fabric design into FPGA. + c) Verify that the programming was successful. + The system controller will take 2 to 3 minutes to complete each operation. + The application must provide the starting location address of the new FPGA + fabric design present in SPI Flash when invoking the IAP service. + The system controller will return a response indicating the status of the + operation on completing the execution of the IAP service except in the case + of successful programming. The system controller will reset the device and + start execution of the new FPGA fabric design after successfully programming + the device. The system controller will not return any response information + when a successful programming operation completes. + + Digest Check Service + The System Service driver can be used to recalculate and compare digests of + selected components using the following function. + - MSS_SYS_check_digest() + Note: This function is not used for the power-on-reset (POR) digest check + service. An asynchronous event handler registered with the + MSS_SYS_init() function is used to support the POR digest check + service. + + Elliptic Curve services + The System Service driver can be used to perform elliptic curve cryptography + (ECC) mathematical operations over the field defined by the NIST P-384 + curve. point addition and point multiplication using the following functions + are provided: + - MSS_SYS_ecc_point_multiplication() + - MSS_SYS_ecc_point_addition() + - MSS_SYS_ecc_get_base_point() + One example use of these functions is the elliptic curve Diffie-Hellman + (ECDH) key establishment protocol. In this protocol, a public key is computed + by performing a point multiplication of a 384-bit private key with the base + point for the NIST P-384 curve. Both parties involved in the key + establishment compute their public keys and send them to each other. A shared + secret is established by point multiplication of each party�s private key + with the remote party�s public key. The elliptic curve mathematical + properties ensure that the private key point multiplication with the remote + party�s public key results in the same point on the curve for both parties. + The coordinates of this point on the curve is used as the shared secret for + further cryptographic operations. + Note: There is no checking done to see if the given input point or points + are valid points on the elliptic curve. Supplying illegal X-Y coordinates + for a point will result in a garbage output. However, if a valid point or + points are given, then the resulting output point is guaranteed to be valid. + + PUF Services + The SRAM-PUF system services provide a Physically Unclonable Function (PUF) + that can be used for key generation and storage as well as device + authentication. + The large SmartFusion2 devices starting from the M2S060 include an SRAM-PUF + hardware block as part of the System Controller. This hardware block makes + use of a 16Kbit SRAM block to determine an intrinsic secret unique to each + device. This intrinsic secret is in turn used to regenerate keys enrolled + with the SRAM-PUF hardware block. + The SRAM-PUF is also used in design security. Although the system services + are not used for design security, it is possible to retrieve the design + security ECC public key for device authentication purpose. + The SRAM-PUF start-up value can also be used to generate a random number + generator seed. + Note: PUF service should be executed from DDR/SRAM/eNVM-0 except for the + M2S060 device. On the M2S060 device, PUF service should be executed + from DDR/SRAM. + + Activation Code + An activation code is required by the SRAM-PUF to regenerate the intrinsic + secret from the SRAM-PUF start-up value. The start-up value of the PUF�s SRAM + block is slightly different from one power-up to the next. Some processing is + performed on the PUF�s SRAM start-up value to eliminate randomness and + retrieve the exact same intrinsic secret on each power-up cycle. This + processing is performed using the activation code, which can be thought of as + parity bits that are used to reconstruct the same PUF intrinsic secret each + time, in spite of the fact that some SRAM bits are flipped compared to the + original snapshot used when the activation code was first enrolled. + The devices are shipped with one activation code that was enrolled during + the manufacturing process. The PUF secret computed from this enrollment is + used to protect a 376-bit ECC private key that may be used for design + security purposes as described elsewhere. The user may optionally enroll a + second activation code in special �S� -suffix (i.e., security enabled) + devices. The activation code is usually generated only once, typically when + the system containing the SmartFusion2 device is being commissioned, using a + JTAG or SPI programming command. Alternatively, the activation code is + created using the following system service function: + + - MSS_SYS_puf_create_activation_code() + This might be used if the first user activation code were intentionally + deleted and a new one was desired. The activation code is stored the System + Controller�s private eNVM after being created. Its value is never exported in + clear text from the System Controller. Because of the inherent noise in each + SRAM start-up, there is a negligible probability two activation codes or the + associated PUF intrinsic secret are ever the same, even if the same device is + repeatedly re-enrolled. + The activation code can later be destroyed using the following function: + - MSS_SYS_puf_delete_activation_code() + This function would typically only be used when the system containing + SmartFusion2 is being decommissioned or repurposed. + + Enrolling Keys + The SRAM-PUF can be used to store cryptographic keys. The keys are stored in + such a way that the key�s actual value never appears in the system unless it + is retrieved by the user. A so-called "Key Code" is stored in the System + Controller�s private eNVM instead of the key�s value. The key code is + generated when a key is enrolled. The key code value is created from the + enrolled key�s value and the intrinsic secret value. The key�s value can then + later be regenerated from the key code value and intrinsic secret value upon + user request. + NOTE:Note: Key #0 and key #1 are used for design security and are not + accessible to the user. Key Code #2 may be used to store a user + data security key, but has an important optional use in JTAG- or + SPI-based key validation, as will be described below. + + The enrolled keys can be intrinsic keys or extrinsic keys. The value of an + intrinsic key is a random number generated from the SRAM-PUF start-up value. + Intrinsic keys are useful where a security protocol executing on SmartFusion2 + needs to generate a key�s value and store it for later use. For example, the + user could request a 384-bit long intrinsic key to be enrolled and use it as + private key in an elliptic curve Diffie-Hellman key exchange. + The value of an extrinsic key is specified by the user. For example, the user + could request a symmetric key obtained from a key exchange protocol to be + enrolled for later use. + The following functions are used for key enrollment: + - MSS_SYS_puf_get_number_of_keys() + - MSS_SYS_puf_enroll_key() + - MSS_SYS_puf_fetch_key() + - MSS_SYS_puf_delete_key() + + Keys are identified by a number and must be enrolled sequentially. Key codes + #0 and #1 are reserved as a 256-bit symmetric extrinsic key and a 384-bit + private (asymmetric) intrinsic key, both used for design security only, and + are enrolled by JTAG (or SPI) programming commands. These commands also + enroll the user activation code and key code #2, a 256-bit value that has a + special use in key validation, and which is enrolled at the same time as key + code #1, as will be described below. + The first step in enrolling a new key is to determine how many keys are + already enrolled. This is achieved by a call to function + MSS_SYS_puf_get_number_of_keys() which returns the number of enrolled keys. + Keys are numbered from 0 up to 57 (the maximum number of keys assuming all + user keys are less than or equal to 256 bits in length). For example, + assuming only the first three key codes mentioned above have been enrolled + using the JTAG programming commands, the value returned would be �3�. The + number of keys returned by MSS_SYS_puf_get_number_of_keys() can then be used + as the newly enrolled key identification number since key numbering is zero + based. Thus, the first data security key enrolled by the user would generate + key code #3. + + A key is enrolled through a call to function MSS_SYS_puf_enroll_key(). This + function takes the following parameters: + � The key identification number that will be used to later retrieve the + key�s value. This is the value returned by a call to + MSS_SYS_puf_get_number_of_keys(). + � The key size. + � A pointer to the buffer containing the value of the key to enroll. The + value of this pointer must be NULL if enrolling an intrinsic key where + the SRAM-PUF will generate the actual key value. + � A pointer to the buffer where the enrolled key will be regenerated when + later fetched by the user. + + The value of the enrolled keys can be regenerated through a call to function + MSS_SYS_puf_fetch_key(). The identification number of the key to fetch is + passed as parameter to this function. The requested key�s value will be + regenerated and copied to the buffer specified during key enrollment. The + key�s value is then available for use until it is no further required and + wiped, by the user�s application, from the memory buffer it was fetched into. + + Note: It is not possible to fetch a key if the key codes have been exported + and not re-imported. + + A key can be removed from the system through a call to function + MSS_SYS_puf_delete_key(). This function only requires the key identification + number to specify which key should be removed from the SRAM-PUF. + + Note: If a new key is enrolled in a key-slot where a key was previously + enrolled and deleted and which is not the highest key number enrolled, + it must be the same size as the key it replaced or an error will be + reported. + + Exporting and Importing Key Codes + The activation code and key codes used to regenerate the enrolled keys can be + exported out of the SRAM-PUF. The exported activation code and key codes are + encrypted using a one-time pad. The one-time pad is stored in the System + Controller�s private eNVM and is never exported. This means that the exported + activation and key codes can only be decrypted by the unique device that + exported them. + The activation and key code values stored in eNVM are replaced with hash + values of themselves as part of the export procedure. This means that + enrolled keys cannot be regenerated anymore after the activation and key + codes have been exported. The enrolled keys will only be regenerated + successfully if the exported activation and key codes for that unique + SmartFusion2 device are imported back. + + The activation and all the key codes are exported in one single operation + using the following function: + - MSS_SYS_puf_export_keycodes() + The MSS_SYS_puf_export_keycodes() function can only be called once since the + activation and key codes are not present anymore in the device after this + function completes. The activation and key codes must be imported back + before they can be exported again. + The activation and all the key codes are imported back in one single + operation using the following function: + - MSS_SYS_puf_import_keycodes() + It is only possible to import activation and key codes exported from the + same unique device. The imported activation and key codes are decrypted + using the one-time pad stored in eNVM used during the export procedure. + The decrypted activation and key codes are then checked again the hash + values stored in place of the activation and key codes. The activation + and key codes will only be successfully imported back if the hash values + for the imported activation and key codes match the hash values stored in + eNVM during the export procedure. Imported activation and key codes are + never again restored to non-volatile memory; rather, they are imported to + volatile scratch-pad memory, used to regenerate a key, and then deleted. + Therefore, they must be re-imported each time a key is needed. + + Retrieving the Design Security ECC Public Key + When the 384 bit user design security private ECC key is intrinsically + generated and key code #1 is stored using the JTAG or SPI programming + commands, the associated 768 bit public key is also generated and stored + in the system controller�s private eNVM. At the same time, the256 bit SHA-256 + hash of the ECC public key is enrolled to key code #2. + The 768 bit design security ECC public key can be retrieved using the following + system service function: + - MSS_SYS_puf_fetch_ecc_public_key() + Note that the public key is also exported via JTAG (or SPI) programming + commands when it is used in ECDH design security operations such as + bitstream encryption or device authentication. + + In order to mitigate man-in-the-middle attacks on the public key when it is + exported and used, it is recommended that the ECC public key is validated + using an already trusted key. This could be a user design security key, for + example. Perhaps the most convenient keys to use are one of the Microsemi + certified ECC key pairs, which are trusted because of the verifiable + Microsemi signatures on the X.509 public key certificates. This is why when + the 384 bit user ECC private key was generated and stored using key code #1, + the 256 bit hash of the associated 768 bit public key was stored using key + code #2. The JTAG (or SPI) key verification protocol has a special option + which includes the value stored in key code #2 in the computation. Thus, + besides also validating the device really �knows� the already trusted key, + with this option selected, the 256-bit value stored using key code #2 is also + validated. If this is the hash of the user ECC public key, then it is proved + that the public key is the authentic public key as stored in the device, and + not one supplied by an adversary in a man-in-the-middle attack on this key. + After the user ECC public key has been thus validated, key code #2 can be + deleted and replaced with another 256-bit value the user wishes to validate, + such as the hash of user data security key. It is recommended that key code + #2 only be used to store hashes of critical security parameters such as + secret or private keys, and not the actual secrets, themselves. + Note: The user's application need to reserve a defined block of SRAM when + using PUF system services, to prevent the compiler from using the SRAM + memory range from address 0x2000800 to 0x2000802F inclusive. This is + the default location used by the system controller to automatically + enroll KC#2, when KC#1 is enrolled. + + Random Number Generator Seed + The PUF�s SRAM start-up value randomness can be harvested to generate a + 256-bit full entropy true random seed. A random seed can be obtained using + function: + - MSS_SYS_puf_get_random_seed() + Note: Random seeds can only be generated after the SRAM-PUF has been powered + -down for 250 msec. Thus, if the PUF has been used more recently than + that, there may be a delay before the seed is generated. + + Tamper control service + The tamper control system services provide the following services: + - Enable/disable clock monitoring + - Control power to PUF + - Clear mesh short tamper + - Clear lock parity tamper + + The tamper control services are accessed using the following functions: + - MSS_SYS_start_clock_monitor() + - MSS_SYS_stop_clock_monitor() + - MSS_SYS_enable_puf_power_down() + - MSS_SYS_disable_puf_power_down() + - MSS_SYS_clear_lock_parity() + - MSS_SYS_clear_mesh_short() + + *//*=========================================================================*/ + +#ifndef __MSS_SYS_SERVICES_H_ +#define __MSS_SYS_SERVICES_H_ 1 + +#include "../../CMSIS/m2sxxx.h" +#include "mss_comblk_page_handler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================== + * Status codes: + */ +/*-------------------------------------------------------------------------*//** + These constants are used by multiple services to communicate the outcome of a + system services request. These status codes are used across all types of + services. + + - MSS_SYS_SUCCESS: + Indicates that the system services completed successfully. + + - MSS_SYS_UNEXPECTED_ERROR: + Indicates that the system failed in an unexpected way. + + - MSS_SYS_MEM_ACCESS_ERROR: + Indicates that the System Controller could not access the memory used to + pass parameters to the System Controller or to return a service result to + the Cortex-M3. + + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY: + Indicates that the requested system service is not available on the + SmartFusion2 device. + + - MSS_SYS_SERVICE_DISABLED_BY_USER: + Indicates that the requested system service has been disabled as part of + the hardware design. + + - MSS_SYS_SERVICE_NOT_LICENSED + Indicates that the license is not available in SmartFusion2 device for + this service. + + - MSS_SYS_CLK_DIVISOR_ERROR + Indicates that on 060 device the divisor values for fclk, pclk0, pclk1, + clk_fic64 are not equal to each other or the divisor values is set to + divide by 32. + */ +#define MSS_SYS_SUCCESS 0u +#define MSS_SYS_UNEXPECTED_ERROR 200u +#define MSS_SYS_CLK_DIVISOR_ERROR 201u + +#define MSS_SYS_MEM_ACCESS_ERROR 127u +#define MSS_SYS_SERVICE_NOT_LICENSED 253u +#define MSS_SYS_SERVICE_DISABLED_BY_FACTORY 254u +#define MSS_SYS_SERVICE_DISABLED_BY_USER 255u + +/*-------------------------------------------------------------------------*//** + These constants are used by PUF services to communicate the outcome of a + system services request. These status codes are only used by PUF services. + + - MSS_SYS_ENVM_ERROR: + Indicates that a eNVM error occurred for both create and delete user + activation code sub command. + + - MSS_SYS_PUF_ERROR_WHEN_CREATING: + Indicates that PUF error occur while creating new user activation code. + + - MSS_SYS_INVALID_SUBCMD: + Indicates that the sub command is invalid. + + - MSS_SYS_INVALID_REQUEST_OR_KC: + Indicates that request or Key code is invalid, when exporting or + importing. + + - MSS_SYS_INVALID_KEYNUM_OR_ARGUMENT + Indicates that the supplied key number or argument is invalid. + + - MSS_SYS_NO_VALID_PUBLIC_KEY + Indicates that no valid public key present in eNVM. + + - MSS_SYS_INVALID_MEMORY_ADDRESS: + Indicates that memory address is invalid. + + - MSS_SYS_ENVM_PROGRAM_ERROR + Indicates that the eNVM program error occur when writing to the private eNVM + for both create and delete user activation code sub command. + + - MSS_SYS_INVALID_HASH: + Indicates that 32 byte hash is invalid. + + - MSS_SYS_INVALID_USER_AC1: + Indicates that invalid user activation code has been imported. + + - MSS_SYS_ENVM_VERIFY_ERROR: + Indicates that the eNVM verify error occur when writing to the private eNVM + for both create and delete user activation code sub command. + + - MSS_SYS_INCORRECT_KEYSIZE_FOR_RENEWING_A_KC: + Indicates that the supplied key size is incorrect while renewing the key + code. + + - MSS_SYS_PRIVATE_ENVM_USER_DIGEST_MISMATCH: + Indicates that digest mismatch occurs for private eNVM. + + - MSS_SYS_USER_KEY_CODE_INVALID_SUBCMD: + Indicate that the sub command is invalid. + + - MSS_SYS_DRBG_ERROR: + Indicates that DRBG error occurred while populating one time pad reminder + by random bits. +*/ +#define MSS_SYS_ENVM_ERROR 1u +#define MSS_SYS_PUF_ERROR_WHEN_CREATING 2u +#define MSS_SYS_INVALID_SUBCMD 3u +#define MSS_SYS_INVALID_REQUEST_OR_KC 3u +#define MSS_SYS_INVALID_KEYNUM_OR_ARGUMENT 3u +#define MSS_SYS_NO_VALID_PUBLIC_KEY 3u +#define MSS_SYS_INVALID_MEMORY_ADDRESS 4u +#define MSS_SYS_ENVM_PROGRAM_ERROR 4u +#define MSS_SYS_INVALID_HASH 5u +#define MSS_SYS_INVALID_USER_AC1 6u +#define MSS_SYS_ENVM_VERIFY_ERROR 7u +#define MSS_SYS_INCORRECT_KEYSIZE_FOR_RENEWING_A_KC 8u +#define MSS_SYS_PRIVATE_ENVM_USER_DIGEST_MISMATCH 10u +#define MSS_SYS_USER_KEY_CODE_INVALID_SUBCMD 11u +#define MSS_SYS_DRBG_ERROR 12u + +/*-------------------------------------------------------------------------*//** + * Programming services specific status codes: + */ +#define MSS_SYS_CHAINING_MISMATCH 1u +#define MSS_SYS_UNEXPECTED_DATA_RECEIVED 2u +#define MSS_SYS_INVALID_ENCRYPTION_KEY 3u +#define MSS_SYS_INVALID_COMPONENT_HEADER 4u +#define MSS_SYS_BACK_LEVEL_NOT_SATISFIED 5u +#define MSS_SYS_DSN_BINDING_MISMATCH 7u +#define MSS_SYS_ILLEGAL_COMPONENT_SEQUENCE 8u +#define MSS_SYS_INSUFFICIENT_DEV_CAPABILITIES 9u +#define MSS_SYS_INCORRECT_DEVICE_ID 10u +#define MSS_SYS_UNSUPPORTED_BITSTREAM_PROT_VER 11u +#define MSS_SYS_VERIFY_NOT_PERMITTED_ON_BITSTR 12u +#define MSS_SYS_INVALID_DEVICE_CERTIFICATE 13u +#define MSS_SYS_ABORT 127u +#define MSS_SYS_NVM_VERIFY_FAILED 129u +#define MSS_SYS_DEVICE_SECURITY_PROTECTED 130u +#define MSS_SYS_PROGRAMMING_MODE_NOT_ENABLED 131u +#define MSS_SYS_ENVM_PROGRAMMING_OPERATION_FAIL 132u +#define MSS_SYS_ENVM_VERIFY_OPERATION_FAIL 133u +#define MSS_SYS_ACCESS_ERROR 134u +#define MSS_SYS_PUF_ACCESS_ERROR 135u +#define MSS_SYS_BAD_COMPONENT 136u + +/*-------------------------------------------------------------------------*//** + These constants are used to specify the event_opcode parameter for the + event_handler() function registered with the MSS_SYS_init() function. They are + used to specify which asynchronous event is notified to the Cortex-M3 software + by the System Controller. Asynchronous events are sent by the System + Controller to the Cortex-M3 when some system events of interest occur. + + - FLASH_FREEZE_SHUTDOWN_OPCODE: + Indicates that the system is being shutdown as a result of entering the + Flash*Freeze mode. + + - FLASH_FREEZE_EXIT_OPCODE: + Indicates that the system is exiting Flash*Freeze mode. + + - POR_DIGEST_ERROR_OPCODE + Indicates that the MSS has received the POR Digest Check message. + + - TAMPER_ATTEMPT_BOUNDARY_SCAN_OPCODE + Indicates that the MSS has received the tamper boundary scan attempt + detected. + + - TAMPER_ATTEMPT_BUFFER_ACCESS_OPCODE + Indicates that the MSS has received the tamper buffer access attempt + detected. + + - TAMPER_ATTEMPT_DEBUG_OPCODE + Indicates that the MSS has received the tamper debug attempt detected. + + - TAMPER_ATTEMPT_CHECK_DIGESTS_OPCODE + Indicates that the MSS has received the tamper check digest attempt + detected. + + - TAMPER_ATTEMPT_ECC_SETUP_INSTRUCTION_OPCODE + Indicates that the MSS has received the tamper ECC setup instruction + attempt detected. + + - TAMPER_ATTEMPT_FACTORY_PRIVATE_OPCODE + Indicates that the MSS has received the tamper factory private attempt + detected. + + - TAMPER_ATTEMPT_KEY_VALIDATION_OPCODE + Indicates that the MSS has received the tamper key validation attempt + detected. + + - TAMPER_ATTEMPT_MISC_OPCODE + Indicates that the MSS has received the tamper misc attempt detected. + + - TAMPER_ATTEMPT_PASSCODE_MATCH_OPCODE + Indicates that the MSS has received the tamper passcode match attempt + detected. + + - TAMPER_ATTEMPT_PASSCODE_SETUP_INSTRUCTION_OPCODE + Indicates that the MSS has received the tamper passcode setup instruction + attempt detected. + + - TAMPER_ATTEMPT_PROGRAMMING_OPCODE + Indicates that the MSS has received the tamper programming attempt detected. + + - TAMPER_ATTEMPT_PUBLIC_INFORMATION_OPCODE + Indicates that the MSS has received the tamper public information attempt + detected. + + - TAMPER_ATTEMPT_PUF_KEY_MANAGEMENT_OPCODE + Indicates that the MSS has received the tamper PUF key management attempt + detected. + + - TAMPER_ATTEMPT_UNUSED_OPCODE + Indicates that the MSS has received the tamper unused attempt detected. + + - TAMPER_ATTEMPT_USER_JTAG_OPCODE + Indicates that the MSS has received the tamper user JTAG attempt detected. + + - TAMPER_ATTEMPT_ZEROIZATION_RECOVERY_OPCODE + Indicates that the MSS has received the tamper zeroization recovery + attempt detected. + + - TAMPER_FAILURE_BOUNDARY_SCAN_OPCODE + Indicates that the MSS has received the tamper boundary scan failure + detected. + + - TAMPER_FAILURE_BUFFER_ACCESS_OPCODE + Indicates that the MSS has received the tamper buffer access + failure detected. + + - TAMPER_FAILURE_DEBUG_OPCODE + Indicates that the MSS has received the tamper debug failure detected. + + - TAMPER_FAILURE_CHECK_DIGESTS_OPCODE + Indicates that the MSS has received the tamper check digest failure + detected. + + - TAMPER_FAILURE_ECC_SETUP_INSTRUCTION_OPCODE + Indicates that the MSS has received the tamper ECC setup instruction + failure detected. + + - TAMPER_FAILURE_FACTORY_PRIVATE_OPCODE + Indicates that the MSS has received the tamper factory private failure + detected. + + - TAMPER_FAILURE_KEY_VALIDATION_OPCODE + Indicates that the MSS has received the tamper key validation failure + detected. + + - TAMPER_FAILURE_MISC_OPCODE + Indicates that the MSS has received the tamper misc failure detected. + + - TAMPER_FAILURE_PASSCODE_MATCH_OPCODE + Indicates that the MSS has received the tamper passcode match failure + detected. + + - TAMPER_FAILURE_PASSCODE_SETUP_INSTRUCTION_OPCODE + Indicates that the MSS has received the tamper passcode setup instruction + failure detected. + + - TAMPER_FAILURE_PROGRAMMING_OPCODE + Indicates that the MSS has received the tamper programming failure detected. + + - TAMPER_FAILURE_PUBLIC_INFORMATION_OPCODE + Indicates that the MSS has received the tamper public information failure + detected. + + - TAMPER_FAILURE_PUF_KEY_MANAGEMENT_OPCODE + Indicates that the MSS has received the tamper PUF key management failure + detected. + + - TAMPER_FAILURE_UNUSED_OPCODE + Indicates that the MSS has received the tamper unused failure detected. + + - TAMPER_FAILURE_USER_JTAG_OPCODE + Indicates that the MSS has received the tamper user jtag failure detected. + + - TAMPER_FAILURE_ZEROIZATION_RECOVERY_OPCODE + Indicates that the MSS has received the tamper zeroization recovery + failure detected. + + - TAMPER_CLOCK_ERROR_DETECT_OPCODE0 + Indicates that the MSS has received the tamper clock monitor error detected. + + - TAMPER_HARDWARE_MONITOR_JTAGACTIVE_ERROR_OPCODE + Indicates that the MSS has received the tamper jtag active hardware + monitor error detected. + + - TAMPER_HARDWARE_MONITOR_LOCKPARITY_ERROR_OPCODE + Indicates that the MSS has received the tamper lock parity hardware + monitor error detected. + + - TAMPER_HARDWARE_MONITOR_MESHSHORT_ERROR_OPCODE + Indicates that the MSS has received the tamper mesh short hardware monitor + error detected. +*/ +#define FLASH_FREEZE_SHUTDOWN_OPCODE 0xE0u +#define FLASH_FREEZE_EXIT_OPCODE 0xE1u +#define POR_DIGEST_ERROR_OPCODE 0xF1u +#define TAMPER_ATTEMPT_BOUNDARY_SCAN_OPCODE 0x80u +#define TAMPER_ATTEMPT_BUFFER_ACCESS_OPCODE 0x81u +#define TAMPER_ATTEMPT_DEBUG_OPCODE 0x82u +#define TAMPER_ATTEMPT_CHECK_DIGESTS_OPCODE 0x83u +#define TAMPER_ATTEMPT_ECC_SETUP_INSTRUCTION_OPCODE 0x84u +#define TAMPER_ATTEMPT_FACTORY_PRIVATE_OPCODE 0x85u +#define TAMPER_ATTEMPT_KEY_VALIDATION_OPCODE 0x86u +#define TAMPER_ATTEMPT_MISC_OPCODE 0x87u +#define TAMPER_ATTEMPT_PASSCODE_MATCH_OPCODE 0x88u +#define TAMPER_ATTEMPT_PASSCODE_SETUP_INSTRUCTION_OPCODE 0x89u +#define TAMPER_ATTEMPT_PROGRAMMING_OPCODE 0x8Au +#define TAMPER_ATTEMPT_PUBLIC_INFORMATION_OPCODE 0x8Bu +#define TAMPER_ATTEMPT_PUF_KEY_MANAGEMENT_OPCODE 0x8Cu +#define TAMPER_ATTEMPT_UNUSED_OPCODE 0x8Du +#define TAMPER_ATTEMPT_USER_JTAG_OPCODE 0x8Eu +#define TAMPER_ATTEMPT_ZEROIZATION_RECOVERY_OPCODE 0x8Fu +#define TAMPER_FAILURE_BOUNDARY_SCAN_OPCODE 0x90u +#define TAMPER_FAILURE_BUFFER_ACCESS_OPCODE 0x91u +#define TAMPER_FAILURE_DEBUG_OPCODE 0x92u +#define TAMPER_FAILURE_CHECK_DIGESTS_OPCODE 0x93u +#define TAMPER_FAILURE_ECC_SETUP_INSTRUCTION_OPCODE 0x94u +#define TAMPER_FAILURE_FACTORY_PRIVATE_OPCODE 0x95u +#define TAMPER_FAILURE_KEY_VALIDATION_OPCODE 0x96u +#define TAMPER_FAILURE_MISC_OPCODE 0x97u +#define TAMPER_FAILURE_PASSCODE_MATCH_OPCODE 0x98u +#define TAMPER_FAILURE_PASSCODE_SETUP_INSTRUCTION_OPCODE 0x99u +#define TAMPER_FAILURE_PROGRAMMING_OPCODE 0x9Au +#define TAMPER_FAILURE_PUBLIC_INFORMATION_OPCODE 0x9Bu +#define TAMPER_FAILURE_PUF_KEY_MANAGEMENT_OPCODE 0x9Cu +#define TAMPER_FAILURE_UNUSED_OPCODE 0x9Du +#define TAMPER_FAILURE_USER_JTAG_OPCODE 0x9Eu +#define TAMPER_FAILURE_ZEROIZATION_RECOVERY_OPCODE 0x9Fu +#define TAMPER_CLOCK_ERROR_DETECT_OPCODE 0xA0u +#define TAMPER_HARDWARE_MONITOR_JTAGACTIVE_ERROR_OPCODE 0xB1u +#define TAMPER_HARDWARE_MONITOR_LOCKPARITY_ERROR_OPCODE 0xB2u +#define TAMPER_HARDWARE_MONITOR_MESHSHORT_ERROR_OPCODE 0xB4u + +/*-------------------------------------------------------------------------*//** + These constants are used to specify the options parameter for the + MSS_SYS_flash_freeze() function. + + - MSS_SYS_FPGA_POWER_DOWN: + Indicates that the MSS_SYS_flash_freeze() function should request the FPGA + fabric to enter Flash*Freeze mode. + + - MSS_SYS_MPLL_POWER_DOWN: + Indicates that the MSS_SYS_flash_freeze() function should request the MSS + PLL to enter Flash*Freeze mode. + */ +#define MSS_SYS_FPGA_POWER_DOWN 0x00u +#define MSS_SYS_MPLL_POWER_DOWN 0x04u + +/*-------------------------------------------------------------------------*//** + These constants are used to specify the mode parameter for the + MSS_SYS_128aes() and MSS_SYS_256bit_aes() functions. + + - MSS_SYS_ECB_ENCRYPT: + Indicates that the cryptography function should perform encryption using + the Electronic Codebook (ECB) mode. + + - MSS_SYS_ECB_DECRYPT: + Indicates that the cryptography function should perform decryption using + the Electronic Codebook (ECB) mode. + + - MSS_SYS_CBC_ENCRYPT: + Indicates that the cryptography function should perform encryption using + the Cipher-Block Chaining (CBC) mode. + + - MSS_SYS_CBC_DECRYPT: + Indicates that the cryptography function should perform decryption using + the Cipher-Block Chaining (CBC) mode. + + - MSS_SYS_OFB_ENCRYPT: + Indicates that the cryptography function should perform encryption using + the Output Feedback (OFB) mode. + + - MSS_SYS_OFB_DECRYPT: + Indicates that the cryptography function should perform decryption using + the Output Feedback (OFB) mode. + + - MSS_SYS_CTR_ENCRYPT: + Indicates that the cryptography function should perform encryption using + the Counter (CTR) mode. + + - MSS_SYS_CTR_DECRYPT: + Indicates that the cryptography function should perform decryption using + the Counter (CTR) mode. + */ +#define MSS_SYS_ECB_ENCRYPT 0x00u +#define MSS_SYS_ECB_DECRYPT 0x80u +#define MSS_SYS_CBC_ENCRYPT 0x01u +#define MSS_SYS_CBC_DECRYPT 0x81u +#define MSS_SYS_OFB_ENCRYPT 0x02u +#define MSS_SYS_OFB_DECRYPT 0x82u +#define MSS_SYS_CTR_ENCRYPT 0x03u +#define MSS_SYS_CTR_DECRYPT 0x83u + +/*------------------------------------------------------------------------------ + These constants are used by non deterministic random bit generator (NDRBG) + services to communicate the outcome of a system services request. These status + codes are only used by NDRBG services. + + - MSS_SYS_NRBG_CATASTROPHIC_ERROR: + Indicates that a catastrophic error occurred. + + - MSS_SYS_NRBG_MAX_INST_EXCEEDED: + Indicates that the maximum number of NDRBG instances has been exceeded. + You need to release already instantiated NDRBG instances using the + MSS_SYS_ndrbg_uninstantiate() function. + + - MSS_SYS_NRBG_INVALID_HANDLE: + Indicates that the handle parameter has an invalid value. + + - MSS_SYS_NRBG_GEN_REQ_TOO_BIG: + Indicates that the requested random number is too long. The requested + length is larger than the maximum number of digits that can be generated. + + - MSS_SYS_NRBG_MAX_LENGTH_EXCEEDED: + Indicates that the supplied additional data length is exceeded. + */ +#define MSS_SYS_NRBG_CATASTROPHIC_ERROR 1u +#define MSS_SYS_NRBG_MAX_INST_EXCEEDED 2u +#define MSS_SYS_NRBG_INVALID_HANDLE 3u +#define MSS_SYS_NRBG_GEN_REQ_TOO_BIG 4u +#define MSS_SYS_NRBG_MAX_LENGTH_EXCEEDED 5u + +/*-------------------------------------------------------------------------*//** + The sys_serv_isp_complete_handler_t typedef specifies the function prototype + of the in-system programming (ISP) completion handler that is passed as a + parameter to the MSS_SYS_start_isp() function. The ISP completion handler + function must be implemented by the application program and it is called by + the System Services driver when an ISP operation initiated by a call to + MSS_SYS_start_isp() completes. The ISP completion handler function receives + a status parameter indicating the outcome of the ISP operation. Refer to the + description of the MSS_SYS_start_isp() function for more details. + */ +typedef void (*sys_serv_isp_complete_handler_t)(uint32_t status); + +/*-------------------------------------------------------------------------*//** + The sys_serv_async_event_handler_t type specifies the function prototype of + an asynchronous event handler that can be implemented by the application to + handle asynchronous messages from the System Controller. The System + Controller sends asynchronous messages to the MSS COMM_BLK when certain + events such as Flash*Freeze shutdown, Flash*Freeze exit and power-on-reset + (POR) digest check errors are detected during the execution of the following + system services: + - Flash*Freeze + - Power-on-reset (POR) digest check + The asynchronous event handler function is registered with the System + Services driver through the MSS_SYS_init() function. The driver calls the + asynchronous event handler when the MSS COMM_BLK receives an asynchronous message. + */ +typedef void (*sys_serv_async_event_handler_t)(uint8_t event_opcode, uint8_t response); + +/*-------------------------------------------------------------------------*//** + This constant is used as parameter to the MSS_SYS_init() function to indicate + that the application code does not supply an asynchronous event handler + function. + */ +#define MSS_SYS_NO_EVENT_HANDLER ((sys_serv_async_event_handler_t)0) + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_init function initializes the system services communication with + the System Controller. + + @param + The event_handler parameter specifies an optional asynchronous event + handler function. This event handler function is provided by the + application. It will be called by the System Services driver whenever an + asynchronous event is received from the SmartFusion2 System controller. + This event handler is typically used to handle entry and exit of + Flash*Freeze mode. + + @return + This function does not return a value. + */ +void MSS_SYS_init +( + sys_serv_async_event_handler_t event_handler +); + +/*============================================================================== + * Device and Design Information Services. + */ + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_get_serial_number function fetches the 128-bit Device Serial + Number (DSN). + + @param p_serial_number + The p_serial_number parameter is a pointer to the 16-bytes buffer where the + serial number will be written by this system service. + + @return + The MSS_SYS_get_serial_number function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_UNEXPECTED_ERROR + */ +uint8_t MSS_SYS_get_serial_number +( + uint8_t * p_serial_number +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_get_user_code functions fetches the 32-bit USERCODE. + + @param p_user_code + The p_user_code parameter is a pointer to the 4-bytes buffer where the + USERCODE will be written by this system service. + + @return + The MSS_SYS_get_user_code function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_UNEXPECTED_ERROR + */ +uint8_t MSS_SYS_get_user_code +( + uint8_t * p_user_code +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_get_design_version function fetches the design version. + + @param p_design_version + The p_design_version parameter is a pointer to the 2-bytes buffer where the + design version will be written by this system service. + + @return + The MSS_SYS_get_design_version function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_UNEXPECTED_ERROR + */ +uint8_t MSS_SYS_get_design_version +( + uint8_t * p_design_version +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_get_device_certificate function fetches the device certificate. + + @param p_device_certificate + The p_device_certificate parameter is a pointer to the 512-bytes buffer + where the device certificate will be written by this system service. + + @return + The MSS_SYS_get_device_certificate function returns one of following status + codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_UNEXPECTED_ERROR + */ +uint8_t MSS_SYS_get_device_certificate +( + uint8_t * p_device_certificate +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_get_secondary_device_certificate function fetches the secondary + device certificate. The secondary device certificate is second ECC Key + Certificate which is a 640-byte digitally-signed X-509 certificate programmed + during manufacturing. This certificate only contains the public key for the + ECC key and is otherwise unused by the device. + + @param p_secondary_device_certificate + The p_secondary_device_certificate parameter is a pointer to the 640-bytes + buffer where the secondary device certificate will be written by this system + service. + + @return + The MSS_SYS_get_secondary_device_certificate function returns one of + following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_UNEXPECTED_ERROR + */ +uint8_t MSS_SYS_get_secondary_device_certificate +( + uint8_t * p_secondary_device_certificate +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_flash_freeze function requests the FPGA to enter the Flash*Freeze + mode. + + @param options + The options parameter can be used to power down additional parts of + SmartFusion2 when the FPGA fabric enters Flash*Freeze mode. This parameter + is a bit mask of the following options: + - MSS_SYS_FPGA_POWER_DOWN + - MSS_SYS_MPLL_POWER_DOWN + MSS_SYS_FPGA_POWER_DOWN on its own will only power down the FPGA fabric. + MSS_SYS_MPLL_POWER_DOWN specifies that the MSS PLL is powered down during + the Flash*Freeze period. + + @return + The MSS_SYS_flash_freeze function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR + - MSS_SYS_CLK_DIVISOR_ERROR + + The following example demonstrates how to request the FPGA fabric to enter + the Flash*Freeze mode: + @code + MSS_SYS_flash_freeze(MSS_SYS_FPGA_POWER_DOWN | MSS_SYS_MPLL_POWER_DOWN); + @endcode + */ +uint8_t MSS_SYS_flash_freeze(uint8_t options); + +/*============================================================================== + * Cryptographic Services. + */ + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_128bit_aes function provides access to the SmartFusion2 AES-128 + cryptography service. + + @param key + The key parameter is a pointer to a 16-bytes array containing the key to use + for the requested encryption/decryption operation. + + @param iv + The iv parameter is a pointer to a 16-bytes array containing the + initialization vector that will be used as part of the requested + encryption/decryption operation. Its use is different depending on the mode. + ----------------------------------------- + | Mode | Usage | + ----------------------------------------- + | ECB | Ignored. | + ----------------------------------------- + | CBC | Randomization. | + ----------------------------------------- + | OFB | Randomization. | + ----------------------------------------- + | CTR | Used as initial counter value. | + ----------------------------------------- + + @param nb_blocks + The nb_blocks parameter specifies the number of 128-bit blocks of + plaintext/ciphertext to be processed by the AES-128 system service. + + @param mode + The mode parameter specifies the cipher mode of operation and whether the + source text must be encrypted or decrypted. The modes of operation are: + - Electronic Codebook (ECB) + - Cipher-Block Chaining (CBC) + - Output Feedback (OFB) + - Counter (CTR) + The CTR mode uses the content of the initialization vector as its initial + counter value. The counter increment is 2^64. + Allowed values for the mode parameter are: + - MSS_SYS_ECB_ENCRYPT + - MSS_SYS_ECB_DECRYPT + - MSS_SYS_CBC_ENCRYPT + - MSS_SYS_CBC_DECRYPT + - MSS_SYS_OFB_ENCRYPT + - MSS_SYS_OFB_DECRYPT + - MSS_SYS_CTR_ENCRYPT + - MSS_SYS_CTR_DECRYPT + + @param dest_addr + The dest_addr parameter is a pointer to the memory buffer where the result + of the encryption/decryption operation will be stored. + + @param src_addr + The src_addr parameter is a pointer to the memory buffer containing the source + plaintext/ciphertext to be encrypted/decrypted. + + @return + The MSS_SYS_128bit_aes function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + */ +uint8_t MSS_SYS_128bit_aes +( + const uint8_t * key, + const uint8_t * iv, + uint16_t nb_blocks, + uint8_t mode, + uint8_t * dest_addr, + const uint8_t * src_addr +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_256bit_aes function provides access to the SmartFusion2 AES-256 + cryptography service. + + @param key + The key parameter is a pointer to a 32-bytes array containing the key to use + for the requested encryption/decryption operation. + + @param iv + The iv parameter is a pointer to a 16-bytes array containing the + initialization vector that will be used as part of the requested + encryption/decryption operation. Its use is different depending on the mode. + ----------------------------------------- + | Mode | Usage | + ----------------------------------------- + | ECB | Ignored. | + ----------------------------------------- + | CBC | Randomization. | + ----------------------------------------- + | OFB | Randomization. | + ----------------------------------------- + | CTR | Used as initial counter value. | + ----------------------------------------- + + @param nb_blocks + The nb_blocks parameter specifies the number of 128-bit blocks of + plaintext/ciphertext requested to be processed by the AES-128 system service. + + @param mode + The mode parameter specifies the cipher mode of operation and whether the + source text must be encrypted or decrypted. The modes of operation are: + - Electronic Codebook (ECB) + - Cypher-Block Chaining (CBC) + - Output Feedback (OFB) + - Counter (CTR) + The CTR mode uses the content of the initialization vector as its initial + counter value. The counter increment is 2^64. + Allowed values for the mode parameter are: + - MSS_SYS_ECB_ENCRYPT + - MSS_SYS_ECB_DECRYPT + - MSS_SYS_CBC_ENCRYPT + - MSS_SYS_CBC_DECRYPT + - MSS_SYS_OFB_ENCRYPT + - MSS_SYS_OFB_DECRYPT + - MSS_SYS_CTR_ENCRYPT + - MSS_SYS_CTR_DECRYPT + + @param dest_addr + The dest_addr parameter is a pointer to the memory buffer where the result + of the encryption/decryption operation will be stored. + + @param src_addr + The src_addr parameter is a pointer to the memory buffer containing the source + plaintext/ciphertext to be encrypted/decrypted. + + @return + The MSS_SYS_256bit_aes function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + */ +uint8_t MSS_SYS_256bit_aes +( + const uint8_t * key, + const uint8_t * iv, + uint16_t nb_blocks, + uint8_t mode, + uint8_t * dest_addr, + const uint8_t * src_addr +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_sha256 function provides access to the SmartFusion2 SHA-256 + cryptography service. + + @param p_data_in + The p_data_in parameter is a pointer to the memory location containing the + data that will be hashed using the SHA-256 system service. + + @param length + The length parameter specifies the length in bits of the data to hash. + + @param result + The result parameter is a pointer to a 32 bytes buffer where the hash result + will be stored. + + @return + The MSS_SYS_sha256 function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + */ +uint8_t MSS_SYS_sha256 +( + const uint8_t * p_data_in, + uint32_t length, + uint8_t * result +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_hmac function provides access to the SmartFusion2 HMAC + cryptography service. The HMAC system service generates message authentication + codes using the SHA-256 hash function. + + @param key + The key parameter is a pointer to a 32 bytes array containing the key used + to generate the message authentication code. + + @param p_data_in + The p_data_in parameter is a pointer to the data to be authenticated. + + @param length + The length parameter specifies the number of data bytes for which to generate + the authentication code. It is the size of the data pointed to by the + p_data_in parameter. + + @param p_result + The p_result parameter is a pointer to a 32 bytes buffer where the + authentication code generated by the HMAC system service will be stored. + + @return + The MSS_SYS_hmac function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + */ +uint8_t MSS_SYS_hmac +( + const uint8_t * key, + const uint8_t * p_data_in, + uint32_t length, + uint8_t * p_result +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_key_tree() function provides access to a SHA-256 based key-tree + cryptography algorithm. The key-tree service begins with a user-supplied root + key and derives an output key based on a 7-bit parameter which can be used to + create uniqueness for different applications using the same root key, and a + 128-bit path variable. Both the 7-bit input parameter and the 128-bit path + variable are assumed to be publicly known. One common use for the output key + is as a keyed validator, similar to a message authentication code tag. + + @param p_key + The p_key parameter is a pointer to a 32 bytes array containing root key + used to generate derived key by Key Tree service and also used to store the + derived key. + + @param op_type + The op_type parameter specifies the operational parameter to be used to + generate the output key. + + @param path + The path parameter specifies the 128-bit path to be used to generate the + output key. + + @return + The MSS_SYS_key_tree function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_DISABLED_BY_USER + */ +uint8_t MSS_SYS_key_tree +( + uint8_t* p_key, + uint8_t op_type, + const uint8_t* path +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_challenge_response function... + + The MSS_SYS_challenge_response() function accept a challenge comprising a + 7-bit optype and 128-bit path and return a 256-bit response unique to the + given challenge and the device. + + @param p_key + The key parameter is a pointer to a 32 bytes array containing 256 bit + unique response to the given challenge. + + @param op_type + The op_type parameter specifies the operational parameter to be used to + generate the unique 256-bits unique response. + + @param path + The path parameter specifies the 128-bit path to be used to generate the + unique 256-bits unique response. + + @return + The MSS_SYS_challenge_response function returns one of following status + codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + */ +uint8_t MSS_SYS_challenge_response +( + uint8_t* p_key, + uint8_t op_type, + const uint8_t* path +); + +/*============================================================================== + * Non Deterministic Random Bit Generator Services. + */ + /*-------------------------------------------------------------------------*//** + The MSS_SYS_nrbg_reset() function is used to reset the + non-deterministic random bit generator (NRBG). + + @return + The MSS_SYS_nrbg_self_test function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_NRBG_CATASTROPHIC_ERROR + - MSS_SYS_NRBG_MAX_INST_EXCEEDED + - MSS_SYS_NRBG_INVALID_HANDLE + - MSS_SYS_NRBG_GEN_REQ_TOO_BIG + - MSS_SYS_NRBG_MAX_LENGTH_EXCEEDED + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_nrbg_reset(void); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_nrbg_self_test() function performs a self test of the + non-deterministic random bit generator (NRBG). + + @return + The MSS_SYS_nrbg_self_test function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_NRBG_CATASTROPHIC_ERROR + - MSS_SYS_NRBG_MAX_INST_EXCEEDED + - MSS_SYS_NRBG_INVALID_HANDLE + - MSS_SYS_NRBG_GEN_REQ_TOO_BIG + - MSS_SYS_NRBG_MAX_LENGTH_EXCEEDED + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR + */ +uint8_t MSS_SYS_nrbg_self_test(void); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_nrbg_instantiate() function instantiates a non-deterministic + random bit generator (NRBG) instance. A maximum of two concurrent instances + are available. + + @param personalization_str + The personalization_str parameter is a pointer to a buffer containing a + random bit generator personalization string. The personalization string + can be up to 128 bytes long. + + @param personalization_str_length + The personalization_str_length parameter specifies the byte length of the + personalization string pointed to by personalization_str. + + @param p_nrbg_handle + The p_nrbg_handle parameter is a pointer to a byte that will contain the + handle of the instantiated NRBG if this function call succeeds. + + @return + The MSS_SYS_nrbg_instantiate function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_NRBG_CATASTROPHIC_ERROR + - MSS_SYS_NRBG_MAX_INST_EXCEEDED + - MSS_SYS_NRBG_INVALID_HANDLE + - MSS_SYS_NRBG_GEN_REQ_TOO_BIG + - MSS_SYS_NRBG_MAX_LENGTH_EXCEEDED + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + */ +uint8_t MSS_SYS_nrbg_instantiate +( + const uint8_t * personalization_str, + uint16_t personalization_str_length, + uint8_t * p_nrbg_handle +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_nrbg_generate function generates a random bit sequence up to + 128 bytes long. + + @param p_requested_data + The p_requested_data parameter is a pointer to the buffer where the requested + random data will be stored on completion of this system service. + + @param p_additional_input + The p_additional_input parameter is a pointer to the buffer containing + additional input data for the random bit generation. + + @param requested_length + The requested_length parameter specifies the number of random data bytes + requested to be generated. The maximum generated data length is 128 bytes. + + @param additional_input_length + The additional_input_length parameter specifies the number of additional + input bytes to use in the random data generation. + + @param pr_req + The pr_req parameter specifies if prediction resistance is requested. + + @param nrbg_handle + The nrbg_handle parameter specifies which non-deterministic random bit + generator (NRBG) instance will be used to generate the random data. The + value of nrbg_handle is obtained as a result of a previous call to the + MSS_SYS_nrbg_instantiate() function. + + @return + The MSS_SYS_nrbg_generate function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_NRBG_CATASTROPHIC_ERROR + - MSS_SYS_NRBG_MAX_INST_EXCEEDED + - MSS_SYS_NRBG_INVALID_HANDLE + - MSS_SYS_NRBG_GEN_REQ_TOO_BIG + - MSS_SYS_NRBG_MAX_LENGTH_EXCEEDED + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + */ +uint8_t MSS_SYS_nrbg_generate +( + const uint8_t * p_requested_data, + const uint8_t * p_additional_input, + uint8_t requested_length, + uint8_t additional_input_length, + uint8_t pr_req, + uint8_t nrbg_handle +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_nrbg_reseed() function is used to reseed the non-deterministic + random bit generator (NRBG) identified by the nrbg_handle parameter. + + @param p_additional_input + The additional_input_length parameter specifies the number of additional + input bytes used to reseed the NRBG identified by the nrbg_handle parameter. + + @param additional_input_length + The additional_input_length parameter specifies the number of additional + input bytes used to reseed the NRBG. + + @param nrbg_handle + The nrbg_handle parameter specifies which NRBG instance to reseed. The value + of nrbg_handle is obtained as a result of a previous call to the + MSS_SYS_nrbg_instantiate() function. + + @return + The MSS_SYS_nrbg_reseed function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_NRBG_CATASTROPHIC_ERROR + - MSS_SYS_NRBG_MAX_INST_EXCEEDED + - MSS_SYS_NRBG_INVALID_HANDLE + - MSS_SYS_NRBG_GEN_REQ_TOO_BIG + - MSS_SYS_NRBG_MAX_LENGTH_EXCEEDED + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + + */ +uint8_t MSS_SYS_nrbg_reseed +( + const uint8_t * p_additional_input, + uint8_t additional_input_length, + uint8_t nrbg_handle +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_nrbg_uninstantiate() function releases the non-deterministic + random bit generator (NRBG) identified by the nrbg_handle parameter. + + @param nrbg_handle + The nrbg_handle parameter specifies which NRBG instance will be released. + The value of nrbg_handle is obtained as a result of a previous call to the + MSS_SYS_nrbg_instantiate() function. + + @return + The MSS_SYS_nrbg_uninstantiate function returns one of following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_NRBG_CATASTROPHIC_ERROR + - MSS_SYS_NRBG_MAX_INST_EXCEEDED + - MSS_SYS_NRBG_INVALID_HANDLE + - MSS_SYS_NRBG_GEN_REQ_TOO_BIG + - MSS_SYS_NRBG_MAX_LENGTH_EXCEEDED + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR + */ +uint8_t MSS_SYS_nrbg_uninstantiate +( + uint8_t nrbg_handle +); + +/*============================================================================== + * Zeroization Services. + */ +/*-------------------------------------------------------------------------*//** + The MSS_SYS_zeroize_device() function destroys sensitive information stored on + the device. Zeroization system services driver will destroy all user configuration + data, user keys, user security settings, NVM, SRAM, FPGA fabric, system + controller memory, and crypto-engine registers are erased. The level of + information destroyed by this function is configured as part of the hardware + flow of the design programmed into the device. + + @param + This function does not take any parameters + + @return + This function does not return any value. +*/ +void MSS_SYS_zeroize_device +( + void +); + +/*============================================================================== + * Programming Services. + */ + +#define MSS_SYS_PROG_AUTHENTICATE 0u +#define MSS_SYS_PROG_PROGRAM 1u +#define MSS_SYS_PROG_VERIFY 2u + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_start_isp() function starts the In-System Programming (ISP) + system service which allows the Cortex-M3 processor to directly provide a + bitstream for programming the SmartFusion2 device. + The ISP system service can perform these services: + � Authenticate a programming bitstream + � Program the device with a programming bitstream + � Verify that a programming bitstream has been correctly programmed + The mode parameter specifies the ISP system service to perform. The + application must also provide two functions as parameters to the + MSS_SYS_start_isp() function. The first function is used by the ISP system + service to read the programming bitstream. The second function is used by + the ISP system service to notify the application that the ISP system service + has completed. + + @param mode + The mode parameter specifies ISP service to perform. It can be one of: + - MSS_SYS_PROG_AUTHENTICATE + - MSS_SYS_PROG_PROGRAM + - MSS_SYS_PROG_VERIFY + + @param page_read_handler + The page_read_handler parameter is a pointer to a function with the + following prototype: + uint32_t page_read_handler(uint8 const ** pp_next_page); + The page_read_handler function must be implemented by the application + program to provide the System Services driver with the address of the + next page of programming data to be sent to the System Controller and + the number of bytes contained in the next page. Refer to the description + of the comblk_page_handler_t type for details of the page_read_handler + function�s parameters and return values. + + @param isp_completion_handler + The isp_completion_handler parameter is a pointer to a function with the + following prototype. + void (*sys_serv_isp_complete_handler_t)(uint32_t status); + The isp_completion_handler function must be implemented by the application + program and it is called by the System Services driver when an ISP + operation initiated by a call to MSS_SYS_start_isp() completes. + + The isp_completion_handler function receives one of the following status + codes through its status parameter indicating the outcome of the ISP + operation: + - MSS_SYS_SUCCESS + - MSS_SYS_CHAINING_MISMATCH + - MSS_SYS_UNEXPECTED_DATA_RECEIVED + - MSS_SYS_INVALID_ENCRYPTION_KEY + - MSS_SYS_INVALID_COMPONENT_HEADER + - MSS_SYS_BACK_LEVEL_NOT_SATISFIED + - MSS_SYS_DSN_BINDING_MISMATCH + - MSS_SYS_ILLEGAL_COMPONENT_SEQUENCE + - MSS_SYS_INSUFFICIENT_DEV_CAPABILITIES + - MSS_SYS_INCORRECT_DEVICE_ID + - MSS_SYS_UNSUPPORTED_BITSTREAM_PROT_VER + - MSS_SYS_VERIFY_NOT_PERMITTED_ON_BITSTR + - MSS_SYS_ABORT + - MSS_SYS_NVM_VERIFY_FAILED + - MSS_SYS_DEVICE_SECURITY_PROTECTED + - MSS_SYS_PROGRAMMING_MODE_NOT_ENABLED + - MSS_SYS_SERVICE_DISABLED_BY_USER + + @return + This function return status as MSS_SYS_CLK_DIVISOR_ERROR, if fclk, pclk0, + pclk1 and clk_fic64 divisor are not equal to each other or set to divide by + 32 on 060 device. + */ +uint8_t MSS_SYS_start_isp +( + uint8_t mode, + comblk_page_handler_t page_read_handler, + sys_serv_isp_complete_handler_t isp_completion_handler +); + + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_initiate_iap() function invokes the In application programming + system service by sending the request to System Controller to reprogram the + device using a bitstream present in SPI FLASH connected to MSS SPI-0. The + IAP Service is initiated by a call to MSS_SYS_initiate_iap(). The IAP + Service can perform these services: + - authenticate a programming bitstream + - program a bitstream + - verify that a programming bitstream has been correctly programmed + + @param mode + The mode parameter specifies IAP service to perform. It can be one of: + - MSS_SYS_PROG_AUTHENTICATE + - MSS_SYS_PROG_PROGRAM + - MSS_SYS_PROG_VERIFY + + @param bitstream_spi_addr + The bitstream_spi_addr parameter specifies the starting location address of + the programmed bitstream present in SPI flash connected to MSS SPI 0. + User should copy the programming bitstream into SPI Flash before calling + IAP system service. + + @return + The MSS_SYS_initiate_iap function will receive one of the following status + codes: + - MSS_SYS_SUCCESS + - MSS_SYS_CHAINING_MISMATCH + - MSS_SYS_UNEXPECTED_DATA_RECEIVED + - MSS_SYS_INVALID_ENCRYPTION_KEY + - MSS_SYS_INVALID_COMPONENT_HEADER + - MSS_SYS_BACK_LEVEL_NOT_SATISFIED + - MSS_SYS_DSN_BINDING_MISMATCH + - MSS_SYS_ILLEGAL_COMPONENT_SEQUENCE + - MSS_SYS_INSUFFICIENT_DEV_CAPABILITIES + - MSS_SYS_INCORRECT_DEVICE_ID + - MSS_SYS_UNSUPPORTED_BITSTREAM_PROT_VER + - MSS_SYS_VERIFY_NOT_PERMITTED_ON_BITSTR + - MSS_SYS_INVALID_DEVICE_CERTIFICATE + - MSS_SYS_ABORT + - MSS_SYS_NVM_VERIFY_FAILED + - MSS_SYS_DEVICE_SECURITY_PROTECTED + - MSS_SYS_PROGRAMMING_MODE_NOT_ENABLED + - MSS_SYS_ENVM_PROGRAMMING_OPERATION_FAIL + - MSS_SYS_ENVM_VERIFY_OPERATION_FAIL + - MSS_SYS_ACCESS_ERROR + - MSS_SYS_PUF_ACCESS_ERROR + - MSS_SYS_BAD_COMPONENT + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_CLK_DIVISOR_ERROR +*/ +uint8_t MSS_SYS_initiate_iap +( + uint8_t mode, + uint32_t bitstream_spi_addr +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_check_digest() function is used to recalculate and compare + cryptographic digests of selected NVM component(s) � FPGA fabric, eNVM0, and + eNVM1 � to those previously computed and saved in NVM. + Note: The FPGA fabric will enter the Flash*Freeze state if it is powered up + when its digest is checked. + + @param options + The options parameter specifies which components' digest will be recalculated + and checked. The allowed values for the options parameter are any one of the + following bitmask constants or a bitwise OR of more than one: + � MSS_SYS_DIGEST_CHECK_FABRIC (bit mask = 0x01) + � MSS_SYS_DIGEST_CHECK_ENVM0 (bit mask = 0x02) + � MSS_SYS_DIGEST_CHECK_ENVM1 (bit mask = 0x04) + � MSS_SYS_DIGEST_CHECK_SYS (bit mask = 0x08) + � MSS_SYS_DIGEST_CHECK_ENVMFP (bit mask = 0x10) + � MSS_SYS_DIGEST_CHECK_ENVMUP (bit mask = 0x20) + NOTE: Private factory eNVM and private user eNVM digest checks are only + available on the M2S060 and larger devices. + @return + The MSS_SYS_check_digest function returns the result of the digest check as + an 8-bit unsigned integer. The meaning of the digest check return value is + as follows: + bit 0: Fabric digest error + bit 1: ENVM0 digest error + bit 2: ENVM1 digest error + bit 3: System Controller ROM digest error + bit 4: Private eNVM factory digest error + bit 5: Private eNVM user digest error + bit 7: Service Disable by user lock. + A '1' in one of the above bits indicates a digest mismatch. The return + value can be compared to the bitmask constants specified as allowed values + for the options parameter to discover which of the NVM components produced + a digest check error. + On 060 device, the MSS_SYS_check_digest function returns + MSS_SYS_CLK_DIVISOR_ERROR, if the the divisor values of fclk, pclk0, pclk1 + and clk_fic64 divisor are not equal to each other or set to divide by 32. + */ +#define MSS_SYS_DIGEST_CHECK_FABRIC 0x01u +#define MSS_SYS_DIGEST_CHECK_ENVM0 0x02u +#define MSS_SYS_DIGEST_CHECK_ENVM1 0x04u +#define MSS_SYS_DIGEST_CHECK_SYS 0x08u +#define MSS_SYS_DIGEST_CHECK_ENVMFP 0x10u +#define MSS_SYS_DIGEST_CHECK_ENVMUP 0x20u + +#define MSS_SYS_DIGEST_CHECK_SVCDISABLED 0x80u + +uint8_t MSS_SYS_check_digest +( + uint8_t options +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_create_activation_code() function is used to create the + SRAM-PUF user activation code. This function is typically only used once when + enrolling the device into the overall system it operates in. It creates an + activation code which will be used to regenerate the SRAM-PUF secret key after + each power-up of the SRAM-PUF. The activation code is used to eliminate the + randomness of the SRAM-PUF power-up content in order to retrieve the device�s + unique PUF secret key. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param + This function does not take any parameters. + + @return + The MSS_SYS_puf_create_activation_code() function returns one of the + following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_ENVM_ERROR + - MSS_SYS_PUF_ERROR_WHEN_CREATING + - MSS_SYS_INVALID_SUBCMD + - MSS_SYS_ENVM_PROGRAM_ERROR + - MSS_SYS_ENVM_VERIFY_ERROR + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_puf_create_activation_code +( + void +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_delete_activation_code() function is used to delete the user + activation code. This function would typically be used only once when + decommissioning the device. + Note: This system services is only available on large SmartFusion2 devices + starting with the M2S060. + + @param + This function does not take any parameters. + + @return + The MSS_SYS_puf_delete_activation_code() function returns one of the + following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_ENVM_ERROR + - MSS_SYS_PUF_ERROR_WHEN_CREATING + - MSS_SYS_INVALID_SUBCMD + - MSS_SYS_ENVM_PROGRAM_ERROR + - MSS_SYS_ENVM_VERIFY_ERROR + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_puf_delete_activation_code +( + void +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_get_number_of_keys() function is used to retrieve the number + of user keys enrolled with the SRAM-PUF service. The number of enrolled keys + is also the key identification number to use for the next key to enroll since + keys must be enrolled sequentially and the key numbering starts at zero. Up + to 58 keys can be enrolled. Keys number 0 and 1 are used for design security + and are not available to the user. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param p_number_of_user_keys + The p_user_key parameter is a pointer to the byte in which the number of + keys will be written on successful completion of the system service. + + @return + The MSS_SYS_puf_get_number_of_user_keys() function returns one of the + following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_ENVM_ERROR + - MSS_SYS_PUF_ERROR_WHEN_CREATING + - MSS_SYS_ENVM_PROGRAM_ERROR + - MSS_SYS_INVALID_HASH + - MSS_SYS_INVALID_USER_AC1 + - MSS_SYS_ENVM_VERIFY_ERROR + - MSS_SYS_PRIVATE_ENVM_USER_DIGEST_MISMATCH + - MSS_SYS_DRBG_ERROR + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_puf_get_number_of_keys +( + uint8_t* p_number_of_keys +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_enroll_key() function is used to enroll keys into the + SRAM-PUF hardware block. Keys can be either intrinsic keys or extrinsic keys. + An intrinsic key�s value is randomly generated by the SRAM-PUF hardware block + during key enrollment. An extrinsic key�s value is supplied by the user. A key + code is created and stored in the System Controller�s private eNVM during key + enrollment. The key code along with the activation code created as part of the + call to MSS_SYS_puf_create_activation_code() and the SRAM-PUF start-up value + can then be used later to regenerate the enrolled key�s value. Enrolled keys + can be later reconstructed and retrieved using the MSS_SYS_puf_fetch_key() + function. The value of the key is protected until it is fetched since its + actual value is not stored anywhere in the system. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param key_number + The key_number parameter specifies the key number that will be used to + identify the key in later use after enrollment. The key number will be used + to identify which key to retrieve in subsequent calls to function + MSS_SYS_puf_fetch_key(). + Keys must be enrolled sequentially. Therefore, an arbitrary value cannot be + used for key_number when enrolling a new key. The value for key_number must + be derived from a call to MSS_SYS_puf_get_number_of_keys() to find the + number of keys currently enrolled and derive the next key number in the + sequence. + Note: Valid values for key identification numbers are 2 to 57. Keys number + 0 and 1 are used for design security and not available to the user. + + @param key_size + The key_size parameter specifies the size of the key to enroll. The key size + is a multiple of 64-bit up to 4096-bit. + + @param p_key_value + The p_key_value parameter is a pointer to the buffer containing the value of + the key to enroll. The buffer pointed to by p_key_value contains the value + of the extrinsic key specified by the user. + Setting this pointer�s value to zero specifies that an intrinsic key is to + be enrolled. In this case, a random value is generated using the SRAM-PUF as + the key value. + + @param p_key_location + The p_key_location parameter is a pointer to the buffer where the key will + be copied when it is fetched through a call to MSS_SYS_puf_fetch_key(). + + @return + The MSS_SYS_puf_enroll_key() function returns one of the following status + codes: + - MSS_SYS_SUCCESS + - MSS_SYS_ENVM_ERROR + - MSS_SYS_PUF_ERROR_WHEN_CREATING + - MSS_SYS_INVALID_REQUEST_OR_KC + - MSS_SYS_ENVM_PROGRAM_ERROR + - MSS_SYS_INVALID_HASH + - MSS_SYS_INVALID_USER_AC1 + - MSS_SYS_ENVM_VERIFY_ERROR + - MSS_SYS_INCORRECT_KEYSIZE_FOR_RENEWING_A_KC + - MSS_SYS_PRIVATE_ENVM_USER_DIGEST_MISMATCH + - MSS_SYS_USER_KEY_CODE_INVALID_SUBCMD + - MSS_SYS_DRBG_ERROR + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_puf_enroll_key +( + uint8_t key_number, + uint16_t key_size, + uint8_t* p_key_value, + uint8_t* p_key_location +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_delete_key() function is used to delete a previously enrolled + key from the SRAM-PUF. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param key_number + The key_number parameter specifies the key number of the key to delete. + + @return + The MSS_SYS_puf_delete_key() function returns one of the following status + codes: + - MSS_SYS_SUCCESS + - MSS_SYS_ENVM_ERROR + - MSS_SYS_PUF_ERROR_WHEN_CREATING + - MSS_SYS_INVALID_REQUEST_OR_KC + - MSS_SYS_ENVM_PROGRAM_ERROR + - MSS_SYS_INVALID_HASH + - MSS_SYS_INVALID_USER_AC1 + - MSS_SYS_ENVM_VERIFY_ERROR + - MSS_SYS_INCORRECT_KEYSIZE_FOR_RENEWING_A_KC + - MSS_SYS_PRIVATE_ENVM_USER_DIGEST_MISMATCH + - MSS_SYS_USER_KEY_CODE_INVALID_SUBCMD + - MSS_SYS_DRBG_ERROR + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_puf_delete_key +( + uint8_t key_number +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_fetch_key() function is used to retrieve a user PUF key from + the SRAM-PUF hardware block. The key must have been previously enrolled using + the MSS_SYS_puf_enroll_key() function. The key to retrieve is identified + through the key number used at key enrollment time. The key value is copied + into the buffer location specified at key enrollment time. The location of + this buffer is returned through function argument pp_key. + The key value is reconstructed based on the SRAM-PUF power-on value, the + activation code created when the device was commissioned using the + MSS_SYS_puf_create_activation_code() function and the key code stored in the + SRAM-PUF hardware block�s private eNVM at key enrollment time. The key value + does not exist anywhere in the system until it is retrieved by a call to + MSS_SYS_puf_fetch_key(). Care must be taken to destroy the key value returned + by MSS_SYS_puf_fetch_key() once it is not required anymore. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param key_number + The key_number parameter specifies the key number identifying the user key + to fetch. The valid range of key numbers is from 2 to 57. + + @param pp_key + The pp_key parameter is a pointer to a pointer to the buffer that will + contain the user key value on successful completion of the system service. + The pp_key parameter can be set to zero if your application keeps track of + the location of the key specified though the call to function + MSS_SYS_puf_enroll_key() at key enrollment time. + + @return + The MSS_SYS_puf_fetch_key() function returns one of the following status + codes: + - MSS_SYS_SUCCESS + - MSS_SYS_PUF_ERROR_WHEN_CREATING + - MSS_SYS_INVALID_KEYNUM_OR_ARGUMENT + - MSS_SYS_INVALID_HASH + - MSS_SYS_PRIVATE_ENVM_USER_DIGEST_MISMATCH + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_puf_fetch_key +( + uint8_t key_number, + uint8_t ** pp_key +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_export_keycodes() function is used to export an encrypted + copy of all the key codes used internally by the SRAM-PUF hardware block to + reconstruct the enrolled keys. Up to 3894 bytes of data can be exported + depending on the number and size of keys enrolled. + Keys cannot be fetched any more after calling MSS_SYS_puf_export_keycodes() + until a subsequent call to function MSS_SYS_puf_import_keycodes() is made + with the exported encrypted key codes. + Calling MSS_SYS_puf_export_keycodes() and moving the exported data off chip + is similar to removing the enrolled keys from the device. The enrolled keys + will only be available again if the exported key codes are imported back into + the device. + A SmartFusion2 device will only accept imported key codes generated from the + last set of enrolled keys on that specific device. This makes the exported + key codes data specific to one unique SmartFuson2 device. Key codes cannot + be exported from one SmartFusion2 device and imported into another + SmartFusion2 device. The exported key codes data is specific to the unique + SmartFusion2 device it was exported from. + Keys cannot be reconstructed from the exported key codes data since the + intrinsic secret of the SRAM-PUF is required to reconstruct the keys from + the key codes. Furthermore, the key codes data is also encrypted using a + random key generated from the SRAM-PUF thus preventing an attacker from + deriving useful information from the exported key codes data. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param p_keycodes + The p_keycodes parameter is a pointer to the buffer where the PUF key codes + will be exported. + + @return + The MSS_SYS_puf_export_keycodes() function returns one of the following + status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_ENVM_ERROR + - MSS_SYS_PUF_ERROR_WHEN_CREATING + - MSS_SYS_INVALID_REQUEST_OR_KC + - MSS_SYS_ENVM_PROGRAM_ERROR + - MSS_SYS_INVALID_HASH + - MSS_SYS_INVALID_USER_AC1 + - MSS_SYS_ENVM_VERIFY_ERROR + - MSS_SYS_INCORRECT_KEYSIZE_FOR_RENEWING_A_KC + - MSS_SYS_PRIVATE_ENVM_USER_DIGEST_MISMATCH + - MSS_SYS_USER_KEY_CODE_INVALID_SUBCMD + - MSS_SYS_DRBG_ERROR + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR + */ +uint8_t MSS_SYS_puf_export_keycodes +( + uint8_t * p_keycodes +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_import_keycodes() function is used to import a set of PUF + key codes that was previously exported using the MSS_SYS_puf_export_keycodes() + function. Importing the exported key codes allows the enrolled keys to be + regenerated. Enrolled keys cannot be regenerated while the key codes have + been exported and not imported back. + Importing back the key codes results in all keys being regenerated and copied + to the memory locations specified during key enrollment. The content of the + buffer holding the imported key codes is modified by function + MSS_SYS_puf_import_keycodes() to contain the list of pointers to the + locations where the keys have been regenerated. This list starts with the + address where key number 2 has been regenerated. The location for keys 0 and + 1 are not contained in that list because these keys are used for design + security and are not accessible to the user. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param p_keycodes + The p_keycodes parameter is a pointer to the buffer containing the PUF key + codes to import. + + @return + The MSS_SYS_puf_import_keycodes() function returns one of the following status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_ENVM_ERROR + - MSS_SYS_PUF_ERROR_WHEN_CREATING + - MSS_SYS_INVALID_REQUEST_OR_KC + - MSS_SYS_ENVM_PROGRAM_ERROR + - MSS_SYS_INVALID_HASH + - MSS_SYS_INVALID_USER_AC1 + - MSS_SYS_ENVM_VERIFY_ERROR + - MSS_SYS_INCORRECT_KEYSIZE_FOR_RENEWING_A_KC + - MSS_SYS_PRIVATE_ENVM_USER_DIGEST_MISMATCH + - MSS_SYS_USER_KEY_CODE_INVALID_SUBCMD + - MSS_SYS_DRBG_ERROR + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR + */ +uint8_t MSS_SYS_puf_import_keycodes +( + uint8_t * p_keycodes +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_fetch_ecc_public_key() function is used to fetch PUF ECC + public key from eNVM. + + @param p_puf_public_key + The p_puf_public_key parameter is a pointer to buffer where the PUF ECC + public key will be stored on successful completion of system service. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @return + The MSS_SYS_puf_fetch_ecc_public_key() function returns one of the following + status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_NO_VALID_PUBLIC_KEY + - MSS_SYS_PRIVATE_ENVM_USER_DIGEST_MISMATCH + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_puf_fetch_ecc_public_key +( + uint8_t* p_puf_public_key +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_puf_get_random_seed() function is used to generate a 256-bit true + random number seed using the SmartFusion2 SRAM-PUF. + + @param p_puf_seed + The p_puf_seed parameter is a pointer to the buffer where the PUF seed will + be stored on successful completion of the system service. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @return + The MSS_SYS_puf_get_random_seed() function returns one of the following + status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_PUF_ERROR_WHEN_CREATING + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_puf_get_random_seed +( + uint8_t* p_puf_seed +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_ecc_point_multiplication() function provides access to the + SmartFusion2 System Controller�s Elliptic Curve Cryptography (ECC) point + multiplication system service. The MSS_SYS_ecc_point_multiplication() function + computes the point multiplication of a point P on the NIST-384 curve by a + scalar value d. The point multiplication results in point Q as follows: + d * P = Q + The points are defined by their x and y coordinates as follows: + P = (x1, y1) + Q = (x2, y2) + Each x and y coordinate and the scalar d are 384-bit long big-endian numbers. + Note: The point at infinity is specified using point x =0, y = 0. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param p_scalar_d + The p_scalar_d parameter is a pointer to a buffer containing the 384-bit + scalar d. The scalar d is 384-bit long meaning that p_scalar_d should point + to a 96 bytes buffer. + + @param p_point_p + The p_point_p parameter is a pointer to a buffer containing the (x1, y1) + coordinates of input point P. Each x and y coordinate is 384-bit long + meaning that p_point_p should point to a 96 bytes buffer. + + @param p_point_q + The p_point_q parameter is a pointer to a buffer where the (x2, y2) + coordinates of result Q will be stored. Each x and y coordinate is 384-bit + long meaning that p_point_q should point to a 96 bytes buffer. + + @return + The MSS_SYS_ecc_point_multiplication function returns one of the following + status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_ecc_point_multiplication +( + uint8_t* p_scalar_d, + uint8_t* p_point_p, + uint8_t* p_point_q +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_ecc_point_addition() function provides access to the SmartFusion2 + System Controller�s Elliptic Curve Cryptography (ECC) point addition system + service. The MSS_SYS_ecc_point_addition() function computes the addition of + two points, P and Q, on the NIST P-384 curve. The point addition results in + point R as follows: + P + Q = R + The points are defined by their x and y coordinates as follows: + P = (x1, y1) + Q = (x2, y2) + R = (x3, y3) + Each x and y coordinate are 384-bit long big-endian numbers. + Note: The point at infinity is specified using point x =0, y = 0. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param p_point_p + The p_point_p parameter is a pointer to a buffer containing the (x1, y1) + coordinates of input point P. Each x and y coordinate is 384-bit long + meaning that p_point_p should point to a 96 bytes buffer. + + @param p_point_q + The p_point_q parameter is a pointer to a buffer containing the (x2, y2) + coordinates of input point Q. Each x and y coordinate is 384-bit long + meaning that p_point_q should point to a 96 bytes buffer. + + @param p_point_r + The p_point_r parameter is a pointer to a buffer where the (x3, y3) + coordinates of result R will be stored. Each x and y coordinate is 384-bit + long meaning that p_point_r should point to a 96 bytes buffer. + + @return + The MSS_SYS_ecc_point_addition() function returns one of the following + status codes: + - MSS_SYS_SUCCESS + - MSS_SYS_MEM_ACCESS_ERROR + - MSS_SYS_SERVICE_NOT_LICENSED + - MSS_SYS_SERVICE_DISABLED_BY_FACTORY + - MSS_SYS_SERVICE_DISABLED_BY_USER + - MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_ecc_point_addition +( + uint8_t* p_point_p, + uint8_t* p_point_q, + uint8_t* p_point_r +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_ecc_get_base_point() function provides the value of the base + point G for NIST elliptic curve P-384. The value of the base point can then + be used to generate a public key by multiplying the base point G with a + private key using function MSS_SYS_ecc_point_multiplication(). + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param p_point_p + The p_point_g parameter is a pointer to a buffer where the coordinate of + base point G (xG, yG) for curve P-384 will be stored. Each x and y + coordinate is 384-bit long meaning that p_point_g should point to a 96 + bytes buffer. + + @return + This function does not return a value. +*/ +void MSS_SYS_ecc_get_base_point +( + uint8_t* p_point_g +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_start_clock_monitor() function enables clock monitoring based on + user configuration. The system controller will start monitoring the 50MHz + clock timing reference for four 1MHz clock cycle. The expected count is 200 + +/- tolerance. If the clock fall outside the tolerance limits, interrupt will + be generated and system controller will send clock monitor tamper detect + event through COMBLK. MSS should inform to the application about clock + monitoring tamper detect event though call back function. + NOTE: Do not enable both start clock monitoring and stop clock monitoring at + the same time. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param + This function does not take any parameters + + @return + The MSS_SYS_start_clock_monitor() function returns one of the following + status codes: + � MSS_SYS_SUCCESS + � MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_start_clock_monitor +( + void +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_stop_clock_monitor() function is used to stop the clock monitoring. + System controller will disable 50 MHZ timing clock monitoring and clock + monitor tamper detect interrupt. + NOTE: Do not enable both start clock monitoring and stop clock monitoring at + the same time. + NOTE: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param + This function does not take any parameters + + @return + The MSS_SYS_stop_clock_monitor() function returns one of the following + status codes: + � MSS_SYS_SUCCESS + � MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_stop_clock_monitor +( + void +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_enable_puf_power_down() function is used to instruct the system + controller to power down the PUF after each of the following operations: + � key fetch + � key creation + � key import + � random seed generation + Powering down the PUF after these operations is the default PUF behaviour. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param + This function does not take any parameters. + + @return + The MSS_SYS_enable_puf_power_down() function returns one of the following + status codes: + � MSS_SYS_SUCCESS + � MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_enable_puf_power_down +( + void +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_disable_puf_power_down() function is used to retain PUF power + after the following operations: + � key fetch + � key creation + � key import + � random seed generation + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param + This function does not take any parameters + + @return + The MSS_SYS_disable_puf_power_down() function returns one of the following + status codes: + � MSS_SYS_SUCCESS + � MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_disable_puf_power_down +( + void +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_clear_lock_parity() function is used to clear the previously set + Lock Parity tamper flag. System controller will set this flag on detection of + parity error on internal lock data. To clear lock parity flag, use tamper + control service with bit 4 of Option set to 1, then the LOCKPARITY tamper flag + is cleared provided the hardware conditions are no longer present to raise + this flag. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param + This function does not take any parameters + + @return + The MSS_SYS_clear_lock_parity() function returns one of the following + status codes: + � MSS_SYS_SUCCESS + � MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_clear_lock_parity +( + void +); + +/*-------------------------------------------------------------------------*//** + The MSS_SYS_clear_mesh_short() function is used to clear the previously mesh + short tamper flag. System Controller monitors the security flash array for + invasive tampering using an active mesh. This mesh is driven by LFSR and the + return value is monitored for discrepancies against the expected value generated + by the LFSR. When a tamper event is detected the MESHSHORT tamper flag is set, + generating a tamper interrupt. To clear mesh short tamper flag, use tamper + control service with bit 5 of Options set to 1. The MESHSHORT tamper flag is + cleared provided the hardware conditions are no longer present to raise this + flag. + Note: This system service is only available on large SmartFusion2 devices + starting with the M2S060. + + @param + This function does not take any parameters + + @return + The MSS_SYS_clear_mesh_short() function returns one of the following + status codes: + � MSS_SYS_SUCCESS + � MSS_SYS_UNEXPECTED_ERROR +*/ +uint8_t MSS_SYS_clear_mesh_short +( + void +); + +/*-------------------------------------------------------------------------*//** + The IAP Service requests the System Controller to reprogram the device using + a bitstream already programmed into MSS SPI 0. The IAP Service is initiated by + a call to MSS_SYS_initiate_IAP(). The IAP Service can: + - authenticate a programming bitstream + - program a bitstream + - verify that a programming bitstream has been correctly programmed + + @param mode + The mode parameter specifies IAP service to perform. It can be one of: + - MSS_SYS_PROG_AUTHENTICATE + - MSS_SYS_PROG_PROGRAM + - MSS_SYS_PROG_VERIFY + + @param bitstream_spi_addr + The bitstream_spi_addr parameter specifies the address of the programming + bitstream within the SPI flash connected to MSS SPI 0. + + @return + The MSS_SYS_initiate_IAP function will receive one of the following status + codes: + - MSS_SYS_SUCCESS + - MSS_SYS_CHAINING_MISMATCH + - MSS_SYS_UNEXPECTED_DATA_RECEIVED + - MSS_SYS_INVALID_ENCRYPTION_KEY + - MSS_SYS_INVALID_COMPONENT_HEADER + - MSS_SYS_BACK_LEVEL_NOT_SATISFIED + - MSS_SYS_DSN_BINDING_MISMATCH + - MSS_SYS_ILLEGAL_COMPONENT_SEQUENCE + - MSS_SYS_INSUFFICIENT_DEV_CAPABILITIES + - MSS_SYS_INCORRECT_DEVICE_ID + - MSS_SYS_UNSUPPORTED_BITSTREAM_PROT_VER + - MSS_SYS_VERIFY_NOT_PERMITTED_ON_BITSTR + - MSS_SYS_INVALID_DEVICE_CERTIFICATE + - MSS_SYS_ABORT + - MSS_SYS_NVM_VERIFY_FAILED + - MSS_SYS_DEVICE_SECURITY_PROTECTED + - MSS_SYS_PROGRAMMING_MODE_NOT_ENABLED + - MSS_SYS_ENVM_PROGRAMMING_OPERATION_FAIL + - MSS_SYS_ENVM_VERIFY_OPERATION_FAIL + - MSS_SYS_ACCESS_ERROR + - MSS_SYS_PUF_ACCESS_ERROR + - MSS_SYS_BAD_COMPONENT + - MSS_SYS_SERVICE_DISABLED_BY_USER +*/ +uint8_t MSS_SYS_initiate_IAP +( + uint8_t mode, + uint32_t bitstream_spi_addr +); + +#ifdef __cplusplus +} +#endif + +#endif /* __MSS_SYS_SERVICES_H_ */ diff --git a/bsp/smartfusion2/libraries/mss_uart/mss_uart.c b/bsp/smartfusion2/libraries/mss_uart/mss_uart.c new file mode 100644 index 0000000000..2d04985fbc --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_uart/mss_uart.c @@ -0,0 +1,1762 @@ +/******************************************************************************* + * (c) Copyright 2011-2013 Microsemi SoC Products Group. All rights reserved. + * + * SmartFusion2 Microcontroller Subsystem MMUART bare metal software driver + * implementation. + * + * SVN $Revision: 5610 $ + * SVN $Date: 2013-04-05 18:49:30 +0530 (Fri, 05 Apr 2013) $ + */ +#include "mss_uart.h" +#include "mss_uart_regs.h" +#include "../../CMSIS/mss_assert.h" +#include "../../CMSIS/hw_reg_io.h" +#include "../../CMSIS/system_m2sxxx.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + * Defines + */ +#define TX_COMPLETE 0u +#define TX_FIFO_SIZE 16u + +#define FCR_TRIG_LEVEL_MASK 0xC0u + +#define IIRF_MASK 0x0Fu + +#define INVALID_INTERRUPT 0u +#define INVALID_IRQ_HANDLER ((mss_uart_irq_handler_t) 0) +#define NULL_HANDLER ((mss_uart_irq_handler_t) 0) + +#define MSS_UART_DATA_READY ((uint8_t) 0x01) + +#define SYNC_ASYNC_MODE_MASK (0x7u) + +/******************************************************************************* + * Possible values for Interrupt Identification Register Field. + */ +#define IIRF_MODEM_STATUS 0x00u +#define IIRF_THRE 0x02u +#define IIRF_MMI 0x03u +#define IIRF_RX_DATA 0x04u +#define IIRF_RX_LINE_STATUS 0x06u +#define IIRF_DATA_TIMEOUT 0x0Cu + +/******************************************************************************* + * Receiver error status mask. + */ +#define STATUS_ERROR_MASK ( MSS_UART_OVERUN_ERROR | MSS_UART_PARITY_ERROR | \ + MSS_UART_FRAMING_ERROR | MSS_UART_BREAK_ERROR | \ + MSS_UART_FIFO_ERROR) + +/******************************************************************************* + * Cortex-M3 interrupt handler functions implemented as part of the MSS UART + * driver. + */ +#if defined(__GNUC__) +__attribute__((__interrupt__)) void UART0_IRQHandler(void); +#else +void UART0_IRQHandler(void); +#endif + +#if defined(__GNUC__) +__attribute__((__interrupt__)) void UART1_IRQHandler(void); +#else +void UART1_IRQHandler(void); +#endif + +/******************************************************************************* + * Local functions. + */ +static void global_init(mss_uart_instance_t * this_uart, uint32_t baud_rate, + uint8_t line_config); +static void MSS_UART_isr(mss_uart_instance_t * this_uart); +static void default_tx_handler(mss_uart_instance_t * this_uart); + +static void config_baud_divisors +( + mss_uart_instance_t * this_uart, + uint32_t baudrate +); + +/******************************************************************************* + * Instance definitions + */ +mss_uart_instance_t g_mss_uart0; +mss_uart_instance_t g_mss_uart1; + + +/******************************************************************************* + * Public Functions + *******************************************************************************/ +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_init +( + mss_uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +) +{ + /* The driver expects g_mss_uart0 and g_mss_uart1 to be the only + * mss_uart_instance_t instances used to identify UART0 and UART1. */ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + /* Perform generic initialization */ + global_init(this_uart, baud_rate, line_config); + + /* Disable LIN mode */ + clear_bit_reg8(&this_uart->hw_reg->MM0, ELIN); + + /* Disable IrDA mode */ + clear_bit_reg8(&this_uart->hw_reg->MM1, EIRD); + + /* Disable SmartCard Mode */ + clear_bit_reg8(&this_uart->hw_reg->MM2, EERR); + + /* set default tx handler for automated TX using interrupt in USART mode */ + this_uart->tx_handler = default_tx_handler; +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void MSS_UART_lin_init +( + mss_uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +) +{ + /* The driver expects g_mss_uart0 and g_mss_uart1 to be the only + * mss_uart_instance_t instances used to identify UART0 and UART1. */ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + /* Perform generic initialization */ + global_init(this_uart, baud_rate, line_config); + + /* Enable LIN mode */ + set_bit_reg8(&this_uart->hw_reg->MM0, ELIN); + + /* Disable IrDA mode */ + clear_bit_reg8(&this_uart->hw_reg->MM1, EIRD); + + /* Disable SmartCard Mode */ + clear_bit_reg8(&this_uart->hw_reg->MM2, EERR); +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_irda_init +( + mss_uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config, + mss_uart_rzi_polarity_t rxpol, + mss_uart_rzi_polarity_t txpol, + mss_uart_rzi_pulsewidth_t pw +) +{ + /* The driver expects g_mss_uart0 and g_mss_uart1 to be the only + * mss_uart_instance_t instances used to identify UART0 and UART1. */ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + /* Perform generic initialization */ + global_init(this_uart, baud_rate, line_config); + + /* Enable LIN mode */ + clear_bit_reg8(&this_uart->hw_reg->MM0, ELIN); + + /* Disable IrDA mode */ + set_bit_reg8(&this_uart->hw_reg->MM1, EIRD); + ((rxpol == MSS_UART_ACTIVE_LOW) ? clear_bit_reg8(&this_uart->hw_reg->MM1,EIRX) : + set_bit_reg8(&this_uart->hw_reg->MM1,EIRX)); + + ((txpol == MSS_UART_ACTIVE_LOW) ? clear_bit_reg8(&this_uart->hw_reg->MM1,EITX) : + set_bit_reg8(&this_uart->hw_reg->MM1,EITX)); + + ((pw == MSS_UART_3_BY_16) ? clear_bit_reg8(&this_uart->hw_reg->MM1,EITP) : + set_bit_reg8(&this_uart->hw_reg->MM1,EITP)); + /* Disable SmartCard Mode */ + clear_bit_reg8(&this_uart->hw_reg->MM2, EERR); +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_smartcard_init +( + mss_uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +) +{ + /* The driver expects g_mss_uart0 and g_mss_uart1 to be the only + * mss_uart_instance_t instances used to identify UART0 and UART1. */ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + /* Perform generic initialization */ + global_init(this_uart, baud_rate, line_config); + + /* Disable LIN mode */ + clear_bit_reg8(&this_uart->hw_reg->MM0, ELIN); + + /* Disable IrDA mode */ + clear_bit_reg8(&this_uart->hw_reg->MM1, EIRD); + + /* Enable SmartCard Mode : Only when data is 8-bit and 2 stop bits*/ + if( ( MSS_UART_DATA_8_BITS | MSS_UART_TWO_STOP_BITS) == + (line_config & (MSS_UART_DATA_8_BITS | MSS_UART_TWO_STOP_BITS))) + { + set_bit_reg8(&this_uart->hw_reg->MM2, EERR); + /* Enable single wire half-duplex mode */ + set_bit_reg8(&this_uart->hw_reg->MM2,ESWM); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_polled_tx +( + mss_uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +) +{ + uint32_t char_idx = 0u; + uint32_t size_sent; + uint8_t status; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(pbuff != ( (uint8_t *)0)); + ASSERT(tx_size > 0u); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (pbuff != ((uint8_t *)0)) && (tx_size > 0u)) + { + /* Remain in this loop until the entire input buffer + * has been transferred to the UART. + */ + do { + /* Read the Line Status Register and update the sticky record */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + /* Check if TX FIFO is empty. */ + if(status & MSS_UART_THRE) + { + uint32_t fill_size = TX_FIFO_SIZE; + + /* Calculate the number of bytes to transmit. */ + if(tx_size < TX_FIFO_SIZE) + { + fill_size = tx_size; + } + + /* Fill the TX FIFO with the calculated the number of bytes. */ + for(size_sent = 0u; size_sent < fill_size; ++size_sent) + { + /* Send next character in the buffer. */ + this_uart->hw_reg->THR = pbuff[char_idx]; + char_idx++; + } + + /* Calculate the number of untransmitted bytes remaining. */ + tx_size -= size_sent; + } + } while(tx_size); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_polled_tx_string +( + mss_uart_instance_t * this_uart, + const uint8_t * p_sz_string +) +{ + uint32_t char_idx = 0u; + uint32_t fill_size; + uint8_t data_byte; + uint8_t status; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(p_sz_string != ((uint8_t *)0)); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (p_sz_string != ((uint8_t *)0))) + { + /* Get the first data byte from the input buffer */ + data_byte = p_sz_string[char_idx]; + + /* First check for the NULL terminator byte. + * Then remain in this loop until the entire string in the input buffer + * has been transferred to the UART. + */ + while(0u != data_byte) + { + /* Wait until TX FIFO is empty. */ + do { + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + } while (0u == (status & MSS_UART_THRE)); + + /* Send bytes from the input buffer until the TX FIFO is full + * or we reach the NULL terminator byte. + */ + fill_size = 0u; + while((0u != data_byte) && (fill_size < TX_FIFO_SIZE)) + { + /* Send the data byte */ + this_uart->hw_reg->THR = data_byte; + ++fill_size; + char_idx++; + /* Get the next data byte from the input buffer */ + data_byte = p_sz_string[char_idx]; + } + } + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_irq_tx +( + mss_uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(pbuff != ((uint8_t *)0)); + ASSERT(tx_size > 0u); + + if((tx_size > 0u) && ( pbuff != ((uint8_t *)0)) && + ((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1))) + { + /*Initialise the transmit info for the UART instance with the arguments.*/ + this_uart->tx_buffer = pbuff; + this_uart->tx_buff_size = tx_size; + this_uart->tx_idx = (uint16_t)0; + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ(this_uart->irqn); + + /* assign default handler for data transfer */ + this_uart->tx_handler = default_tx_handler; + + /* enables TX interrupt */ + set_bit_reg8(&this_uart->hw_reg->IER,ETBEI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +int8_t +MSS_UART_tx_complete +( + mss_uart_instance_t * this_uart +) +{ + int8_t ret_value = 0; + uint8_t status = 0u; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* Read the Line Status Register and update the sticky record. */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + if((TX_COMPLETE == this_uart->tx_buff_size) && + ((status & MSS_UART_TEMT) != 0u)) + { + ret_value = (int8_t)1; + } + } + return ret_value; +} + + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +size_t +MSS_UART_get_rx +( + mss_uart_instance_t * this_uart, + uint8_t * rx_buff, + size_t buff_size +) +{ + size_t rx_size = 0u; + uint8_t status = 0u; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(rx_buff != ((uint8_t *)0)); + ASSERT(buff_size > 0u); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (rx_buff != ((uint8_t *)0)) && (buff_size > 0u)) + { + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + while(((status & MSS_UART_DATA_READY) != 0u) && + (rx_size < buff_size)) + { + rx_buff[rx_size] = this_uart->hw_reg->RBR; + ++rx_size; + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + } + } + return rx_size; +} +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_enable_irq +( + mss_uart_instance_t * this_uart, + mss_uart_irq_t irq_mask +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(MSS_UART_INVALID_IRQ > irq_mask); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (MSS_UART_INVALID_IRQ > irq_mask)) + { + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ(this_uart->irqn); + + /* irq_mask encoding: 1- enable + * bit 0 - Receive Data Available Interrupt + * bit 1 - Transmitter Holding Register Empty Interrupt + * bit 2 - Receiver Line Status Interrupt + * bit 3 - Modem Status Interrupt + */ + this_uart->hw_reg->IER |= (uint8_t)irq_mask & IIRF_MASK; + + /* + * bit 4 - Receiver time-out interrupt + * bit 5 - NACK / ERR signal interrupt + * bit 6 - PID parity error interrupt + * bit 7 - LIN break detection interrupt + * bit 8 - LIN Sync detection interrupt + */ + this_uart->hw_reg->IEM |= (uint8_t)(((uint32_t)irq_mask & ~((uint32_t)IIRF_MASK)) >> 4u); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_disable_irq +( + mss_uart_instance_t * this_uart, + mss_uart_irq_t irq_mask +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* irq_mask encoding: 1 - disable + * bit 0 - Receive Data Available Interrupt + * bit 1 - Transmitter Holding Register Empty Interrupt + * bit 2 - Receiver Line Status Interrupt + * bit 3 - Modem Status Interrupt + */ + this_uart->hw_reg->IER &= ((uint8_t)(~((uint32_t)irq_mask & (uint32_t)IIRF_MASK))); + + /* + * bit 4 - Receiver time-out interrupt + * bit 5 - NACK / ERR signal interrupt + * bit 6 - PID parity error interrupt + * bit 7 - LIN break detection interrupt + * bit 8 - LIN Sync detection interrupt + */ + this_uart->hw_reg->IEM |= (uint8_t)(~(((uint32_t)irq_mask & ~((uint32_t)IIRF_MASK)) >> 8u)); + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ(this_uart->irqn); + + if(irq_mask == IIRF_MASK) + { + /* Disable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_DisableIRQ(this_uart->irqn); + + } + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_rx_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler, + mss_uart_rx_trig_level_t trigger_level +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(handler != INVALID_IRQ_HANDLER ); + ASSERT(trigger_level < MSS_UART_FIFO_INVALID_TRIG_LEVEL); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (handler != INVALID_IRQ_HANDLER) && + (trigger_level < MSS_UART_FIFO_INVALID_TRIG_LEVEL)) + { + this_uart->rx_handler = handler; + + /* Set the receive interrupt trigger level. */ + this_uart->hw_reg->FCR = (this_uart->hw_reg->FCR & + (uint8_t)(~((uint8_t)FCR_TRIG_LEVEL_MASK))) | + (uint8_t)trigger_level; + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ(this_uart->irqn); + + /* Enable receive interrupt. */ + set_bit_reg8(&this_uart->hw_reg->IER,ERBFI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_loopback +( + mss_uart_instance_t * this_uart, + mss_uart_loopback_t loopback +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(MSS_UART_INVALID_LOOPBACK > loopback); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) || + (MSS_UART_INVALID_LOOPBACK > loopback)) + { + switch(loopback) + { + case MSS_UART_LOCAL_LOOPBACK_OFF: + /* Disable local loopback */ + clear_bit_reg8(&this_uart->hw_reg->MCR,LOOP); + break; + + case MSS_UART_LOCAL_LOOPBACK_ON: + /* Enable local loopback */ + set_bit_reg8(&this_uart->hw_reg->MCR,LOOP); + break; + + case MSS_UART_REMOTE_LOOPBACK_OFF: + case MSS_UART_AUTO_ECHO_OFF: + /* Disable remote loopback & automatic echo*/ + this_uart->hw_reg->MCR &= ~RLOOP_MASK; + break; + + case MSS_UART_REMOTE_LOOPBACK_ON: + /* Enable remote loopback */ + this_uart->hw_reg->MCR |= (1u << RLOOP); + break; + + case MSS_UART_AUTO_ECHO_ON: + /* Enable automatic echo */ + this_uart->hw_reg->MCR |= (1u << ECHO); + break; + + case MSS_UART_INVALID_LOOPBACK: + /* Fall through to default. */ + default: + ASSERT(0); + break; + } + } +} + +/***************************************************************************//** + * UART0 interrupt service routine. + * UART0_IRQHandler is included within the Cortex-M3 vector table as part of the + * Fusion 2 CMSIS. + */ +#if defined(__GNUC__) +__attribute__((__interrupt__)) void UART0_IRQHandler(void) +#else +void UART0_IRQHandler(void) +#endif +{ + MSS_UART_isr(&g_mss_uart0); +} + +/***************************************************************************//** + * UART1 interrupt service routine. + * UART2_IRQHandler is included within the Cortex-M3 vector table as part of the + * Fusion 2 CMSIS. + */ +#if defined(__GNUC__) +__attribute__((__interrupt__)) void UART1_IRQHandler(void) +#else +void UART1_IRQHandler(void) +#endif +{ + MSS_UART_isr(&g_mss_uart1); +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_rxstatus_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(handler != INVALID_IRQ_HANDLER); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (handler != INVALID_IRQ_HANDLER)) + { + this_uart->linests_handler = handler; + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ(this_uart->irqn); + + /* Enable receiver line status interrupt. */ + set_bit_reg8(&this_uart->hw_reg->IER,ELSI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_tx_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(handler != INVALID_IRQ_HANDLER); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (handler != INVALID_IRQ_HANDLER)) + { + this_uart->tx_handler = handler; + + /* Make TX buffer info invalid */ + this_uart->tx_buffer = (const uint8_t *)0; + this_uart->tx_buff_size = 0u; + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ(this_uart->irqn); + + /* Enable transmitter holding register Empty interrupt. */ + set_bit_reg8(&this_uart->hw_reg->IER,ETBEI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_modemstatus_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(handler != INVALID_IRQ_HANDLER); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (handler != INVALID_IRQ_HANDLER)) + { + this_uart->modemsts_handler = handler; + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ(this_uart->irqn); + + /* Enable modem status interrupt. */ + set_bit_reg8(&this_uart->hw_reg->IER,EDSSI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +size_t +MSS_UART_fill_tx_fifo +( + mss_uart_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +) +{ + uint8_t status = 0u; + size_t size_sent = 0u; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(tx_buffer != ( (uint8_t *)0)); + ASSERT(tx_size > 0); + + /* Fill the UART's Tx FIFO until the FIFO is full or the complete input + * buffer has been written. */ + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (tx_buffer != ((uint8_t *)0)) && + (tx_size > 0u)) + { + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + if(status & MSS_UART_THRE) + { + uint32_t fill_size = TX_FIFO_SIZE; + + if(tx_size < TX_FIFO_SIZE) + { + fill_size = tx_size; + } + /* Fill up FIFO */ + for(size_sent = 0u; size_sent < fill_size; ++size_sent) + { + + /* Send next character in the buffer. */ + this_uart->hw_reg->THR = tx_buffer[size_sent]; + } + } + } + return size_sent; +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +uint8_t +MSS_UART_get_rx_status +( + mss_uart_instance_t * this_uart +) +{ + uint8_t status = MSS_UART_INVALID_PARAM; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* + * Extract UART receive error status. + * Bit 1 - Overflow error status + * Bit 2 - Parity error status + * Bit 3 - Frame error status + * Bit 4 - Break interrupt indicator + * Bit 7 - FIFO data error status + */ + this_uart->status |= (this_uart->hw_reg->LSR); + status = (this_uart->status & STATUS_ERROR_MASK); + /* Clear the sticky status after reading */ + this_uart->status = 0u; + } + return status; +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +uint8_t +MSS_UART_get_modem_status +( + mss_uart_instance_t * this_uart +) +{ + uint8_t status = MSS_UART_INVALID_PARAM; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* + * Extract UART modem status and place in lower bits of "status". + * Bit 0 - Delta Clear to Send Indicator + * Bit 1 - Delta Clear to Receive Indicator + * Bit 2 - Trailing edge of Ring Indicator detector + * Bit 3 - Delta Data Carrier Detect indicator + * Bit 4 - Clear To Send + * Bit 5 - Data Set Ready + * Bit 6 - Ring Indicator + * Bit 7 - Data Carrier Detect + */ + status = this_uart->hw_reg->MSR; + } + return status; +} + +/***************************************************************************//** + * MSS_UART_get_tx_status. + * See mss_uart.h for details of how to use this function. + */ +uint8_t +MSS_UART_get_tx_status +( + mss_uart_instance_t * this_uart +) +{ + uint8_t status = MSS_UART_TX_BUSY; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* Read the Line Status Register and update the sticky record. */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + /* + * Extract the transmit status bits from the UART's Line Status Register. + * Bit 5 - Transmitter Holding Register/FIFO Empty (THRE) status. (If = 1, TX FIFO is empty) + * Bit 6 - Transmitter Empty (TEMT) status. (If = 1, both TX FIFO and shift register are empty) + */ + status &= (MSS_UART_THRE | MSS_UART_TEMT); + } + return status; +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_break +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* set break charecter on Tx line */ + set_bit_reg8(&this_uart->hw_reg->LCR,SB); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_clear_break +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* remove break charecter from Tx line */ + clear_bit_reg8(&this_uart->hw_reg->LCR,SB); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_pidpei_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(handler != INVALID_IRQ_HANDLER); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (handler != INVALID_IRQ_HANDLER)) + { + this_uart->pid_pei_handler = handler; + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ( this_uart->irqn ); + + /* Enable PID parity error interrupt. */ + set_bit_reg8(&this_uart->hw_reg->IEM,EPID_PEI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_linbreak_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(handler != INVALID_IRQ_HANDLER); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (handler != INVALID_IRQ_HANDLER)) + { + this_uart->break_handler = handler; + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ( this_uart->irqn ); + + /* Enable LIN break detection interrupt. */ + set_bit_reg8(&this_uart->hw_reg->IEM,ELINBI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_linsync_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(handler != INVALID_IRQ_HANDLER); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (handler != INVALID_IRQ_HANDLER)) + { + this_uart->sync_handler = handler; + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ( this_uart->irqn ); + + /* Enable LIN sync detection interrupt. */ + set_bit_reg8(&this_uart->hw_reg->IEM,ELINSI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_nack_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(handler != INVALID_IRQ_HANDLER); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (handler != INVALID_IRQ_HANDLER)) + { + this_uart->nack_handler = handler; + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ( this_uart->irqn ); + + /* Enable LIN sync detection interrupt. */ + set_bit_reg8(&this_uart->hw_reg->IEM,ENACKI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_rx_timeout_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(handler != INVALID_IRQ_HANDLER); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (handler != INVALID_IRQ_HANDLER)) + { + this_uart->rto_handler = handler; + + /* Clear any previously pended interrupts */ + NVIC_ClearPendingIRQ( this_uart->irqn ); + + /* Enable receiver timeout interrupt. */ + set_bit_reg8(&this_uart->hw_reg->IEM,ERTOI); + + /* Enable UART instance interrupt in Cortex-M3 NVIC. */ + NVIC_EnableIRQ(this_uart->irqn); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_enable_half_duplex +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* enable single wire half-duplex mode */ + set_bit_reg8(&this_uart->hw_reg->MM2,ESWM); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_disable_half_duplex +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* enable single wire half-duplex mode */ + clear_bit_reg8(&this_uart->hw_reg->MM2,ESWM); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_rx_endian +( + mss_uart_instance_t * this_uart, + mss_uart_endian_t endian +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(MSS_UART_INVALID_ENDIAN > endian); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (MSS_UART_INVALID_ENDIAN > endian)) + { + /* Configure MSB first / LSB first for receiver */ + ((MSS_UART_LITTLEEND == endian) ? (clear_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_RX)) : + (set_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_RX))); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_tx_endian +( + mss_uart_instance_t * this_uart, + mss_uart_endian_t endian +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(MSS_UART_INVALID_ENDIAN > endian); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (MSS_UART_INVALID_ENDIAN > endian)) + { + /* Configure MSB first / LSB first for transmitter */ + ((MSS_UART_LITTLEEND == endian) ? (clear_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_TX)) : + (set_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_TX)) ) ; + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_filter_length +( + mss_uart_instance_t * this_uart, + mss_uart_filter_length_t length +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(MSS_UART_INVALID_FILTER_LENGTH > length); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (MSS_UART_INVALID_FILTER_LENGTH > length)) + { + /* Configure glitch filter length */ + this_uart->hw_reg->GFR = (uint8_t)length; + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_enable_afm +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* Disable RX FIFO till address flag with correct address is received */ + set_bit_reg8(&this_uart->hw_reg->MM2,EAFM); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_disable_afm +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* Enable RX FIFO irrespective of address flag and + correct address is received */ + clear_bit_reg8(&this_uart->hw_reg->MM2,EAFM); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_enable_afclear +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* Enable address flag clearing */ + /* Disable RX FIFO till another address flag with + correct address is received */ + set_bit_reg8(&this_uart->hw_reg->MM2,EAFC); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_disable_afclear +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* Disable address flag clearing */ + clear_bit_reg8(&this_uart->hw_reg->MM2,EAFC); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_enable_rx_timeout +( + mss_uart_instance_t * this_uart, + uint8_t timeout +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* Load the receive timeout value */ + this_uart->hw_reg->RTO = timeout; + /*Enable receiver time-out */ + set_bit_reg8(&this_uart->hw_reg->MM0,ERTO); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_disable_rx_timeout +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /*Disable receiver time-out */ + clear_bit_reg8(&this_uart->hw_reg->MM0,ERTO); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_enable_tx_time_guard +( + mss_uart_instance_t * this_uart, + uint8_t timeguard +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /* Load the transmitter time guard value */ + this_uart->hw_reg->TTG = timeguard; + /*Enable transmitter time guard */ + set_bit_reg8(&this_uart->hw_reg->MM0,ETTG); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_disable_tx_time_guard +( + mss_uart_instance_t * this_uart +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + /*Disable transmitter time guard */ + clear_bit_reg8(&this_uart->hw_reg->MM0,ETTG); + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_address +( + mss_uart_instance_t * this_uart, + uint8_t address +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + this_uart->hw_reg->ADR = address; + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_ready_mode +( + mss_uart_instance_t * this_uart, + mss_uart_ready_mode_t mode +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(MSS_UART_INVALID_READY_MODE > mode); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (MSS_UART_INVALID_READY_MODE > mode ) ) + { + /* Configure mode 0 or mode 1 for TXRDY and RXRDY */ + ((MSS_UART_READY_MODE0 == mode) ? clear_bit_reg8(&this_uart->hw_reg->FCR,RDYMODE) : + set_bit_reg8(&this_uart->hw_reg->FCR,RDYMODE) ); + } +} + +/***************************************************************************//** + * Configure baud divisors using fractional baud rate if possible. + */ +static void +config_baud_divisors +( + mss_uart_instance_t * this_uart, + uint32_t baudrate +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + uint32_t baud_value; + uint32_t baud_value_by_64; + uint32_t baud_value_by_128; + uint32_t fractional_baud_value; + uint32_t pclk_freq; + + this_uart->baudrate = baudrate; + + /* Force the value of the CMSIS global variables holding the various system + * clock frequencies to be updated. */ + SystemCoreClockUpdate(); + if(this_uart == &g_mss_uart0) + { + pclk_freq = g_FrequencyPCLK0; + } + else + { + pclk_freq = g_FrequencyPCLK1; + } + + /* + * Compute baud value based on requested baud rate and PCLK frequency. + * The baud value is computed using the following equation: + * baud_value = PCLK_Frequency / (baud_rate * 16) + */ + baud_value_by_128 = (8u * pclk_freq) / baudrate; + baud_value_by_64 = baud_value_by_128 / 2u; + baud_value = baud_value_by_64 / 64u; + fractional_baud_value = baud_value_by_64 - (baud_value * 64u); + fractional_baud_value += (baud_value_by_128 - (baud_value * 128u)) - (fractional_baud_value * 2u); + + /* Assert if integer baud value fits in 16-bit. */ + ASSERT(baud_value <= UINT16_MAX); + + if(baud_value <= (uint32_t)UINT16_MAX) + { + if(baud_value > 1u) + { + /* + * Use Frational baud rate divisors + */ + /* set divisor latch */ + set_bit_reg8(&this_uart->hw_reg->LCR,DLAB); + + /* msb of baud value */ + this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8); + /* lsb of baud value */ + this_uart->hw_reg->DLR = (uint8_t)baud_value; + + /* reset divisor latch */ + clear_bit_reg8(&this_uart->hw_reg->LCR,DLAB); + + /* Enable Fractional baud rate */ + set_bit_reg8(&this_uart->hw_reg->MM0,EFBR); + + /* Load the fractional baud rate register */ + ASSERT(fractional_baud_value <= (uint32_t)UINT8_MAX); + this_uart->hw_reg->DFR = (uint8_t)fractional_baud_value; + } + else + { + /* + * Do NOT use Frational baud rate divisors. + */ + /* set divisor latch */ + set_bit_reg8(&this_uart->hw_reg->LCR,DLAB); + + /* msb of baud value */ + this_uart->hw_reg->DMR = (uint8_t)(baud_value >> 8u); + /* lsb of baud value */ + this_uart->hw_reg->DLR = (uint8_t)baud_value; + + /* reset divisor latch */ + clear_bit_reg8(&this_uart->hw_reg->LCR,DLAB); + + /* Disable Fractional baud rate */ + clear_bit_reg8(&this_uart->hw_reg->MM0,EFBR); + } + } + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +void +MSS_UART_set_usart_mode +( + mss_uart_instance_t * this_uart, + mss_uart_usart_mode_t mode +) +{ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(MSS_UART_INVALID_SYNC_MODE > mode); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (MSS_UART_INVALID_SYNC_MODE > mode)) + { + /* Nothing to do for the baudrate: operates at PCLK / 2 + glitch filter length */ + /* Clear the ESYN bits 2:0 */ + this_uart->hw_reg->MM0 &= ~SYNC_ASYNC_MODE_MASK; + this_uart->hw_reg->MM0 |= (uint8_t)mode; + } +} + +/******************************************************************************* + * Local Functions + *******************************************************************************/ +/******************************************************************************* + * Global initialization for all modes + */ +static void global_init +( + mss_uart_instance_t * this_uart, + uint32_t baud_rate, + uint8_t line_config +) +{ + /* The driver expects g_mss_uart0 and g_mss_uart1 to be the only + * mss_uart_instance_t instances used to identify UART0 and UART1. */ + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if(this_uart == &g_mss_uart0) + { + this_uart->hw_reg = UART0; + this_uart->irqn = UART0_IRQn; + /* reset UART0 */ + SYSREG->SOFT_RST_CR |= SYSREG_MMUART0_SOFTRESET_MASK; + /* Clear any previously pended UART0 interrupt */ + NVIC_ClearPendingIRQ(UART0_IRQn); + /* Take UART0 out of reset. */ + SYSREG->SOFT_RST_CR &= ~SYSREG_MMUART0_SOFTRESET_MASK; + } + else + { + this_uart->hw_reg = UART1; + this_uart->irqn = UART1_IRQn; + /* Reset UART1 */ + SYSREG->SOFT_RST_CR |= SYSREG_MMUART1_SOFTRESET_MASK; + /* Clear any previously pended UART1 interrupt */ + NVIC_ClearPendingIRQ(UART1_IRQn); + /* Take UART1 out of reset. */ + SYSREG->SOFT_RST_CR &= ~SYSREG_MMUART1_SOFTRESET_MASK; + } + + /* disable interrupts */ + this_uart->hw_reg->IER = 0u; + + /* FIFO configuration */ + this_uart->hw_reg->FCR = (uint8_t)MSS_UART_FIFO_SINGLE_BYTE; + /* clear receiver FIFO */ + set_bit_reg8(&this_uart->hw_reg->FCR,CLEAR_RX_FIFO); + /* clear transmitter FIFO */ + set_bit_reg8(&this_uart->hw_reg->FCR,CLEAR_TX_FIFO); + + /* set default READY mode : Mode 0*/ + /* enable RXRDYN and TXRDYN pins. The earlier FCR write to set the TX FIFO + * trigger level inadvertently disabled the FCR_RXRDY_TXRDYN_EN bit. */ + set_bit_reg8(&this_uart->hw_reg->FCR,RXRDY_TXRDYN_EN); + + /* disable loopback : local * remote */ + clear_bit_reg8(&this_uart->hw_reg->MCR,LOOP); + clear_bit_reg8(&this_uart->hw_reg->MCR,RLOOP); + + /* set default TX endian */ + clear_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_TX); + /* set default RX endian */ + clear_bit_reg8(&this_uart->hw_reg->MM1,E_MSB_RX); + + /* default AFM : disabled */ + clear_bit_reg8(&this_uart->hw_reg->MM2,EAFM); + + /* disable TX time gaurd */ + clear_bit_reg8(&this_uart->hw_reg->MM0,ETTG); + + /* set default RX timeout */ + clear_bit_reg8(&this_uart->hw_reg->MM0,ERTO); + + /* disable fractional baud-rate */ + clear_bit_reg8(&this_uart->hw_reg->MM0,EFBR); + + /* disable single wire mode */ + clear_bit_reg8(&this_uart->hw_reg->MM2,ESWM); + + /* set filter to minimum value */ + this_uart->hw_reg->GFR = 0u; + /* set default TX time gaurd */ + this_uart->hw_reg->TTG = 0u; + /* set default RX timeout */ + this_uart->hw_reg->RTO = 0u; + + /* + * Configure baud rate divisors. This uses the frational baud rate divisor + * where possible to provide the most accurate baud rat possible. + */ + config_baud_divisors(this_uart, baud_rate); + + /* set the line control register (bit length, stop bits, parity) */ + this_uart->hw_reg->LCR = line_config; + + /* Instance setup */ + this_uart->baudrate = baud_rate; + this_uart->lineconfig = line_config; + this_uart->tx_buff_size = TX_COMPLETE; + this_uart->tx_buffer = (const uint8_t *)0; + this_uart->tx_idx = 0u; + + /* Default handlers for MSS UART interrupts */ + this_uart->rx_handler = NULL_HANDLER; + this_uart->tx_handler = NULL_HANDLER; + this_uart->linests_handler = NULL_HANDLER; + this_uart->modemsts_handler = NULL_HANDLER; + this_uart->rto_handler = NULL_HANDLER; + this_uart->nack_handler = NULL_HANDLER; + this_uart->pid_pei_handler = NULL_HANDLER; + this_uart->break_handler = NULL_HANDLER; + this_uart->sync_handler = NULL_HANDLER; + + /* Initialize the sticky status */ + this_uart->status = 0u; +} + +/***************************************************************************//** + * Interrupt service routine triggered by any MSS UART interrupt. This routine + * will call the handler function appropriate to the interrupt from the + * handlers previously registered with the driver through calls to the + * MSS_UART_set_*_handler() functions, or it will call the default_tx_handler() + * function in response to transmit interrupts if MSS_UART_irq_tx() is used to + * transmit data. + */ +static void +MSS_UART_isr +( + mss_uart_instance_t * this_uart +) +{ + uint8_t iirf; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + + if((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) + { + iirf = this_uart->hw_reg->IIR & IIRF_MASK; + + switch (iirf) + { + case IIRF_MODEM_STATUS: /* Modem status interrupt */ + { + ASSERT(NULL_HANDLER != this_uart->modemsts_handler); + if(NULL_HANDLER != this_uart->modemsts_handler) + { + (*(this_uart->modemsts_handler))(this_uart); + } + } + break; + + case IIRF_THRE: /* Transmitter Holding Register Empty */ + { + ASSERT(NULL_HANDLER != this_uart->tx_handler); + if(NULL_HANDLER != this_uart->tx_handler) + { + (*(this_uart->tx_handler))(this_uart); + } + } + break; + + case IIRF_RX_DATA: /* Received Data Available */ + case IIRF_DATA_TIMEOUT: /* Received Data Timed-out */ + { + ASSERT(NULL_HANDLER != this_uart->rx_handler); + if(NULL_HANDLER != this_uart->rx_handler) + { + (*(this_uart->rx_handler))(this_uart); + } + } + break; + + case IIRF_RX_LINE_STATUS: /* Line Status Interrupt */ + { + ASSERT(NULL_HANDLER != this_uart->linests_handler); + if(NULL_HANDLER != this_uart->linests_handler) + { + (*(this_uart->linests_handler))(this_uart); + } + } + break; + + case IIRF_MMI: + { + /* Identify multimode interrupts and handle */ + + /* Receiver time-out interrupt */ + if(read_bit_reg8(&this_uart->hw_reg->IIM,ERTOI)) + { + ASSERT(NULL_HANDLER != this_uart->rto_handler); + if(NULL_HANDLER != this_uart->rto_handler) + { + (*(this_uart->rto_handler))(this_uart); + } + } + /* NACK interrupt */ + if(read_bit_reg8(&this_uart->hw_reg->IIM,ENACKI)) + { + ASSERT(NULL_HANDLER != this_uart->nack_handler); + if(NULL_HANDLER != this_uart->nack_handler) + { + (*(this_uart->nack_handler))(this_uart); + } + } + + /* PID parity error interrupt */ + if(read_bit_reg8(&this_uart->hw_reg->IIM,EPID_PEI)) + { + ASSERT(NULL_HANDLER != this_uart->pid_pei_handler); + if(NULL_HANDLER != this_uart->pid_pei_handler) + { + (*(this_uart->pid_pei_handler))(this_uart); + } + } + + /* LIN break detection interrupt */ + if(read_bit_reg8(&this_uart->hw_reg->IIM,ELINBI)) + { + ASSERT(NULL_HANDLER != this_uart->break_handler); + if(NULL_HANDLER != this_uart->break_handler) + { + (*(this_uart->break_handler))(this_uart); + } + } + + /* LIN Sync detection interrupt */ + if(read_bit_reg8(&this_uart->hw_reg->IIM,ELINSI)) + { + ASSERT(NULL_HANDLER != this_uart->sync_handler); + if(NULL_HANDLER != this_uart->sync_handler) + { + (*(this_uart->sync_handler))(this_uart); + } + } + break; + } + + default: + { + ASSERT(INVALID_INTERRUPT); + } + break; + } + } +} + +/***************************************************************************//** + * See mss_uart.h for details of how to use this function. + */ +static void +default_tx_handler +( + mss_uart_instance_t * this_uart +) +{ + uint8_t status; + + ASSERT((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)); + ASSERT(( (uint8_t *)0 ) != this_uart->tx_buffer); + ASSERT(0u < this_uart->tx_buff_size); + + if(((this_uart == &g_mss_uart0) || (this_uart == &g_mss_uart1)) && + (((uint8_t *)0 ) != this_uart->tx_buffer) && + (0u < this_uart->tx_buff_size)) + { + /* Read the Line Status Register and update the sticky record. */ + status = this_uart->hw_reg->LSR; + this_uart->status |= status; + + /* + * This function should only be called as a result of a THRE interrupt. + * Verify that this is true before proceeding to transmit data. + */ + if(status & MSS_UART_THRE) + { + uint32_t i; + uint32_t fill_size = TX_FIFO_SIZE; + uint32_t tx_remain = this_uart->tx_buff_size - this_uart->tx_idx; + + /* Calculate the number of bytes to transmit. */ + if(tx_remain < TX_FIFO_SIZE) + { + fill_size = tx_remain; + } + + /* Fill the TX FIFO with the calculated the number of bytes. */ + for(i = 0u; i < fill_size; ++i) + { + /* Send next character in the buffer. */ + this_uart->hw_reg->THR = this_uart->tx_buffer[this_uart->tx_idx]; + ++this_uart->tx_idx; + } + } + + /* Flag Tx as complete if all data has been pushed into the Tx FIFO. */ + if(this_uart->tx_idx == this_uart->tx_buff_size) + { + this_uart->tx_buff_size = TX_COMPLETE; + /* disables TX interrupt */ + clear_bit_reg8(&this_uart->hw_reg->IER,ETBEI); + } + } +} + +#ifdef __cplusplus +} +#endif diff --git a/bsp/smartfusion2/libraries/mss_uart/mss_uart.h b/bsp/smartfusion2/libraries/mss_uart/mss_uart.h new file mode 100644 index 0000000000..9efa7ed234 --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_uart/mss_uart.h @@ -0,0 +1,2639 @@ +/******************************************************************************* + * (c) Copyright 2011-2013 Microsemi SoC Products Group. All rights reserved. + * + * SmartFusion2 Microcontroller Subsystem MMUART bare metal software driver + * public API. + * + * SVN $Revision: 5610 $ + * SVN $Date: 2013-04-05 18:49:30 +0530 (Fri, 05 Apr 2013) $ + */ +/*=========================================================================*//** + @mainpage SmartFusion2 MSS UART Bare Metal Driver. + ============================================================================== + @section intro_sec Introduction + ============================================================================== + The SmartFusion2 microcontroller subsystem (MSS) includes two multi-mode UART + (MMUART) peripherals for serial communication. This driver provides a set of + functions for controlling the MSS MMUARTs 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. + Note: MSS UART is synonymous with MSS MMUART in this document. + + ============================================================================== + @section hw_dependencies Hardware Flow Dependencies + ============================================================================== + The configuration of all features of the MSS MMUART peripherals is covered by + this driver with the exception of the SmartFusion2 IOMUX configuration. + SmartFusion2 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 MMUART serial signals are routed through IOMUXs to the + SmartFusion2 device external pins. The MSS MMUART serial signals may also be + routed through IOMUXs to the SmartFusion2 FPGA fabric. For more information on + IOMUX, refer to the IOMUX section of the SmartFusion2 Microcontroller + Subsystem (MSS) User�s Guide. + The IOMUXs are configured using the SmartFusion2 MSS configurator tool. You + must ensure that the MSS MMUART peripherals are enabled and configured in the + SmartFusion2 MSS configurator if you wish to use them. For more information on + IOMUXs, refer to the IOMUX section of the SmartFusion2 Microcontroller + Subsystem (MSS) User�s Guide. + The base address, register addresses and interrupt number assignment for the + MSS MMUART peripherals are defined as constants in the SmartFusion2 CMSIS HAL. + You must ensure that the latest SmartFusion2 CMSIS HAL is included in the + project settings of the software tool chain used to build your project and + that it is generated into your project. + + ============================================================================== + @section theory_op Theory of Operation + ============================================================================== + The MSS MMUART driver functions are grouped into the following categories: + - Initialization and configuration functions + - Polled transmit and receive functions + - Interrupt driven transmit and receive functions + + -------------------------------- + Initialization and Configuration + -------------------------------- + The MSS MMUART supports the following four broad modes of operation: + - UART or USART mode + - LIN mode + - IrDA mode + - Smartcard or ISO 7816 mode + The MSS MMUART driver provides the MSS_UART_init(), MSS_UART_lin_init(), + MSS_UART_irda_init() and MSS_UART_smartcard_init() functions to initialize the + MSS MMUARTs for operation in one of these modes. One of these initialization + functions must be called before any other MSS MMUART driver functions can be + called. The MSS MMUART operating modes are mutually exclusive; therefore only + one of the initialization functions must be called. The first parameter of the + initialization functions is a pointer to one of two global data structures + used to store state information for each MSS MMUART. A pointer to these data + structures is also used as the first parameter to many of the driver functions + to identify which MSS MMUART will be used by the called function. The names of + these two data structures are g_mss_uart0 and g_mss_uart1. Therefore, any call + to an MSS MMUART function should be of the form + MSS_UART_function_name( &g_mss_uart0, ... ) or + MSS_UART_function_name( &g_mss_uart1, ... ). + + UART or USART Mode + For the UART or USART modes of operation, the MSS MMUART driver is initialized + through a call to the MSS_UART_init() function. This function takes the UART�s + configuration as its parameters. The MSS_UART_init() function must be called + before any other MSS MMUART driver functions can be called. + The MSS_UART_init() function configures the baud rate based on the input baud + rate parameter and if possible uses a fractional baud rate for greater + precision. This function disables the LIN, IrDA and SmartCard modes. + + LIN mode + For the LIN mode of operation, the MSS MMUART driver is initialized through a + call to the MSS_UART_lin_init() function. This function takes the LIN node�s + configuration as its parameters. The MSS_UART_lin_init() function must be + called before any other MSS MMUART driver functions can be called. The + MSS_UART_lin_init() function configures the baud rate based on the input baud + rate parameter and if possible uses a fractional baud rate for greater + precision. This function disables the IrDA and SmartCard modes. + The driver also provides the following LIN mode configuration functions: + - MSS_UART_set_break() + - MSS_UART_clear_break() + - MSS_UART_set_pidpei_handler() + - MSS_UART_set_linbreak_handler() + - MSS_UART_set_linsync_handler() + Note: These LIN mode configuration functions can only be called after the + MSS_UART_lin_init() function is called. + + IrDA mode + For the IrDA mode of operation, the driver is initialized through a call to + the MSS_UART_irda_init() function. This function takes the IrDA node�s + configuration as its parameters. The MSS_UART_irda_init() function must be + called before any other MSS MMUART driver functions can be called. The + MSS_UART_irda_init() function configures the baud rate based on the input baud + rate parameter and if possible uses a fractional baud rate for greater + precision. This function disables the LIN and SmartCard modes. + + Smartcard or ISO 7816 mode + For the Smartcard or ISO 7816 mode of operation, the driver is initialized + through a call to the MSS_UART_smartcard_init() function. This function takes + the smartcard configuration as its parameters. The MSS_UART_smartcard_init() + function must be called before any other MSS MMUART driver functions can be + called. The MSS_UART_smartcard_init() function configures the baud rate based + on the input baud rate parameter and if possible uses a fractional baud rate + for greater precision. This function disables the LIN and IrDA modes. + The driver also provides the following Smartcard mode configuration functions: + - MSS_UART_enable_halfduplex() + - MSS_UART_disable_halfduplex() + - MSS_UART_set_nack_handler() + Note: These Smartcard mode configuration functions can only be called after + the MSS_UART_smartcard_init() function is called. + + Common Configuration Functions + The driver also provides the configuration functions that can be used with all + MSS MMUART operating modes. These common configuration functions are as + follows: + - MSS_UART_set_rx_endian() + - MSS_UART_set_tx_endian() + - MSS_UART_enable_afclear() + - MSS_UART_disable_afclear() + - MSS_UART_enable_rx_timeout() + - MSS_UART_disable_rx_timeout() + - MSS_UART_enable_tx_time_guard() + - MSS_UART_disable_tx_time_guard() + - MSS_UART_set_address() + - MSS_UART_set_ready_mode() + - MSS_UART_set_usart_mode() + - MSS_UART_set_filter_length() + - MSS_UART_enable_afm() + - MSS_UART_disable_afm() + Note: These configuration functions can only be called after one of the + MSS_UART_init(), MSS_UART_lin_init(), MSS_UART_irda_init() or + MSS_UART_smartcard_init() functions is called. + + -------------------------------------- + Polled Transmit and Receive Operations + -------------------------------------- + The driver can be used to transmit and receive data once initialized. + Data is transmitted using the MSS_UART_polled_tx() function. This function is + blocking, meaning that it will only return once the data passed to the + function has been sent to the MSS MMUART hardware transmitter. Data received + by the MSS MMUART hardware receiver can be read by the MSS_UART_get_rx() + function. + The MSS_UART_polled_tx_string() function is provided to transmit a NULL (�\0�) + terminated string in polled mode. This function is blocking, meaning that it + will only return once the data passed to the function has been sent to the MSS + MMUART hardware transmitter. + The MSS_UART_fill_tx_fifo() function fills the MSS MMUART hardware transmit + FIFO with data from a buffer passed as a parameter and returns the number of + bytes transferred to the FIFO. If the transmit FIFO is not empty when the + MSS_UART_fill_tx_fifo() function is called it returns immediately without + transferring any data to the FIFO. + + --------------------------- + Interrupt Driven Operations + --------------------------- + The driver can also transmit or receive data under interrupt control, freeing + your application to perform other tasks until an interrupt occurs indicating + that the driver�s attention is required. + + Interrupt Handlers + The MSS MMUART driver supports all types of interrupt triggered by the MSS + MMUART. The driver�s internal top level interrupt handler identifies the + source of the MSS MMUART interrupt and calls the corresponding lower level + handler function that you previously registered with the driver through calls + to the MSS_UART_set_rx_handler(), MSS_UART_set_tx_handler(), + MSS_UART_set_rxstatus_handler(), and MSS_UART_set_modemstatus_handler() + functions. You are responsible for creating these lower level interrupt + handlers as part of your application program and registering them with the + driver. + Note: The SmartFusion2 CMSIS-PAL defines the UART0_IRQHandler() and + UART1_IRQHandler() functions (with weak linkage) and assigns them as the + interrupt service routines (ISR) for the MSS MMUART interrupt inputs to + the Cortex-M3 NVIC. The MSS MMUART driver provides the implementation + functions for both of these ISRs from which it calls its own internal + top level, interrupt handler function. + The MSS_UART_enable_irq() and MSS_UART_disable_irq() functions are used to + enable or disable the received line status, received data available/character + timeout, transmit holding register empty and modem status interrupts at the + MSS MMUART level. The MSS_UART_enable_irq() function also enables the MSS + MMUART instance interrupt at the Cortex-M3 level. + + Transmitting Data + Interrupt-driven transmit is initiated by a call to MSS_UART_irq_tx(), + specifying the block of data to transmit. Your application is then free to + perform other tasks and inquire later whether transmit has completed by + calling the MSS_UART_tx_complete() function. The MSS_UART_irq_tx() function + enables the UART�s transmit holding register empty (THRE) interrupt and then, + when the interrupt goes active, the driver�s default THRE interrupt handler + transfers the data block to the UART until the entire block is transmitted. + Note: You can use the MSS_UART_set_tx_handler() function to assign an + alternative handler to the THRE interrupt. In this case, you must not + use the MSS_UART_irq_tx() function to initiate the transmit, as this + will re-assign the driver�s default THRE interrupt handler to the THRE + interrupt. Instead, your alternative THRE interrupt handler must include + a call to the MSS_UART_fill_tx_fifo() function to transfer the data to + the UART. + + Receiving Data + Interrupt-driven receive is performed by first calling + MSS_UART_set_rx_handler() to register a receive handler function that will be + called by the driver whenever receive data is available. You must provide this + receive handler function which must include a call to the MSS_UART_get_rx() + function to actually read the received data. + + ----------- + UART Status + ----------- + The function MSS_UART_get_rx_status() is used to read the receiver error + status. This function returns the overrun, parity, framing, break, and FIFO + error status of the receiver. + The function MSS_UART_get_tx_status() is used to read the transmitter status. + This function returns the transmit empty (TEMT) and transmit holding register + empty (THRE) status of the transmitter. + The function MSS_UART_get_modem_status() is used to read the modem status + flags. This function returns the current value of the modem status register. + + -------- + Loopback + -------- + The MSS_UART_set_loopback() function can be used to locally loopback the Tx + and Rx lines of a UART. This is not to be confused with the loopback of UART0 + to UART1, which can be achieved through the microcontroller subsystem�s system + registers. + + *//*=========================================================================*/ +#ifndef __MSS_UART_H_ +#define __MSS_UART_H_ 1 + +#include "../../CMSIS/m2sxxx.h" +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + Baud rates + The following definitions are used to specify standard baud rates as a + parameter to the MSS_UART_init() function. + */ +#define MSS_UART_110_BAUD 110 +#define MSS_UART_300_BAUD 300 +#define MSS_UART_1200_BAUD 1200 +#define MSS_UART_2400_BAUD 2400 +#define MSS_UART_4800_BAUD 4800 +#define MSS_UART_9600_BAUD 9600 +#define MSS_UART_19200_BAUD 19200 +#define MSS_UART_38400_BAUD 38400 +#define MSS_UART_57600_BAUD 57600 +#define MSS_UART_115200_BAUD 115200 +#define MSS_UART_230400_BAUD 230400 +#define MSS_UART_460800_BAUD 460800 +#define MSS_UART_921600_BAUD 921600 + +/***************************************************************************//** + Data Bits Length + The following defines are used to build the value of the MSS_UART_init() + function line_config parameter. + */ +#define MSS_UART_DATA_5_BITS ( (uint8_t) 0x00 ) +#define MSS_UART_DATA_6_BITS ( (uint8_t) 0x01 ) +#define MSS_UART_DATA_7_BITS ( (uint8_t) 0x02 ) +#define MSS_UART_DATA_8_BITS ( (uint8_t) 0x03 ) + +/***************************************************************************//** + Parity + The following defines are used to build the value of the MSS_UART_init() + function line_config parameter. + */ +#define MSS_UART_NO_PARITY ( (uint8_t) 0x00 ) +#define MSS_UART_ODD_PARITY ( (uint8_t) 0x08 ) +#define MSS_UART_EVEN_PARITY ( (uint8_t) 0x18 ) +#define MSS_UART_STICK_PARITY_0 ( (uint8_t) 0x38 ) +#define MSS_UART_STICK_PARITY_1 ( (uint8_t) 0x28 ) + +/***************************************************************************//** + Number of Stop Bits + The following defines are used to build the value of the MSS_UART_init() + function line_config parameter. + */ +#define MSS_UART_ONE_STOP_BIT ( (uint8_t) 0x00 ) +#define MSS_UART_ONEHALF_STOP_BIT ( (uint8_t) 0x04 ) +#define MSS_UART_TWO_STOP_BITS ( (uint8_t) 0x04 ) + +/***************************************************************************//** + Receiver Error Status + The following defines are used to determine the UART receiver error type. + These bit mask constants are used with the return value of the + MSS_UART_get_rx_status() function to find out if any errors occurred while + receiving data. + */ +#define MSS_UART_INVALID_PARAM ( (uint8_t)0xFF ) +#define MSS_UART_NO_ERROR ( (uint8_t)0x00 ) +#define MSS_UART_OVERUN_ERROR ( (uint8_t)0x02 ) +#define MSS_UART_PARITY_ERROR ( (uint8_t)0x04 ) +#define MSS_UART_FRAMING_ERROR ( (uint8_t)0x08 ) +#define MSS_UART_BREAK_ERROR ( (uint8_t)0x10 ) +#define MSS_UART_FIFO_ERROR ( (uint8_t)0x80 ) + +/***************************************************************************//** + Transmitter Status + The following definitions are used to determine the UART transmitter status. + These bit mask constants are used with the return value of the + MSS_UART_get_tx_status() function to find out the status of the transmitter. + */ +#define MSS_UART_TX_BUSY ( (uint8_t) 0x00 ) +#define MSS_UART_THRE ( (uint8_t) 0x20 ) +#define MSS_UART_TEMT ( (uint8_t) 0x40 ) + +/***************************************************************************//** + Modem Status + The following defines are used to determine the modem status. These bit + mask constants are used with the return value of the + MSS_UART_get_modem_status() function to find out the modem status of + the UART. + */ +#define MSS_UART_DCTS ( (uint8_t) 0x01 ) +#define MSS_UART_DDSR ( (uint8_t) 0x02 ) +#define MSS_UART_TERI ( (uint8_t) 0x04 ) +#define MSS_UART_DDCD ( (uint8_t) 0x08 ) +#define MSS_UART_CTS ( (uint8_t) 0x10 ) +#define MSS_UART_DSR ( (uint8_t) 0x20 ) +#define MSS_UART_RI ( (uint8_t) 0x40 ) +#define MSS_UART_DCD ( (uint8_t) 0x80 ) + +/***************************************************************************//** + This typedef specifies the irq_mask parameter for the MSS_UART_enable_irq() + and MSS_UART_disable_irq() functions. The driver defines a set of bit masks + that are used to build the value of the irq_mask parameter. A bitwise OR of + these bit masks is used to enable or disable multiple MSS MMUART interrupts. + */ +typedef uint16_t mss_uart_irq_t; + +/***************************************************************************//** + The following defines specify the interrupt masks to enable and disable MSS + MMUART interrupts. They are used to build the value of the irq_mask parameter + for the MSS_UART_enable_irq() and MSS_UART_disable_irq() functions. A bitwise + OR of these constants is used to enable or disable multiple interrupts. + */ +#define MSS_UART_RBF_IRQ 0x001 +#define MSS_UART_TBE_IRQ 0x002 +#define MSS_UART_LS_IRQ 0x004 +#define MSS_UART_MS_IRQ 0x008 +#define MSS_UART_RTO_IRQ 0x010 +#define MSS_UART_NACK_IRQ 0x020 +#define MSS_UART_PIDPE_IRQ 0x040 +#define MSS_UART_LINB_IRQ 0x080 +#define MSS_UART_LINS_IRQ 0x100 +#define MSS_UART_INVALID_IRQ UINT16_MAX + +/***************************************************************************//** + This enumeration specifies the receiver FIFO trigger level. This is the number + of bytes that must be received before the UART generates a receive data + available interrupt. It provides the allowed values for the + MSS_UART_set_rx_handler() function trigger_level parameter. + */ +typedef enum { + MSS_UART_FIFO_SINGLE_BYTE = 0x00, + MSS_UART_FIFO_FOUR_BYTES = 0x40, + MSS_UART_FIFO_EIGHT_BYTES = 0x80, + MSS_UART_FIFO_FOURTEEN_BYTES = 0xC0, + MSS_UART_FIFO_INVALID_TRIG_LEVEL +} mss_uart_rx_trig_level_t; + +/***************************************************************************//** + This enumeration specifies the loopback configuration of the UART. It provides + the allowed values for the MSS_UART_set_loopback() function�s loopback + parameter. Use MSS_UART_LOCAL_LOOPBACK_ON to set up the UART to locally + loopback its Tx and Rx lines. Use MSS_UART_REMOTE_LOOPBACK_ON to set up the + UART in remote loopback mode. + */ +typedef enum { + MSS_UART_LOCAL_LOOPBACK_OFF, + MSS_UART_LOCAL_LOOPBACK_ON, + MSS_UART_REMOTE_LOOPBACK_OFF, + MSS_UART_REMOTE_LOOPBACK_ON, + MSS_UART_AUTO_ECHO_OFF, + MSS_UART_AUTO_ECHO_ON, + MSS_UART_INVALID_LOOPBACK +} mss_uart_loopback_t; + +/***************************************************************************//** + IrDA input / output polarity. + This enumeration specifies the RZI modem polarity for input and output signals. + This is passed as parameters in MSS_UART_irda_init() function. + */ +typedef enum { + MSS_UART_ACTIVE_LOW = 0u, + MSS_UART_ACTIVE_HIGH = 1u, + MSS_UART_INVALID_POLARITY +} mss_uart_rzi_polarity_t; + +/***************************************************************************//** + IrDA input / output pulse width. + This enumeration specifies the RZI modem pulse width for input and output signals. + This is passed as parameters in MSS_UART_irda_init() function. + */ +typedef enum { + MSS_UART_3_BY_16 = 0u, + MSS_UART_1_BY_4 = 1u, + MSS_UART_INVALID_PW +} mss_uart_rzi_pulsewidth_t; + +/***************************************************************************//** + Tx / Rx endianess. + This enumeration specifies the MSB first or LSB first for MSS UART transmitter + and receiver. The parameter of this type shall be passed in + MSS_UART_set_rx_endian()and MSS_UART_set_tx_endian() functions. + */ +typedef enum { + MSS_UART_LITTLEEND, + MSS_UART_BIGEND, + MSS_UART_INVALID_ENDIAN +} mss_uart_endian_t; + +/***************************************************************************//** + Glitch filter length. + This enumeration specifies the glitch filter length. The function + MSS_UART_set_filter_length() accepts the parameter of this type. + */ +typedef enum { + MSS_UART_LEN0 = 0, + MSS_UART_LEN1 = 1, + MSS_UART_LEN2 = 2, + MSS_UART_LEN3 = 3, + MSS_UART_LEN4 = 4, + MSS_UART_LEN5 = 5, + MSS_UART_LEN6 = 6, + MSS_UART_LEN7 = 7, + MSS_UART_INVALID_FILTER_LENGTH = 8 +} mss_uart_filter_length_t; + +/***************************************************************************//** + TXRDY and RXRDY mode. + This enumeration specifies the TXRDY and RXRDY signal modes. The function + MSS_UART_set_ready_mode() accepts the parameter of this type. + */ +typedef enum { + MSS_UART_READY_MODE0, + MSS_UART_READY_MODE1, + MSS_UART_INVALID_READY_MODE +} mss_uart_ready_mode_t; + +/***************************************************************************//** + USART mode of operation. + This enumeration specifies the mode of operation of MSS UART when operating + as USART. The function MSS_UART_set_usart_mode() accepts the parameter of this type. + */ +typedef enum { + MSS_UART_ASYNC_MODE = 0, + MSS_UART_SYNC_SLAVE_POS_EDGE_CLK = 1, + MSS_UART_SYNC_SLAVE_NEG_EDGE_CLK = 2, + MSS_UART_SYNC_MASTER_POS_EDGE_CLK = 3, + MSS_UART_SYNC_MASTER_NEG_EDGE_CLK = 4, + MSS_UART_INVALID_SYNC_MODE = 5 +} mss_uart_usart_mode_t; + + +/***************************************************************************//** + MSS UART instance type. + This is type definition for MSS UART instance. You need to create and + maintain a record of this type. This holds all data regarding the MSS UART + instance + */ +typedef struct mss_uart_instance mss_uart_instance_t; + +/***************************************************************************//** + Interrupt handler prototype. + This typedef specifies the function prototype for MSS UART interrupt handlers. + All interrupt handlers registered with the MSS UART driver must be of this type. + The interrupt handlers are registered with the driver through the + MSS_UART_set_rx_handler(), MSS_UART_set_tx_handler(), + MSS_UART_set_rxstatus_handler(), and MSS_UART_set_modemstatus_handler() + functions. + The this_uart parameter is a pointer to either g_mss_uart0 or g_mss_uart1 to + identify the MSS UART to associate with the handler function. + */ +typedef void (*mss_uart_irq_handler_t)( mss_uart_instance_t * this_uart ); + +/***************************************************************************//** + mss_uart_instance. + There is one instance of this structure for each instance of the + microcontroller subsystem�s UARTs. Instances of this structure are used to + identify a specific UART. A pointer to an initialized instance of the + mss_uart_instance_t structure is passed as the first parameter to + MSS UART driver functions to identify which UART should perform the + requested operation. + */ +struct mss_uart_instance{ + /* CMSIS related defines identifying the UART hardware. */ + UART_TypeDef * hw_reg; /*!< Pointer to UART registers. */ + IRQn_Type irqn; /*!< UART's Cortex-M3 NVIC interrupt number. */ + uint32_t baudrate; /*!< Operating baud rate. */ + uint8_t lineconfig; /*!< Line configuration parameters. */ + uint8_t status; /*!< Sticky line status. */ + + /* transmit related info (used with interrupt driven transmit): */ + const uint8_t * tx_buffer; /*!< Pointer to transmit buffer. */ + uint32_t tx_buff_size; /*!< Transmit buffer size. */ + uint32_t tx_idx; /*!< Index within transmit buffer of next byte to transmit.*/ + + /* line status interrupt handler:*/ + mss_uart_irq_handler_t linests_handler; /*!< Pointer to user registered line status handler. */ + /* receive interrupt handler:*/ + mss_uart_irq_handler_t rx_handler; /*!< Pointer to user registered receiver handler. */ + /* transmit interrupt handler:*/ + mss_uart_irq_handler_t tx_handler; /*!< Pointer to user registered transmit handler. */ + /* modem status interrupt handler:*/ + mss_uart_irq_handler_t modemsts_handler; /*!< Pointer to user registered modem status handler. */ + /* receiver timeout interrupt handler */ + mss_uart_irq_handler_t rto_handler; /*!< Pointer to user registered receiver timeout handler. */ + /* NACK interrupt handler */ + mss_uart_irq_handler_t nack_handler; /*!< Pointer to user registered NACK handler. */ + /* PID parity prror interrup handler */ + mss_uart_irq_handler_t pid_pei_handler; /*!< Pointer to user registered PID parity error handler. */ + /* LIN break interrupt handler */ + mss_uart_irq_handler_t break_handler; /*!< Pointer to user registered LIN break handler. */ + /* LIN sync detection interrupt handler */ + mss_uart_irq_handler_t sync_handler; /*!< Pointer to user registered LIN sync dectection handler. */ +}; + +/***************************************************************************//** + This instance of mss_uart_instance_t holds all data related to the operations + performed by UART0. The function MSS_UART_init() initializes this structure. + A pointer to g_mss_uart0 is passed as the first parameter to MSS UART driver + functions to indicate that UART0 should perform the requested operation. + */ +extern mss_uart_instance_t g_mss_uart0; + +/***************************************************************************//** + This instance of mss_uart_instance_t holds all data related to the operations + performed by UART1. The function MSS_UART_init() initializes this structure. + A pointer to g_mss_uart1 is passed as the first parameter to MSS UART driver + functions to indicate that UART1 should perform the requested operation. + */ +extern mss_uart_instance_t g_mss_uart1; + +/***************************************************************************//** + The MSS_UART_init() function initializes and configures one of the SmartFusion2 + MSS UARTs with the configuration passed as a parameter. The configuration + parameters are the baud_rate which is used to generate the baud value and the + line_config which is used to specify the line configuration (bit length, + stop bits and parity). + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t structure + identifying the MSS UART hardware block to be initialized. There are two + such data structures, g_mss_uart0 and g_mss_uart1, associated with MSS + UART0 and MSS UART1 respectively. This parameter must point to either + the g_mss_uart0 or g_mss_uart1 global data structure defined within + the UART driver.. + + @param baud_rate + The baud_rate parameter specifies the baud rate. It can be specified for + common baud rates� using the following defines: + � MSS_UART_110_BAUD + � MSS_UART_300_BAUD + � MSS_UART_1200_BAUD + � MSS_UART_2400_BAUD + � MSS_UART_4800_BAUD + � MSS_UART_9600_BAUD + � MSS_UART_19200_BAUD + � MSS_UART_38400_BAUD + � MSS_UART_57600_BAUD + � MSS_UART_115200_BAUD + � MSS_UART_230400_BAUD + � MSS_UART_460800_BAUD + � MSS_UART_921600_BAUD + Alternatively, any nonstandard baud rate can be specified by simply passing + the actual required baud rate as the value for this parameter. + + @param line_config + The line_config parameter is the line configuration specifying the bit length, + number of stop bits and parity settings. This is a bitwise OR of one value + from each of the following groups of allowed values: + � One of the following to specify the transmit/receive data bit length: + MSS_UART_DATA_5_BITS + MSS_UART_DATA_6_BITS, + MSS_UART_DATA_7_BITS + MSS_UART_DATA_8_BITS + � One of the following to specify the parity setting: + MSS_UART_NO_PARITY + MSS_UART_EVEN_PARITY + MSS_UART_ODD_PARITY + MSS_UART_STICK_PARITY_0 + MSS_UART_STICK_PARITY_1 + � One of the following to specify the number of stop bits: + MSS_UART_ONE_STOP_BIT + MSS_UART_ONEHALF_STOP_BIT + MSS_UART_TWO_STOP_BITS + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + int main(void) + { + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + return(0); + } + @endcode + */ +void +MSS_UART_init +( + mss_uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +); + +/***************************************************************************//** + The MSS_UART_lin_init() function is used to initialize the MSS UART for + LIN mode of operation. The configuration parameters are the baud_rate which is + used to generate the baud value and the line_config which is used to specify + the line configuration (bit length, stop bits and parity). + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param baud_rate + The baud_rate parameter specifies the baud rate. It can be specified for + common baud rates� using the following defines: + � MSS_UART_110_BAUD + � MSS_UART_300_BAUD + � MSS_UART_1200_BAUD + � MSS_UART_2400_BAUD + � MSS_UART_4800_BAUD + � MSS_UART_9600_BAUD + � MSS_UART_19200_BAUD + � MSS_UART_38400_BAUD + � MSS_UART_57600_BAUD + � MSS_UART_115200_BAUD + � MSS_UART_230400_BAUD + � MSS_UART_460800_BAUD + � MSS_UART_921600_BAUD + Alternatively, any nonstandard baud rate can be specified by simply passing + the actual required baud rate as the value for this parameter. + + @param line_config + The line_config parameter is the line configuration specifying the bit length, + number of stop bits and parity settings. This is a bitwise OR of one value + from each of the following groups of allowed values: + � One of the following to specify the transmit/receive data bit length: + MSS_UART_DATA_5_BITS + MSS_UART_DATA_6_BITS, + MSS_UART_DATA_7_BITS + MSS_UART_DATA_8_BITS + � One of the following to specify the parity setting: + MSS_UART_NO_PARITY + MSS_UART_EVEN_PARITY + MSS_UART_ODD_PARITY + MSS_UART_STICK_PARITY_0 + MSS_UART_STICK_PARITY_1 + � One of the following to specify the number of stop bits: + MSS_UART_ONE_STOP_BIT + MSS_UART_ONEHALF_STOP_BIT + MSS_UART_TWO_STOP_BITS + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + int main(void) + { + MSS_UART_lin_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + return(0); + } + @endcode + */ +void +MSS_UART_lin_init +( + mss_uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +); + +/***************************************************************************//** + The MSS_UART_irda_init() function is used to initialize the MSS UART instance + referenced by the parameter this_uart for IrDA mode of operation. This + function must be called before calling any other IrDA functionality specific + functions. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param baud_rate + The baud_rate parameter specifies the baud rate. It can be specified for + common baud rates� using the following defines: + � MSS_UART_110_BAUD + � MSS_UART_300_BAUD + � MSS_UART_1200_BAUD + � MSS_UART_2400_BAUD + � MSS_UART_4800_BAUD + � MSS_UART_9600_BAUD + � MSS_UART_19200_BAUD + � MSS_UART_38400_BAUD + � MSS_UART_57600_BAUD + � MSS_UART_115200_BAUD + � MSS_UART_230400_BAUD + � MSS_UART_460800_BAUD + � MSS_UART_921600_BAUD + Alternatively, any nonstandard baud rate can be specified by simply passing + the actual required baud rate as the value for this parameter. + + @param line_config + The line_config parameter is the line configuration specifying the bit length, + number of stop bits and parity settings. This is a bitwise OR of one value + from each of the following groups of allowed values: + � One of the following to specify the transmit/receive data bit length: + MSS_UART_DATA_5_BITS + MSS_UART_DATA_6_BITS, + MSS_UART_DATA_7_BITS + MSS_UART_DATA_8_BITS + � One of the following to specify the parity setting: + MSS_UART_NO_PARITY + MSS_UART_EVEN_PARITY + MSS_UART_ODD_PARITY + MSS_UART_STICK_PARITY_0 + MSS_UART_STICK_PARITY_1 + � One of the following to specify the number of stop bits: + MSS_UART_ONE_STOP_BIT + MSS_UART_ONEHALF_STOP_BIT + MSS_UART_TWO_STOP_BITS + + @return + This function does not return a value. + + Example: + @code + MSS_UART_irda_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT, + MSS_UART_ACTIVE_LOW, + MSS_UART_ACTIVE_LOW, + MSS_UART_3_BY_16); + @endcode + */ +void +MSS_UART_irda_init +( + mss_uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config, + mss_uart_rzi_polarity_t rxpol, + mss_uart_rzi_polarity_t txpol, + mss_uart_rzi_pulsewidth_t pw +); + +/***************************************************************************//** + The MSS_UART_smartcard_init() function is used to initialize the MSS UART + for ISO 7816 (smartcard) mode of operation. The configuration parameters are + the baud_rate which is used to generate the baud value and the line_config + which is used to specify the line configuration (bit length, stop bits and parity). + This function disables all other modes of the MSS UART instance pointed by + the parameter this_uart. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param baud_rate + The baud_rate parameter specifies the baud rate. It can be specified for + common baud rates� using the following defines: + � MSS_UART_110_BAUD + � MSS_UART_300_BAUD + � MSS_UART_1200_BAUD + � MSS_UART_2400_BAUD + � MSS_UART_4800_BAUD + � MSS_UART_9600_BAUD + � MSS_UART_19200_BAUD + � MSS_UART_38400_BAUD + � MSS_UART_57600_BAUD + � MSS_UART_115200_BAUD + � MSS_UART_230400_BAUD + � MSS_UART_460800_BAUD + � MSS_UART_921600_BAUD + Alternatively, any nonstandard baud rate can be specified by simply passing + the actual required baud rate as the value for this parameter. + + @param line_config + The line_config parameter is the line configuration specifying the bit length, + number of stop bits and parity settings. This is a bitwise OR of one value + from each of the following groups of allowed values: + � One of the following to specify the transmit/receive data bit length: + MSS_UART_DATA_5_BITS + MSS_UART_DATA_6_BITS, + MSS_UART_DATA_7_BITS + MSS_UART_DATA_8_BITS + � One of the following to specify the parity setting: + MSS_UART_NO_PARITY + MSS_UART_EVEN_PARITY + MSS_UART_ODD_PARITY + MSS_UART_STICK_PARITY_0 + MSS_UART_STICK_PARITY_1 + � One of the following to specify the number of stop bits: + MSS_UART_ONE_STOP_BIT + MSS_UART_ONEHALF_STOP_BIT + MSS_UART_TWO_STOP_BITS + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + int main(void) + { + MSS_UART_smartcard_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + return(0); + } + @endcode + */ +void +MSS_UART_smartcard_init +( + mss_uart_instance_t* this_uart, + uint32_t baud_rate, + uint8_t line_config +); + +/***************************************************************************//** + The function MSS_UART_polled_tx() is used to transmit data. It transfers the + contents of the transmitter data buffer, passed as a function parameter, into + the UART�s hardware transmitter FIFO. It returns when the full content of the + transmit data buffer has been transferred to the UART�s transmit FIFO. It is + safe to release or reuse the memory used as the transmitter data buffer once + this function returns. + + Note: This function reads the UART�s line status register (LSR) to poll + for the active state of the transmitter holding register empty (THRE) bit + before transferring data from the data buffer to the transmitter FIFO. It + transfers data to the transmitter FIFO in blocks of 16 bytes or less and + allows the FIFO to empty before transferring the next block of data. + + Note: The actual transmission over the serial connection will still be + in progress when this function returns. Use the MSS_UART_get_tx_status() + function if you need to know when the transmitter is empty. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param pbuff + The pbuff parameter is a pointer to a buffer containing the data to + be transmitted. + + @param tx_size + The tx_size parameter specifies the size, in bytes, of the data to + be transmitted. + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + int main(void) + { + uint8_t message[12] = "Hello World"; + + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_polled_tx(&g_mss_uart0, message, sizeof(message)); + + return(0); + } + @endcode + */ +void +MSS_UART_polled_tx +( + mss_uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +); + +/***************************************************************************//** + The function MSS_UART_polled_tx_string() is used to transmit a NULL ('\0') + terminated string. It transfers the text string, from the buffer starting at + the address pointed to by p_sz_string into the UART�s hardware transmitter + FIFO. It returns when the complete string has been transferred to the UART's + transmit FIFO. It is safe to release or reuse the memory used as the string + buffer once this function returns. + + Note: This function reads the UART�s line status register (LSR) to poll + for the active state of the transmitter holding register empty (THRE) bit + before transferring data from the data buffer to the transmitter FIFO. It + transfers data to the transmitter FIFO in blocks of 16 bytes or less and + allows the FIFO to empty before transferring the next block of data. + + Note: The actual transmission over the serial connection will still be + in progress when this function returns. Use the MSS_UART_get_tx_status() + function if you need to know when the transmitter is empty. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param p_sz_string + The p_sz_string parameter is a pointer to a buffer containing the NULL + ('\0') terminated string to be transmitted. + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + int main(void) + { + uint8_t message[12] = "Hello World"; + + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_polled_tx_string(&g_mss_uart0, message); + + return(0); + } + @endcode + + */ +void +MSS_UART_polled_tx_string +( + mss_uart_instance_t * this_uart, + const uint8_t * p_sz_string +); + + +/***************************************************************************//** + The function MSS_UART_irq_tx() is used to initiate an interrupt-driven + transmit. It returns immediately after making a note of the transmit buffer + location and enabling transmit interrupts both at the UART and Cortex-M3 NVIC + level. This function takes a pointer via the pbuff parameter to a memory + buffer containing the data to transmit. The memory buffer specified through + this pointer must remain allocated and contain the data to transmit until + the transmit completion has been detected through calls to function + MSS_UART_tx_complete(). The actual transmission over the serial connection + is still in progress until calls to the MSS_UART_tx_complete() function + indicate transmit completion. + + Note: The MSS_UART_irq_tx() function enables both the transmit holding + register empty (THRE) interrupt in the UART and the MSS UART instance + interrupt in the Cortex-M3 NVIC as part of its implementation. + + Note: The MSS_UART_irq_tx() function assigns an internal default transmit + interrupt handler function to the UART�s THRE interrupt. This interrupt + handler overrides any custom interrupt handler that you may have previously + registered using the MSS_UART_set_tx_handler() function. + + Note: The MSS_UART_irq_tx() function�s default transmit interrupt + handler disables the UART�s THRE interrupt when all of the data has + been transferred to the UART's transmit FIFO. + + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param pbuff + The pbuff parameter is a pointer to a buffer containing the data + to be transmitted. + + @param tx_size + The tx_size parameter specifies the size, in bytes, of the data + to be transmitted. + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + int main(void) + { + uint8_t tx_buff[10] = "abcdefghi"; + + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_irq_tx(&g_mss_uart0, tx_buff, sizeof(tx_buff)); + + while(0 == MSS_UART_tx_complete(&g_mss_uart0)) + { + ; + } + return(0); + } + @endcode + */ +void +MSS_UART_irq_tx +( + mss_uart_instance_t * this_uart, + const uint8_t * pbuff, + uint32_t tx_size +); + +/***************************************************************************//** + The MSS_UART_tx_complete() function is used to find out if the interrupt-driven + transmit previously initiated through a call to MSS_UART_irq_tx() is complete. + This is typically used to find out when it is safe to reuse or release the + memory buffer holding transmit data. + + Note: The transfer of all of the data from the memory buffer to the UART�s + transmit FIFO and the actual transmission over the serial connection are both + complete when a call to the MSS_UART_tx_complete() function indicates transmit + completion. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function return a non-zero value if transmit has completed, otherwise + it returns zero. + + Example: + See the MSS_UART_irq_tx() function for an example that uses the + MSS_UART_tx_complete() function. + */ +int8_t +MSS_UART_tx_complete +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_get_rx() function reads the content of the UART receiver�s FIFO + and stores it in the receive buffer that is passed via the rx_buff function + parameter. It copies either the full contents of the FIFO into the receive + buffer, or just enough data from the FIFO to fill the receive buffer, + dependent upon the size of the receive buffer passed by the buff_size + parameter. The MSS_UART_get_rx() function returns the number of bytes copied + into the receive buffer .This function is non-blocking and will return 0 + immediately if no data has been received. + + Note: The MSS_UART_get_rx() function reads and accumulates the receiver + status of the MSS UART instance before reading each byte from the receiver's + data register/FIFO. This allows the driver to maintain a sticky record of any + receiver errors that occur as the UART receives each data byte; receiver + errors would otherwise be lost after each read from the receiver's data register. + A call to the MSS_UART_get_rx_status() function returns any receiver errors + accumulated during the execution of the MSS_UART_get_rx() function. + + Note: If you need to read the error status for each byte received, set + the buff_size to 1 and read the receive line error status for each byte + using the MSS_UART_get_rx_status() function. + The MSS_UART_get_rx() function can be used in polled mode, where it is called + at regular intervals to find out if any data has been received, or in interrupt + driven-mode, where it is called as part of a receive handler that is called + by the driver as a result of data being received. + + Note: In interrupt driven mode you should call the MSS_UART_get_rx() + function as part of the receive handler function that you register with + the MSS UART driver through a call to MSS_UART_set_rx_handler(). + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param rx_buff + The rx_buff parameter is a pointer to a buffer where the received + data is copied. + + @param buff_size + The buff_size parameter specifies the size of the receive buffer in bytes. + + @return + This function returns the number of bytes that were copied into the + rx_buff buffer. It returns 0 if no data has been received. + + Polled mode example: + @code + int main( void ) + { + uint8_t rx_buff[RX_BUFF_SIZE]; + uint32_t rx_idx = 0; + + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + while(1) + { + rx_size = MSS_UART_get_rx(&g_mss_uart0, rx_buff, sizeof(rx_buff)); + if(rx_size > 0) + { + process_rx_data(rx_buff, rx_size); + } + task_a(); + task_b(); + } + return 0; + } + @endcode + + Interrupt driven example: + @code + int main( void ) + { + MSS_UART_init(&g_mss_uart1, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_rx_handler(&g_mss_uart1, + uart1_rx_handler, + MSS_UART_FIFO_SINGLE_BYTE); + + while(1) + { + task_a(); + task_b(); + } + return 0; + } + + void uart1_rx_handler(mss_uart_instance_t * this_uart) + { + uint8_t rx_buff[RX_BUFF_SIZE]; + uint32_t rx_idx = 0; + rx_size = MSS_UART_get_rx(this_uart, rx_buff, sizeof(rx_buff)); + process_rx_data(rx_buff, rx_size); + } + @endcode + */ +size_t +MSS_UART_get_rx +( + mss_uart_instance_t * this_uart, + uint8_t * rx_buff, + size_t buff_size +); + +/***************************************************************************//** + The MSS_UART_set_rx_handler() function is used to register a receive handler + function that is called by the driver when a UART receive data available (RDA) + interrupt occurs. You must create and register the receive handler function + to suit your application and it must include a call to the MSS_UART_get_rx() + function to actually read the received data. + + Note: The MSS_UART_set_rx_handler() function enables both the RDA + interrupt in the UART and the MSS UART instance interrupt in the Cortex-M3 + NVIC as part + of its implementation. + + Note: You can disable the RDA interrupt once the data is received by + calling the MSS_UART_disable_irq() function. This is your choice and is + dependent upon your application. + + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param handler + The handler parameter is a pointer to a receive interrupt handler function + provided by your application that will be called as a result of a UART RDA + interrupt. This handler function must be of type mss_uart_irq_handler_t. + + @param trigger_level + The trigger_level parameter is the receive FIFO trigger level. This + specifies the number of bytes that must be received before the UART + triggers an RDA interrupt. + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + #define RX_BUFF_SIZE 64 + + uint8_t g_rx_buff[RX_BUFF_SIZE]; + + void uart0_rx_handler(mss_uart_instance_t * this_uart) + { + MSS_UART_get_rx(this_uart, &g_rx_buff[g_rx_idx], sizeof(g_rx_buff)); + } + + int main(void) + { + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_rx_handler(&g_mss_uart0, + uart0_rx_handler, + MSS_UART_FIFO_SINGLE_BYTE); + + while(1) + { + ; + } + return(0); + } + @endcode + */ +void +MSS_UART_set_rx_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler, + mss_uart_rx_trig_level_t trigger_level +); + +/***************************************************************************//** + The MSS_UART_set_loopback() function is used to locally loopback the Tx and + Rx lines of a UART. This is not to be confused with the loopback of UART0 + to UART1, which can be achieved through the microcontroller subsystem�s + system registers. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param loopback + The loopback parameter indicates whether or not the UART�s transmit + and receive lines should be looped back. Allowed values are as follows: + - MSS_UART_LOCAL_LOOPBACK_ON + - MSS_UART_LOCAL_LOOPBACK_OFF + - MSS_UART_REMOTE_LOOPBACK_ON + - MSS_UART_REMOTE_LOOPBACK_OFF + - MSS_UART_AUTO_ECHO_ON + - MSS_UART_AUTO_ECHO_OFF + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_loopback(&g_mss_uart0, MSS_UART_LOCAL_LOOPBACK_OFF); + @endcode + */ +void +MSS_UART_set_loopback +( + mss_uart_instance_t * this_uart, + mss_uart_loopback_t loopback +); + +/***************************************************************************//** + The MSS_UART_enable_irq() function enables the MSS UART interrupts specified + by the irq_mask parameter. The irq_mask parameter identifies the MSS UART + interrupts by bit position, as defined in the interrupt enable register (IER) + of MSS UART. The MSS UART interrupts and their identifying irq_mask bit + positions are as follows: + When an irq_mask bit position is set to 1, this function enables the + corresponding MSS UART interrupt in the IER register. When an irq_mask bit + position is set to 0, the corresponding interrupt�s state remains unchanged in + the IER register. + Note: The MSS_UART_enable_irq() function also enables the MSS UART instance + interrupt in the Cortex-M3 NVIC. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t structure + identifying the MSS UART hardware block that will perform the requested + function. There are two such data structures, g_mss_uart0 and g_mss_uart1, + associated with MSS UART0 and MSS UART1. This parameter must point to either + the g_mss_uart0 or g_mss_uart1 global data structure defined within the UART + driver. + + @param irq_mask + The irq_mask parameter is used to select which of the MSS UART�s interrupts + you want to enable. The allowed value for the irq_mask parameter is one of + the following constants or a bitwise OR of more than one: + - MSS_UART_RBF_IRQ (bit mask = 0x001) + - MSS_UART_TBE_IRQ (bit mask = 0x002) + - MSS_UART_LS_IRQ (bit mask = 0x004) + - MSS_UART_MS_IRQ (bit mask = 0x008) + - MSS_UART_RTO_IRQ (bit mask = 0x010) + - MSS_UART_NACK_IRQ (bit mask = 0x020) + - MSS_UART_PIDPE_IRQ (bit mask = 0x040) + - MSS_UART_LINB_IRQ (bit mask = 0x080) + - MSS_UART_LINS_IRQ (bit mask = 0x100) + + @return + This function does not return a value. + + Example: + @code + MSS_UART_enable_irq(&g_mss_uart0,(MSS_UART_RBF_IRQ | MSS_UART_TBE_IRQ)); + @endcode + */ +void +MSS_UART_enable_irq +( + mss_uart_instance_t * this_uart, + mss_uart_irq_t irq_mask +); + +/***************************************************************************//** + The MSS_UART_disable_irq() function disables the MSS UART interrupts specified + by the irq_mask parameter. The irq_mask parameter identifies the MSS UART + interrupts by bit position, as defined in the interrupt enable register (IER) + of MSS UART. The MSS UART interrupts and their identifying bit positions are + as follows: + When an irq_mask bit position is set to 1, this function disables the + corresponding MSS UART interrupt in the IER register. When an irq_mask bit + position is set to 0, the corresponding interrupt�s state remains unchanged in + the IER register. + Note: If you disable all four of the UART�s interrupts, the + MSS_UART_disable_irq() function also disables the MSS UART instance + interrupt in the Cortex-M3 NVIC. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param irq_mask + The irq_mask parameter is used to select which of the MSS UART�s interrupts + you want to disable. The allowed value for the irq_mask parameter is one of + the following constants or a bitwise OR of more than one: + - MSS_UART_RBF_IRQ (bit mask = 0x001) + - MSS_UART_TBE_IRQ (bit mask = 0x002) + - MSS_UART_LS_IRQ (bit mask = 0x004) + - MSS_UART_MS_IRQ (bit mask = 0x008) + - MSS_UART_RTO_IRQ (bit mask = 0x010) + - MSS_UART_NACK_IRQ (bit mask = 0x020) + - MSS_UART_PIDPE_IRQ (bit mask = 0x040) + - MSS_UART_LINB_IRQ (bit mask = 0x080) + - MSS_UART_LINS_IRQ (bit mask = 0x100) + + @return + This function does not return a value. + + Example: + @code + MSS_UART_disable_irq(&g_mss_uart0, (MSS_UART_RBF_IRQ | MSS_UART_TBE_IRQ)); + @endcode + */ +void +MSS_UART_disable_irq +( + mss_uart_instance_t * this_uart, + mss_uart_irq_t irq_mask +); + +/***************************************************************************//** + The MSS_UART_set_pidpei_handler() function is used assign a custom interrupt + handler for the PIDPEI (PID parity error interrupt) when the MSS UART is + operating in LIN mode. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param handler + The handler parameter is the pointer to the custom handler function. + This parameter is of type mss_uart_irq_handler_t. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_ set_pidpei_handler(&g_mss_uart0, my_pidpei_handler); + @endcode + */ +void +MSS_UART_set_pidpei_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +); + +/***************************************************************************//** + The MSS_UART_set_linbreak_handler () function is used assign a custom + interrupt handler for the LIN Break detection interrupt when the MSS UART + is operating in LIN mode. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param handler + The handler parameter is the pointer to the custom handler function. + This parameter is of type mss_uart_irq_handler_t. + + @return + This function does not return a value. + Example: + @code + MSS_UART_set_linbreak_handler(&g_mss_uart0, my_break_handler); + @endcode + */ +void +MSS_UART_set_linbreak_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +); + +/***************************************************************************//** + The MSS_UART_set_linsync_handler() function is used assign a custom interrupt + handler for the LIN Sync character detection interrupt when the MSS UART + is operating in LIN mode. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param handler + The handler parameter is the pointer to the custom handler function. + This parameter is of type mss_uart_irq_handler_t. + + @return + This function does not return a value. + Example: + @code + MSS_UART_set_linsync_handler(&g_mss_uart0, my_linsync_handler); + @endcode + */ +void +MSS_UART_set_linsync_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +); + +/***************************************************************************//** + The MSS_UART_set_nack_handler() function is used assign a custom interrupt + handler for the NACK character detection interrupt when the MSS UART + is operating in Smartcard mode. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param handler + The handler parameter is the pointer to the custom handler function. + This parameter is of type mss_uart_irq_handler_t. + + @return + This function does not return a value. + Example: + @code + MSS_UART_set_nack_handler(&g_mss_uart0, my_nack_handler); + @endcode + */ +void +MSS_UART_set_nack_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +); + +/***************************************************************************//** + The MSS_UART_set_rx_timeout_handler() function is used assign a custom + interrupt handler for the receiver timeout interrupt when the MSS UART is + operating in mode. It finds application in IrDA mode of operation. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param handler + The handler parameter is the pointer to the custom handler function. + This parameter is of type mss_uart_irq_handler_t. + + @return + This function does not return a value. + Example: + @code + MSS_UART_set_rx_timeout_handler(&g_mss_uart0, my_rxtimeout_handler); + @endcode + */ +void +MSS_UART_set_rx_timeout_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +); + +/***************************************************************************//** + The MSS_UART_set_rxstatus_handler() function is used to register a receiver + status handler function that is called by the driver when a UART receiver + line status (RLS) interrupt occurs. You must create and register the handler + function to suit your application. + + Note: The MSS_UART_set_rxstatus_handler() function enables both the RLS + interrupt in the UART and the MSS UART instance interrupt in the Cortex-M3 + NVIC as part of its implementation. + + Note: You can disable the RLS interrupt when required by calling the + MSS_UART_disable_irq() function. This is your choice and is dependent upon + your application. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param handler + The handler parameter is a pointer to a receiver line status interrupt + handler function provided by your application that will be called as a + result of a UART RLS interrupt. This handler function must be of type + mss_uart_irq_handler_t. + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + void uart_rxsts_handler(mss_uart_instance_t * this_uart) + { + uint8_t status; + status = MSS_UART_get_rx_status(this_uart); + if(status & MSS_UART_OVERUN_ERROR) + { + discard_rx_data(); + } + } + + int main(void) + { + MSS_UART_init( &g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | + MSS_UART_ONE_STOP_BIT ); + + MSS_UART_set_rxstatus_handler(&g_mss_uart0, uart_rxsts_handler); + + while(1) + { + ; + } + return(0); + } + @endcode + */ +void +MSS_UART_set_rxstatus_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +); + +/***************************************************************************//** + The MSS_UART_set_tx_handler() function is used to register a transmit handler + function that is called by the driver when a UART transmit holding register + empty (THRE) interrupt occurs. You must create and register the transmit + handler function to suit your application. You can use the + MSS_UART_fill_tx_fifo() function in your transmit handler function to + write data to the transmitter. + + Note: The MSS_UART_set_tx_handler() function enables both the THRE + interrupt in the UART and the MSS UART instance interrupt in the Cortex-M3 + NVIC as part of its implementation. + + Note: You can disable the THRE interrupt when required by calling the + MSS_UART_disable_irq() function. This is your choice and is dependent upon + your application. + + Note: The MSS_UART_irq_tx() function does not use the transmit handler + function that you register with the MSS_UART_set_tx_handler() function. + It uses its own internal THRE interrupt handler function that overrides + any custom interrupt handler that you register using the + MSS_UART_set_tx_handler() function. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param handler + The handler parameter is a pointer to a transmit interrupt handler + function provided by your application that will be called as a result + of a UART THRE interrupt. This handler function must be of type + mss_uart_irq_handler_t. + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + uint8_t * g_tx_buffer; + size_t g_tx_size = 0; + + void uart_tx_handler(mss_uart_instance_t * this_uart) + { + size_t size_in_fifo; + size_in_fifo = MSS_UART_fill_tx_fifo(this_uart, + (const uint8_t *)g_tx_buffer, + g_tx_size); + + if(size_in_fifo == g_tx_size) + { + g_tx_size = 0; + MSS_UART_disable_irq(this_uart, MSS_UART_TBE_IRQ); + } + else + { + g_tx_buffer = &g_tx_buffer[size_in_fifo]; + g_tx_size = g_tx_size - size_in_fifo; + } + } + + int main(void) + { + uint8_t message[12] = "Hello world"; + + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | + MSS_UART_ONE_STOP_BIT); + + g_tx_buffer = message; + g_tx_size = sizeof(message); + + MSS_UART_set_tx_handler(&g_mss_uart0, uart_tx_handler); + + while(1) + { + ; + } + return(0); + } + @endcode + */ +void +MSS_UART_set_tx_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +); + +/***************************************************************************//** + The MSS_UART_set_modemstatus_handler() function is used to register a modem + status handler function that is called by the driver when a UART modem status + (MS) interrupt occurs. You must create and register the handler function to + suit your application. + + Note: The MSS_UART_set_modemstatus_handler() function enables both the MS + interrupt in the UART and the MSS UART instance interrupt in the Cortex-M3 NVIC + as part of its implementation. + + Note: You can disable the MS interrupt when required by calling the + MSS_UART_disable_irq() function. This is your choice and is dependent + upon your application. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param handler + The handler parameter is a pointer to a modem status interrupt handler + function provided by your application that will be called as a result + of a UART MS interrupt. This handler function must be of type + mss_uart_irq_handler_t. + + @return + This function does not return a value. + + Example: + @code + #include "mss_uart.h" + + void uart_modem_handler(mss_uart_instance_t * this_uart) + { + uint8_t status; + status = MSS_UART_get_modem_status(this_uart); + if(status & MSS_UART_CTS) + { + uart_cts_handler(); + } + } + + int main(void) + { + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | + MSS_UART_ONE_STOP_BIT); + MSS_UART_set_modemstatus_handler(&g_mss_uart0, uart_modem_handler); + + while(1) + { + ; + } + return(0); + } + @endcode + */ + +void +MSS_UART_set_modemstatus_handler +( + mss_uart_instance_t * this_uart, + mss_uart_irq_handler_t handler +); + +/***************************************************************************//** + The MSS_UART_fill_tx_fifo() function fills the UART's hardware transmitter + FIFO with the data found in the transmitter buffer that is passed via the + tx_buffer function parameter. If the transmitter FIFO is not empty when + the function is called, the function returns immediately without transferring + any data to the FIFO; otherwise, the function transfers data from the + transmitter buffer to the FIFO until it is full or until the complete + contents of the transmitter buffer have been copied into the FIFO. The + function returns the number of bytes copied into the UART's transmitter FIFO. + + Note: This function reads the UART�s line status register (LSR) to check + for the active state of the transmitter holding register empty (THRE) bit + before transferring data from the data buffer to the transmitter FIFO. If + THRE is 0, the function returns immediately, without transferring any data + to the FIFO. If THRE is 1, the function transfers up to 16 bytes of data + to the FIFO and then returns. + + Note: The actual transmission over the serial connection will still be + in progress when this function returns. Use the MSS_UART_get_tx_status() + function if you need to know when the transmitter is empty. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param tx_buffer + The tx_buffer parameter is a pointer to a buffer containing the data + to be transmitted. + + @param tx_size + The tx_size parameter is the size in bytes, of the data to be transmitted. + + @return + This function returns the number of bytes copied into the UART's + transmitter FIFO. + + Example: + @code + void send_using_interrupt(uint8_t * pbuff, size_t tx_size) + { + size_t size_in_fifo; + size_in_fifo = MSS_UART_fill_tx_fifo(&g_mss_uart0, pbuff, tx_size); + } + @endcode + */ +size_t +MSS_UART_fill_tx_fifo +( + mss_uart_instance_t * this_uart, + const uint8_t * tx_buffer, + size_t tx_size +); + +/***************************************************************************//** + The MSS_UART_get_rx_status() function returns the receiver error status of the + MSS UART instance. It reads both the current error status of the receiver from + the UART�s line status register (LSR) and the accumulated error status from + preceding calls to the MSS_UART_get_rx() function, and it combines them using + a bitwise OR. It returns the cumulative overrun, parity, framing, break and + FIFO error status of the receiver, since the previous call to + MSS_UART_get_rx_status(), as an 8-bit encoded value. + + Note: The MSS_UART_get_rx() function reads and accumulates the receiver + status of the MSS UART instance before reading each byte from the receiver�s + data register/FIFO. The driver maintains a sticky record of the cumulative + receiver error status, which persists after the MSS_UART_get_rx() function + returns. The MSS_UART_get_rx_status() function clears the driver�s sticky + receiver error record before returning. + + Note: The driver�s transmit functions also read the line status + register (LSR) as part of their implementation. When the driver reads the + LSR, the UART clears any active receiver error bits in the LSR. This could + result in the driver losing receiver errors. To avoid any loss of receiver + errors, the transmit functions also update the driver�s sticky record of the + cumulative receiver error status whenever they read the LSR. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function returns the UART�s receiver error status as an 8-bit unsigned + integer. The returned value is 0 if no receiver errors occurred. The driver + provides a set of bit mask constants that should be compared with and/or + used to mask the returned value to determine the receiver error status. + When the return value is compared to the following bit masks, a non-zero + result indicates that the corresponding error occurred: + � MSS_UART_OVERRUN_ERROR (bit mask = 0x02) + � MSS_UART_PARITY_ERROR (bit mask = 0x04) + � MSS_UART_FRAMING_ERROR (bit mask = 0x08) + � MSS_UART_BREAK_ERROR (bit mask = 0x10) + � MSS_UART_FIFO_ERROR (bit mask = 0x80) + When the return value is compared to the following bit mask, a non-zero + result indicates that no error occurred: + � MSS_UART_NO_ERROR (bit mask = 0x00) + Upon unsuccessful execution, this function returns: + � MSS_UART_INVALID_PARAM (bit mask = 0xFF) + + Example: + @code + uint8_t rx_data[MAX_RX_DATA_SIZE]; + uint8_t err_status; + err_status = MSS_UART_get_rx_status(&g_mss_uart0); + + if(MSS_UART_NO_ERROR == err_status) + { + rx_size = MSS_UART_get_rx(&g_mss_uart0, rx_data, MAX_RX_DATA_SIZE); + } + @endcode + */ +uint8_t +MSS_UART_get_rx_status +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_get_modem_status() function returns the modem status of the + MSS UART instance. It reads the modem status register (MSR) and returns + the 8 bit value. The bit encoding of the returned value is exactly the + same as the definition of the bits in the MSR. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function returns current state of the UART's MSR as an 8 bit + unsigned integer. The driver provides the following set of bit mask + constants that should be compared with and/or used to mask the + returned value to determine the modem status: + � MSS_UART_DCTS (bit mask = 0x01) + � MSS_UART_DDSR (bit mask = 0x02) + � MSS_UART_TERI (bit mask = 0x04) + � MSS_UART_DDCD (bit mask = 0x08) + � MSS_UART_CTS (bit mask = 0x10) + � MSS_UART_DSR (bit mask = 0x20) + � MSS_UART_RI (bit mask = 0x40) + � MSS_UART_DCD (bit mask = 0x80) + + Example: + @code + void uart_modem_status_isr(mss_uart_instance_t * this_uart) + { + uint8_t status; + status = MSS_UART_get_modem_status(this_uart); + if( status & MSS_UART_DCTS ) + { + uart_dcts_handler(); + } + if( status & MSS_UART_CTS ) + { + uart_cts_handler(); + } + } + @endcode + */ +uint8_t +MSS_UART_get_modem_status +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_get_tx_status() function returns the transmitter status of the + MSS UART instance. It reads both the UART�s line status register (LSR) and + returns the status of the transmit holding register empty (THRE) and + transmitter empty (TEMT) bits.* + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function returns the UART�s transmitter status as an 8-bit unsigned + integer. The returned value is 0 if the transmitter status bits are not + set or the function execution failed. The driver provides a set of bit + mask constants that should be compared with and/or used to mask the + returned value to determine the transmitter status. + When the return value is compared to the following bit mask, a non-zero + result indicates that the corresponding transmitter status bit is set: + � MSS_UART_THRE (bit mask = 0x20) + � MSS_UART_TEMT (bit mask = 0x40) + When the return value is compared to the following bit mask, a non-zero + result indicates that the transmitter is busy or the function execution + failed. + � MSS_UART_TX_BUSY (bit mask = 0x00) + + Example: + @code + uint8_t tx_buff[10] = "abcdefghi"; + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_polled_tx(&g_mss_uart0, tx_buff, sizeof(tx_buff)); + + while(!(MSS_UART_TEMT & MSS_UART_get_tx_status(&g_mss_uart0))) + { + ; + } + @endcode + */ +uint8_t +MSS_UART_get_tx_status +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_set_break() function is used to send the break + (9 zeros after stop bit) signal on the TX line. This function can be used + only when the MSS UART is initialized in LIN mode by using MSS_UART_lin_init(). + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_break(&g_mss_uart0); + @endcode + */ +void +MSS_UART_set_break +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_clear_break() function is used to remove the break signal on the + TX line. This function can be used only when the MSS UART is initialized in + LIN mode by using MSS_UART_lin_init(). + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_clear_break(&g_mss_uart0); + @endcode + */ +void +MSS_UART_clear_break +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_enable_half_duplex() function is used to enable the half-duplex + (single wire) mode for the MSS UART. Though it finds application in Smartcard + mode, half-duplex mode can be used in other modes as well. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_enable_half_duplex(&g_mss_uart0); + @endcode + */ +void +MSS_UART_enable_half_duplex +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_disable_half_duplex() function is used to disable the half-duplex + (single wire) mode for the MSS UART. Though it finds application in Smartcard + mode, half-duplex mode can be used in other modes as well. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_disable_half_duplex(&g_mss_uart0); + @endcode + */ +void +MSS_UART_disable_half_duplex +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_set_rx_endian() function is used to configure the LSB first or + MSB first setting for MSS UART receiver + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param endian + The endian parameter tells the LSB first or MSB first configuration. + This parameter is of type mss_uart_endian_t. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_rx_endian(&g_mss_uart0, MSS_UART_LITTLEEND); + @endcode + */ +void +MSS_UART_set_rx_endian +( + mss_uart_instance_t * this_uart, + mss_uart_endian_t endian +); + +/***************************************************************************//** + The MSS_UART_set_tx_endian() function is used to configure the LSB first or + MSB first setting for MSS UART transmitter. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param endian + The endian parameter tells the LSB first or MSB first configuration. + This parameter is of type mss_uart_endian_t. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_tx_endian(&g_mss_uart0, MSS_UART_LITTLEEND); + @endcode + */ +void +MSS_UART_set_tx_endian +( + mss_uart_instance_t * this_uart, + mss_uart_endian_t endian +); + +/***************************************************************************//** + The MSS_UART_set_filter_length () function is used to configure the glitch + filter length of the MSS UART. This should be configured in accordance with + the chosen baud rate. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param length + The length parameter is of mss_uart_filter_length_t type that determines + the length of the glitch filter. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_filter_length(&g_mss_uart0, MSS_UART_LEN2); + @endcode + */ +void +MSS_UART_set_filter_length +( + mss_uart_instance_t * this_uart, + mss_uart_filter_length_t length +); + +/***************************************************************************//** + The MSS_UART_enable_afm() function is used to enable address flag detection + mode of the MSS UART + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_enable_afm(&g_mss_uart0); + @endcode + */ +void +MSS_UART_enable_afm +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_disable_afm() function is used to disable address flag detection + mode of the MSS UART. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_disable_afm(&g_mss_uart0); + @endcode + */ +void +MSS_UART_disable_afm +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_enable_afclear () function is used to enable address flag clear + of the MSS UART. This should be used in conjunction with address flag + detection mode (AFM). + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_enable_afclear(&g_mss_uart0); + @endcode + */ +void +MSS_UART_enable_afclear +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_disable_afclear () function is used to disable address flag + clear of the MSS UART. This should be used in conjunction with address flag + detection mode (AFM). + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_disable_afclear(&g_mss_uart0); + @endcode + */ +void +MSS_UART_disable_afclear +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_enable_rx_timeout() function is used to enable and configure + the receiver timeout functionality of MSS UART. This function accepts the + timeout parameter and applies the timeout based up on the baud rate as per + the formula 4 x timeout x bit time. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param timeout + The timeout parameter specifies the receiver timeout multiple. + It should be configured according to the baud rate in use. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_enable_rx_timeout(&g_mss_uart0 , 24); + @endcode + */ +void +MSS_UART_enable_rx_timeout +( + mss_uart_instance_t * this_uart, + uint8_t timeout +); + +/***************************************************************************//** + The MSS_UART_disable_rx_timeout() function is used to disable the receiver + timeout functionality of MSS UART. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_disable_rx_timeout(&g_mss_uart0); + @endcode + */ +void +MSS_UART_disable_rx_timeout +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_enable_tx_time_guard() function is used to enable and configure + the transmitter time guard functionality of MSS UART. This function accepts + the timeguard parameter and applies the timeguard based up on the baud rate + as per the formula timeguard x bit time. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_enable_tx_time_guard(&g_mss_uart0 , 24); + @endcode + */ +void +MSS_UART_enable_tx_time_guard +( + mss_uart_instance_t * this_uart, + uint8_t timeguard +); + +/***************************************************************************//** + The MSS_UART_disable_tx_time_guard() function is used to disable the + transmitter time guard functionality of MSS UART. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_disable_tx_time_guard(&g_mss_uart0); + @endcode + */ +void +MSS_UART_disable_tx_time_guard +( + mss_uart_instance_t * this_uart +); + +/***************************************************************************//** + The MSS_UART_set_address() function is used to set the 8-bit address for + the MSS UART referenced by this_uart parameter. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param address + The address parameter is the 8-bit address which is to be configured + to the MSS UART referenced by this_uart parameter. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_address(&g_mss_uart0, 0xAA); + @endcode + */ +void +MSS_UART_set_address +( + mss_uart_instance_t * this_uart, + uint8_t address +); + +/***************************************************************************//** + The MSS_UART_set_ready_mode() function is used to configure the MODE0 or MODE1 + to the TXRDY and RXRDY signals of the MSS UART referenced by this_uart + parameter. The mode parameter is used to provide the mode to be configured. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param mode + The mode parameter is the mss_uart_ready_mode_t type which is used to + configure the TXRDY and RXRDY signal modes. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_ready_mode(&g_mss_uart0, MSS_UART_READY_MODE0); + @endcode + */ +void +MSS_UART_set_ready_mode +( + mss_uart_instance_t * this_uart, + mss_uart_ready_mode_t mode +); + +/***************************************************************************//** + The MSS_UART_set_usart_mode() function is used to configure the MSS UART + referenced by the parameter this_uart in USART mode. Various USART modes + are supported which can be configured by the parameter mode of type + mss_uart_usart_mode_t. + + @param this_uart + The this_uart parameter is a pointer to an mss_uart_instance_t + structure identifying the MSS UART hardware block that will perform + the requested function. There are two such data structures, + g_mss_uart0 and g_mss_uart1, associated with MSS UART0 and MSS UART1. + This parameter must point to either the g_mss_uart0 or g_mss_uart1 + global data structure defined within the UART driver. + + @param mode + The mode parameter is the USART mode to be configured. + This parameter is of type mss_uart_usart_mode_t. + + @return + This function does not return a value. + + Example: + @code + MSS_UART_init(&g_mss_uart0, + MSS_UART_57600_BAUD, + MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT); + + MSS_UART_set_usart_mode(&g_mss_uart0, MSS_UART_SYNC_MASTER_POS_EDGE_CLK); + @endcode + */ +void +MSS_UART_set_usart_mode +( + mss_uart_instance_t * this_uart, + mss_uart_usart_mode_t mode +); + +#ifdef __cplusplus +} +#endif + +#endif /* __MSS_UART_H_ */ diff --git a/bsp/smartfusion2/libraries/mss_uart/mss_uart_regs.h b/bsp/smartfusion2/libraries/mss_uart/mss_uart_regs.h new file mode 100644 index 0000000000..3079ad4ba3 --- /dev/null +++ b/bsp/smartfusion2/libraries/mss_uart/mss_uart_regs.h @@ -0,0 +1,83 @@ +/******************************************************************************* + * (c) Copyright 2011-2013 Microsemi SoC Products Group. All rights reserved. + * + * Register bit offsets and masks defintions for SmartFusion2 MSS MMUART. + * + * SVN $Revision: 5610 $ + * SVN $Date: 2013-04-05 18:49:30 +0530 (Fri, 05 Apr 2013) $ + */ +#ifndef MSS_UART_REGS_H_ +#define MSS_UART_REGS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/******************************************************************************* + Register Bit definitions + */ + +/* Line Control register bit definitions */ +#define SB 6u /* Set break */ +#define DLAB 7u /* Divisor latch access bit */ + +/* FIFO Control register bit definitions */ +#define RXRDY_TXRDYN_EN 0u /* Enable TXRDY and RXRDY signals */ +#define CLEAR_RX_FIFO 1u /* Clear receiver FIFO */ +#define CLEAR_TX_FIFO 2u /* Clear transimtter FIFO */ +#define RDYMODE 3u /* Mode 0 or Mode 1 for TXRDY and RXRDY */ + +/* Modem Control register bit definitions */ +#define LOOP 4u /* Local loopback */ +#define RLOOP 5u /* Remote loopback */ +#define ECHO 6u /* Automatic echo */ +#define RLOOP_MASK 0x6u /* Remote loopback & Automatic echo*/ + +/* Line Status register bit definitions */ +#define DR 0u /* Data ready */ +#define THRE 5u /* Transmitter holding register empty */ +#define TEMT 6u /* Transitter empty */ + +/* Interrupt Enable register bit definitions */ +#define ERBFI 0u /* Enable receiver buffer full interrupt */ +#define ETBEI 1u /* Enable transmitter buffer empty interrupt */ +#define ELSI 2u /* Enable line status interrupt */ +#define EDSSI 3u /* Enable modem status interrupt */ + +/* Multimode register 0 bit definitions */ +#define ELIN 3u /* Enable LIN header detection */ +#define ETTG 5u /* Enable transmitter time guard */ +#define ERTO 6u /* Enable receiver time-out */ +#define EFBR 7u /* Enable fractional baud rate mode */ + +/* Multimode register 1 bit definitions */ +#define E_MSB_RX 0u /* MSB / LSB first for receiver */ +#define E_MSB_TX 1u /* MSB / LSB first for transmitter */ +#define EIRD 2u /* Enable IrDA modem */ +#define EIRX 3u /* Input polarity for IrDA modem */ +#define EITX 4u /* Output polarity for IrDA modem */ +#define EITP 5u /* Output pulse width for IrDA modem */ + +/* Multimode register 2 bit definitions */ +#define EERR 0u /* Enable ERR / NACK during stop time */ +#define EAFM 1u /* Enable 9-bit address flag mode */ +#define EAFC 2u /* Enable address flag clear */ +#define ESWM 3u /* Enable single wire half-duplex mode */ + +/* Multimode Interrupt Enable register and + Multimode Interrupt Identification register definitions */ +#define ERTOI 0u /* Enable receiver timeout interrupt */ +#define ENACKI 1u /* Enable NACK / ERR interrupt */ +#define EPID_PEI 2u /* Enable PID parity error interrupt */ +#define ELINBI 3u /* Enable LIN break interrupt */ +#define ELINSI 4u /* Enable LIN sync detection interrupt */ + + +#ifdef __cplusplus +} +#endif + +#endif /* MSS_UART_REGS_H_ */ + + + diff --git a/bsp/smartfusion2/libraries/sys_config/sys_config.c b/bsp/smartfusion2/libraries/sys_config/sys_config.c new file mode 100644 index 0000000000..b7d72fe08f --- /dev/null +++ b/bsp/smartfusion2/libraries/sys_config/sys_config.c @@ -0,0 +1,385 @@ +/******************************************************************************* + * (c) Copyright 2012 Microsemi SoC Products Group. All rights reserved. + * + * Smartfusion2 system configuration. This file is automatically generated + * by the Libero tools. It contains the Smartfusion2 system configuration that + * was selected during the hardware configuration flow. + * + */ + +#include "../../CMSIS/m2sxxx.h" +#include "../../CMSIS/sys_init_cfg_types.h" +#include "sys_config.h" + +/*============================================================================== + * !!! WARNING !!! + *============================================================================== + * The project including this file must be linked so that the content of this + * file is located in internal eNVM at run time. The content of this file is + * used to configure the system prior to RAM content initialization. This means + * that the content of the data structures below will be used before the copy + * from LMA to VMA takes place. The LMA and VMA locations of the content of this + * file must be identical for the system to be seamlessly configured as part of + * the CMSIS boot process. + */ + +/*============================================================================== + * Clock configuration + */ +/* No configuration data structure required. */ + +/*============================================================================== + * Memory remapping configuration + */ +/* TBD. */ + +/*============================================================================== + * MDDR configuration + */ +#if MSS_SYS_MDDR_CONFIG_BY_CORTEX + +#include "sys_config_mddr_define.h" + +MDDR_TypeDef * const g_m2s_mddr_addr = (MDDR_TypeDef *)0x40020800; + +const ddr_subsys_cfg_t g_m2s_mddr_subsys_config = +{ + /*--------------------------------------------------------------------- + * DDR Controller registers. + * All registers are 16-bit wide unless mentioned beside the definition. + */ + { + MDDR_DDRC_DYN_SOFT_RESET_CR, + MDDR_DDRC_RESERVED0, + MDDR_DDRC_DYN_REFRESH_1_CR, + MDDR_DDRC_DYN_REFRESH_2_CR, + MDDR_DDRC_DYN_POWERDOWN_CR, + MDDR_DDRC_DYN_DEBUG_CR, + MDDR_DDRC_MODE_CR, + MDDR_DDRC_ADDR_MAP_BANK_CR, + MDDR_DDRC_ECC_DATA_MASK_CR, + MDDR_DDRC_ADDR_MAP_COL_1_CR, + MDDR_DDRC_ADDR_MAP_COL_2_CR, + MDDR_DDRC_ADDR_MAP_ROW_1_CR, + MDDR_DDRC_ADDR_MAP_ROW_2_CR, + MDDR_DDRC_INIT_1_CR, + MDDR_DDRC_CKE_RSTN_CYCLES_1_CR, + MDDR_DDRC_CKE_RSTN_CYCLES_2_CR, + MDDR_DDRC_INIT_MR_CR, + MDDR_DDRC_INIT_EMR_CR, + MDDR_DDRC_INIT_EMR2_CR, + MDDR_DDRC_INIT_EMR3_CR, + MDDR_DDRC_DRAM_BANK_TIMING_PARAM_CR, + MDDR_DDRC_DRAM_RD_WR_LATENCY_CR, + MDDR_DDRC_DRAM_RD_WR_PRE_CR, + MDDR_DDRC_DRAM_MR_TIMING_PARAM_CR, + MDDR_DDRC_DRAM_RAS_TIMING_CR, + MDDR_DDRC_DRAM_RD_WR_TRNARND_TIME_CR, + MDDR_DDRC_DRAM_T_PD_CR, + MDDR_DDRC_DRAM_BANK_ACT_TIMING_CR, + MDDR_DDRC_ODT_PARAM_1_CR, + MDDR_DDRC_ODT_PARAM_2_CR, + MDDR_DDRC_ADDR_MAP_COL_3_CR, + MDDR_DDRC_MODE_REG_RD_WR_CR, + MDDR_DDRC_MODE_REG_DATA_CR, + MDDR_DDRC_PWR_SAVE_1_CR, + MDDR_DDRC_PWR_SAVE_2_CR, + MDDR_DDRC_ZQ_LONG_TIME_CR, + MDDR_DDRC_ZQ_SHORT_TIME_CR, + MDDR_DDRC_ZQ_SHORT_INT_REFRESH_MARGIN_1_CR, + MDDR_DDRC_ZQ_SHORT_INT_REFRESH_MARGIN_2_CR, + MDDR_DDRC_PERF_PARAM_1_CR, + MDDR_DDRC_HPR_QUEUE_PARAM_1_CR, + MDDR_DDRC_HPR_QUEUE_PARAM_2_CR, + MDDR_DDRC_LPR_QUEUE_PARAM_1_CR, + MDDR_DDRC_LPR_QUEUE_PARAM_2_CR, + MDDR_DDRC_WR_QUEUE_PARAM_CR, + MDDR_DDRC_PERF_PARAM_2_CR, + MDDR_DDRC_PERF_PARAM_3_CR, + MDDR_DDRC_DFI_RDDATA_EN_CR, + MDDR_DDRC_DFI_MIN_CTRLUPD_TIMING_CR, + MDDR_DDRC_DFI_MAX_CTRLUPD_TIMING_CR, + MDDR_DDRC_DFI_WR_LVL_CONTROL_1_CR, + MDDR_DDRC_DFI_WR_LVL_CONTROL_2_CR, + MDDR_DDRC_DFI_RD_LVL_CONTROL_1_CR, + MDDR_DDRC_DFI_RD_LVL_CONTROL_2_CR, + MDDR_DDRC_DFI_CTRLUPD_TIME_INTERVAL_CR, + MDDR_DDRC_DYN_SOFT_RESET_ALIAS_CR, + MDDR_DDRC_AXI_FABRIC_PRI_ID_CR, + }, + + /*--------------------------------------------------------------------- + * DDR PHY configuration registers + */ + { + MDDR_PHY_LOOPBACK_TEST_CR, + MDDR_PHY_BOARD_LOOPBACK_CR, + MDDR_PHY_CTRL_SLAVE_RATIO_CR, + MDDR_PHY_CTRL_SLAVE_FORCE_CR, + MDDR_PHY_CTRL_SLAVE_DELAY_CR, + MDDR_PHY_DATA_SLICE_IN_USE_CR, + MDDR_PHY_LVL_NUM_OF_DQ0_CR, + MDDR_PHY_DQ_OFFSET_1_CR, + MDDR_PHY_DQ_OFFSET_2_CR, + MDDR_PHY_DQ_OFFSET_3_CR, + MDDR_PHY_DIS_CALIB_RST_CR, + MDDR_PHY_DLL_LOCK_DIFF_CR, + MDDR_PHY_FIFO_WE_IN_DELAY_1_CR, + MDDR_PHY_FIFO_WE_IN_DELAY_2_CR, + MDDR_PHY_FIFO_WE_IN_DELAY_3_CR, + MDDR_PHY_FIFO_WE_IN_FORCE_CR, + MDDR_PHY_FIFO_WE_SLAVE_RATIO_1_CR, + MDDR_PHY_FIFO_WE_SLAVE_RATIO_2_CR, + MDDR_PHY_FIFO_WE_SLAVE_RATIO_3_CR, + MDDR_PHY_FIFO_WE_SLAVE_RATIO_4_CR, + MDDR_PHY_GATELVL_INIT_MODE_CR, + MDDR_PHY_GATELVL_INIT_RATIO_1_CR, + MDDR_PHY_GATELVL_INIT_RATIO_2_CR, + MDDR_PHY_GATELVL_INIT_RATIO_3_CR, + MDDR_PHY_GATELVL_INIT_RATIO_4_CR, + MDDR_PHY_LOCAL_ODT_CR, + MDDR_PHY_INVERT_CLKOUT_CR, + MDDR_PHY_RD_DQS_SLAVE_DELAY_1_CR, + MDDR_PHY_RD_DQS_SLAVE_DELAY_2_CR, + MDDR_PHY_RD_DQS_SLAVE_DELAY_3_CR, + MDDR_PHY_RD_DQS_SLAVE_FORCE_CR, + MDDR_PHY_RD_DQS_SLAVE_RATIO_1_CR, + MDDR_PHY_RD_DQS_SLAVE_RATIO_2_CR, + MDDR_PHY_RD_DQS_SLAVE_RATIO_3_CR, + MDDR_PHY_RD_DQS_SLAVE_RATIO_4_CR, + MDDR_PHY_WR_DQS_SLAVE_DELAY_1_CR, + MDDR_PHY_WR_DQS_SLAVE_DELAY_2_CR, + MDDR_PHY_WR_DQS_SLAVE_DELAY_3_CR, + MDDR_PHY_WR_DQS_SLAVE_FORCE_CR, + MDDR_PHY_WR_DQS_SLAVE_RATIO_1_CR, + MDDR_PHY_WR_DQS_SLAVE_RATIO_2_CR, + MDDR_PHY_WR_DQS_SLAVE_RATIO_3_CR, + MDDR_PHY_WR_DQS_SLAVE_RATIO_4_CR, + MDDR_PHY_WR_DATA_SLAVE_DELAY_1_CR, + MDDR_PHY_WR_DATA_SLAVE_DELAY_2_CR, + MDDR_PHY_WR_DATA_SLAVE_DELAY_3_CR, + MDDR_PHY_WR_DATA_SLAVE_FORCE_CR, + MDDR_PHY_WR_DATA_SLAVE_RATIO_1_CR, + MDDR_PHY_WR_DATA_SLAVE_RATIO_2_CR, + MDDR_PHY_WR_DATA_SLAVE_RATIO_3_CR, + MDDR_PHY_WR_DATA_SLAVE_RATIO_4_CR, + MDDR_PHY_WRLVL_INIT_MODE_CR, + MDDR_PHY_WRLVL_INIT_RATIO_1_CR, + MDDR_PHY_WRLVL_INIT_RATIO_2_CR, + MDDR_PHY_WRLVL_INIT_RATIO_3_CR, + MDDR_PHY_WRLVL_INIT_RATIO_4_CR, + MDDR_PHY_WR_RD_RL_CR, + MDDR_PHY_RDC_FIFO_RST_ERR_CNT_CLR_CR, + MDDR_PHY_RDC_WE_TO_RE_DELAY_CR, + MDDR_PHY_USE_FIXED_RE_CR, + MDDR_PHY_USE_RANK0_DELAYS_CR, + MDDR_PHY_USE_LVL_TRNG_LEVEL_CR, + MDDR_PHY_DYN_CONFIG_CR, + MDDR_PHY_RD_WR_GATE_LVL_CR, + MDDR_PHY_DYN_RESET_CR + }, + + /*--------------------------------------------------------------------- + * FIC-64 registers + * These registers are 16-bit wide and 32-bit aligned. + */ + { + MDDR_DDR_FIC_NB_ADDR_CR, + MDDR_DDR_FIC_NBRWB_SIZE_CR, + MDDR_DDR_FIC_WB_TIMEOUT_CR, + MDDR_DDR_FIC_HPD_SW_RW_EN_CR, + MDDR_DDR_FIC_HPD_SW_RW_INVAL_CR, + MDDR_DDR_FIC_SW_WR_ERCLR_CR, + MDDR_DDR_FIC_ERR_INT_ENABLE_CR, + MDDR_DDR_FIC_NUM_AHB_MASTERS_CR, + MDDR_DDR_FIC_LOCK_TIMEOUTVAL_1_CR, + MDDR_DDR_FIC_LOCK_TIMEOUTVAL_2_CR, + MDDR_DDR_FIC_LOCK_TIMEOUT_EN_CR + } +}; + +#endif + +/*============================================================================== + * FDDR configuration + */ +#if MSS_SYS_FDDR_CONFIG_BY_CORTEX + +#include "sys_config_fddr_define.h" + +FDDR_TypeDef * const g_m2s_fddr_addr = (FDDR_TypeDef *)0x40021000; + +const fddr_sysreg_t g_m2s_fddr_sysreg_subsys_config = +{ + 0x0001u, /* PLL_CONFIG_LOW_1 */ + 0x0002u, /* PLL_CONFIG_LOW_2 */ + 0x0003u, /* PLL_CONFIG_HIGH */ + 0x0004u, /* FACC_CLK_EN */ + 0x0005u, /* FACC_MUX_CONFIG */ + 0x0006u, /* FACC_DIVISOR_RATIO */ + 0x0007u, /* PLL_DELAY_LINE_SEL */ + 0x0008u, /* SOFT_RESET */ + 0x0009u, /* IO_CALIB */ + 0x000Au, /* INTERRUPT_ENABLE */ + 0x000Bu, /* AXI_AHB_MODE_SEL */ + 0x000Cu /* PHY_SELF_REF_EN */ +}; + +const ddr_subsys_cfg_t g_m2s_fddr_subsys_config = +{ + /*--------------------------------------------------------------------- + * DDR Controller registers. + * All registers are 16-bit wide unless mentioned beside the definition. + */ + { + FDDR_DDRC_DYN_SOFT_RESET_CR, + FDDR_DDRC_RESERVED0, + FDDR_DDRC_DYN_REFRESH_1_CR, + FDDR_DDRC_DYN_REFRESH_2_CR, + FDDR_DDRC_DYN_POWERDOWN_CR, + FDDR_DDRC_DYN_DEBUG_CR, + FDDR_DDRC_MODE_CR, + FDDR_DDRC_ADDR_MAP_BANK_CR, + FDDR_DDRC_ECC_DATA_MASK_CR, + FDDR_DDRC_ADDR_MAP_COL_1_CR, + FDDR_DDRC_ADDR_MAP_COL_2_CR, + FDDR_DDRC_ADDR_MAP_ROW_1_CR, + FDDR_DDRC_ADDR_MAP_ROW_2_CR, + FDDR_DDRC_INIT_1_CR, + FDDR_DDRC_CKE_RSTN_CYCLES_1_CR, + FDDR_DDRC_CKE_RSTN_CYCLES_2_CR, + FDDR_DDRC_INIT_MR_CR, + FDDR_DDRC_INIT_EMR_CR, + FDDR_DDRC_INIT_EMR2_CR, + FDDR_DDRC_INIT_EMR3_CR, + FDDR_DDRC_DRAM_BANK_TIMING_PARAM_CR, + FDDR_DDRC_DRAM_RD_WR_LATENCY_CR, + FDDR_DDRC_DRAM_RD_WR_PRE_CR, + FDDR_DDRC_DRAM_MR_TIMING_PARAM_CR, + FDDR_DDRC_DRAM_RAS_TIMING_CR, + FDDR_DDRC_DRAM_RD_WR_TRNARND_TIME_CR, + FDDR_DDRC_DRAM_T_PD_CR, + FDDR_DDRC_DRAM_BANK_ACT_TIMING_CR, + FDDR_DDRC_ODT_PARAM_1_CR, + FDDR_DDRC_ODT_PARAM_2_CR, + FDDR_DDRC_ADDR_MAP_COL_3_CR, + FDDR_DDRC_MODE_REG_RD_WR_CR, + FDDR_DDRC_MODE_REG_DATA_CR, + FDDR_DDRC_PWR_SAVE_1_CR, + FDDR_DDRC_PWR_SAVE_2_CR, + FDDR_DDRC_ZQ_LONG_TIME_CR, + FDDR_DDRC_ZQ_SHORT_TIME_CR, + FDDR_DDRC_ZQ_SHORT_INT_REFRESH_MARGIN_1_CR, + FDDR_DDRC_ZQ_SHORT_INT_REFRESH_MARGIN_2_CR, + FDDR_DDRC_PERF_PARAM_1_CR, + FDDR_DDRC_HPR_QUEUE_PARAM_1_CR, + FDDR_DDRC_HPR_QUEUE_PARAM_2_CR, + FDDR_DDRC_LPR_QUEUE_PARAM_1_CR, + FDDR_DDRC_LPR_QUEUE_PARAM_2_CR, + FDDR_DDRC_WR_QUEUE_PARAM_CR, + FDDR_DDRC_PERF_PARAM_2_CR, + FDDR_DDRC_PERF_PARAM_3_CR, + FDDR_DDRC_DFI_RDDATA_EN_CR, + FDDR_DDRC_DFI_MIN_CTRLUPD_TIMING_CR, + FDDR_DDRC_DFI_MAX_CTRLUPD_TIMING_CR, + FDDR_DDRC_DFI_WR_LVL_CONTROL_1_CR, + FDDR_DDRC_DFI_WR_LVL_CONTROL_2_CR, + FDDR_DDRC_DFI_RD_LVL_CONTROL_1_CR, + FDDR_DDRC_DFI_RD_LVL_CONTROL_2_CR, + FDDR_DDRC_DFI_CTRLUPD_TIME_INTERVAL_CR, + FDDR_DDRC_DYN_SOFT_RESET_ALIAS_CR, + FDDR_DDRC_AXI_FABRIC_PRI_ID_CR + }, + + /*--------------------------------------------------------------------- + * DDR PHY configuration registers + */ + { + FDDR_PHY_LOOPBACK_TEST_CR, + FDDR_PHY_BOARD_LOOPBACK_CR, + FDDR_PHY_CTRL_SLAVE_RATIO_CR, + FDDR_PHY_CTRL_SLAVE_FORCE_CR, + FDDR_PHY_CTRL_SLAVE_DELAY_CR, + FDDR_PHY_DATA_SLICE_IN_USE_CR, + FDDR_PHY_LVL_NUM_OF_DQ0_CR, + FDDR_PHY_DQ_OFFSET_1_CR, + FDDR_PHY_DQ_OFFSET_2_CR, + FDDR_PHY_DQ_OFFSET_3_CR, + FDDR_PHY_DIS_CALIB_RST_CR, + FDDR_PHY_DLL_LOCK_DIFF_CR, + FDDR_PHY_FIFO_WE_IN_DELAY_1_CR, + FDDR_PHY_FIFO_WE_IN_DELAY_2_CR, + FDDR_PHY_FIFO_WE_IN_DELAY_3_CR, + FDDR_PHY_FIFO_WE_IN_FORCE_CR, + FDDR_PHY_FIFO_WE_SLAVE_RATIO_1_CR, + FDDR_PHY_FIFO_WE_SLAVE_RATIO_2_CR, + FDDR_PHY_FIFO_WE_SLAVE_RATIO_3_CR, + FDDR_PHY_FIFO_WE_SLAVE_RATIO_4_CR, + FDDR_PHY_GATELVL_INIT_MODE_CR, + FDDR_PHY_GATELVL_INIT_RATIO_1_CR, + FDDR_PHY_GATELVL_INIT_RATIO_2_CR, + FDDR_PHY_GATELVL_INIT_RATIO_3_CR, + FDDR_PHY_GATELVL_INIT_RATIO_4_CR, + FDDR_PHY_LOCAL_ODT_CR, + FDDR_PHY_INVERT_CLKOUT_CR, + FDDR_PHY_RD_DQS_SLAVE_DELAY_1_CR, + FDDR_PHY_RD_DQS_SLAVE_DELAY_2_CR, + FDDR_PHY_RD_DQS_SLAVE_DELAY_3_CR, + FDDR_PHY_RD_DQS_SLAVE_FORCE_CR, + FDDR_PHY_RD_DQS_SLAVE_RATIO_1_CR, + FDDR_PHY_RD_DQS_SLAVE_RATIO_2_CR, + FDDR_PHY_RD_DQS_SLAVE_RATIO_3_CR, + FDDR_PHY_RD_DQS_SLAVE_RATIO_4_CR, + FDDR_PHY_WR_DQS_SLAVE_DELAY_1_CR, + FDDR_PHY_WR_DQS_SLAVE_DELAY_2_CR, + FDDR_PHY_WR_DQS_SLAVE_DELAY_3_CR, + FDDR_PHY_WR_DQS_SLAVE_FORCE_CR, + FDDR_PHY_WR_DQS_SLAVE_RATIO_1_CR, + FDDR_PHY_WR_DQS_SLAVE_RATIO_2_CR, + FDDR_PHY_WR_DQS_SLAVE_RATIO_3_CR, + FDDR_PHY_WR_DQS_SLAVE_RATIO_4_CR, + FDDR_PHY_WR_DATA_SLAVE_DELAY_1_CR, + FDDR_PHY_WR_DATA_SLAVE_DELAY_2_CR, + FDDR_PHY_WR_DATA_SLAVE_DELAY_3_CR, + FDDR_PHY_WR_DATA_SLAVE_FORCE_CR, + FDDR_PHY_WR_DATA_SLAVE_RATIO_1_CR, + FDDR_PHY_WR_DATA_SLAVE_RATIO_2_CR, + FDDR_PHY_WR_DATA_SLAVE_RATIO_3_CR, + FDDR_PHY_WR_DATA_SLAVE_RATIO_4_CR, + FDDR_PHY_WRLVL_INIT_MODE_CR, + FDDR_PHY_WRLVL_INIT_RATIO_1_CR, + FDDR_PHY_WRLVL_INIT_RATIO_2_CR, + FDDR_PHY_WRLVL_INIT_RATIO_3_CR, + FDDR_PHY_WRLVL_INIT_RATIO_4_CR, + FDDR_PHY_WR_RD_RL_CR, + FDDR_PHY_RDC_FIFO_RST_ERR_CNT_CLR_CR, + FDDR_PHY_RDC_WE_TO_RE_DELAY_CR, + FDDR_PHY_USE_FIXED_RE_CR, + FDDR_PHY_USE_RANK0_DELAYS_CR, + FDDR_PHY_USE_LVL_TRNG_LEVEL_CR, + FDDR_PHY_DYN_CONFIG_CR, + FDDR_PHY_RD_WR_GATE_LVL_CR, + FDDR_PHY_DYN_RESET_CR, + }, + + /*--------------------------------------------------------------------- + * FIC-64 registers + * These registers are 16-bit wide and 32-bit aligned. + */ + { + FDDR_DDR_FIC_NB_ADDR_CR, + FDDR_DDR_FIC_NBRWB_SIZE_CR, + FDDR_DDR_FIC_WB_TIMEOUT_CR, + FDDR_DDR_FIC_HPD_SW_RW_EN_CR, + FDDR_DDR_FIC_HPD_SW_RW_INVAL_CR, + FDDR_DDR_FIC_SW_WR_ERCLR_CR, + FDDR_DDR_FIC_ERR_INT_ENABLE_CR, + FDDR_DDR_FIC_NUM_AHB_MASTERS_CR, + FDDR_DDR_FIC_LOCK_TIMEOUTVAL_1_CR, + FDDR_DDR_FIC_LOCK_TIMEOUTVAL_2_CR, + FDDR_DDR_FIC_LOCK_TIMEOUT_EN_CR + } +}; + +#endif + diff --git a/bsp/smartfusion2/libraries/sys_config/sys_config.h b/bsp/smartfusion2/libraries/sys_config/sys_config.h new file mode 100644 index 0000000000..65c49b1d7d --- /dev/null +++ b/bsp/smartfusion2/libraries/sys_config/sys_config.h @@ -0,0 +1,66 @@ +/******************************************************************************* + * (c) Copyright 2012 Microsemi SoC Products Group. All rights reserved. + * + * Smartfusion2 system configuration. This file is automatically generated + * by the Libero tools. + * + */ +#ifndef MSS_SYSTEM_CONFIGURATION +#define MSS_SYSTEM_CONFIGURATION + +/*============================================================================== + * Clock configuration + */ +#include "sys_config_mss_clocks.h" + +/*============================================================================== + * Memory remapping configuration + */ +/* TBD */ + +/*============================================================================== + * FACC_INIT (Cortex-M3 runs the FACC INIT procedure) + * Only set to 1 for design targeting the M2S050T_ES device + */ +#define MSS_SYS_FACC_INIT_BY_CORTEX 0 + +/*============================================================================== + * MDDR configuration + */ +#define MSS_SYS_MDDR_CONFIG_BY_CORTEX 0 + +/*============================================================================== + * FDDR configuration + */ +#define MSS_SYS_FDDR_CONFIG_BY_CORTEX 0 + +/*============================================================================== + * SERDES Interface configuration + */ +#define MSS_SYS_SERDES_0_CONFIG_BY_CORTEX 0 +#if MSS_SYS_SERDES_0_CONFIG_BY_CORTEX +#include "sys_config_SERDESIF_0.h" +#endif + +#define MSS_SYS_SERDES_1_CONFIG_BY_CORTEX 0 +#if MSS_SYS_SERDES_1_CONFIG_BY_CORTEX +#include "sys_config_SERDESIF_1.h" +#endif + +#define MSS_SYS_SERDES_2_CONFIG_BY_CORTEX 0 +#if MSS_SYS_SERDES_2_CONFIG_BY_CORTEX +#include "sys_config_SERDESIF_2.h" +#endif + +#define MSS_SYS_SERDES_3_CONFIG_BY_CORTEX 0 +#if MSS_SYS_SERDES_3_CONFIG_BY_CORTEX +#include "sys_config_SERDESIF_3.h" +#endif + +/*============================================================================== + * Cache configuration + */ +#define MSS_SYS_CACHE_CONFIG_BY_CORTEX 0 + +#endif /* MSS_SYSTEM_CONFIGURATION */ + diff --git a/bsp/smartfusion2/libraries/sys_config/sys_config_mss_clocks.h b/bsp/smartfusion2/libraries/sys_config/sys_config_mss_clocks.h new file mode 100644 index 0000000000..1110c97169 --- /dev/null +++ b/bsp/smartfusion2/libraries/sys_config/sys_config_mss_clocks.h @@ -0,0 +1,21 @@ +/*=============================================================*/ +/* Created by Microsemi SmartDesign Fri May 22 15:04:18 2020 */ +/* */ +/* Warning: Do not modify this file, it may lead to unexpected */ +/* functional failures in your design. */ +/* */ +/*=============================================================*/ + +#ifndef SYS_CONFIG_MSS_CLOCKS +#define SYS_CONFIG_MSS_CLOCKS + +#define MSS_SYS_M3_CLK_FREQ 100000000u +#define MSS_SYS_MDDR_CLK_FREQ 100000000u +#define MSS_SYS_APB_0_CLK_FREQ 100000000u +#define MSS_SYS_APB_1_CLK_FREQ 100000000u +#define MSS_SYS_APB_2_CLK_FREQ 25000000u +#define MSS_SYS_FIC_0_CLK_FREQ 100000000u +#define MSS_SYS_FIC_1_CLK_FREQ 100000000u +#define MSS_SYS_FIC64_CLK_FREQ 100000000u + +#endif /* SYS_CONFIG_MSS_CLOCKS */ |
