From 4f72353c19f425c1fa8572f1089c722eac80a6a8 Mon Sep 17 00:00:00 2001 From: Rohitkumar Girase Date: Mon, 15 May 2023 10:51:24 +0100 Subject: [PATCH] Squashed 'applications/' changes from 529d667..e2a7298 e2a7298 Merged bootloaders source code version 2.1.102. 9b9dc2f Squashed 'bootloaders/' changes from 8c8d325..90a7460 git-subtree-dir: applications git-subtree-split: e2a7298b2568585cbd29a83bab3271c151ffc7ab --- bootloaders/miv-rv32-bootloader/README.md | 52 +- .../miv-rv32-bootloader debug.launch | 6 +- .../miv-rv32-bootloader hw debug.launch | 62 - .../src/application/bootloader/bootloader.c | 93 +- .../src/application/bootstrap/bootstrap.c | 43 +- .../driver_config/phy_sw_cfg.h | 136 + .../src/middleware/ymodem/ymodem.c | 62 +- .../src/middleware/ymodem/ymodem.h | 31 +- .../src/platform/README.md | 27 + .../fpga_ip/Core10GBaseKR_PHY/Jenkinsfile | 2 + .../fpga_ip/Core10GBaseKR_PHY/README.md | 1 + .../Core10GBaseKR_PHY/core10gbasekr_phy.c | 447 ++++ .../core10gbasekr_phy_link_training.c | 548 ++++ .../core10gbasekr_phy_link_training.h | 231 ++ .../Core10GBaseKR_PHY/core10gbasekr_phy_reg.h | 1284 +++++++++ .../drivers/fpga_ip/Core10GBaseKR_PHY/phy.h | 569 ++++ .../fpga_ip/Core10GBaseKR_PHY/phy_types.h | 337 +++ .../link_training_10gbasekr_status.txt | 28 + .../Core10GBaseKR_PHY/uint_32_bit_masks.h | 114 + .../CoreGPIO/core_gpio.c | 4 +- .../CoreGPIO/core_gpio.h | 374 +-- .../CoreGPIO/coregpio_regs.h | 4 +- .../drivers/fpga_ip/CoreI2C/core_i2c.c | 1495 +++++++++++ .../drivers/fpga_ip/CoreI2C/core_i2c.h | 2306 +++++++++++++++++ .../drivers/fpga_ip/CoreI2C/core_smbus_regs.h | 190 ++ .../drivers/fpga_ip/CoreI2C/i2c_interrupt.c | 27 + .../{fabric_ip => fpga_ip}/CoreSPI/core_spi.c | 217 +- .../{fabric_ip => fpga_ip}/CoreSPI/core_spi.h | 635 +++-- .../CoreSPI/corespi_regs.h | 13 +- .../CoreSysServices_PF/core_sysservices_pf.c | 95 +- .../CoreSysServices_PF/core_sysservices_pf.h | 679 ++--- .../coresysservicespf_regs.h | 4 +- .../CoreUARTapb/core_uart_apb.c | 4 +- .../CoreUARTapb/core_uart_apb.h | 349 +-- .../CoreUARTapb/coreuartapb_regs.h | 8 +- .../{fabric_ip => fpga_ip}/miv_i2c/miv_i2c.c | 29 +- .../{fabric_ip => fpga_ip}/miv_i2c/miv_i2c.h | 6 +- .../miv_i2c/miv_i2c_interrupt.c | 0 .../miv_i2c/miv_i2c_regs.h} | 4 + .../miv_plic/miv_plic.c | 4 - .../miv_plic/miv_plic.h | 14 + .../miv_plic/miv_plic_regs.h | 12 +- .../miv_timer/miv_timer.h | 48 +- .../miv_udma/miv_udma.c | 4 +- .../miv_udma/miv_udma.h | 169 +- .../miv_udma/miv_udma_regs.h | 3 + .../miv_watchdog/miv_watchdog.c | 7 - .../miv_watchdog/miv_watchdog.h | 0 .../miv_watchdog/miv_watchdog_regs.h | 12 +- .../drivers/off_chip/spi_flash/spi_flash.c | 2 +- .../src/platform/hal/hal_assert.h | 3 +- .../src/platform/hal/hal_irq.c | 2 +- .../src/platform/hal/hw_macros.h | 2 +- .../src/platform/hal/hw_reg_access.S | 2 +- .../src/platform/hal/hw_reg_access.h | 2 +- .../src/platform/hal/readme.md | 38 - .../src/platform/miv_rv32_hal/Jenkinsfile | 2 + .../platform/miv_rv32_hal/miv_rv32_entry.S | 670 ++--- .../src/platform/miv_rv32_hal/miv_rv32_hal.c | 178 +- .../src/platform/miv_rv32_hal/miv_rv32_hal.h | 732 ++++-- .../src/platform/miv_rv32_hal/miv_rv32_plic.h | 12 +- .../src/platform/miv_rv32_hal/miv_rv32_regs.h | 30 +- .../platform/miv_rv32_hal/miv_rv32_stubs.c | 40 +- .../platform/miv_rv32_hal/miv_rv32_subsys.h | 293 +++ .../platform/miv_rv32_hal/miv_rv32_syscall.c | 2 +- 65 files changed, 10704 insertions(+), 2095 deletions(-) delete mode 100644 bootloaders/miv-rv32-bootloader/miv-rv32-bootloader hw debug.launch create mode 100644 bootloaders/miv-rv32-bootloader/src/boards/polarfire-eval-kit/platform_config/driver_config/phy_sw_cfg.h create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/README.md create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/Jenkinsfile create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/README.md create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy.c create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_link_training.c create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_link_training.h create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_reg.h create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/phy.h create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/phy_types.h create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/resources/link_training_10gbasekr_status.txt create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/uint_32_bit_masks.h rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreGPIO/core_gpio.c (99%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreGPIO/core_gpio.h (60%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreGPIO/coregpio_regs.h (92%) create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreSPI/core_spi.c (83%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreSPI/core_spi.h (67%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreSPI/corespi_regs.h (98%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreSysServices_PF/core_sysservices_pf.c (91%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreSysServices_PF/core_sysservices_pf.h (69%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreSysServices_PF/coresysservicespf_regs.h (97%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreUARTapb/core_uart_apb.c (98%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreUARTapb/core_uart_apb.h (50%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/CoreUARTapb/coreuartapb_regs.h (95%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_i2c/miv_i2c.c (98%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_i2c/miv_i2c.h (99%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_i2c/miv_i2c_interrupt.c (100%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip/miv_i2c/mivi2c_regs.h => fpga_ip/miv_i2c/miv_i2c_regs.h} (99%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_plic/miv_plic.c (99%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_plic/miv_plic.h (99%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_plic/miv_plic_regs.h (82%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_timer/miv_timer.h (89%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_udma/miv_udma.c (96%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_udma/miv_udma.h (57%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_udma/miv_udma_regs.h (99%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_watchdog/miv_watchdog.c (97%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_watchdog/miv_watchdog.h (100%) rename bootloaders/miv-rv32-bootloader/src/platform/drivers/{fabric_ip => fpga_ip}/miv_watchdog/miv_watchdog_regs.h (95%) delete mode 100644 bootloaders/miv-rv32-bootloader/src/platform/hal/readme.md create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/Jenkinsfile create mode 100644 bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_subsys.h diff --git a/bootloaders/miv-rv32-bootloader/README.md b/bootloaders/miv-rv32-bootloader/README.md index ea5cb4f..89f16bd 100644 --- a/bootloaders/miv-rv32-bootloader/README.md +++ b/bootloaders/miv-rv32-bootloader/README.md @@ -1,10 +1,9 @@ # Mi-V Bootloader firmware - This project allows you to write application executable into the SPI flash or - the I2C EEPROM. - The executable is expected to be preloaded in the LSRAM memory using the Libero - memory client configurator. + This project provides the capability to download an executable to the LSRAM and run a new application from there. + Additionally, you can write the application executable into the SPI flash or I2C EEPROM. + Note that the default executable is usually preloaded in the LSRAM memory using the Libero memory client configurator Writing to the SPI flash is tested on PolarFire Eval Kit on-board SPI flash. Writing to the EEPROM is tested on PolarFire Avalanche kit with MikroBus Dual @@ -21,7 +20,7 @@ HyperTerminal or PuTTY configured as follows: - no parity - no flow control -This program displays a self explainatory menu which can be used to perform +This program displays a self-explanatory menu which can be used to perform different actions. ### Build configurations @@ -32,11 +31,13 @@ The following build configurations are provided with this project | Bootloader-Debug | Run Bootloader in step-debug mode. RV32 IMC extensions. Links to default TCM base address 0x40000000. Not Optimized (-O0). | | Bootstrap | Used to generate the elf file used by the DGC designs. Links to default TCM base address 0x40000000. Not Optimized (-O0).
For general usage, the *Bootloader-Debug* configuration is recommended| -The Bootloader-Debug configuration provides additional YMODEM functionality to -download a hex file over UART terminal to the LSRAM at address 0x80000000. It can -then be copied into either the SPI flash or the LSRAM. +The Bootloader-Debug configuration provides additional YMODEM functionality to +download a raw binary file over UART terminal to the LSRAM at address 0x80000000. Once the new executable is downloaded to the LSRAM, +you can choose to do the following two actions using UART menu options. + - Jump to LSRAM start address and execute the newly downloaded executable + - Copy the executable into either the SPI flash or the I2C EEPROM (For bootstrap functionality) -The Bootstrap configuration assumes that the LSRAM is preloaded with the hex +The Bootstrap configuration assumes that the LSRAM is preloaded with the raw binary file as a memory client in the Libero design flow as explained in the design guide. If you are using this flow, you may not need the YMODEM functionality. ## Target hardware @@ -46,7 +47,7 @@ The Libero designs that are compatible with the use cases provided by this examp | ----------- | ---------------------- | -------------------------- | -------------------------- | | Copy to SPI flash | DGC1 | SPI Flash Bootstrap | [PolarFire® Evaluation Kit](https://github.com/Mi-V-Soft-RISC-V/PolarFire-Eval-Kit) | | Copy to EEPROM | DGC2 | I2C Flash Bootstrap | [PolarFire® Avalanche board](https://github.com/Mi-V-Soft-RISC-V/Future-Avalanche-Board) | -| Download hex file to LSRAM | DGC1 and DGC2 can be used | Download hex file to LSRAM.
Both DGC1 and DGC2 designs boot with a default hex file attached to the LSRAM as a client.
Use this menu to overwrite the LSRAM with a new hex file.| See above | +| Download raw binary file to LSRAM | DGC1 and DGC2 can be used | Download raw binary file to LSRAM.
Both DGC1 and DGC2 designs boot with a default raw binary file attached to the LSRAM as a client.
Use this menu to overwrite the LSRAM with a new raw binary file.| See above | Notes: - MikroBus Dual EE Click board is available from https://www.mikroe.com/dual-ee-click @@ -54,16 +55,37 @@ Notes: All the design specific definitions such as peripheral base addresses, system clock frequency etc. are included in fpga_design_config.h. +To ensure that a 10ms timer is provided, the Systick handler must be set based on the system clock frequency. Additionally, sufficient packet time +must be set in order to initiate YMODEM data transfer + +while using the YMODEM download option, it is important to set the maximum file size to avoid encountering +an "YMODEM file transfer Failed- Aborted/File size exceeds limit" error. + +The LSRAM used in the Libero design used to run this example project has a size of 128KB. However, it is important to note +that the maximum size of the SPI flash and I2C eeprom when copying from the LSRAM is 32KB. + This example project can be used with another design using a different hardware configuration. This can be achieved by overwriting the content of this example project's _fpga_design_config.h_ file with the correct data from your Libero design. -### Booting the system: -The boot flow is as below: - - Run this project in step-debug mode from TCM address space - - Download new hex file to LSRAM address space using UART menu option 3. (This step is optional if the LSRAM is preloaded) - - Copy the downloaded hex file to EEPROM or SPI flash per your design using UART menu options 1 and 2 +### Bootloader-Debug : Memory details and Boot flow: + +#### Memory details: +| Memory/Functionality | Default values | How to change default values | +| ----------- | ---------------------- | -------------------------- | +| LSRAM | 128KB | LSRAM Configurator in Libero design| +| Copy from LSRAM to NVM(SPI Flash or I2C EEPROM) | 32KB | FLASH_EXECUTABLE_SIZE macro in source code| +| Copy from NVM to TCM | 32KB | MIV_ESS Configurator in Libero design| +| Download from YMODEM to LSRAM | 128KB | LSRAM_SIZE macro in source code | + +Note: LSRAM_SIZE value should not exceed LSRAM size configured in the Libero design. + +#### The boot flow is as below: + - Launch the project in step-debug mode from the TCM address space + - (Optional) If the LSRAM is not initialized with a memory client in the Libero design, download a new raw binary file to the LSRAM address space using UART menu option 3 + - To Run the loaded application select UART menu option 4 + - To Copy the downloaded raw binary file to the SPI flash or EEPROM based on your Libero design using UART menu options 1 and 2 - For SPI boot on PolarFire Eval Kit: - Push and hold SW8 and press and release SW6 or SW7. - For I2C boot on Avalanche board: diff --git a/bootloaders/miv-rv32-bootloader/miv-rv32-bootloader debug.launch b/bootloaders/miv-rv32-bootloader/miv-rv32-bootloader debug.launch index e36aad5..6f6bce6 100644 --- a/bootloaders/miv-rv32-bootloader/miv-rv32-bootloader debug.launch +++ b/bootloaders/miv-rv32-bootloader/miv-rv32-bootloader debug.launch @@ -46,12 +46,12 @@ - - + + - + diff --git a/bootloaders/miv-rv32-bootloader/miv-rv32-bootloader hw debug.launch b/bootloaders/miv-rv32-bootloader/miv-rv32-bootloader hw debug.launch deleted file mode 100644 index 3e309cf..0000000 --- a/bootloaders/miv-rv32-bootloader/miv-rv32-bootloader hw debug.launch +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bootloaders/miv-rv32-bootloader/src/application/bootloader/bootloader.c b/bootloaders/miv-rv32-bootloader/src/application/bootloader/bootloader.c index 3f208a7..e8149ae 100644 --- a/bootloaders/miv-rv32-bootloader/src/application/bootloader/bootloader.c +++ b/bootloaders/miv-rv32-bootloader/src/application/bootloader/bootloader.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -11,14 +11,14 @@ */ #include #include "miv_rv32_hal/miv_rv32_hal.h" -#include "drivers/fabric_ip/CoreUARTapb/core_uart_apb.h" -#include "drivers/fabric_ip/miv_i2c/miv_i2c.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "drivers/fpga_ip/miv_i2c/miv_i2c.h" #include "drivers/off_chip/spi_flash/spi_flash.h" #include "ymodem/ymodem.h" #define FLASH_SECTOR_SIZE 65536 /* flash memory size */ -#define FLASH_SECTORS 128 // There are 126 sectors of 64kB size, using 124 -#define FLASH_BLOCK_SIZE 4096 //Sectors compose of 4kB eraseable blocks +#define FLASH_SECTORS 128 // There are 126 sectors of 64KB size, using 124 +#define FLASH_BLOCK_SIZE 4096 //Sectors compose of 4KB eraseable blocks #define FLASH_SEGMENT_SIZE 256 // Write segment size is 256 #define FLASH_BLOCK_SEGMENTS (FLASH_BLOCK_SIZE / FLASH_SEGMENT_SIZE) @@ -30,6 +30,7 @@ static int write_program_to_flash(uint8_t *write_buf, uint32_t file_size); static void copy_hex_to_i2ceeprom(void); static void copy_hex_to_spiflash(void); static uint32_t rx_app_file(uint8_t *dest_address); +static void Bootloader_JumpToApplication(uint32_t reset_vector); static uint8_t file_name[FILE_NAME_LENGTH + 1]; /* +1 for nul */ @@ -51,14 +52,16 @@ const uint8_t g_bootstrap_choice[] = ================================================================================\r\n\ \r\n\ \r\n\ -This program supports writing HEX data from Source LSRAM (@ Address 0x800000000) into a Non-Volatile memory\r\n\ +This program supports writing Raw binary from Source LSRAM (@ Address 0x80000000) into a \ +Non-Volatile memory\r\n\ \r\n\ \r\n\ Choose the destination Non-Volatile memory: \r\n\ Type 0 to show this menu\r\n\ - Type 1 copy .hex from LSRAM to SPI Flash \r\n\ - Type 2 copy .hex from LSRAM to MikroBus EEPROM \r\n\ - Type 3 Download .hex from the host PC over UART terminal using YMODEM\r\n\ + Type 1 to copy raw binary from LSRAM to SPI Flash \r\n\ + Type 2 to copy raw binary from LSRAM to MikroBus EEPROM \r\n\ + Type 3 to download a raw binary over UART YMODEM to LSRAM\r\n\ + Type 4 to jump and run loaded application from LSRAM start address\r\n\ "; /* @@ -84,14 +87,11 @@ UART_instance_t g_uart; * I2C instance data. *****************************************************************************/ #define I2C_XFR_DATA_LEN 258u // 2 byte address + 256 bytes data -//#define I2C_XFR_DATA_LEN 16u + uint8_t target_slave_addr = 0x50; uint8_t i2c_tx_buffer[I2C_XFR_DATA_LEN]; miv_i2c_instance_t g_miv_i2c_inst; -//uint8_t i2c_tx_buffer[7] = {0x0A,0x0B,0x0C,0x0A,0x0B,0x0C,0x0A}; -//uint16_t write_length;//DATA_LENGTH; - volatile uint32_t g_10ms_count; const uint8_t g_greeting_msg_spi[] = @@ -107,11 +107,11 @@ const char * g_greeting_msg_i2c = /* * Used for bootstrap from SPI FLASH - * The LSRAM max size is 64K. - * Assuming the executable 32k byte. - * Copy the whole 32k chunk from LSRAM to flash. + * The Libero Design specifies a LSRAM size of 128KB and a flash size of 32KB + * The 32KB chunk from LSRAM is copied to flash */ #define FLASH_EXECUTABLE_SIZE 32768u +#define LSRAM_SIZE 131072u /* MIV I2C interrupt handler */ void MSYS_EI2_IRQHandler(void) @@ -119,7 +119,6 @@ void MSYS_EI2_IRQHandler(void) MIV_I2C_isr (&g_miv_i2c_inst); } - void SysTick_Handler(void) { g_10ms_count += 10; @@ -140,6 +139,7 @@ int main() uint8_t rx_data[UART_RX_BUF_SIZE]; size_t rx_size; static uint32_t file_size = 0; + /************************************************************************** * Initialize CoreUARTapb with its base address, baud value, and line * configuration. @@ -181,10 +181,14 @@ int main() case '3': file_size = rx_app_file((uint8_t *)LSRAM_BASE_ADDRESS_LOAD); break; + case '4': + Bootloader_JumpToApplication((uint32_t)LSRAM_BASE_ADDRESS_LOAD); + break; default: UART_polled_tx_string( &g_uart, "Invalid selection. Try again...\r\n"); break; } + } } @@ -200,17 +204,34 @@ static uint32_t rx_app_file(uint8_t *dest_address) uint8_t *g_bin_base = (uint8_t *)dest_address; uint32_t g_rx_size = 1024 * 1024 * 8; - MRV_systick_config(SYS_CLK_FREQ); + /* Configure systick timer for interrupt at 10msec intervals */ + MRV_systick_config(SYS_CLK_FREQ/100); + + UART_polled_tx_string( &g_uart, + "\r\n------------------------ Starting YModem file transfer ------------------------\r\n" ); + UART_polled_tx_string( &g_uart, + "Please select file and initiate transfer on host computer.\r\n" ); - UART_polled_tx_string( &g_uart, "\r\n------------------------ Starting YModem file transfer ------------------------\r\n" ); - UART_polled_tx_string( &g_uart, "Please select file and initiate transfer on host computer.\r\n" ); + /* data copied to LSRAM */ + received = ymodem_receive(g_bin_base, g_rx_size, file_name, LSRAM_SIZE); - received = ymodem_receive(g_bin_base, g_rx_size, file_name); + if(received) + { + UART_polled_tx_string( &g_uart, + "\r\n----------------------- YModem file transfer Completed -------------------\r\n"); + + } + else + { + UART_polled_tx_string( &g_uart, + "\r\n--- YModem file transfer Failed- Aborted/File size exceeds limit --------\r\n"); + } + + UART_polled_tx_string( &g_uart, g_bootstrap_choice); return received; } - void copy_hex_to_i2ceeprom(void) { uint8_t rx_size = 0u; @@ -236,12 +257,16 @@ void copy_hex_to_i2ceeprom(void) #endif MRV_systick_config(SYS_CLK_FREQ); + + /* Copy 32KB from LSRAM which has the size of 128KB */ write_program_to_i2ceeprom((uint8_t *)LSRAM_BASE_ADDRESS_LOAD, FLASH_EXECUTABLE_SIZE); } void copy_hex_to_spiflash(void) { spi_flash_init(FLASH_CORE_SPI_BASE); + + /* Copy 32KB from LSRAM which has the size of 128KB */ write_program_to_flash((uint8_t *)LSRAM_BASE_ADDRESS_LOAD, FLASH_EXECUTABLE_SIZE); } @@ -252,12 +277,12 @@ static int write_program_to_i2ceeprom(uint8_t *write_buf, uint32_t file_size) { uint32_t mem_addr = 0x80000000; // source address uint32_t mem_val; // read data word from source - uint8_t page_no; // I2C device page no. Each page is 256 Bytes. 256 x 64 = 16 Kb + uint8_t page_no; // I2C device page no. Each page is 256 Bytes. 256 x 64 = 16 KB miv_i2c_status_t status; volatile uint8_t miv_i2c_status = 0u; UART_polled_tx_string(&g_uart, (const uint8_t *)"\r\nWriting Data into EEPROM using MIV_I2C\n\r"); - for (page_no = 0; page_no <= 127 ; page_no++) //32kb = 128 pages of 256 bytes + for (page_no = 0; page_no <= 127 ; page_no++) //32KB = 128 pages of 256 Bytes { uint16_t n = 0; i2c_tx_buffer[0] = page_no; // 1st word address byte (needs to increment for pages) @@ -289,6 +314,7 @@ static int write_program_to_i2ceeprom(uint8_t *write_buf, uint32_t file_size) UART_polled_tx_string(&g_uart, (const uint8_t *)"\r\nMIV_I2C Write Complete!\n\r"); return 0u; } + /* * Write to flash memory */ @@ -302,8 +328,10 @@ static int write_program_to_flash(uint8_t *write_buf, uint32_t file_size) spi_flash_status_t result; struct device_Info DevInfo; - UART_polled_tx_string( &g_uart, "\r\n---------------------- Writing SPI flash from DDR memory ----------------------\r\n" ); - UART_polled_tx_string( &g_uart, "This may take several minutes to complete if writing a large file.\r\n" ); + UART_polled_tx_string( &g_uart, + "\r\n---------------------- Writing SPI flash from DDR memory ----------------------\r\n" ); + UART_polled_tx_string( &g_uart, + "This may take several minutes to complete if writing a large file.\r\n" ); spi_flash_control_hw( SPI_FLASH_RESET, 0, &status ); @@ -583,3 +611,16 @@ static int write_program_to_flash(uint8_t *write_buf, uint32_t file_size) return(0); } + +/*------------------------------------------------------------------------------ + * Call this function if you want to switch to another program. + */ +static void Bootloader_JumpToApplication(uint32_t reset_vector) +{ + __asm__ volatile ("fence.i"); + __asm__ volatile("mv ra, a0"); + __asm__ volatile("ret"); + + /*User application execution should now start and never return here.... */ + __builtin_unreachable(); +} diff --git a/bootloaders/miv-rv32-bootloader/src/application/bootstrap/bootstrap.c b/bootloaders/miv-rv32-bootloader/src/application/bootstrap/bootstrap.c index 7181bd4..8cffbe5 100644 --- a/bootloaders/miv-rv32-bootloader/src/application/bootstrap/bootstrap.c +++ b/bootloaders/miv-rv32-bootloader/src/application/bootstrap/bootstrap.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -11,13 +11,13 @@ */ #include #include "miv_rv32_hal/miv_rv32_hal.h" -#include "drivers/fabric_ip/CoreUARTapb/core_uart_apb.h" -#include "drivers/fabric_ip/miv_i2c/miv_i2c.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" +#include "drivers/fpga_ip/miv_i2c/miv_i2c.h" #include "drivers/off_chip/spi_flash/spi_flash.h" #define FLASH_SECTOR_SIZE 65536 /* flash memory size */ -#define FLASH_SECTORS 128 // There are 126 sectors of 64kB size, using 124 -#define FLASH_BLOCK_SIZE 4096 //Sectors compose of 4kB eraseable blocks +#define FLASH_SECTORS 128 // There are 126 sectors of 64KB size, using 124 +#define FLASH_BLOCK_SIZE 4096 //Sectors compose of 4KB eraseable blocks #define FLASH_SEGMENT_SIZE 256 // Write segment size is 256 #define FLASH_BLOCK_SEGMENTS (FLASH_BLOCK_SIZE / FLASH_SEGMENT_SIZE) @@ -50,11 +50,13 @@ static void copy_hex_to_spiflash(void); const uint8_t g_bootstrap_choice[] = "\r\n\r\n\ ======================================================================================\r\n\ - MIV_ESS Bootstrap support utility to load binary executable from LSRRAM to Non-Volatile memory \r\n\ + MIV_ESS Bootstrap support utility to load binary executable from LSRRAM to \ + Non-Volatile memory \r\n\ ======================================================================================\r\n\ \r\n\ \r\n\ -This program supports writing HEX data from Source LSRAM (@ Address 0x800000000) into a Non-Volatile memory\r\n\ +This program supports writing HEX data from Source LSRAM (@ Address 0x800000000) into \ +a Non-Volatile memory\r\n\ \r\n\ \r\n\ Choose the destination Non-Volatile memory: \r\n\ @@ -216,12 +218,22 @@ void copy_hex_to_i2ceeprom(void) #endif MRV_systick_config(SYS_CLK_FREQ); + + /* The LSRAM used in the Libero Design has a size of 64KB. However, + * it is important to note that the maximum size of the I2C eeprom + * when copying from the LSRAM is 32KB + */ write_program_to_i2ceeprom((uint8_t *)LSRAM_BASE_ADDRESS_LOAD, FLASH_EXECUTABLE_SIZE); } void copy_hex_to_spiflash(void) { spi_flash_init(FLASH_CORE_SPI_BASE); + + /* The LSRAM used in the Libero Design has a size of 64KB. However, + * it is important to note that the maximum size of the SPI flash + * when copying from the LSRAM is 32KB + */ write_program_to_flash((uint8_t *)LSRAM_BASE_ADDRESS_LOAD, FLASH_EXECUTABLE_SIZE); } @@ -232,12 +244,12 @@ static int write_program_to_i2ceeprom(uint8_t *write_buf, uint32_t file_size) { uint32_t mem_addr = 0x80000000; // source address uint32_t mem_val; // read data word from source - uint8_t page_no; // I2C device page no. Each page is 256 Bytes. 256 x 64 = 16 Kb + uint8_t page_no; // I2C device page no. Each page is 256 Bytes. 256 x 64 = 16 KB miv_i2c_status_t status; volatile uint8_t miv_i2c_status = 0u; UART_polled_tx_string(&g_uart, (const uint8_t *)"\r\nWriting Data into EEPROM using MIV_I2C\n\r"); - for (page_no = 0; page_no <= 127 ; page_no++) //32kb = 128 pages of 256 bytes + for (page_no = 0; page_no <= 127 ; page_no++) //32KB = 128 pages of 256 Bytes { uint16_t n = 0; i2c_tx_buffer[0] = page_no; // 1st word address byte (needs to increment for pages) @@ -282,8 +294,10 @@ static int write_program_to_flash(uint8_t *write_buf, uint32_t file_size) spi_flash_status_t result; struct device_Info DevInfo; - UART_polled_tx_string( &g_uart, "\r\n---------------------- Writing SPI flash from DDR memory ----------------------\r\n" ); - UART_polled_tx_string( &g_uart, "This may take several minutes to complete if writing a large file.\r\n" ); + UART_polled_tx_string( &g_uart, + "\r\n---------------------- Writing SPI flash from DDR memory ----------------------\r\n" ); + UART_polled_tx_string( &g_uart, + "This may take several minutes to complete if writing a large file.\r\n" ); spi_flash_control_hw( SPI_FLASH_RESET, 0, &status ); @@ -800,8 +814,11 @@ static int read_program_from_flash(uint8_t *read_buf, uint32_t read_byte_length) struct device_Info DevInfo; flash_content_t flash_content; - UART_polled_tx_string( &g_uart, "\r\n------------------- Reading from SPI flash into DDR memory --------------------\r\n" ); - UART_polled_tx_string( &g_uart, "This will take several minutes to complete in order to read the full SPI flash \r\ncontent.\r\n" ); + UART_polled_tx_string( &g_uart, + "\r\n------------------- Reading from SPI flash into TCM memory --------------------\r\n" ); + UART_polled_tx_string( &g_uart, + "This will take several minutes to complete in order to read the full SPI \ + flash \r\ncontent.\r\n" ); spi_flash_control_hw( SPI_FLASH_RESET, 0, &status ); diff --git a/bootloaders/miv-rv32-bootloader/src/boards/polarfire-eval-kit/platform_config/driver_config/phy_sw_cfg.h b/bootloaders/miv-rv32-bootloader/src/boards/polarfire-eval-kit/platform_config/driver_config/phy_sw_cfg.h new file mode 100644 index 0000000..6783c90 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/boards/polarfire-eval-kit/platform_config/driver_config/phy_sw_cfg.h @@ -0,0 +1,136 @@ +/***************************************************************************//** + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core10gbasekr_phy_sw_cfg.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief PHY software configuration + * + */ + +#ifndef BOARDS_POLARFIRE_EVAL_KIT_PLATFORM_CONFIG_DRIVER_CONFIG_PHY_SW_CFG_H_ +#define BOARDS_POLARFIRE_EVAL_KIT_PLATFORM_CONFIG_DRIVER_CONFIG_PHY_SW_CFG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/***************************************************************************//** + * Driver versioning macros. + */ +#define CORE_VENDOR "Microchip" +#define CORE_LIBRARY "Firmware" +#define CORE_NAME "Core10GBaseKR_PHY_Driver" +#define CORE_VERSION "x.x.x" + +/***************************************************************************//** + * Supported PHY models, used to control compile time inclusion of the + * associated PHY sub-drivers. + */ +#define CORE10GBASEKR_PHY +#define PF_XCVR_C10GB + +/***************************************************************************//** + * Define this macro to enable performance messages in the application. + */ +#undef C10GBKR_PERFORMANCE_MESSAGES + +/***************************************************************************//** + * User config options for overriding driver defaults of Core10GBaseKR_PHY + * + * These definitions can be overridden by defining the macro and assigning the + * desired value. + */ +#ifdef CORE10GBASEKR_PHY + +/* Main tap limits */ +#undef C10GBKR_LT_MAIN_TAP_MAX_LIMIT +#undef C10GBKR_LT_MAIN_TAP_MIN_LIMIT + +/* Post tap limits */ +#undef C10GBKR_LT_POST_TAP_MAX_LIMIT +#undef C10GBKR_LT_POST_TAP_MIN_LIMIT + +/* Pre tap limits */ +#undef C10GBKR_LT_PRE_TAP_MAX_LIMIT +#undef C10GBKR_LT_PRE_TAP_MIN_LIMIT + +/* Request to be sent to Link Partner + 0U => Preset + 1U => Initialize + */ +#undef C10GBKR_LT_INITIAL_REQUEST + +#undef C10GBKR_LT_INITIALIZE_MAIN_TAP +#undef C10GBKR_LT_INITIALIZE_POST_TAP +#undef C10GBKR_LT_INITIALIZE_PRE_TAP + +/***************************************************************************//** + Override XCVR configurations + */ +#undef PF_XCVR_C10GB_REG_VAL_SER_DRV_CTRL +#undef PF_XCVR_C10GB_REG_VAL_SER_DRV_DATA_CTRL +#undef PF_XCVR_C10GB_REG_VAL_SER_DRV_CTRL_SEL +#undef PF_XCVR_C10GB_REG_VAL_DES_DFE_CAL_CTRL_0 +#undef PF_XCVR_C10GB_REG_VAL_DES_DFE_CAL_CTRL_1 +#undef PF_XCVR_C10GB_REG_VAL_DES_DFE_CAL_CTRL_2 +#undef PF_XCVR_C10GB_REG_VAL_DES_DFE_CAL_CMD +#undef PF_XCVR_C10GB_REG_VAL_SER_RTL_CTRL +#undef PF_XCVR_C10GB_REG_VAL_DES_CDR_CTRL_2 +#undef PF_XCVR_C10GB_REG_VAL_DES_CDR_CTRL_3 +#undef PF_XCVR_C10GB_REG_VAL_DES_DFEEM_CTRL_1 +#undef PF_XCVR_C10GB_REG_VAL_DES_DFEEM_CTRL_2 +#undef PF_XCVR_C10GB_REG_VAL_DES_DFEEM_CTRL_3 +#undef PF_XCVR_C10GB_REG_VAL_DES_DFE_CTRL_2 +#undef PF_XCVR_C10GB_REG_VAL_DES_EM_CTRL_2 + +/***************************************************************************//** + Override Auto-Negotiation data rate configurations + */ +#undef PF_XCVR_C10GB_AN_CFG_DES_RXPLL_DIV +#undef PF_XCVR_C10GB_AN_CFG_PMA_DES_RSTPD_POWER_DOWN +#undef PF_XCVR_C10GB_AN_CFG_PMA_SERDES_RTL_CTRL +#undef PF_XCVR_C10GB_AN_CFG_PMA_DES_RTL_LOCK_CTRL +#undef PF_XCVR_C10GB_AN_CFG_PMA_DES_RSTPD_POWER_UP +#undef PF_XCVR_C10GB_AN_CFG_PCS_LRST_R0_RESET_ASSERT +#undef PF_XCVR_C10GB_AN_CFG_PCS_LRST_R0_RESET_DEASSERT + + +/***************************************************************************//** + Override Link Training data rate configurations + */ +#undef PF_XCVR_C10GB_LT_CFG_PMA_DES_RSTPD_POWER_DOWN +#undef PF_XCVR_C10GB_LT_CFG_PMA_DES_RSTPD_POWER_UP +#undef PF_XCVR_C10GB_LT_CFG_DES_RXPLL_DIV +#undef PF_XCVR_C10GB_LT_CFG_PMA_SERDES_RTL_CTRL +#undef PF_XCVR_C10GB_LT_CFG_PMA_DES_DFE_CAL_BYPASS +#undef PF_XCVR_C10GB_LT_CFG_PCS_LRST_R0_RESET_ASSERT +#undef PF_XCVR_C10GB_LT_CFG_PCS_LRST_R0_RESET_DEASSERT + +#endif /* CORE10GBASEKR_PHY */ + +#ifdef __cplusplus +} +#endif + + +#endif /* BOARDS_POLARFIRE_EVAL_KIT_PLATFORM_CONFIG_DRIVER_CONFIG_PHY_SW_CFG_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/middleware/ymodem/ymodem.c b/bootloaders/miv-rv32-bootloader/src/middleware/ymodem/ymodem.c index 6cf05dc..9b8cde2 100644 --- a/bootloaders/miv-rv32-bootloader/src/middleware/ymodem/ymodem.c +++ b/bootloaders/miv-rv32-bootloader/src/middleware/ymodem/ymodem.c @@ -1,10 +1,12 @@ -/* - * copyright (c) 2015 Microsemi Inc +/******************************************************************************* + * Copyright 2015-2023 Microchip FPGA Embedded Systems Solutions. * * based on ymodem.c for rtdsr, copyright (c) 2011 Pete B. * based on ymodem.c for bootldr, copyright (c) 2001 John G Dorsey * baded on ymodem.c for reimage, copyright (c) 2009 Rich M Legrand * + * SPDX-License-Identifier: MIT + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of @@ -30,7 +32,7 @@ #include "sf2_bl_options.h" #include "sf2_bl_defs.h" #else -#include "drivers/fabric_ip/CoreUARTapb/core_uart_apb.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" #endif #include "ymodem.h" @@ -38,6 +40,9 @@ extern UART_instance_t g_uart; extern volatile uint32_t g_10ms_count; +static uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD]; +static int32_t packet_length; + /***************************************************************************//** * Calculate CRC for block of data. */ @@ -48,13 +53,13 @@ uint16_t sf2bl_crc16(const uint8_t *buf, uint32_t count) while(count--) { - crc = crc ^ *buf++ << 8; + crc = crc ^ (*buf++ << 8); for (i=0; i<8; i++) { if (crc & 0x8000) { - crc = crc << 1 ^ 0x1021; + crc = (crc << 1) ^ 0x1021; } else { @@ -62,11 +67,9 @@ uint16_t sf2bl_crc16(const uint8_t *buf, uint32_t count) } } } - return crc; } - /***************************************************************************//** * The rest of this is only needed for YMODEM builds. */ @@ -173,7 +176,6 @@ void sf2bl_ymodem_deinit(void) * o void _putchar(int c): A serial putchar() call */ - /***************************************************************************//** * */ @@ -189,8 +191,6 @@ static void _sleep(uint32_t seconds_delay) ; } - - /***************************************************************************//** * */ @@ -275,7 +275,6 @@ static int32_t _getchar(int32_t timeout) return(ret_value); } - /***************************************************************************//** * */ @@ -307,7 +306,6 @@ void _putchar(int32_t data) #endif } - /***************************************************************************//** * */ @@ -321,7 +319,6 @@ void _putstring(uint8_t *string) #endif } - /***************************************************************************//** * */ @@ -347,7 +344,6 @@ static uint32_t str_to_u32(uint8_t *str) return acc; } - /***************************************************************************//** * Returns 0 on success, 1 on corrupt packet, -1 on error (timeout): * *length will be set to the length of @@ -414,7 +410,8 @@ static int32_t receive_packet(uint8_t *data, int32_t *length) { *data = (uint8_t)rx_char; /* Store first character of packet */ - for(index = 1; (index < (int32_t)(packet_size + PACKET_OVERHEAD)) && (0 == return_val); ++index) + for(index = 1; (index < (int32_t)(packet_size + PACKET_OVERHEAD)) && (0 == return_val); + ++index) { rx_char = _getchar(PACKET_TIMEOUT); if (rx_char < 0) @@ -439,7 +436,8 @@ static int32_t receive_packet(uint8_t *data, int32_t *length) return_val = 1; } - if((0 == return_val) && (sf2bl_crc16(data + PACKET_HEADER, packet_size + PACKET_TRAILER) != 0)) + if((0 == return_val) && + (sf2bl_crc16(data + PACKET_HEADER, packet_size + PACKET_TRAILER) != 0)) { return_val = 1; } @@ -459,17 +457,15 @@ static int32_t receive_packet(uint8_t *data, int32_t *length) return(return_val); } - /***************************************************************************//** * */ /* Returns the length of the file received, or 0 on error: */ -uint32_t ymodem_receive(uint8_t *buf, uint32_t length, uint8_t *file_name) +uint32_t ymodem_receive(uint8_t *buf, uint32_t length, uint8_t *file_name, uint32_t memory_size) { - static uint8_t packet_data[PACKET_1K_SIZE + PACKET_OVERHEAD]; /* Declare as static as 1K is a lot to put on our stack */ + uint8_t file_size[FILE_SIZE_LENGTH + 1]; uint8_t *file_ptr; - int32_t packet_length; int32_t index; int32_t file_done; int32_t session_done; @@ -505,10 +501,24 @@ uint32_t ymodem_receive(uint8_t *buf, uint32_t length, uint8_t *file_name) while(0 == file_done) { rx_status = receive_packet(packet_data, &packet_length); + switch(rx_status) { case 0: /* Success */ errors = 0; + + if (packets_received > (memory_size/packet_length)) + { + _putchar(CAN); + _putchar(CAN); + _sleep(1); + + /* Terminate transfer immediately */ + file_done = 1; + session_done = 1; + break; + } + switch(packet_length) { case -1: /* abort */ @@ -537,13 +547,14 @@ uint32_t ymodem_receive(uint8_t *buf, uint32_t length, uint8_t *file_name) * with just C seems to work. Only try this if we get a * repeat of packet 0... */ - if((1 == packets_received) && (0 == (packet_data[PACKET_SEQNO_INDEX] & 0xff))) + if((1 == packets_received) && + (0 == (packet_data[PACKET_SEQNO_INDEX] & 0xff))) { - _putchar(CRC); /* Repeated packet 0 error */ + _putchar(CRC); /* Repeated packet 0 error */ } else { - _putchar(NAK); /* Normal out of sequence packet error */ + _putchar(NAK); /* Normal out of sequence packet error */ } } else @@ -572,14 +583,15 @@ uint32_t ymodem_receive(uint8_t *buf, uint32_t length, uint8_t *file_name) file_name[index] = '\0'; - while(*file_ptr != 0) /* Search for nul terminator if not there already */ + while(*file_ptr != 0) /* Check for null terminator if not present */ { ++file_ptr; } ++file_ptr; /* Step over nul */ - for(index = 0; *file_ptr && (*file_ptr != ' ') && (index < FILE_SIZE_LENGTH);) + for(index = 0; *file_ptr && (*file_ptr != ' ') && + (index < FILE_SIZE_LENGTH);) { file_size[index++] = *file_ptr++; } diff --git a/bootloaders/miv-rv32-bootloader/src/middleware/ymodem/ymodem.h b/bootloaders/miv-rv32-bootloader/src/middleware/ymodem/ymodem.h index d50f50c..5ebab98 100644 --- a/bootloaders/miv-rv32-bootloader/src/middleware/ymodem/ymodem.h +++ b/bootloaders/miv-rv32-bootloader/src/middleware/ymodem/ymodem.h @@ -1,12 +1,31 @@ -/* ymodem for SmartFusion2 Bootloader - * - * copyright (c) 2015 Microsemi Inc +/******************************************************************************* + * Copyright 2015-2023 Microchip FPGA Embedded Systems Solutions. * * based on ymodem for RTD Serial Recovery (rtdsr) * copyright (c) 2011 Pete B. * * based on ymodem.h for bootldr, copyright (c) 2001 John G Dorsey * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of @@ -34,7 +53,7 @@ #define PACKET_OVERHEAD (PACKET_HEADER + PACKET_TRAILER) #define PACKET_SIZE (128) #define PACKET_1K_SIZE (1024) -#define PACKET_TIMEOUT (1) +#define PACKET_TIMEOUT (10) #define FILE_NAME_LENGTH (64) #define FILE_SIZE_LENGTH (16) @@ -53,8 +72,8 @@ void sf2bl_ymodem_init(void); void sf2bl_ymodem_deinit(void); -uint32_t ymodem_receive(uint8_t *buf, uint32_t length, uint8_t *file_name); -uint16_t sf2bl_crc16(const uint8_t *buf, uint32_t count); +uint32_t ymodem_receive(uint8_t *buf, uint32_t length, uint8_t *file_name, uint32_t memory_size); +uint16_t sf2bl_crc16(const uint8_t *buf, uint32_t count)__attribute__((optimize("O3"))); void _putchar(int32_t data); void _putstring(uint8_t *string); diff --git a/bootloaders/miv-rv32-bootloader/src/platform/README.md b/bootloaders/miv-rv32-bootloader/src/platform/README.md new file mode 100644 index 0000000..f7f6030 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/README.md @@ -0,0 +1,27 @@ +# Mi-V soft processor platform source code + +## Repo organization + +``` + + | + |-- drivers + | |- fpga_ip + | | | CoreGPIO + | | | CoreSysServices_PF + | | | CoreUARTapb + | | + | |- off_chip + | | | . + | | | . + | | + |-- hal + | | + |-- miv_rv32_hal + + +``` + +The drivers published here are compatible with the improved SoftConsole project folder structure being used in the latest [example projects](https://github.com/Mi-V-Soft-RISC-V/miv-rv32-bare-metal-examples). +These drivers can also be used with the legacy folder structure (projects released via Firmware Catalog) by defining the **LEGACY_DIR_STRUCTURE** macro in the SoftConsole project settings. + diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/Jenkinsfile b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/Jenkinsfile new file mode 100644 index 0000000..3f0f8f4 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/Jenkinsfile @@ -0,0 +1,2 @@ +@Library('automated-testing-library') _ +pipelineSoftIPSrc() \ No newline at end of file diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/README.md b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/README.md new file mode 100644 index 0000000..8561920 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/README.md @@ -0,0 +1 @@ +# Core10GBASEKR_PHY Source \ No newline at end of file diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy.c new file mode 100644 index 0000000..25ed295 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy.c @@ -0,0 +1,447 @@ +#include "phy.h" +#include "core10gbasekr_phy_link_training.h" + +/*------------------------Private Definitions---------------------------------*/ +#define AN_RESET (1U) +#define AN_ENABLE (1U) +#define AN_RESTART (1U) + +#define TX_CTRL_DATA (0U) +#define TX_CTRL_AN (2U) +#define TX_CTRL_LT (3U) + +/*------------------------Public Variables------------------------------------*/ +extern uint32_t prbs_cnt; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + Please see phy.h for description + */ +void +PHY10GKR_init +( + phy10gkr_instance_t * this_phy, + addr_t base_addr +) +{ + /* Set Core10GBaseKR PHY Base addresses */ + this_phy->base_addr = base_addr; + this_phy->an_base_addr = this_phy->base_addr | C10GB_AN_BASE_OFFSET; + this_phy->lt_base_addr = this_phy->base_addr | C10GB_LT_BASE_OFFSET; + this_phy->tx_ctrl_base_addr = this_phy->base_addr | + C10GB_TX_CTRL_BASE_OFFSET; + this_phy->rx_status_base_addr = this_phy->base_addr | + C10GB_RX_STATUS_BASE_OFFSET; + + PHY10GKR_config(this_phy); +} + +/***************************************************************************//** + Please see phy.h for description + */ +void +PHY10GKR_config +( + phy10gkr_instance_t * this_phy +) +{ + /* set data path to AN block */ + HAL_set_32bit_reg_field(this_phy->tx_ctrl_base_addr, + C10GB_TX_CTRL_PMA_DATA, + TX_CTRL_AN); + + /* reset phy tx and rx */ + HAL_set_32bit_reg_field(this_phy->tx_ctrl_base_addr, + C10GB_TX_CTRL_TX_RESET, + 0x1); + HAL_set_32bit_reg_field(this_phy->tx_ctrl_base_addr, + C10GB_TX_CTRL_RX_RESET, + 0x1); + + /* set data path to AN block */ + HAL_set_32bit_reg_field(this_phy->tx_ctrl_base_addr, + C10GB_TX_CTRL_PMA_DATA, + TX_CTRL_AN); + + /* transmit equalization tap limit configurations */ + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_MAX_MAIN_TAP, + C10GBKR_LT_MAIN_TAP_MAX_LIMIT); + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_MIN_MAIN_TAP, + C10GBKR_LT_MAIN_TAP_MIN_LIMIT); + + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_MAX_POST_TAP, + C10GBKR_LT_POST_TAP_MAX_LIMIT); + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_MIN_POST_TAP, + C10GBKR_LT_POST_TAP_MIN_LIMIT); + + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_MAX_PRE_TAP, + C10GBKR_LT_PRE_TAP_MAX_LIMIT); + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_MIN_PRE_TAP, + C10GBKR_LT_PRE_TAP_MIN_LIMIT); + + /* link partner preset conditions */ + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_PRESET_MAIN_TAP, + C10GBKR_LT_PRESET_MAIN_TAP); + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_PRESET_POST_TAP, + C10GBKR_LT_PRESET_POST_TAP); + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_PRESET_PRE_TAP, + C10GBKR_LT_PRESET_PRE_TAP); + + /* link partner preset conditions */ + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_INIT_MAIN_TAP, + C10GBKR_LT_INITIALIZE_MAIN_TAP); + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_INIT_POST_TAP, + C10GBKR_LT_INITIALIZE_POST_TAP); + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_INIT_PRE_TAP, + C10GBKR_LT_INITIALIZE_PRE_TAP); + + /* track number of fails since begining */ + uint32_t tmp_fail_count = this_phy->lt.fail_cnt; + uint32_t tmp_complete_count = this_phy->lt.complete_cnt; + this_phy->lt = (phy10gkr_lt_instance_t){0}; + this_phy->lt.fail_cnt = tmp_fail_count; + this_phy->lt.complete_cnt = tmp_complete_count; + + /* set the request that will be sent to the link partner */ + this_phy->lt.rx_request = C10GBKR_LT_INITIAL_REQUEST; + + /* Set AN and LT api state machine to init state */ + this_phy->an.api_state = AN_API_SM_INIT; + this_phy->lt.api_state = LT_API_SM_INIT; + + /* Set status to original condition */ + this_phy->an.status = STATUS_AN_INCOMPLETE; + this_phy->lt.status = STATUS_LT_INCOMPLETE; + + /* clear link training tap data */ + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_LOCAL_RCVR_LOCKED, LOCAL_RXCVR_UNLOCKED); + this_phy->lt.local_rxcvr = LOCAL_RXCVR_UNLOCKED; + + + this_phy->lt.main = (const phy10gkr_coeff_update_t) {0}; + this_phy->lt.post = (const phy10gkr_coeff_update_t) {0}; + this_phy->lt.pre = (const phy10gkr_coeff_update_t) {0}; + + this_phy->lt.lp_cal_sweep_state = MAIN_TAP; + + this_phy->lt.tx_equ_cnt = 0; + this_phy->lt.rx_cal_cnt = 0; + + prbs_cnt = 0; +} + +/***************************************************************************//** + Please see phy.h for description + */ +void +PHY10GKR_autonegotiate_sm +( + phy10gkr_instance_t * this_phy +) +{ + switch(this_phy->an.api_state) + { + case AN_API_SM_INIT: + /* Tx control: Auto-negotiation, PCS data transmitted to Serdes */ + HAL_set_32bit_reg_field(this_phy->tx_ctrl_base_addr, + C10GB_TX_CTRL_PMA_DATA, TX_CTRL_AN); + + /* set link fail inhibit timer time to 500 ms*/ + HAL_set_32bit_reg(this_phy->an_base_addr, + C10GB_AN_LINK_FAIL_INHIBIT_TIMER, + C10GBKR_AN_LINK_FAIL_INHITBIT_TIMER); + + /* Reset auto-negotiation. */ + HAL_set_32bit_reg_field(this_phy->an_base_addr, + C10GB_AN_RESET, + AN_RESET); + + /* Enable auto-negotiation. */ + HAL_set_32bit_reg_field(this_phy->an_base_addr, + C10GB_AN_ENABLE, + AN_ENABLE); + + /* Restart auto-negotiation */ + HAL_set_32bit_reg_field(this_phy->an_base_addr, + C10GB_AN_RESTART, + AN_RESTART); + + this_phy->an.status = STATUS_AN_INCOMPLETE; + this_phy->an.api_state = AN_API_SM_STATUS_UPDATE; + break; + + case AN_API_SM_STATUS_UPDATE: + /* Get auto-negotiation state machine state */ + this_phy->an.state = HAL_get_32bit_reg_field(this_phy->an_base_addr, + C10GB_AN_STATE); + if(ST_AN_GOOD_CHECK == this_phy->an.state) + { + this_phy->an.complete_cnt++; + + this_phy->an.status = STATUS_AN_COMPLETE; + + + /* Set data path to LT block, enable LT and timers */ + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_MAX_WAIT_TIMER, + MAX_WAIT_TIMER_500MS); + + HAL_set_32bit_reg_field(this_phy->tx_ctrl_base_addr, + C10GB_TX_CTRL_PMA_DATA, + TX_CTRL_LT); + + this_phy->lt.timer.start = PHY10GKR_get_current_time_ms(); + } + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/***************************************************************************//** + Please see phy.h for description + */ +void +PHY10GKR_link_training_sm +( + phy10gkr_instance_t * this_phy +) +{ + uint32_t c10gbkr_status = 0; + + this_phy->lt.state = HAL_get_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_TRAINING_SM); + + switch(this_phy->lt.api_state) + { + case LT_API_SM_INIT: + if(C10GBKR_LT_PRESET == this_phy->lt.rx_request) + { + HAL_set_32bit_reg(this_phy->lt_base_addr, C10GB_LT_CTRL, + (C10GB_LT_RESTART_EN_MASK | C10GB_LT_PRESET_MASK)); + } + else if(C10GBKR_LT_INITALISE == this_phy->lt.rx_request) + { + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_CTRL, + (C10GB_LT_RESTART_EN_MASK | C10GB_LT_INIT_MASK)); + } + + this_phy->lt.api_state = LT_API_SM_STATUS_UPDATE; + break; + + case LT_API_SM_STATUS_UPDATE: + c10gbkr_status = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_STATUS); + + this_phy->lt.timer.end = PHY10GKR_get_current_time_ms() - + this_phy->lt.timer.start; + + if((c10gbkr_status & C10GB_LT_TRAINING_FAIL_MASK) || + this_phy->lt.timer.end > LT_SOFTWARE_WAIT_TIMER_MS) + { + this_phy->lt.fail_cnt++; + this_phy->lt.status = STATUS_LT_FAILURE; + + /* disable lt hardware in the case that the software timer + * trigger the failure + */ + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_RESTART_EN, + 0x0); + break; + } + + if(c10gbkr_status & C10GB_LT_REQ_TX_EQUAL_MASK) + { + uint32_t tx_main_tap; + uint32_t tx_post_tap; + uint32_t tx_pre_tap; + + this_phy->lt.tx_equ_cnt++; + + tx_main_tap = HAL_get_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_TX_NEW_MAIN_TAP); + tx_post_tap = HAL_get_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_TX_NEW_POST_TAP) - + C10GBKR_LT_POST_TAP_MAX_LIMIT; + tx_pre_tap = HAL_get_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_TX_NEW_PRE_TAP) - + C10GBKR_LT_PRE_TAP_MAX_LIMIT; + + PHY10GKR_serdes_tx_equalization(tx_main_tap, + tx_post_tap, + tx_pre_tap); + + /* signal to hardware to set tx status report field */ + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_EQUAL, + C10GB_LT_TX_EQUAL_PRE_DONE_MASK | + C10GB_LT_TX_EQUAL_POST_DONE_MASK | + C10GB_LT_TX_EQUAL_MAIN_DONE_MASK | + C10GB_LT_TX_EQUAL_DONE_MASK); + } + + if((c10gbkr_status & C10GB_LT_REQ_RX_CAL_MASK) && + LOCAL_RXCVR_UNLOCKED == this_phy->lt.local_rxcvr) + { + /* signal to hardware to set tx coefficient update field */ + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_RX_CAL_DONE, + 1U); + + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_RX_CAL_DONE, + 0U); + + this_phy->lt.rx_cal_cnt++; + if(C10GBKR_LT_PRESET == this_phy->lt.tx_request) + { + link_partner_calibration_sm(this_phy); + } + else if(C10GBKR_LT_INITALISE == this_phy->lt.tx_request) + { + this_phy->lt.local_rxcvr = LOCAL_RXCVR_LOCKED; + + this_phy->lt.rcvr_cnt++; + + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_LOCAL_RCVR_LOCKED, + LOCAL_RXCVR_LOCKED); + } + + } + + if(c10gbkr_status & C10GB_LT_SIGNAL_DETECT_MASK) + { + this_phy->lt.complete_cnt++; + + /* Tx control: CL49 Data, PCS data transmitted to Serdes */ + HAL_set_32bit_reg_field(this_phy->tx_ctrl_base_addr, + C10GB_TX_CTRL_PMA_DATA, + TX_CTRL_DATA); + this_phy->lt.sig_cnt++; + this_phy->lt.status = STATUS_LT_COMPLETE; + break; + } + break; + + default: + HAL_ASSERT(0); + break; + } + this_phy->lt.sm_cycle_cnt++; +} + +/***************************************************************************//** + Please see phy.h for description + */ +uint32_t +PHY10GKR_10gbasekr_sm +( + phy10gkr_instance_t * this_phy +) +{ + switch(this_phy->c10gbkr_state) + { + case AN_SERDES_CONFIG: + this_phy->c10gbkr_status = AN_SERDES_CONFIGURATION; + PHY10GKR_config(this_phy); + PHY10GKR_serdes_an_config(); + this_phy->c10gbkr_state = AN_SM; + break; + + case AN_SM: + this_phy->c10gbkr_status = AN_IN_PROGRESS; + + PHY10GKR_autonegotiate_sm(this_phy); + if(STATUS_AN_COMPLETE == this_phy->an.status) + { + this_phy->c10gbkr_status = AN_COMPLETE; + + this_phy->c10gbkr_state = LT_SERDES_CONFIG; + } + break; + + case LT_SERDES_CONFIG: + this_phy->c10gbkr_status = LT_SERDES_CONFIGURATION; + if(PHY10GKR_serdes_lt_config() >= 1) + { + this_phy->c10gbkr_status = LT_SERDES_CAL_FAILURE; + this_phy->c10gbkr_state = AN_SERDES_CONFIG; + } + else + { + this_phy->c10gbkr_status = LT_SERDES_CAL_COMPLETE; + this_phy->c10gbkr_state = LT_SM; + } + break; + + case LT_SM: + this_phy->c10gbkr_status = LT_IN_PROGRESS; + PHY10GKR_link_training_sm(this_phy); + + if(STATUS_LT_FAILURE == this_phy->lt.status) + { + /* reset the state machine for next time its called */ + this_phy->c10gbkr_state = AN_SERDES_CONFIG; + + this_phy->c10gbkr_status = LT_FAILURE; + } + else if(STATUS_LT_COMPLETE == this_phy->lt.status) + { + this_phy->c10gbkr_state = LINK_ESTABLISHED_CHECK; + this_phy->c10gbkr_status = LINK_ESTABLISHED; + } + break; + + case LINK_ESTABLISHED_CHECK: + if(PHY10GKR_serdes_cdr_lock() > 0) + { + /* reset the state machine for next time its called */ + this_phy->c10gbkr_state = AN_SERDES_CONFIG; + + this_phy->c10gbkr_status = LINK_BROKEN; + } + else + { + this_phy->c10gbkr_status = LINK_ESTABLISHED; + } + break; + + default: + HAL_ASSERT(0); + break; + } + return this_phy->c10gbkr_status; +} + +/***************************************************************************//** + Please see phy.h for description + */ +void +PHY10GKR_set_lane_los_signal +( + phy10gkr_instance_t * this_phy, + uint32_t state +) +{ + HAL_set_32bit_reg_field(this_phy->tx_ctrl_base_addr, + C10GB_TX_CTRL_XCVR_LOS, state); +} diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_link_training.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_link_training.c new file mode 100644 index 0000000..e2225c1 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_link_training.c @@ -0,0 +1,548 @@ +/***************************************************************************//** + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core10gbasekr_phy_link_training.c + * @author Microchip FPGA Embedded Systems Solutions + * @brief PHY software configuration + * + */ +#include "phy.h" +#include "core10gbasekr_phy_link_training.h" + +/*------------------------Private Variables-----------------------------------*/ +uint32_t prbs_arr[64] = {0}; +uint32_t prbs_cnt = 0; + +/***************************************************************************//** + Please see core10gbasekr_phy_link_training.h for description + */ +void +link_partner_calibration_sm +( + phy10gkr_instance_t * this_phy +) +{ + switch(this_phy->lt.lp_cal_sweep_state) + { + case MAIN_TAP: + link_partner_main_sweep(this_phy); + break; + + case POST_TAP: + link_partner_post_sweep(this_phy); + break; + + case PRE_TAP: + link_partner_pre_sweep(this_phy); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/***************************************************************************//** + Please see core10gbasekr_phy_link_training.h for description + */ +void +link_partner_main_sweep +( + phy10gkr_instance_t * this_phy +) +{ + phy10gkr_coeff_status_report_t tap_coeff = HAL_get_32bit_reg_field( + this_phy->lt_base_addr, + C10GB_LT_RCVD_COEFF_MAIN_VALUE); + + if(this_phy->lt.main.lp_tap_cal_state == TAP_OPTIMISE_CAL) + { + if(this_phy->lt.main.optimal_cnt == (this_phy->lt.main.optimal_index)) + { + lt_tap_increment(this_phy, POST_TAP); + this_phy->lt.post.cnt++; + this_phy->lt.post.inc_cnt++; + this_phy->lt.lp_cal_sweep_state = POST_TAP; + prbs_cnt = 0; + } + else + { + lt_tap_increment(this_phy, MAIN_TAP); + this_phy->lt.main.optimal_cnt++; + } + } + else + { + switch(tap_coeff) + { + case LT_COEFF_STATUS_MAX: + prbs_arr[prbs_cnt] = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_PRBS_ERR_WRD); + prbs_cnt++; + lt_tap_decrement(this_phy, MAIN_TAP); + this_phy->lt.main.cnt++; + this_phy->lt.main.dec_cnt++; + break; + + case LT_COEFF_STATUS_NOT_UPDATED: + lt_tap_hold(this_phy, MAIN_TAP); + this_phy->lt.main.cnt++; + break; + + case LT_COEFF_STATUS_UPDATED: + prbs_arr[prbs_cnt] = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_PRBS_ERR_WRD); + prbs_cnt++; + lt_tap_decrement(this_phy, MAIN_TAP); + this_phy->lt.main.cnt++; + this_phy->lt.main.dec_cnt++; + break; + + case LT_COEFF_STATUS_MIN: + prbs_arr[prbs_cnt] = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_PRBS_ERR_WRD); + prbs_cnt++; + + this_phy->lt.main.optimal_index = lt_get_optimal_tap_index( + prbs_arr, + prbs_cnt); + + if(this_phy->lt.main.optimal_index == 0) + { + lt_tap_increment(this_phy, POST_TAP); + this_phy->lt.post.cnt++; + this_phy->lt.post.inc_cnt++; + this_phy->lt.lp_cal_sweep_state = POST_TAP; + prbs_cnt = 0; + } + else + { + this_phy->lt.main.lp_tap_cal_state = TAP_OPTIMISE_CAL; + lt_tap_increment(this_phy, MAIN_TAP); + this_phy->lt.main.optimal_cnt++; + } + break; + + default: + HAL_ASSERT(0); + break; + } + } +} + +/***************************************************************************//** + Please see core10gbasekr_phy_link_training.h for description + */ +void +link_partner_post_sweep +( + phy10gkr_instance_t * this_phy +) +{ + phy10gkr_coeff_status_report_t tap_coeff = HAL_get_32bit_reg_field( + this_phy->lt_base_addr, + C10GB_LT_RCVD_COEFF_POST_VALUE); + + if(this_phy->lt.post.lp_tap_cal_state == TAP_OPTIMISE_CAL) + { + if(this_phy->lt.post.optimal_cnt == (this_phy->lt.post.optimal_index)) + { + lt_tap_increment(this_phy, PRE_TAP); + this_phy->lt.pre.cnt++; + this_phy->lt.pre.inc_cnt++; + this_phy->lt.lp_cal_sweep_state = PRE_TAP; + prbs_cnt = 0; + } + else + { + lt_tap_increment(this_phy, POST_TAP); + this_phy->lt.post.optimal_cnt++; + } + } + else + { + switch(tap_coeff) + { + case LT_COEFF_STATUS_MAX: + prbs_arr[prbs_cnt] = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_PRBS_ERR_WRD); + prbs_cnt++; + lt_tap_decrement(this_phy, POST_TAP); + this_phy->lt.post.cnt++; + this_phy->lt.post.dec_cnt++; + break; + + case LT_COEFF_STATUS_NOT_UPDATED: + lt_tap_hold(this_phy, POST_TAP); + this_phy->lt.post.cnt++; + break; + + case LT_COEFF_STATUS_UPDATED: + prbs_arr[prbs_cnt] = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_PRBS_ERR_WRD); + prbs_cnt++; + lt_tap_decrement(this_phy, POST_TAP); + this_phy->lt.post.cnt++; + this_phy->lt.post.dec_cnt++; + break; + + case LT_COEFF_STATUS_MIN: + prbs_arr[prbs_cnt] = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_PRBS_ERR_WRD); + prbs_cnt++; + + this_phy->lt.post.optimal_index = lt_get_optimal_tap_index( + prbs_arr, + prbs_cnt); + + if(this_phy->lt.post.optimal_index == 0) + { + lt_tap_increment(this_phy, PRE_TAP); + this_phy->lt.pre.cnt++; + this_phy->lt.pre.inc_cnt++; + this_phy->lt.lp_cal_sweep_state = PRE_TAP; + prbs_cnt = 0; + } + else + { + this_phy->lt.post.lp_tap_cal_state = TAP_OPTIMISE_CAL; + lt_tap_increment(this_phy, POST_TAP); + this_phy->lt.post.optimal_cnt++; + } + break; + + default: + HAL_ASSERT(0); + break; + } + } +} + +/***************************************************************************//** + link partner pre cursor sweep + */ +void +link_partner_pre_sweep +( + phy10gkr_instance_t * this_phy +) +{ + phy10gkr_coeff_status_report_t tap_coeff = HAL_get_32bit_reg_field( + this_phy->lt_base_addr, + C10GB_LT_RCVD_COEFF_PRE_VALUE); + + if(this_phy->lt.pre.lp_tap_cal_state == TAP_OPTIMISE_CAL) + { + + if(this_phy->lt.pre.optimal_cnt == (this_phy->lt.pre.optimal_index)) + { + while((PHY10GKR_serdes_dfe_cal() == 1) && + (STATUS_LT_FAILURE != this_phy->lt.status)) + { + uint32_t c10gbkr_status = HAL_get_32bit_reg( + this_phy->lt_base_addr, + C10GB_LT_STATUS); + + this_phy->lt.timer.end = PHY10GKR_get_current_time_ms() - + this_phy->lt.timer.start; + + if((c10gbkr_status & C10GB_LT_TRAINING_FAIL_MASK) || + this_phy->lt.timer.end > LT_SOFTWARE_WAIT_TIMER_MS) + { + this_phy->lt.status = STATUS_LT_FAILURE; + break; + } + } + + if(STATUS_LT_FAILURE != this_phy->lt.status) + { + /* All sweeps complete set to best ber index */ + this_phy->lt.local_rxcvr = LOCAL_RXCVR_LOCKED; + + this_phy->lt.rcvr_cnt++; + + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_LOCAL_RCVR_LOCKED, + LOCAL_RXCVR_LOCKED); + prbs_cnt = 0; + } + } + else + { + lt_tap_increment(this_phy, PRE_TAP); + this_phy->lt.pre.optimal_cnt++; + } + } + else + { + switch(tap_coeff) + { + case LT_COEFF_STATUS_MAX: + prbs_arr[prbs_cnt] = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_PRBS_ERR_WRD); + prbs_cnt++; + lt_tap_decrement(this_phy, PRE_TAP); + this_phy->lt.pre.cnt++; + this_phy->lt.pre.dec_cnt++; + break; + + case LT_COEFF_STATUS_NOT_UPDATED: + lt_tap_hold(this_phy, PRE_TAP); + this_phy->lt.pre.cnt++; + break; + + case LT_COEFF_STATUS_UPDATED: + prbs_arr[prbs_cnt] = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_PRBS_ERR_WRD); + prbs_cnt++; + lt_tap_decrement(this_phy, PRE_TAP); + this_phy->lt.pre.cnt++; + this_phy->lt.pre.dec_cnt++; + break; + + case LT_COEFF_STATUS_MIN: + prbs_arr[prbs_cnt] = HAL_get_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_PRBS_ERR_WRD); + prbs_cnt++; + + this_phy->lt.pre.optimal_index = lt_get_optimal_tap_index( + prbs_arr, + prbs_cnt); + + if(this_phy->lt.post.optimal_index == 0) + { + while((PHY10GKR_serdes_dfe_cal() == 1) && + (STATUS_LT_FAILURE != this_phy->lt.status)) + { + uint32_t c10gbkr_status = HAL_get_32bit_reg( + this_phy->lt_base_addr, + C10GB_LT_STATUS); + + this_phy->lt.timer.end = PHY10GKR_get_current_time_ms() + - this_phy->lt.timer.start; + + if((c10gbkr_status & C10GB_LT_TRAINING_FAIL_MASK) + || (this_phy->lt.timer.end > + LT_SOFTWARE_WAIT_TIMER_MS)) + { + this_phy->lt.status = STATUS_LT_FAILURE; + break; + } + } + + if(STATUS_LT_FAILURE != this_phy->lt.status) + { + /* All sweeps complete set to best ber index */ + this_phy->lt.local_rxcvr = LOCAL_RXCVR_LOCKED; + + this_phy->lt.rcvr_cnt++; + + HAL_set_32bit_reg_field(this_phy->lt_base_addr, + C10GB_LT_LOCAL_RCVR_LOCKED, + LOCAL_RXCVR_LOCKED); + prbs_cnt = 0; + } + } + else + { + this_phy->lt.pre.lp_tap_cal_state = TAP_OPTIMISE_CAL; + lt_tap_increment(this_phy, PRE_TAP); + this_phy->lt.pre.optimal_cnt++; + } + break; + + default: + HAL_ASSERT(0); + break; + } + } +} + +/***************************************************************************//** + * set the decrement bit of a specific transmit equalizer tap register + */ +void +lt_tap_decrement +( + phy10gkr_instance_t * this_phy, + phy10gkr_tx_equalizer_tap_t tap_type +) +{ + switch(tap_type) + { + case MAIN_TAP: + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_COEFF_CFG, + C10GB_LT_TX_DEC_MAIN_MASK); + break; + + case POST_TAP: + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_COEFF_CFG, + C10GB_LT_TX_DEC_POST_MASK); + break; + + case PRE_TAP: + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_COEFF_CFG, + C10GB_LT_TX_DEC_PRE_MASK); + break; + + default: + HAL_ASSERT(0); + break; + } +} + + +/***************************************************************************//** + * set the hold bit of a specific transmit equalizer tap register + */ +void +lt_tap_hold +( + phy10gkr_instance_t * this_phy, + phy10gkr_tx_equalizer_tap_t tap_type +) +{ + switch(tap_type) + { + case MAIN_TAP: + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_COEFF_CFG, + C10GB_LT_TX_HOLD_MAIN_MASK); + break; + + case POST_TAP: + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_COEFF_CFG, + C10GB_LT_TX_HOLD_POST_MASK); + break; + + case PRE_TAP: + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_COEFF_CFG, + C10GB_LT_TX_HOLD_PRE_MASK); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/***************************************************************************//** + * set the increment bit of a specific transmit equalizer tap register + */ +void +lt_tap_increment +( + phy10gkr_instance_t * this_phy, + phy10gkr_tx_equalizer_tap_t tap_type +) +{ + switch(tap_type) + { + case MAIN_TAP: + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_COEFF_CFG, + C10GB_LT_TX_INC_MAIN_MASK); + break; + + case POST_TAP: + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_COEFF_CFG, + C10GB_LT_TX_INC_POST_MASK); + break; + + case PRE_TAP: + HAL_set_32bit_reg(this_phy->lt_base_addr, + C10GB_LT_TX_COEFF_CFG, + C10GB_LT_TX_INC_PRE_MASK); + break; + + default: + HAL_ASSERT(0); + break; + } +} + +/***************************************************************************//** + calculate the optimal tap setting index based on the PRBS error counts + + sweep the prbs error array to find the minimum error. + + if there are multiple samples that have the same error, determine which of + the minimum samples is closest to the center tap setting + */ +uint32_t +lt_get_optimal_tap_index +( + uint32_t * prbs_arr, + uint32_t prbs_arr_size +) +{ + uint32_t i = 0; + uint32_t min_error = prbs_arr[0]; + uint32_t min_index = 0; + uint32_t min_midpoint_distance = prbs_arr_size/2; + + /* sweep to find min prbs error */ + for(i = 0; i < prbs_arr_size; i++) + { + if(prbs_arr[i] < min_error) + { + min_error = prbs_arr[i]; + min_index = i; + } + } + + /* sweep to find which index are equal the min, weighted by distance to mid + * point of array + */ + for(i = 0; i < prbs_arr_size; i++) + { + if(prbs_arr[i] == min_error) + { + int32_t midpoint_distance = (prbs_arr_size/2) - i; + if(midpoint_distance < 0) + { + midpoint_distance *= -1; + } + + if(midpoint_distance < min_midpoint_distance) + { + min_midpoint_distance = midpoint_distance; + min_index = i; + } + + if(midpoint_distance == 0) + { + break; + } + } + } + + /* index reversed as the order was set while decrementing from max to min */ + return prbs_arr_size - min_index; +} diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_link_training.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_link_training.h new file mode 100644 index 0000000..4f9a06c --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_link_training.h @@ -0,0 +1,231 @@ +/***************************************************************************//** + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core10gbasekr_phy_link_training.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief PHY software configuration + * + */ +#ifndef CORE10GBASEKR_PHY_LINK_TRAINING_H_ +#define CORE10GBASEKR_PHY_LINK_TRAINING_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/// @cond @private + +#include "phy.h" + +/***************************************************************************//** + Link partner calibration state machine. + + This function determines which of the link partners transmitter taps are to be + calibrated. + + @param this_phy + The this_phy parameter specifies the 10GBaseKR PHY block. + + @return + This function does not return a value. + */ +void +link_partner_calibration_sm +( + phy10gkr_instance_t * this_phy +); + +/***************************************************************************//** + Link partner main (c(0)) cursor sweep. + + The algorithm increments the link partners transmit taps to maximum (as this + algorithm is only used when preset is sent the link partner main tap should be + maximum). When the main tap is maximum the algorithm will decrement the link + partner's main transmit tap to minimum before decrementing the algorithm + stores the PRBS for optimisation. + + When the link partners transmit main tap is minimum algorithm determines the + optimal tap setting based on the PRBS errors stored during sweeping. The + algorithm now increments the link partners transmit tap back to the optimal + tap setting. + + @param this_phy + The this_phy parameter specifies the 10GBaseKR PHY block. + + @return + This function does not return a value. + */ +void +link_partner_main_sweep +( + phy10gkr_instance_t * this_phy +); + +/***************************************************************************//** + Link partner post (c(+1)) cursor sweep. + + The algorithm increments the link partners transmit taps to maximum (as this + algorithm is only used when preset is sent the link partner post tap should be + maximum). When the post tap is maximum the algorithm will decrement the link + partner's post transmit tap to minimum before decrementing the algorithm + stores the PRBS for optimisation. + + When the link partners transmit post tap is minimum algorithm determines the + optimal tap setting based on the PRBS errors stored during sweeping. The + algorithm now increments the link partners transmit tap back to the optimal + tap setting. + + @param this_phy + The this_phy parameter specifies the 10GBaseKR PHY block. + + @return + This function does not return a value. + */ +void +link_partner_post_sweep +( + phy10gkr_instance_t * this_phy +); + +/***************************************************************************//** + Link partner pre (c(-1)) cursor sweep. + + The algorithm increments the link partners transmit taps to maximum (as this + algorithm is only used when preset is sent the link partner pre tap should be + maximum). When the pre tap is maximum the algorithm will decrement the link + partner's pre transmit tap to minimum before decrementing the algorithm + stores the PRBS for optimisation. + + When the link partners transmit pre tap is minimum algorithm determines the + optimal tap setting based on the PRBS errors stored during sweeping. The + algorithm now increments the link partners transmit tap back to the optimal + tap setting. + + Once the link partner's pre tap has incremented back to the optimal setting + the local receiver ready bit is set to indicate to the link partner that + this device is finished calibrating the link partners transmitter taps. + + @param this_phy + The this_phy parameter specifies the 10GBaseKR PHY block. + + @return + This function does not return a value. + */ +void +link_partner_pre_sweep +( + phy10gkr_instance_t * this_phy +); + +/***************************************************************************//** + This function sets the decrement bit of a specific transmit equalizer tap + register which updates the transmitted coefficient update to the link partner. + + @param this_phy + The this_phy parameter specifies the 10GBaseKR PHY block. + + @param tap_type + This enumeration specifies the which transmitter tap will be decremented + + @return + This function does not return a value. + */ +void +lt_tap_decrement +( + phy10gkr_instance_t * this_phy, + phy10gkr_tx_equalizer_tap_t tap_type +); + +/***************************************************************************//** + This function sets the hold bit of a specific transmit equalizer tap + register which updates the transmitted coefficient update to the link partner. + + @param this_phy + The this_phy parameter specifies the 10GBaseKR PHY block. + + @param tap_type + This enumeration specifies the which transmitter tap will be held + + @return + This function does not return a value. + */ +void +lt_tap_hold +( + phy10gkr_instance_t * this_phy, + phy10gkr_tx_equalizer_tap_t tap_type +); + +/***************************************************************************//** + This function sets the increment bit of a specific transmit equalizer tap + register which updates the transmitted coefficient update to the link partner. + + @param this_phy + The this_phy parameter specifies the 10GBaseKR PHY block. + + @param tap_type + This enumeration specifies the which transmitter tap will be incremented + + @return + This function does not return a value. + */ +void +lt_tap_increment +( + phy10gkr_instance_t * this_phy, + phy10gkr_tx_equalizer_tap_t tap_type +); + +/***************************************************************************//** + This function calculates the optimal tap setting index based on the PRBS error + counts stored during maximum to minimum tap sweep. + + Sweeps the PRBS error array to find the minimum error, if there are multiple + samples that have the same error a weighting is applied to select the tap + setting closest to the center tap setting. + + @param prbs_arr + This is a pointer to the first sample of the PRBS error sample array + + @param prbs_arr_size + This identifies the number of samples. + + @return + This function returns the number of increments required to increment a tap + to its optimal tap setting. + */ +uint32_t +lt_get_optimal_tap_index +( + uint32_t * prbs_arr, + uint32_t prbs_arr_size +); + +/// @endcond + +#ifdef __cplusplus +} +#endif + +#endif /* CORE10GBASEKR_PHY_LINK_TRAINING_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_reg.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_reg.h new file mode 100644 index 0000000..a867004 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/core10gbasekr_phy_reg.h @@ -0,0 +1,1284 @@ +/***************************************************************************//** + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file core10gbasekr_phy_reg.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Core10GBaseKR PHY memory map + * + */ + +#ifndef CORE10GBASEKR_PHY_REG_H_ +#define CORE10GBASEKR_PHY_REG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/// @cond @private + +#include "uint_32_bit_masks.h" + +#define __I const volatile +#define __O volatile +#define __IO volatile + +/******************************************************************************/ +/* Core10GBaseKR PHY Clause 73 (Auto Negotiation) */ +/******************************************************************************/ + +/*------------------------------------------------------------------------------ + * AN_CONTROL register details + */ +#define C10GB_AN_CONTROL_REG_OFFSET (0x0U << 2U) + +/* + * Auto Negotiation Restart + * + * Restart_negotiation. Self clears, and always reads as 0. + */ +#define C10GB_AN_RESTART_OFFSET C10GB_AN_CONTROL_REG_OFFSET +#define C10GB_AN_RESTART_MASK MASK_BIT_9 +#define C10GB_AN_RESTART_SHIFT (9U) + +/* + * Auto Negotiation Enable + * + * Auto-negotiation Enable. Writing “1” in this register enables + * auto-negotiation + */ +#define C10GB_AN_ENABLE_OFFSET C10GB_AN_CONTROL_REG_OFFSET +#define C10GB_AN_ENABLE_MASK MASK_BIT_12 +#define C10GB_AN_ENABLE_SHIFT (12U) + +/* + * Auto Negotiation Reset + * + * Main_reset. Self clears. When reads as 0 the reset is complete. + */ +#define C10GB_AN_RESET_OFFSET C10GB_AN_CONTROL_REG_OFFSET +#define C10GB_AN_RESET_MASK MASK_BIT_15 +#define C10GB_AN_RESET_SHIFT (15U) + + +/*------------------------------------------------------------------------------ + * AN_STATUS register details + */ +#define C10GB_AN_STATUS_REG_OFFSET (0x1U << 2U) + +/* + * Auto Negotiation Able + * + * If “1” indicates that Link Partner is Autonegotiation Able + */ +#define C10GB_AN_CAPABLE_OFFSET C10GB_AN_STATUS_REG_OFFSET +#define C10GB_AN_CAPABLE_MASK MASK_BIT_0 +#define C10GB_AN_CAPABLE_SHIFT (0U) + +/* + * Auto Negotiation Support + * + * If “1” indicates that Autonegotiation is supported + */ +#define C10GB_AN_SUPPORT_OFFSET C10GB_AN_STATUS_REG_OFFSET +#define C10GB_AN_SUPPORT_MASK MASK_BIT_3 +#define C10GB_AN_SUPPORT_SHIFT (3U) + +/* + * Auto Negotiation Complete + * + * If “1” indicates that AN is complete + */ +#define C10GB_AN_COMPLETE_OFFSET C10GB_AN_STATUS_REG_OFFSET +#define C10GB_AN_COMPLETE_MASK MASK_BIT_5 +#define C10GB_AN_COMPLETE_SHIFT (5U) + +/* + * Auto Negotiation Page Received + * + * Page_RX. If “1” that Page is received from the link partner. Clear on read + */ +#define C10GB_AN_PAGE_RX_OFFSET C10GB_AN_STATUS_REG_OFFSET +#define C10GB_AN_PAGE_RX_MASK MASK_BIT_6 +#define C10GB_AN_PAGE_RX_SHIFT (6U) + +/* + * Auto Negotiation Parallel Fault Detected + * + * Parallel_Detect_fault. Clear on read + */ +#define C10GB_AN_PARALLEL_DETECT_OFFSET C10GB_AN_STATUS_REG_OFFSET +#define C10GB_AN_PARALLEL_DETECT_MASK MASK_BIT_9 +#define C10GB_AN_PARALLEL_DETECT_SHIFT (9U) + +/* + * Auto Negotiation State Variable + * + * This register returns the state variables of the Auto-Negotiation. + * ST_AUTO_NEG_ENABLE = 0x0; + * ST_TRANSMIT_DISABLE = 0x1; + * ST_CAPABILITY_DETECT = 0x2; + * ST_ACKNOWLEDGE_DETECT = 0x3; + * ST_COMPLETE_ACKNOWLE = 0x4; + * ST_AN_GOOD_CHECK = 0x5; + * ST_AN_GOOD = 0x6; + * ST_NEXT_PAGE_WAIT = 0x7; + * ST_NEXT_PAGE_WAIT_TX_IDLE = 0x8; + * ST_LINK_STATUS_CHECK = 0x9; + * ST_PARALLEL_DETECTION_FAULT = 0xA; + */ +#define C10GB_AN_STATE_OFFSET C10GB_AN_STATUS_REG_OFFSET +#define C10GB_AN_STATE_SHIFT (12U) +#define C10GB_AN_STATE_MASK BIT_MASK_4_BITS << \ + C10GB_AN_STATE_SHIFT + + +/*------------------------------------------------------------------------------ + * MR_ADV_CAPABILITY_1 Bits [16:1] + * + * This register gives the value of the bits 16:1 of the Advertisement Ability + * Register + * Bits [4:0] - Selector Field (S[4:0]) is a five-bit wide field, encoding 32 + * possible messages. Selector Field encoding definitions are shown in Annex + * 28A of the IEEE 802.3 specification + * Bits[9:5] -Echoed Nonce Field (E[4:0]) is a 5-bit wide field containing + * the nonce received from the link partner + * Bits[12:10] - Pause Encoding as defined in Annexure 28B of the IEEE 802.3 + * specification + * Bit 13 - Remote Fault (RF) of the base link codeword. The default value is + * logical zero + * Bit 14 -Acknowledge (Ack) is used by the Auto-Negotiation function to + * indicate that a device has successfully received its link partner’s link + * codeword. + * Bit 15 -Next Page (NP) bit. Support of Next Pages is mandatory. If the + * device does not have any Next Pages to send, the NP bit shall be set to + * logical zero + */ +#define C10GB_AN_MR_ADV_CAPABILITY_1_REG_OFFSET \ + (0x10U << 2U) + + + +/*------------------------------------------------------------------------------ + * MR_ADV_CAPABILITY_2 Bits [32:17] + * + * This register gives the value of the bits 32:17 of the Advertisement Ability + * Register + * Bits[20:16] – Transmitted Nonce Field + * Bits[31:21] – Technology Ability Field bits[ 10:0] . Technology Ability + * Field is a 25-bit wide field containing information indicating supported + * technologies specific to the selector field value when used with the + * Auto-Negotiation for Backplane Ethernet. + */ +#define C10GB_AN_MR_ADV_CAPABILITY_2_REG_OFFSET \ + (0x11U << 2U) + + +/*------------------------------------------------------------------------------ + * MR_ADV_CAPABILITY_3 Bits [48:33] + * + * This register gives the value of the bits 48:33 of the Advertisement Ability + * Register + * Bits [45:32] – Technology Ability Field bits[ 25:11]. For Technology Ability + * Field encoding refer to Table 73-4 of the IEEE specification + * Bits [47:46] - FEC Capability (FEC Not supported in current implementation). + * Bit 46 - FEC ability, if set to ‘1’ PHY has FEC Ability + * Bit 47 - FEC requested When the FEC requested bit is set to logical one, it + * indicates a request to enable FEC on the link. + */ +#define C10GB_AN_MR_ADV_CAPABILITY_3_REG_OFFSET \ + (0x12U << 2U) + + +/* + * Adevertisment Ability Registers Details + */ +#define C10GB_AN_ADV_CAPABILITY_SHIFT (0U) +#define C10GB_AN_ADV_CAPABILITY_MASK BIT_MASK_16_BITS << \ + C10GB_AN_ADV_CAPABILITY_SHIFT + + +/*------------------------------------------------------------------------------ + * MR_LP_BASE_PAGE_CAPABILITY_1 Bits [16:1] + * + * This register gives the value of the bits 16:1 of the Link Partner Base Page + * Ability Register. The bits definition are same as Advertisement ability + * register -1 + */ +#define C10GB_AN_MR_LP_BASE_PG_CAPABILITY_1_REG_OFFSET \ + (0x13U << 2U) + + +/*------------------------------------------------------------------------------ + * MR_LP_BASE_PAGE_CAPABILITY_2 Bits [32:17] + * + * This register gives the value of the bits 32:17 of the Link Partner Base Page + * Ability Register. The bits definition are same as Advertisement ability + * register -2 + */ +#define C10GB_AN_MR_LP_BASE_PG_CAPABILITY_2_REG_OFFSET \ + (0x14U << 2U) + + +/*------------------------------------------------------------------------------ + * MR_LP_BASE_PAGE_CAPABILITY_3 Bits [48:33] + * + * This register gives the value of the bits 48:33 of the Link Partner Base Page + * Ability Register. The bits definition are same as Advertisement ability + * register -3 + * + */ +#define C10GB_AN_MR_LP_BASE_PG_CAPABILITY_3_REG_OFFSET \ + (0x15U << 2U) + +/* + * Link Partner Base Page Ability Registers Details + */ +#define C10GB_AN_LP_BASE_PAGE_CAPABILITY_SHIFT (0U) +#define C10GB_AN_LP_BASE_PAGE_CAPABILITY_MASK BIT_MASK_16_BITS << \ + C10GB_AN_LP_BASE_PAGE_CAPABILITY_SHIFT + +/*------------------------------------------------------------------------------ + * MR_XNP_TRANSMIT_1 Bits [16:1] + * + * This register gives the value of the bits 16:1 of the XNP(next page)Transmit + * Register. + * Bit[10:0] – Message Code Field (M[10:0]) is an eleven bit wide field, + * encoding 2048 possible messages. Message Code Field definitions are shown in + * Annex 28C of the IEEE 802.3 specification + * Bit 11 – Toggle (T) is used by the Arbitration function to ensure + * synchronization with the Link Partner during Next Page exchange. This bit + * shall always take the opposite value of the Toggle bit in the previously + * exchanged link codeword + * Bit 12 – Acknowledge 2 (Ack2) is used by the Next Page function to indicate + * that a device has the ability to comply with the message. Ack2 shall be set + * as follows: + * 0 - cannot comply with message + * 1 - will comply with message + * Bit 13 – Message Page bit + * 0 – Unformatted Page + * 1 – Message Page + * Bit 14 – Acknowledge. Acknowledge (Ack) is used by the Auto-Negotiation + * function to indicate that a device has successfully received its Link + * Partner’s link codeword + * Bit 15 - Next Page Bit + * 0 - last page + * 1 - additional Next Page(s) will follow + */ +#define C10GB_AN_MR_XNP_TRANSMIT_1_REG_OFFSET (0x16U << 2U) + + +/*------------------------------------------------------------------------------ + * MR_XNP_TRANSMIT_2 Bits [32:17] + * + * This register gives the value of the bits 32:17 of the XNP Transmit Register. + * This value corresponds to the Bits[31:16] of the Unformatted Code Field of + * the Next Page Register. + */ +#define C10GB_AN_MR_XNP_TRANSMIT_2_REG_OFFSET (0x17U << 2U) + + +/*------------------------------------------------------------------------------ + * MR_XNP_TRANSMIT_3 Bits [48:33] + * + * This register gives the value of the bits 48:33 of the XNP Transmit Register. + * This value corresponds to the Bits[47:32] of the Unformatted Code Field of + * the Next Page Register. + */ +#define C10GB_AN_MR_XNP_TRANSMIT_3_REG_OFFSET (0x18U << 2U) + +/* + * XNP Transmit Registers Details + */ +#define C10GB_AN_XNP_TRANSMIT_SHIFT (0U) +#define C10GB_AN_XNP_TRANSMIT_MASK BIT_MASK_16_BITS << \ + C10GB_AN_XNP_TRANSMIT_SHIFT + +/*------------------------------------------------------------------------------ + * LP_XNP_CAPABILITY_1 Bits [16:1] + * + * This register gives the value of the bits 16:1 of the Link Partner next page + * Ability register. The bits definition are same as XNP Transmit register -1 + */ +#define C10GB_AN_LP_XNP_CAPABILITY_1_REG_OFFSET \ + (0x19U << 2U) + + +/*------------------------------------------------------------------------------ + * LP_XNP_CAPABILITY_2 Bits [32:17] + * + * This register gives the value of the bits 32:17 of the Link Partner next page + * Ability register. The bits definition are same as XNP Transmit register -2 + */ +#define C10GB_AN_LP_XNP_CAPABILITY_2_REG_OFFSET \ + (0x1aU << 2U) + + +/*------------------------------------------------------------------------------ + * LP_XNP_CAPABILITY_3 Bits [48:33] + * + * This register gives the value of the bits 48:33 of the Link Partner next page + * Ability register. The bits definition are same as XNP Transmit register -3 + */ +#define C10GB_AN_LP_XNP_CAPABILITY_3_REG_OFFSET \ + (0x1bU << 2U) + +/* + * Link Partner Next Page Ability Registers Details + */ +#define C10GB_AN_LP_XNP_CAPABILITY_SHIFT (0U) +#define C10GB_AN_LP_XNP_CAPABILITY_MASK BIT_MASK_16_BITS << \ + C10GB_AN_LP_XNP_CAPABILITY_SHIFT + +/*------------------------------------------------------------------------------ + * AN Link Fail Inhibit Timer + * + * An_link_fail_inhibit_timer is 500ms timer which starts incrementing in + * AN GOOD CHECK state (This state is indication of AN completion) and if it + * elapses in during this state then the Auto negotiation process starts again + */ +#define C10GB_AN_LINK_FAIL_INHIBIT_TIMER_REG_OFFSET \ + (0x0dU << 2U) + +/******************************************************************************/ +/* Core10GBaseKR PHY Clause 72 (Link Training) */ +/******************************************************************************/ + +/*------------------------------------------------------------------------------ + * Link Training Control Register + */ +#define C10GB_LT_CTRL_REG_OFFSET (0x0U << 2U) + +/* + * Link Training Initialize + * + * If “1” initialize coefficient is transmitted to the link partner + */ +#define C10GB_LT_INIT_OFFSET C10GB_LT_CTRL_REG_OFFSET +#define C10GB_LT_INIT_SHIFT (3U) +#define C10GB_LT_INIT_MASK MASK_BIT_3 + +/* + * Link Training Preset + * + * If “1” preset coefficient is transmitted to the link partner + */ +#define C10GB_LT_PRESET_OFFSET C10GB_LT_CTRL_REG_OFFSET +#define C10GB_LT_PRESET_SHIFT (2U) +#define C10GB_LT_PRESET_MASK MASK_BIT_2 + +/* + * Link Restart Training + * + * A write of “1” to this field brings the link training IP in reset mode. + * To bring the Link training IP out of reset, write a value of 0x0 into this + * register + */ +#define C10GB_LT_RESTART_TRAINING_OFFSET C10GB_LT_CTRL_REG_OFFSET +#define C10GB_LT_RESTART_TRAINING_SHIFT (1U) +#define C10GB_LT_RESTART_TRAINING_MASK MASK_BIT_1 + +/* + * Link Training Enable + * + * If “1” enables the link training. This bit should be enabled from the + * software after the AN_GOOD_CHK interrupt is received by the Firmware + */ +#define C10GB_LT_RESTART_EN_OFFSET C10GB_LT_CTRL_REG_OFFSET +#define C10GB_LT_RESTART_EN_SHIFT (0U) +#define C10GB_LT_RESTART_EN_MASK MASK_BIT_0 + +/*------------------------------------------------------------------------------ + * Max Wait Timer Configuration + * + * The value in the MAX wait timer should be configured to 500ms, the training + * state diagram enters into the training failure state once the timer reaches + * 500ms. + */ +#define C10GB_LT_MAX_WAIT_TIMER_REG_OFFSET (0x1U << 2U) + +#define C10GB_LT_MAX_WAIT_TIMER_OFFSET C10GB_LT_MAX_WAIT_TIMER_REG_OFFSET +#define C10GB_LT_MAX_WAIT_TIMER_SHIFT (0U) +#define C10GB_LT_MAX_WAIT_TIMER_MASK BIT_MASK_32_BITS << \ + C10GB_LT_MAX_WAIT_TIMER_SHIFT + +/*------------------------------------------------------------------------------ + * Frame WAIT Timer Configuration Register + * + * The value in the frame WAIT Timer register should be between 100 to 300 + * frames. The default value is configured to 100 frames. + */ +#define C10GB_LT_FRM_WAIT_TIMER_REG_OFFSET (0x2U << 2U) + +#define C10GB_LT_FRM_WAIT_TIMER_OFFSET C10GB_LT_FRM_WAIT_TIMER_REG_OFFSET +#define C10GB_LT_FRM_WAIT_TIMER_SHIFT (0U) +#define C10GB_LT_FRM_WAIT_TIMER_MASK BIT_MASK_32_BITS << \ + C10GB_LT_FRM_WAIT_TIMER_SHIFT + +/*------------------------------------------------------------------------------ + * Preset MAIN-TAP Configuration Register + * + * The value in this register gives the main TAP value, when the preset + * Coefficient is received from the Link Partner. The Link Training Algorithm + * starts from this TAP value. + */ +#define C10GB_LT_PRESET_MAIN_TAP_REG_OFFSET (0x3U << 2U) + +#define C10GB_LT_PRESET_MAIN_TAP_OFFSET C10GB_LT_PRESET_MAIN_TAP_REG_OFFSET +#define C10GB_LT_PRESET_MAIN_TAP_SHIFT (0U) +#define C10GB_LT_PRESET_MAIN_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_PRESET_MAIN_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Preset Post-TAP Configuration Register + * + * The value in this register gives the post-TAP value when the preset + * Coefficient is received from the Link Partner. The Link Training Algorithm + * starts from this TAP value. + */ +#define C10GB_LT_PRESET_POST_TAP_REG_OFFSET (0x4U << 2U) + +#define C10GB_LT_PRESET_POST_TAP_OFFSET C10GB_LT_PRESET_POST_TAP_REG_OFFSET +#define C10GB_LT_PRESET_POST_TAP_SHIFT (0U) +#define C10GB_LT_PRESET_POST_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_PRESET_POST_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Preset Pre-TAP Configuration Register + * + * The value in this register gives the pre-TAP when the preset Coefficient is + * received from the Link Partner. The Link Training Algorithm starts from this + * TAP value. + */ +#define C10GB_LT_PRESET_PRE_TAP_REG_OFFSET (0x5U << 2U) + +#define C10GB_LT_PRESET_PRE_TAP_OFFSET C10GB_LT_PRESET_PRE_TAP_REG_OFFSET +#define C10GB_LT_PRESET_PRE_TAP_SHIFT (0U) +#define C10GB_LT_PRESET_PRE_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_PRESET_PRE_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Initialize MAIN-TAP Configuration Register + * + * The value in this register gives the main TAP value, when the Initialize + * Coefficient is received from the Link Partner. + */ +#define C10GB_LT_INIT_MAIN_TAP_REG_OFFSET (0x6U << 2U) + +#define C10GB_LT_INIT_MAIN_TAP_OFFSET C10GB_LT_INIT_MAIN_TAP_REG_OFFSET +#define C10GB_LT_INIT_MAIN_TAP_SHIFT (0U) +#define C10GB_LT_INIT_MAIN_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_INIT_MAIN_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Initialize Post-TAP Configuration Register + * + * The value in this register gives the post-TAP value when the Initialize + * Coefficient is received from the Link Partner. + */ +#define C10GB_LT_INIT_POST_TAP_REG_OFFSET (0x7U << 2U) + +#define C10GB_LT_INIT_POST_TAP_OFFSET C10GB_LT_INIT_POST_TAP_REG_OFFSET +#define C10GB_LT_INIT_POST_TAP_SHIFT (0U) +#define C10GB_LT_INIT_POST_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_INIT_POST_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Initialize Pre-TAP Configuration Register + * + * The value in this register gives the pre-TAP when the Initialize Coefficient + * is received from the Link Partner. + */ +#define C10GB_LT_INIT_PRE_TAP_REG_OFFSET (0x8U << 2U) + +#define C10GB_LT_INIT_PRE_TAP_OFFSET C10GB_LT_INIT_PRE_TAP_REG_OFFSET +#define C10GB_LT_INIT_PRE_TAP_SHIFT (0U) +#define C10GB_LT_INIT_PRE_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_INIT_PRE_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Maximum Coefficient Limit of Main Tap Configuration Register + * + * The value in this register gives the Maximum value of the main TAP setting + * which will be tested for the TX equalization for the optimum main tap + * settings. + */ +#define C10GB_LT_MAX_MAIN_TAP_REG_OFFSET (0x9U << 2U) + +#define C10GB_LT_MAX_MAIN_TAP_OFFSET C10GB_LT_MAX_MAIN_TAP_REG_OFFSET +#define C10GB_LT_MAX_MAIN_TAP_SHIFT (0U) +#define C10GB_LT_MAX_MAIN_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_MAX_MAIN_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Minimum Coefficient Limit of Main Tap Configuration Register + * + * The value in this register gives the minimum value of the main TAP setting + * which will be tested for the TX equalization for the optimum main tap + * settings. + */ +#define C10GB_LT_MIN_MAIN_TAP_REG_OFFSET (0xAU << 2U) + +#define C10GB_LT_MIN_MAIN_TAP_OFFSET C10GB_LT_MIN_MAIN_TAP_REG_OFFSET +#define C10GB_LT_MIN_MAIN_TAP_SHIFT (0U) +#define C10GB_LT_MIN_MAIN_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_MIN_MAIN_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Maximum Coefficient Limit of Post Tap Configuration Register + * + * The value in this register gives the Maximum value of the post TAP setting + * which will be tested for the TX equalization for the optimum post tap + * settings. + */ +#define C10GB_LT_MAX_POST_TAP_REG_OFFSET (0xBU << 2U) + +#define C10GB_LT_MAX_POST_TAP_OFFSET C10GB_LT_MAX_POST_TAP_REG_OFFSET +#define C10GB_LT_MAX_POST_TAP_SHIFT (0U) +#define C10GB_LT_MAX_POST_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_MAX_POST_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Minimum Coefficient Limit of Post Tap Configuration Register + * + * The value in this register gives the minimum value of the post TAP setting + * which will be tested for the TX equalization for the optimum post tap + * settings. + */ +#define C10GB_LT_MIN_POST_TAP_REG_OFFSET (0xCU << 2U) + +#define C10GB_LT_MIN_POST_TAP_OFFSET C10GB_LT_MIN_POST_TAP_REG_OFFSET +#define C10GB_LT_MIN_POST_TAP_SHIFT (0U) +#define C10GB_LT_MIN_POST_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_MIN_POST_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Maximum Coefficient Limit of Pre Tap Configuration Register + * + * The value in this register gives the Maximum value of the pre TAP setting + * which will be tested for the TX equalization for the optimum pre tap + * settings. + */ +#define C10GB_LT_MAX_PRE_TAP_REG_OFFSET (0xDU << 2U) + +#define C10GB_LT_MAX_PRE_TAP_OFFSET C10GB_LT_MAX_PRE_TAP_REG_OFFSET +#define C10GB_LT_MAX_PRE_TAP_SHIFT (0U) +#define C10GB_LT_MAX_PRE_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_MAX_PRE_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Minimum Coefficient Limit of Pre Tap Configuration Register + * + * The value in this register gives the minimum value of the pre TAP setting + * which will be tested for the TX equalization for the optimum pre tap + * settings. + */ +#define C10GB_LT_MIN_PRE_TAP_REG_OFFSET (0xEU << 2U) + +#define C10GB_LT_MIN_PRE_TAP_OFFSET C10GB_LT_MIN_PRE_TAP_REG_OFFSET +#define C10GB_LT_MIN_PRE_TAP_SHIFT (0U) +#define C10GB_LT_MIN_PRE_TAP_MASK BIT_MASK_16_BITS << \ + C10GB_LT_MIN_PRE_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * TX Equalization Register + */ +#define C10GB_LT_TX_EQUAL_REG_OFFSET (0xFU << 2U) + +/* + * TX Equalization Pre Tap Done + * + * A write to “1” in this field indicates that that tx_equalization is done for + * the PRE TAP + */ +#define C10GB_LT_TX_EQUAL_PRE_DONE_OFFSET C10GB_LT_TX_EQUAL_REG_OFFSET +#define C10GB_LT_TX_EQUAL_PRE_DONE_SHIFT (3U) +#define C10GB_LT_TX_EQUAL_PRE_DONE_MASK MASK_BIT_3 + +/* + * TX Equalization Post Tap Done + * + * A write to “1” in this field indicates that that tx_equalization is done for + * the post TAP + */ +#define C10GB_LT_TX_EQUAL_POST_DONE_OFFSET C10GB_LT_TX_EQUAL_REG_OFFSET +#define C10GB_LT_TX_EQUAL_POST_DONE_SHIFT (2U) +#define C10GB_LT_TX_EQUAL_POST_DONE_MASK MASK_BIT_2 + +/* + * TX Equalization Main Tap Done + * + * A write to “1” in this field indicates that that tx_equalization is done for + * the main TAP + */ +#define C10GB_LT_TX_EQUAL_MAIN_DONE_OFFSET C10GB_LT_TX_EQUAL_REG_OFFSET +#define C10GB_LT_TX_EQUAL_MAIN_DONE_SHIFT (1U) +#define C10GB_LT_TX_EQUAL_MAIN_DONE_MASK MASK_BIT_1 + +/* + * TX Equalization Done + * + * A write to “1” in this field indicates that that tx_equalization is done for + * all the TAPs (pre, post and main) + */ +#define C10GB_LT_TX_EQUAL_DONE_OFFSET C10GB_LT_TX_EQUAL_REG_OFFSET +#define C10GB_LT_TX_EQUAL_DONE_SHIFT (0U) +#define C10GB_LT_TX_EQUAL_DONE_MASK MASK_BIT_0 + +/*------------------------------------------------------------------------------ + * Local Receiver Lock Register + */ +#define C10GB_LT_LOCAL_RCVR_LOCK_REG_OFFSET (0x10U << 2U) + +/* + * Local Receiver Locked + * + * Write “1” to this register from the software once the local receiver is + * ready + */ +#define C10GB_LT_LOCAL_RCVR_LOCKED_OFFSET C10GB_LT_LOCAL_RCVR_LOCK_REG_OFFSET +#define C10GB_LT_LOCAL_RCVR_LOCKED_SHIFT (0U) +#define C10GB_LT_LOCAL_RCVR_LOCKED_MASK MASK_BIT_0 + +/*------------------------------------------------------------------------------ + * TX New Main Tap Register + */ +#define C10GB_LT_TX_NEW_MAIN_TAP_REG_OFFSET (0x11U << 2U) + +/* + * TX New Main Tap + * + * A value in this register gives the value of the new main tap value, which + * is used to update the TX equalization SerDes registers. + */ +#define C10GB_LT_TX_NEW_MAIN_TAP_OFFSET C10GB_LT_TX_NEW_MAIN_TAP_REG_OFFSET +#define C10GB_LT_TX_NEW_MAIN_TAP_SHIFT (0U) +#define C10GB_LT_TX_NEW_MAIN_TAP_MASK BIT_MASK_8_BITS << \ + C10GB_LT_TX_NEW_MAIN_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * TX New Post Tap Register + */ +#define C10GB_LT_TX_NEW_POST_TAP_REG_OFFSET (0x12U << 2U) + +/* + * TX New Post Tap + * + * A value in this register gives the value of the new Post tap value, which + * is used to update the TX equalization SerDes registers. + */ +#define C10GB_LT_TX_NEW_POST_TAP_OFFSET C10GB_LT_TX_NEW_POST_TAP_REG_OFFSET +#define C10GB_LT_TX_NEW_POST_TAP_SHIFT (0U) +#define C10GB_LT_TX_NEW_POST_TAP_MASK BIT_MASK_8_BITS << \ + C10GB_LT_TX_NEW_POST_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * TX New Pre Tap Register + */ +#define C10GB_LT_TX_NEW_PRE_TAP_REG_OFFSET (0x13U << 2U) + +/* + * TX New Pre Tap + * + * A value in this register gives the value of the new Pre tap value, which is + * used to update the TX equalization SerDes registers. + */ +#define C10GB_LT_TX_NEW_PRE_TAP_OFFSET C10GB_LT_TX_NEW_PRE_TAP_REG_OFFSET +#define C10GB_LT_TX_NEW_PRE_TAP_SHIFT (0U) +#define C10GB_LT_TX_NEW_PRE_TAP_MASK BIT_MASK_8_BITS << \ + C10GB_LT_TX_NEW_PRE_TAP_SHIFT + +/*------------------------------------------------------------------------------ + * Training State Machine Status + */ +#define C10GB_LT_TRAINING_SM_STATUS_REG_OFFSET (0x14U << 2U) + +/* + * Remote Receiver Ready + * + * If “1” it indicates that remote receiver is ready + */ +#define C10GB_LT_REMOTE_TRAINED_OFFSET C10GB_LT_TRAINING_SM_STATUS_REG_OFFSET +#define C10GB_LT_REMOTE_TRAINED_SHIFT (4U) +#define C10GB_LT_REMOTE_TRAINED_MASK MASK_BIT_4 + +/* + * Link Up + * + * If “1” it indicates that Link is ready + */ +#define C10GB_LT_LINK_UP_OFFSET C10GB_LT_TRAINING_SM_STATUS_REG_OFFSET +#define C10GB_LT_LINK_UP_SHIFT (3U) +#define C10GB_LT_LINK_UP_MASK MASK_BIT_3 + +/* + * Training State Machine + * + * The value in this register gives the current values of the training state + * machine. + * IDLE = 3'b000 + * INITIALIZE = 3'b001 + * SEND_TRAINING = 3'b011 + * TRAIN_LOCAL = 3'b010 + * TRAIN_REMOTE = 3'b110 + * LINK_READY = 3'b111 + * SEND_DATA = 3'b101 + * RAINING_FAILURE = 3'b100 + + */ +#define C10GB_LT_TRAINING_SM_OFFSET C10GB_LT_TRAINING_SM_STATUS_REG_OFFSET +#define C10GB_LT_TRAINING_SM_SHIFT (0U) +#define C10GB_LT_TRAINING_SM_MASK BIT_MASK_2_BITS << \ + C10GB_LT_TRAINING_SM_SHIFT + +/*------------------------------------------------------------------------------ + * TX Updated Status Register + */ +#define C10GB_LT_TX_UPDATED_STATUS_REG_OFFSET (0x15U << 2U) + +/* + * Tx Updated Status Pre Tap + * + * A value in this register gives the value of the current status transmitted + * to the link partner for the pre Tap + * 1 1 = maximum + * 1 0 = minimum + * 0 1 = updated + * 0 0 = not_updated + */ +#define C10GB_LT_TX_UPDATED_STAT_PRE_OFFSET C10GB_LT_TX_UPDATED_STATUS_REG_OFFSET +#define C10GB_LT_TX_UPDATED_STAT_PRE_SHIFT (16U) +#define C10GB_LT_TX_UPDATED_STAT_PRE_MASK BIT_MASK_2_BITS << \ + C10GB_LT_TX_UPDATED_STAT_PRE_SHIFT + +/* + * Tx Updated Status Post Tap + * + * A value in this register gives the value of the current status transmitted + * to the link partner for the post Tap + * 1 1 = maximum + * 1 0 = minimum + * 0 1 = updated + * 0 0 = not_updated + */ +#define C10GB_LT_TX_UPDATED_STAT_POST_OFFSET C10GB_LT_TX_UPDATED_STATUS_REG_OFFSET +#define C10GB_LT_TX_UPDATED_STAT_POST_SHIFT (14U) +#define C10GB_LT_TX_UPDATED_STAT_POST_MASK BIT_MASK_2_BITS << \ + C10GB_LT_TX_UPDATED_STAT_POST_SHIFT + +/* + * Tx Updated Status Main Tap + * + * A value in this register gives the value of the current status transmitted + * to the link partner for the main Tap + * 1 1 = maximum + * 1 0 = minimum + * 0 1 = updated + * 0 0 = not_updated + */ +#define C10GB_LT_TX_UPDATED_STAT_MAIN_OFFSET C10GB_LT_TX_UPDATED_STATUS_REG_OFFSET +#define C10GB_LT_TX_UPDATED_STAT_MAIN_SHIFT (12U) +#define C10GB_LT_TX_UPDATED_STAT_MAIN_MASK BIT_MASK_2_BITS << \ + C10GB_LT_TX_UPDATED_STAT_MAIN_SHIFT + +/* + * Link Training State Pre Tap + * + * A value in this register gives the value of the coefficient update state + * machine for the pre Tap + * IDLE = 3'b000 + * NOT_UPDATED = 3'b001 + * UPDATE_COEFF = 3'b011 + * MAXIMUM = 3'b010 + * UPDATED = 3'b110 + * MINIMUM = 3'b100 + */ +#define C10GB_LT_STATE_PRE_OFFSET C10GB_LT_TX_UPDATED_STATUS_REG_OFFSET +#define C10GB_LT_STATE_PRE_SHIFT (8U) +#define C10GB_LT_STATE_PRE_MASK BIT_MASK_3_BITS << \ + C10GB_LT_STATE_PRE_SHIFT + +/* + * Link Training State Post Tap + * + * A value in this register gives the value of the coefficient update state + * machine for the post Tap + * IDLE = 3'b000 + * NOT_UPDATED = 3'b001 + * UPDATE_COEFF = 3'b011 + * MAXIMUM = 3'b010 + * UPDATED = 3'b110 + * MINIMUM = 3'b100 + */ +#define C10GB_LT_STATE_POST_OFFSET C10GB_LT_TX_UPDATED_STATUS_REG_OFFSET +#define C10GB_LT_STATE_POST_SHIFT (4U) +#define C10GB_LT_STATE_POST_MASK BIT_MASK_3_BITS << \ + C10GB_LT_STATE_POST_SHIFT + +/* + * Link Training State Main Tap + * + * A value in this register gives the value of the coefficient update state + * machine for the main Tap + * IDLE = 3'b000 + * NOT_UPDATED = 3'b001 + * UPDATE_COEFF = 3'b011 + * MAXIMUM = 3'b010 + * UPDATED = 3'b110 + * MINIMUM = 3'b100 + */ +#define C10GB_LT_STATE_MAIN_OFFSET C10GB_LT_TX_UPDATED_STATUS_REG_OFFSET +#define C10GB_LT_STATE_MAIN_SHIFT (0U) +#define C10GB_LT_STATE_MAIN_MASK BIT_MASK_3_BITS << \ + C10GB_LT_STATE_MAIN_SHIFT + +/*------------------------------------------------------------------------------ + * Received Coefficient Status Register + */ +#define C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET (0x16U << 2U) + +/* + * New Coefficient Received + * + * A value in this register gives the value of the new coefficient received + * from the link partner + */ +#define C10GB_LT_NEW_RCVD_COEFF_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_NEW_RCVD_COEFF_SHIFT (16U) +#define C10GB_LT_NEW_RCVD_COEFF_MASK BIT_MASK_16_BITS << \ + C10GB_LT_NEW_RCVD_COEFF_SHIFT + +/* + * Preset + * + * 1 = Pre-set coefficients + * 0 = Normal operation + */ +#define C10GB_LT_RCVD_COEFF_PRESET_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_RCVD_COEFF_PRESET_SHIFT (29U) +#define C10GB_LT_RCVD_COEFF_PRESET_MASK MASK_BIT_29 + +/* + * Initialize + * + * 1 = Initialize coefficients + * 0 = Normal operation + */ +#define C10GB_LT_RCVD_COEFF_INIT_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_RCVD_COEFF_INIT_SHIFT (28U) +#define C10GB_LT_RCVD_COEFF_INIT_MASK MASK_BIT_28 + +/* + * Post tap coefficient update + * + * 1 1 = Reserved + * 0 1 = Increment + * 1 0 = Decrement + * 0 0 = Hold + */ +#define C10GB_LT_RCVD_COEFF_POST_UPDATE_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_RCVD_COEFF_POST_UPDATE_SHIFT (20U) +#define C10GB_LT_RCVD_COEFF_POST_UPDATE_MASK BIT_MASK_2_BITS << \ + C10GB_LT_RCVD_COEFF_POST_UPDATE_SHIFT + +/* + * Main tap coefficient update + * + * 1 1 = Reserved + * 0 1 = Increment + * 1 0 = Decrement + * 0 0 = Hold + */ +#define C10GB_LT_RCVD_COEFF_MAIN_UPDATE_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_RCVD_COEFF_MAIN_UPDATE_SHIFT (18U) +#define C10GB_LT_RCVD_COEFF_MAIN_UPDATE_MASK BIT_MASK_2_BITS << \ + C10GB_LT_RCVD_COEFF_MAIN_UPDATE_SHIFT + +/* + * Pre tap coefficient update + * + * 1 1 = Reserved + * 0 1 = Increment + * 1 0 = Decrement + * 0 0 = Hold + */ +#define C10GB_LT_RCVD_COEFF_PRE_UPDATE_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_RCVD_COEFF_PRE_UPDATE_SHIFT (16U) +#define C10GB_LT_RCVD_COEFF_PRE_UPDATE_MASK BIT_MASK_2_BITS << \ + C10GB_LT_RCVD_COEFF_PRE_UPDATE_SHIFT + +/* + * New Status Received + * + * A value in this register gives the value of the new status received from the + * link partner + */ +#define C10GB_LT_NEW_RCVD_STATUS_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_NEW_RCVD_STATUS_SHIFT (0U) +#define C10GB_LT_NEW_RCVD_STATUS_MASK BIT_MASK_16_BITS << \ + C10GB_LT_NEW_RCVD_STATUS_SHIFT + +/* + * Receiver Ready + * + * 1 = The remote receiver has determined that training is completed and is + * prepared to receive data. + * 0 = The remote receiver is requesting that training continue. + */ +#define C10GB_LT_RCVD_COEFF_RCVR_READY_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_RCVD_COEFF_RCVR_READY_SHIFT (15U) +#define C10GB_LT_RCVD_COEFF_RCVR_READY_MASK MASK_BIT_15 + +/* + * Post tap coefficient value + * + * 1 1 = Maximum + * 1 0 = Minimum + * 0 1 = updated + * 0 0 = Not Updated + */ +#define C10GB_LT_RCVD_COEFF_POST_VALUE_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_RCVD_COEFF_POST_VALUE_SHIFT (4U) +#define C10GB_LT_RCVD_COEFF_POST_VALUE_MASK BIT_MASK_2_BITS << \ + C10GB_LT_RCVD_COEFF_POST_VALUE_SHIFT + +/* + * Main tap coefficient value + * + * 1 1 = Maximum + * 1 0 = Minimum + * 0 1 = updated + * 0 0 = Not Updated + */ +#define C10GB_LT_RCVD_COEFF_MAIN_VALUE_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_RCVD_COEFF_MAIN_VALUE_SHIFT (2U) +#define C10GB_LT_RCVD_COEFF_MAIN_VALUE_MASK BIT_MASK_2_BITS << \ + C10GB_LT_RCVD_COEFF_MAIN_VALUE_SHIFT + +/* + * Pre tap coefficient value + * + * 1 1 = Maximum + * 1 0 = Minimum + * 0 1 = updated + * 0 0 = Not Updated + */ +#define C10GB_LT_RCVD_COEFF_PRE_VALUE_OFFSET C10GB_LT_RCVD_COEFF_STATUS_REG_OFFSET +#define C10GB_LT_RCVD_COEFF_PRE_VALUE_SHIFT (0U) +#define C10GB_LT_RCVD_COEFF_PRE_VALUE_MASK BIT_MASK_2_BITS << \ + C10GB_LT_RCVD_COEFF_PRE_VALUE_SHIFT + +/*------------------------------------------------------------------------------ + * TX Coefficient Configuration Register + */ +#define C10GB_LT_TX_COEFF_CFG_REG_OFFSET (0x18U << 2U) + +/* + * Hold Pre Cursor Send + * + * If “1” then hold coefficient is sent to the link partner for pre cursor + */ +#define C10GB_LT_TX_HOLD_PRE_OFFSET C10GB_LT_TX_COEFF_CFG_REG_OFFSET +#define C10GB_LT_TX_HOLD_PRE_SHIFT (10U) +#define C10GB_LT_TX_HOLD_PRE_MASK MASK_BIT_10 + +/* + * Decrement Pre Cursor Send + * + * If “1” then the decrement coefficient is sent to the link partner for pre + * cursor + */ +#define C10GB_LT_TX_DEC_PRE_OFFSET C10GB_LT_TX_COEFF_CFG_REG_OFFSET +#define C10GB_LT_TX_DEC_PRE_SHIFT (9U) +#define C10GB_LT_TX_DEC_PRE_MASK MASK_BIT_9 + +/* + * Increment Pre Cursor Send + * + * If “1” then the increment coefficient is sent to the link partner for pre + * cursor + */ +#define C10GB_LT_TX_INC_PRE_OFFSET C10GB_LT_TX_COEFF_CFG_REG_OFFSET +#define C10GB_LT_TX_INC_PRE_SHIFT (8U) +#define C10GB_LT_TX_INC_PRE_MASK MASK_BIT_8 + +/* + * Hold Post Cursor Send + * + * If “1” then the hold coefficient is sent to the link partner for post + * cursor + */ +#define C10GB_LT_TX_HOLD_POST_OFFSET C10GB_LT_TX_COEFF_CFG_REG_OFFSET +#define C10GB_LT_TX_HOLD_POST_SHIFT (6U) +#define C10GB_LT_TX_HOLD_POST_MASK MASK_BIT_6 + +/* + * Decrement Post Cursor Send + * + * If “1” then the decrement coefficient is sent to the link partner for post + * cursor + */ +#define C10GB_LT_TX_DEC_POST_OFFSET C10GB_LT_TX_COEFF_CFG_REG_OFFSET +#define C10GB_LT_TX_DEC_POST_SHIFT (5U) +#define C10GB_LT_TX_DEC_POST_MASK MASK_BIT_5 + +/* + * Increment Post Cursor Send + * + * If “1” then the increment coefficient is sent to the link partner for post + * cursor + */ +#define C10GB_LT_TX_INC_POST_OFFSET C10GB_LT_TX_COEFF_CFG_REG_OFFSET +#define C10GB_LT_TX_INC_POST_SHIFT (4U) +#define C10GB_LT_TX_INC_POST_MASK MASK_BIT_4 + +/* + * Hold Main Cursor Send + * + * If “1” then the hold coefficient is sent to the link partner for mian + * cursor + */ +#define C10GB_LT_TX_HOLD_MAIN_OFFSET C10GB_LT_TX_COEFF_CFG_REG_OFFSET +#define C10GB_LT_TX_HOLD_MAIN_SHIFT (2U) +#define C10GB_LT_TX_HOLD_MAIN_MASK MASK_BIT_2 + +/* + * Decrement Main Cursor Send + * + * If “1” then the decrement coefficient is sent to the link partner for main + * cursor + */ +#define C10GB_LT_TX_DEC_MAIN_OFFSET C10GB_LT_TX_COEFF_CFG_REG_OFFSET +#define C10GB_LT_TX_DEC_MAIN_SHIFT (1U) +#define C10GB_LT_TX_DEC_MAIN_MASK MASK_BIT_1 + +/* + * Increment Main Cursor Send + * + * If “1” then the increment coefficient is sent to the link partner for main + * cursor + */ +#define C10GB_LT_TX_INC_MAIN_OFFSET C10GB_LT_TX_COEFF_CFG_REG_OFFSET +#define C10GB_LT_TX_INC_MAIN_SHIFT (0U) +#define C10GB_LT_TX_INC_MAIN_MASK MASK_BIT_0 + +/*------------------------------------------------------------------------------ + * PRBS error word count register + */ +#define C10GB_LT_PRBS_ERR_WRD_REG_OFFSET (0x1FU << 2U) + +/* + * PRBS error word count + */ +#define C10GB_LT_PRBS_ERR_WRD_CNT_OFFSET C10GB_LT_PRBS_ERR_WRD_REG_OFFSET +#define C10GB_LT_PRBS_ERR_WRD_CNT_SHIFT (0U) +#define C10GB_LT_PRBS_ERR_WRD_CNT_MASK BIT_MASK_32_BITS << \ + C10GB_LT_PRBS_ERR_WRD_CNT_SHIFT + +/*------------------------------------------------------------------------------ + * 10GBASE-KR Status + */ +#define C10GB_LT_STATUS_REG_OFFSET (0x26U << 2U) + +/* + * RX calibration done + * + * 1’ Indicates remote receiver calibration is done. The Firmware should set + * this bit in response to the RX calibration request. + * This Bit will clear the Bit 2 of this Register. + * + */ +#define C10GB_LT_RX_CAL_DONE_OFFSET C10GB_LT_STATUS_REG_OFFSET +#define C10GB_LT_RX_CAL_DONE_SHIFT (6U) +#define C10GB_LT_RX_CAL_DONE_MASK MASK_BIT_6 + +/* + * Request TX equalization + * + * ‘1’ indicates local receiver is responded for remote receiver rx calibration + * request. + * + */ +#define C10GB_LT_REQ_TX_EQUAL_OFFSET C10GB_LT_STATUS_REG_OFFSET +#define C10GB_LT_REQ_TX_EQUAL_SHIFT (5U) +#define C10GB_LT_REQ_TX_EQUAL_MASK MASK_BIT_5 + +/* + * Signal detect + * + * ‘1’ indicated both local and remote receiver ready. + * + */ +#define C10GB_LT_SIGNAL_DETECT_OFFSET C10GB_LT_STATUS_REG_OFFSET +#define C10GB_LT_SIGNAL_DETECT_SHIFT (4U) +#define C10GB_LT_SIGNAL_DETECT_MASK MASK_BIT_4 + +/* + * Training Fail + * + * ‘1’ indicates 500ms of time is expired during link training + * + */ +#define C10GB_LT_TRAINING_FAIL_OFFSET C10GB_LT_STATUS_REG_OFFSET +#define C10GB_LT_TRAINING_FAIL_SHIFT (3U) +#define C10GB_LT_TRAINING_FAIL_MASK MASK_BIT_3 + +/* + * Request RX calibration + * + * ‘1’ Indicates remote receiver is requested for its calibration + * + */ +#define C10GB_LT_REQ_RX_CAL_OFFSET C10GB_LT_STATUS_REG_OFFSET +#define C10GB_LT_REQ_RX_CAL_SHIFT (2U) +#define C10GB_LT_REQ_RX_CAL_MASK MASK_BIT_2 + +/* + * Link training frame lock + * + * ‘1’ indicates link training frame is detected + * + */ +#define C10GB_LT_FRAME_LOCK_OFFSET C10GB_LT_STATUS_REG_OFFSET +#define C10GB_LT_FRAME_LOCK_SHIFT (1U) +#define C10GB_LT_FRAME_LOCK_MASK MASK_BIT_1 + +/* + * Auto-negotiation good link check + * + * ‘1’ indicates Auto negotiation is completed + * + */ +#define C10GB_AN_GOOD_CHECK_OFFSET C10GB_LT_STATUS_REG_OFFSET +#define C10GB_AN_GOOD_CHECK_SHIFT (0U) +#define C10GB_AN_GOOD_CHECK_MASK MASK_BIT_0 + +/******************************************************************************/ +/* Core10GBaseKR PHY Transmit Control */ +/******************************************************************************/ + +/*------------------------------------------------------------------------------ + * Transmit Control Register + */ +#define C10GB_TX_CTRL_REG_OFFSET (0x0U << 2U) + +/* + * PMA Data Select + * + * PMA TX Data Select. Used to select the TX Raw data from the TX Clause Blocks + * to Serdes Interface. + * 2’b00 – PCS Sublayer clause 49 data will be transmitted to the serdes + * interface + * 2’b10 – Auto Negotiation block, PCS sublayer Clause 73 data will be + * transmitted to the serdes interface + * 2’b11 – Link Training block, PCS sublayer Clause 72 data will be transmitted + * to the serdes interface + * 2’b01 – Reserved + + */ +#define C10GB_TX_CTRL_PMA_DATA_OFFSET C10GB_TX_CTRL_REG_OFFSET +#define C10GB_TX_CTRL_PMA_DATA_SHIFT (0U) +#define C10GB_TX_CTRL_PMA_DATA_MASK BIT_MASK_2_BITS << \ + C10GB_TX_CTRL_PMA_DATA_SHIFT + +/* + * XCVR LOS + * + * Loss of sync signal to the XCVR + * 1 - LOS signal is enabled, XCVR will lock to reference + * 0 - LOS signal is disabled, XCVR will lock to data + */ +#define C10GB_TX_CTRL_XCVR_LOS_OFFSET C10GB_TX_CTRL_REG_OFFSET +#define C10GB_TX_CTRL_XCVR_LOS_SHIFT (4U) +#define C10GB_TX_CTRL_XCVR_LOS_MASK MASK_BIT_4 + +/* + * PCS Tx Reset + * + * Soft reset bit for PCS reset + * 1 - TX logic is reset + * 0 - TX logic is not reset + * Self clearing + */ +#define C10GB_TX_CTRL_TX_RESET_OFFSET C10GB_TX_CTRL_REG_OFFSET +#define C10GB_TX_CTRL_TX_RESET_SHIFT (5U) +#define C10GB_TX_CTRL_TX_RESET_MASK MASK_BIT_5 + +/* + * PCS Rx Reset + * + * Soft reset bit for PCS reset + * 1 - RX logic is reset + * 0 - RX logic is not reset + * Self clearing + */ +#define C10GB_TX_CTRL_RX_RESET_OFFSET C10GB_TX_CTRL_REG_OFFSET +#define C10GB_TX_CTRL_RX_RESET_SHIFT (6U) +#define C10GB_TX_CTRL_RX_RESET_MASK MASK_BIT_6 + +/*------------------------------------------------------------------------------ + * IP version register + */ +#define C10GB_IP_VERSION_REG_OFFSET (0x1U << 2U) + +#define C10GB_IP_VERSION_OFFSET C10GB_IP_VERSION_REG_OFFSET +#define C10GB_IP_VERSION_SHIFT (0U) +#define C10GB_IP_VERSION_MASK BIT_MASK_32_BITS << \ + C10GB_IP_VERSION_SHIFT + + +/******************************************************************************/ +/* Core10GBaseKR PHY Receive Status */ +/******************************************************************************/ + +/*------------------------------------------------------------------------------ + * Receive Status Register + */ +#define C10GB_RX_STATUS_REG_OFFSET (0x0U << 2U) + +/* + * PCS49 Status + * + * Receive Status signal + * 1 – Receiver has attained Block Lock + * 0 – Receiver has not attained the Block Lock + */ +#define C10GB_RX_STATUS_PCS49_OFFSET C10GB_RX_STATUS_REG_OFFSET +#define C10GB_RX_STATUS_PCS49_SHIFT (0U) +#define C10GB_RX_STATUS_PCS49_MASK BIT_MASK_2_BITS << \ + C10GB_RX_STATUS_PCS49_SHIFT + +/******************************************************************************/ +/* Core10GBaseKR_PHY Memory Map */ +/******************************************************************************/ + #define C10GB_AN_BASE_OFFSET (0x0U << 8U) + #define C10GB_LT_BASE_OFFSET (0x4U << 8U) + #define C10GB_TX_CTRL_BASE_OFFSET (0x8U << 8U) + #define C10GB_RX_STATUS_BASE_OFFSET (0x9U << 8U) + +/// @endcond + +#ifdef __cplusplus +} +#endif + +#endif /* CORE10GBASEKR_PHY_REG_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/phy.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/phy.h new file mode 100644 index 0000000..fd15e1d --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/phy.h @@ -0,0 +1,569 @@ +/***************************************************************************//** + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file phy.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief PHY prototypes + * + */ + +/*=========================================================================*//** + @mainpage Core10GBaseKR_PHY Bare Metal Driver + + ============================================================================== + Introduction + ============================================================================== + Core10GBaseKR_PHY is designed for the IEEE® 802.3-2012 specification and + supports the Core10GBaseKR_PHY interface for Backplane operations. This + configurable core provides the Physical (PHY) layer when used with a + transceiver interface. This IP interfaces with the Ten Gigabit Media + Independent Interface (XGMII) compliant Media Access Control (MAC) at the + system side and the transceiver block at the line side. The physical layer is + designed to work seamlessly with the PolarFire® and PolarFire SoC transceiver + using the Physical Medium Attachment (PMA) mode. This user guide documents the + features provided by the Core10GBaseKR_PHY firmware driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + This driver covers the configuration details of features such as IEEE802.3 + clauses 73 and 72. + + See the Core10GBaseKR_PHY User Guide for a detailed description of + design requirements when interfacing the Core10GBaseKR_PHY to a transceiver. + + ============================================================================== + Software Flow Dependencies + ============================================================================== + A PHY software configuration file must be included when using this driver. + This will include the macro definition "CORE10GBASEKR_PHY". The purpose of + this file is to configure desired PHY model and to override driver default + values as required. The driver configuration should be stored in a location + away from the driver source code. The following with path is used in our + recommended directory structure: + + \` + /boards//platform_config/driver_config/phy_sw_cfg.h + \` + + ============================================================================== + Theory of Operation + ============================================================================== + The Core10GBaseKR_PHY driver functions are grouped into the following + categories: + - Initialization + - Configuration + - Clause73: Auto-negotiation + - Clause72: Link training + - 10GBASE-KR + + -------------------------------- + Initialization + -------------------------------- + The Core10GBaseKR_PHY driver is initialized through a call to the + PHY10GKR_init() function. The PHY10GKR_init() function must be called before + calling any other Core10GBaseKR_PHY driver functions. + + -------------------------------- + Configuration + -------------------------------- + An instance of the Core10GBaseKR_PHY is configured with a call to the + PHY10GKR_config(). The configuration function resets all the PHY instance + structure members other than information such as performance counters. + Default configurations can be overridden be defining any of the + Core10GBaseKR_PHY constants before loading the driver using a PHY software + configuration file. + + -------------------------------- + Clause73: Auto-negotiation + -------------------------------- + The IEEE802.3 clause 73 auto-negotiation is enabled and executed by calling + PHY10GKR_autonegotiate_sm() function. + + -------------------------------- + Clause72: Link Training + -------------------------------- + The IEEE802.3 clause 72 link training is enabled and executed by a calling + PHY10GKR_link_training_sm(). The Core10GBaseKR_PHY IP and the + Core10GBaseKR_PHY embedded software driver together carry out the link + training. The driver initiates the link training and takes appropriate actions + depending on the events indicated by the 10GBaseKR status register bits during + the link training process. The following figure shows an overview of what + actions are taken for each 10GBaseKR status bit: + + \include resources/link_training_10gbasekr_status.txt + + Training Failure: The training failure bit is set by the IP when the + Core10GBaseKR_PHY link training timer exceeds 500 ms. The driver also + implements a soft timer as an additional protection layer. The + PHY10GKR_get_current_time_ms() function must be overridden by instantiating + this function in user code so that the current time of a timer will be + returned in milli-seconds. When this status is set by Core10GBaseKR_PHY, + the embedded software must reduce the XCVR data rate by calling + PHY10GKR_serdes_an_config() and restart the auto-negotiation state machine by + calling PHY10GKR_autonegotiate_sm(). + + Rx Calibration: The IP sets this status bit to indicate that there is a + received status report of Max/Min/Updated that the Rx calibration algorithm + must handle. The maximum to minimum sweep algorithm described in the + Core10GBaseKR_PHY User Guide is implemented by the functions which are defined + within core10gbasekr_phy_link_training.h. + + After the Rx calibration algorithm completes, the driver updates the + transmit coefficient with new transmitter tap, which will be sent to the + link partner. + + Tx Equalization: This status bit indicates that the received coefficient + update has been updated and that the firmware needs to update the transceiver + transmitter taps. The driver hands off the new coefficient settings to the + transceiver using the PHY10GKR_serdes_tx_equalization() weak function, + which must be overridden. + + Signal Detect: When the driver identifies that this bit has been set by the + Core10GBaseKR_PHY IP, it sets the link training complete flag. The IP updates + this status bit when both the transmitted and received status reports have the + receiver ready bit set. This indicates that both devices have completed their + Rx calibration algorithm. + + -------------------------------- + 10GBASE-KR + -------------------------------- + The full 10GBASE-KR flow is handled by calling PHY10GKR_10gbasekr_sm() + function. As this function is dependent on interacting with a transceiver, + the following weak functions should be overridden for the specific design + being implemented. + - PHY10GKR_get_current_time_ms() + - PHY10GKR_serdes_an_config() + - PHY10GKR_serdes_lt_config() + - PHY10GKR_serdes_cdr_lock() + - PHY10GKR_serdes_dfe_cal() + - PHY10GKR_serdes_tx_equalization() + + *//*=========================================================================*/ +#ifndef PHY_H_ +#define PHY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "phy_types.h" +#include "core10gbasekr_phy_reg.h" + +#ifdef CORE10GBASEKR_PHY + +/*-------------------------------------------------------------------------*//** + These constant definitions are used as an argument for the function + PHY10GKR_config(). + + */ + +#define MAX_WAIT_TIMER_500MS (161000000U) +#define LT_SOFTWARE_WAIT_TIMER_MS (500U) + +/*-------------------------------------------------------------------------*//** + CORE10GBASEKR_PHY LT MAX/MIN LIMITS + ============================ + The max/min limit constants define the XCVR tap coefficient limits. These + constants can be overridden based on the XCVR, which is integrated into a + specific design. + + Note: Post and Pre tap maximum limits are absolute. + + */ +#ifndef C10GBKR_LT_MAIN_TAP_MAX_LIMIT +#define C10GBKR_LT_MAIN_TAP_MAX_LIMIT (41U) +#endif + +#ifndef C10GBKR_LT_MAIN_TAP_MIN_LIMIT +#define C10GBKR_LT_MAIN_TAP_MIN_LIMIT (26U) +#endif + +#ifndef C10GBKR_LT_POST_TAP_MAX_LIMIT +#define C10GBKR_LT_POST_TAP_MAX_LIMIT (16U) +#endif + +#ifndef C10GBKR_LT_POST_TAP_MIN_LIMIT +#define C10GBKR_LT_POST_TAP_MIN_LIMIT (0U) +#endif + +#ifndef C10GBKR_LT_PRE_TAP_MAX_LIMIT +#define C10GBKR_LT_PRE_TAP_MAX_LIMIT (5U) +#endif + +#ifndef C10GBKR_LT_PRE_TAP_MIN_LIMIT +#define C10GBKR_LT_PRE_TAP_MIN_LIMIT (0U) +#endif + +/*-------------------------------------------------------------------------*//** + CORE10GBASEKR_PHY PRESET + ============================ + The preset constants define the XCVR tap coefficient settings for a preset + request. They can be overridden based on the XCVR, which is integrated into a + specific design. + + Note: Post and Pre tap maximum limits are absolute. + + */ +#ifndef C10GBKR_LT_PRESET_MAIN_TAP +#define C10GBKR_LT_PRESET_MAIN_TAP C10GBKR_LT_MAIN_TAP_MAX_LIMIT +#endif + +#ifndef C10GBKR_LT_PRESET_POST_TAP +#define C10GBKR_LT_PRESET_POST_TAP C10GBKR_LT_POST_TAP_MAX_LIMIT +#endif + +#ifndef C10GBKR_LT_PRESET_PRE_TAP +#define C10GBKR_LT_PRESET_PRE_TAP C10GBKR_LT_PRE_TAP_MAX_LIMIT +#endif + +/*-------------------------------------------------------------------------*//** + CORE10GBASEKR_PHY INIT + ============================ + The initialize constants define the coefficient settings, which is set + when an initialize request is received from the link partner. These constants + should be updated if there is no desire to calibrate the links. + + */ +#ifndef C10GBKR_LT_INITIALIZE_MAIN_TAP +#define C10GBKR_LT_INITIALIZE_MAIN_TAP C10GBKR_LT_MAIN_TAP_MIN_LIMIT +#endif + +#ifndef C10GBKR_LT_INITIALIZE_POST_TAP +#define C10GBKR_LT_INITIALIZE_POST_TAP C10GBKR_LT_POST_TAP_MIN_LIMIT +#endif + +#ifndef C10GBKR_LT_INITIALIZE_PRE_TAP +#define C10GBKR_LT_INITIALIZE_PRE_TAP C10GBKR_LT_PRE_TAP_MIN_LIMIT +#endif + +/*-------------------------------------------------------------------------*//** + CORE10GBASEKR_PHY LP REQUEST + ============================ + This constant defines the request, which will be sent to the link partner and + determines which algorithm will be implemented to calibrate the link partner. + + */ +#ifndef C10GBKR_LT_INITIAL_REQUEST +#define C10GBKR_LT_INITIAL_REQUEST C10GBKR_LT_PRESET +#endif + +/*-------------------------------------------------------------------------*//** + CORE10GBASEKR_PHY AN LINK FAIL INHIBIT TIMER + ============================ + This constant defines the auto-negotiation link fail inhibit timer timeout in + milli-seconds. + + */ +#ifndef C10GBKR_AN_LINK_FAIL_INHITBIT_TIMER +#define C10GBKR_AN_LINK_FAIL_INHITBIT_TIMER\ + (500U) +#endif + +#endif /* CORE10GBASEKR_PHY */ + +/*------------------------Public Function-------------------------------------*/ + +#ifdef CORE10GBASEKR_PHY +/***************************************************************************//** + The PHY10GKR_init() function initializes the Core10GBaseKR_PHY bare-metal + driver. This function sets the base address of the Auto-negotiation, link- + training, tx control, and rx status registers. + + @param this_phy + The this_phy parameter specifies the PHY instance. + + @param base_addr + The base_addr specifies the base address of the IP block. + + @return + This function does not return a value. + + @example + @code + #include "phy.h" + int main(void) + { + PHY10GKR_init(&g_phy, CORE10GBKR_0_PHY_BASE_ADDR); + return (0u); + } + @endcode + */ +void +PHY10GKR_init +( + phy10gkr_instance_t * this_phy, + addr_t base_addr +); + +/***************************************************************************//** + The PHY10GKR_config() function configures the PHY registers with the + predefined defaults and user configurations. This function also resets the + structures back to their initial conditions. + + @param this_phy + The this_phy parameter specifies the PHY instance. + + @return + This function does not return a value. + + @example + @code + #include "phy.h" + int main(void) + { + PHY10GKR_init(&g_phy, CORE10GBKR_0_PHY_BASE_ADDR); + PHY10GKR_config(&g_phy); + return (0u); + } + @endcode + */ +void +PHY10GKR_config +( + phy10gkr_instance_t * this_phy +); + +/***************************************************************************//** + The PHY10GKR_autonegotiate_sm() function enables the auto-negotiation API + state machine, which enables the auto-negotiation registers and then checks the + status of the auto-negotiation state machine to determine if auto-negotiation + has complete. + + @param this_phy + The this_phy parameter specifies the PHY instance. + + @return + This function does not return a value. + + @example + @code + #include "phy.h" + int main(void) + { + PHY10GKR_init(&g_phy, CORE10GBKR_0_PHY_BASE_ADDR); + while(1) + { + PHY10GKR_autonegotiate_sm(&g_phy); + if(STATUS_AN_COMPLETE == g_phy.an.complete) + { + break; + } + } + return (0u); + } + @endcode + */ +void +PHY10GKR_autonegotiate_sm +( + phy10gkr_instance_t * this_phy +); + +/***************************************************************************//** + The PHY10GKR_link_training_sm() function enables the link training API + state machine, which enables the link training registers and then runs the + link training algorithm. + + The connected transceiver must have a data rate of 10 Gbps and locked to a + link partner with the same data rate for successful link training. + + @param this_phy + The this_phy parameter specifies the PHY instance. + + @return + This function does not return a value. + + @example + @code + #include "phy.h" + int main(void) + { + PHY10GKR_init(&g_phy, CORE10GBKR_0_PHY_BASE_ADDR); + while(1) + { + PHY10GKR_link_training_sm(&g_phy); + if(STATUS_LT_FAILURE == g_phy.lt.status) + { + HAL_ASSERT(0); + } + } + return (0u); + } + @endcode + */ +void +PHY10GKR_link_training_sm +( + phy10gkr_instance_t * this_phy +); + +/***************************************************************************//** + The PHY10GKR_10gbasekr_sm() executes the full 10GBASE-KR flow required to + complete the auto-negotiation and link training. + + The 10GBASE-KR status enumeration allows the user to debug the auto-negotiation + and link training algorithms. + + @param this_phy + The this_phy parameter specifies the PHY instance. + + @return + This function returns a state machine status. + + @example + @code + #include "phy.h" + int main(void) + { + uint32_t status; + PHY10GKR_init(&g_phy, CORE10GBKR_0_PHY_BASE_ADDR); + while(1) + { + status = PHY10GKR_10gbasekr_sm(&g_phy); + if(LINK_ESTABLISHED == status) + { + break; + } + } + return (0u); + } + @endcode + */ +uint32_t +PHY10GKR_10gbasekr_sm +( + phy10gkr_instance_t * this_phy +); + +/***************************************************************************//** + The PHY10GKR_set_lane_los_signal() asserts and deasserts the transceivers + Lane Loss of signal detection. + + @param state + Asserts or deasserts the lane LOS + + @return + This function does not return a value. + */ +void +PHY10GKR_set_lane_los_signal +( + phy10gkr_instance_t * this_phy, + uint32_t state +); + +/***************************************************************************//** + The PHY10GKR_get_current_time_ms() is a weak function that can be overridden + by the user to get the current time in milli-seconds. + + @return + This function returns the time in milli-seconds. + */ +uint32_t __attribute__((weak)) +PHY10GKR_get_current_time_ms +( + void +); + +/***************************************************************************//** + The PHY10GKR_serdes_an_config() is a weak function that can be overridden + by the user to configure the XCVR instance integrated in their design + for auto-negotiation. + + @return + This function does not return a value. + */ +void __attribute__((weak)) +PHY10GKR_serdes_an_config +( + void +); + +/***************************************************************************//** + The PHY10GKR_serdes_lt_config() is a weak function that can be overridden + by the user to configure the XCVR instance integrated in their design + for link training at 10 Gbps. + + @return + This function does not return a value. + */ +uint32_t __attribute__((weak)) +PHY10GKR_serdes_lt_config +( + void +); + +/***************************************************************************//** + The PHY10GKR_serdes_cdr_lock() is a weak function that can be overridden by + the user to determine that the XCVR instance integrated has achieved a CDR + lock. + + @return + This function returns 0 on success and 1 on failure. + */ +uint32_t __attribute__((weak)) +PHY10GKR_serdes_cdr_lock +( + void +); + +/***************************************************************************//** + The PHY10GKR_serdes_dfe_cal() is a weak function that can be overridden by + the user to determine that the XCVR instance integrated has completed DFE + calibration. + + Note this function should constantly check if the link training + failure time has timeout and if so exit the function. + + @return + This function does not return a value. + */ +uint32_t __attribute__((weak)) +PHY10GKR_serdes_dfe_cal +( + void +); + +/***************************************************************************//** + The PHY10GKR_serdes_tx_equalization() is a weak function that can be + overridden by the user to set the current XCVR tap coefficients. + + @return + This function does not return a value. + */ +void __attribute__((weak)) +PHY10GKR_serdes_tx_equalization +( + uint32_t tx_main_tap, + uint32_t tx_post_tap, + uint32_t tx_pre_tap +); + +#endif /* CORE10GBASEKR_PHY */ + +#ifdef __cplusplus +} +#endif + +#endif /* PHY_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/phy_types.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/phy_types.h new file mode 100644 index 0000000..3b09458 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/phy_types.h @@ -0,0 +1,337 @@ +/***************************************************************************//** + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file phy_types.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief PHY types + * + */ + +#ifndef PHY_TYPES_H_ +#define PHY_TYPES_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "platform_config/driver_config/phy_sw_cfg.h" +#include "hal/hal.h" + +#ifdef CORE10GBASEKR_PHY +/***************************************************************************//** + The phy10gkr_lane_los_t enumeration identifies the state of the lane loss + detection. + */ +typedef enum __lane_los_state +{ + LANE_LOS_LOCK_TO_DATA = 0, + LANE_LOS_LOCK_TO_REF = 1 +} phy10gkr_lane_los_t; + +/***************************************************************************//** + The phy10gkr_timer_t structure describes the start and end time instance of + the measurement with the PHY driver. + */ +typedef struct __phy_timer +{ + uint32_t start; + uint32_t end; +} phy10gkr_timer_t; + +/***************************************************************************//** + The phy10gkr_an_state_t enumeration is used to identify the state of the auto- + negotiation arbitration state machine, which is implemented by the + Core10GBaseKR_PHY. + */ +typedef enum __an_state +{ + ST_AUTO_NEG_ENABLE = 0x0, + ST_TRANSMIT_DISABLE = 0x1, + ST_ABILITY_DETECT = 0x2, + ST_ACKNOWLEDGE_DETECT = 0x3, + ST_COMPLETE_ACKNOWLEDEGE = 0x4, + ST_AN_GOOD_CHECK = 0x5, + ST_AN_GOOD = 0x6, + ST_NEXT_PAGE_WAIT = 0x7, + ST_NEXT_PAGE_WAIT_TX_IDLE = 0x8, + ST_LINK_STATUS_CHECK = 0x9, + ST_PARALLEL_DETECTION_FAULT = 0xA +} phy10gkr_an_state_t; + +/***************************************************************************//** + The phy10gkr_an_status_t enumeration specifies the status of auto-negotiation. + */ +typedef enum __an_status +{ + STATUS_AN_INCOMPLETE, + STATUS_AN_COMPLETE +} phy10gkr_an_status_t; + +/***************************************************************************//** + The phy10gkr_an_api_state_t enumeration identifies the state of the + auto-negotiation state machine API. + */ +typedef enum __api_status +{ + AN_API_SM_INIT, + AN_API_SM_STATUS_UPDATE +} phy10gkr_an_api_state_t; + +/***************************************************************************//** + The phy10gkr_an_instance_t struct describes an instance of the + auto-negotiation parameters. + */ +typedef struct __an_instance +{ + phy10gkr_an_state_t state; + phy10gkr_an_api_state_t api_state; + + uint32_t complete_cnt; + phy10gkr_an_status_t status; +} phy10gkr_an_instance_t; + +/***************************************************************************//** + The phy10gkr_lt_state_t enumeration identifies the link training state machine + state implemented by the Core10GBaseKr_PHY IP block. + */ +typedef enum __lt_state +{ + LT_STATE_IDLE = 0, + LT_STATE_INITIALIZE = 1, + LT_STATE_SEND_TRAINING = 3, + LT_STATE_TRAIN_LOCAL = 2, + LT_STATE_TRAIN_REMOTE = 6, + LT_STATE_LINK_READY = 7, + LT_STATE_SEND_DATA = 5, + LT_STATE_FAILURE = 4 +} phy10gkr_lt_state_t; + +/***************************************************************************//** + The phy10gkr_lt_link_status_t enumeration identifies the status and state of + the link with the link partner. + */ +typedef enum __lt_link_status +{ + STATUS_LT_INCOMPLETE, + STATUS_LT_COMPLETE, + STATUS_LT_LINK_MAINTAINED, + STATUS_LT_FAILURE +} phy10gkr_lt_link_status_t; + +/***************************************************************************//** + The phy10gkr_lt_api_state_t enumeration identifies the link training API state + machine state. + */ +typedef enum __lt_api_status +{ + LT_API_SM_INIT, + LT_API_SM_STATUS_UPDATE +} phy10gkr_lt_api_state_t; + +/***************************************************************************//** + The phy10gkr_coeff_update_status_t enumeration identifies the status of the + coefficient sweep algorithm. + */ +typedef enum coeff_update_status +{ + SWEEP_NOT_STARTED, + SWEEP_START, + SWEEP_INCOMPLETE, + SWEEP_COMPLETE, +} phy10gkr_coeff_update_status_t; + +/***************************************************************************//** + This enumeration identifies the initial conditions of a device. For example, + the local device will calibrate using a preset request. + */ +typedef enum __calirbation_request +{ + C10GBKR_LT_PRESET = 0U, + C10GBKR_LT_INITALISE = 1U +} phy10gkr_calirbation_request_t; + +/***************************************************************************//** + The phy10gkr_coeff_status_report_t enumeration identifies the link training + status report update. + */ +typedef enum coeff_status_report +{ + LT_COEFF_STATUS_NOT_UPDATED = 0U, + LT_COEFF_STATUS_UPDATED = 1U, + LT_COEFF_STATUS_MIN = 2U, + LT_COEFF_STATUS_MAX = 3U +} phy10gkr_coeff_status_report_t; + +/***************************************************************************//** + This enumeration specifies the three different transmitter taps. + */ +typedef enum tx_equalizer_tap +{ + PRE_TAP, + MAIN_TAP, + POST_TAP +} phy10gkr_tx_equalizer_tap_t; + +/***************************************************************************//** + This enumeration specifies the state of the link partner calibration + algorithm. + */ +typedef enum tap_cal_state +{ + TAP_MAX_CAL, + TAP_MIN_CAL, + TAP_OPTIMISE_CAL +} phy10gkr_tap_cal_state_t; + +/***************************************************************************//** + This enumeration specifies the condition of the link partner calibration + algorithm. During training, when the link partner has been calibrated, the + local receiver ready lock get locked and the status report will be updated + to notify the link partner. + */ +typedef enum local_rxcvr_lock +{ + LOCAL_RXCVR_UNLOCKED = 0, + LOCAL_RXCVR_LOCKED = 1 +} phy10gkr_local_rxcvr_lock_t; + +/***************************************************************************//** + The coeff_update_t struct describes an instance of the link training + coefficient update. This structure supports calibrating the link partners + transmitter taps. + */ +typedef struct coeff_update +{ + uint32_t cnt; + uint32_t inc_cnt; + uint32_t hold_cnt; + uint32_t dec_cnt; + uint32_t max_cnt; + uint32_t min_cnt; + uint32_t update_cnt; + uint32_t no_update_cnt; + uint32_t done_cnt; + uint32_t index; + phy10gkr_coeff_update_status_t status; + + phy10gkr_tap_cal_state_t lp_tap_cal_state; + + uint32_t optimal_index; + uint32_t optimal_cnt; +} phy10gkr_coeff_update_t; + +/***************************************************************************//** + The an_instance_t struct describes an instance of the link training + parameters. + */ +typedef struct __lt_instance +{ + phy10gkr_lt_state_t state; + phy10gkr_lt_api_state_t api_state; + phy10gkr_lt_link_status_t status; + + phy10gkr_timer_t timer; + + phy10gkr_calirbation_request_t tx_request; + phy10gkr_calirbation_request_t rx_request; + + uint32_t fail_cnt; + uint32_t complete_cnt; + uint32_t tx_equ_cnt; + uint32_t rx_cal_cnt; + uint32_t sig_cnt; + uint32_t rcvr_cnt; + + uint32_t sm_cycle_cnt; + + phy10gkr_tx_equalizer_tap_t lp_cal_sweep_state; + phy10gkr_coeff_update_t main; + phy10gkr_coeff_update_t post; + phy10gkr_coeff_update_t pre; + + phy10gkr_local_rxcvr_lock_t local_rxcvr; +} phy10gkr_lt_instance_t; + +/***************************************************************************//** + The c10gbkr_state_t enumeration identifies the state of the 10GBASE-KR state + machine. + */ +typedef enum __c10gbkr_state +{ + AN_SERDES_CONFIG, + AN_SM, + LT_SERDES_CONFIG, + LT_SM, + LINK_ESTABLISHED_CHECK +} phy10gkr_state_t; + +/***************************************************************************//** + The c10gbkr_status_t enumeration identifies the status of the 10GBASE-KR + state machine. + + This enumeration can identify failures encountered by the 10GBASE-KR + algorithm. + */ +typedef enum __c10gbkr_status +{ + AN_SERDES_CONFIGURATION = 1, + AN_IN_PROGRESS = 2, + AN_COMPLETE = 3, + LT_SERDES_CONFIGURATION = 4, + LT_SERDES_CAL_FAILURE = 5, + LT_SERDES_CAL_COMPLETE = 6, + LT_IN_PROGRESS = 7, + LT_FAILURE = 8, + LINK_BROKEN = 9, + LINK_ESTABLISHED = 0 +} phy10gkr_status_t; + +/***************************************************************************//** + The phy10gkr_instance_t struct describes an instance of the Core10GBaseKR_PHY + parameters. + */ +typedef struct __phy10gkr_instance +{ + addr_t base_addr; + addr_t an_base_addr; + addr_t lt_base_addr; + addr_t tx_ctrl_base_addr; + addr_t rx_status_base_addr; + + phy10gkr_an_instance_t an; + phy10gkr_lt_instance_t lt; + + phy10gkr_state_t c10gbkr_state; + phy10gkr_status_t c10gbkr_status; + + uint32_t serdes_id; + uint32_t serdes_lane_id; +} phy10gkr_instance_t; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* PHY_TYPES_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/resources/link_training_10gbasekr_status.txt b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/resources/link_training_10gbasekr_status.txt new file mode 100644 index 0000000..5948625 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/resources/link_training_10gbasekr_status.txt @@ -0,0 +1,28 @@ +
+%%{init : {"flowchart" : {"curve" : "linear", "useMaxWidth" : false, "useMaxHeight" : false, "nodeSpacing" : 30, "rankSpacing" : 40 }}}%% + flowchart TB + Start[/10GBASE-KR Status Register\] --> Rx[Rx Calibration] + Start --> Tx[Tx Equalization] + Start --> Fail[Fail] + Start --> Signal[Signal Detect] + + Fail --> LTFail[LT Failure] + + Rx --> IntRx[Set RX Calibration Bit to Clear Status Bit] + IntRx --> Algo[Max/Min Tap Sweep Algorithm] + Algo --> TxCU[Update the Tx Coefficient Update] + + Tx --> SerdesTX[Pass Rx Coefficient Update to Serdes] + SerdesTX --> TxSR[Update Tx Status Report] + TxSR --> TxDone[Set Tx Equalization Done to Clear Status Bit] + + Signal --> LTComp[LT Complete] + +
+ + \ No newline at end of file diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/uint_32_bit_masks.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/uint_32_bit_masks.h new file mode 100644 index 0000000..4826dec --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/Core10GBaseKR_PHY/uint_32_bit_masks.h @@ -0,0 +1,114 @@ +/***************************************************************************//** + * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * @file uint_32_bit_masks.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief unsigned 32 bit masks + * + */ + +#ifndef UNIT_32_BIT_MASKS_H_ +#define UNIT_32_BIT_MASKS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Single Bit Mask + */ +#define MASK_BIT_31 ((uint32_t)(0x80000000UL)) +#define MASK_BIT_30 ((uint32_t)(0x40000000UL)) +#define MASK_BIT_29 ((uint32_t)(0x20000000UL)) +#define MASK_BIT_28 ((uint32_t)(0x10000000UL)) +#define MASK_BIT_27 ((uint32_t)(0x08000000UL)) +#define MASK_BIT_26 ((uint32_t)(0x04000000UL)) +#define MASK_BIT_25 ((uint32_t)(0x02000000UL)) +#define MASK_BIT_24 ((uint32_t)(0x01000000UL)) +#define MASK_BIT_23 ((uint32_t)(0x00800000UL)) +#define MASK_BIT_22 ((uint32_t)(0x00400000UL)) +#define MASK_BIT_21 ((uint32_t)(0x00200000UL)) +#define MASK_BIT_20 ((uint32_t)(0x00100000UL)) +#define MASK_BIT_19 ((uint32_t)(0x00080000UL)) +#define MASK_BIT_18 ((uint32_t)(0x00040000UL)) +#define MASK_BIT_17 ((uint32_t)(0x00020000UL)) +#define MASK_BIT_16 ((uint32_t)(0x00010000UL)) +#define MASK_BIT_15 ((uint32_t)(0x00008000UL)) +#define MASK_BIT_14 ((uint32_t)(0x00004000UL)) +#define MASK_BIT_13 ((uint32_t)(0x00002000UL)) +#define MASK_BIT_12 ((uint32_t)(0x00001000UL)) +#define MASK_BIT_11 ((uint32_t)(0x00000800UL)) +#define MASK_BIT_10 ((uint32_t)(0x00000400UL)) +#define MASK_BIT_9 ((uint32_t)(0x00000200UL)) +#define MASK_BIT_8 ((uint32_t)(0x00000100UL)) +#define MASK_BIT_7 ((uint32_t)(0x00000080UL)) +#define MASK_BIT_6 ((uint32_t)(0x00000040UL)) +#define MASK_BIT_5 ((uint32_t)(0x00000020UL)) +#define MASK_BIT_4 ((uint32_t)(0x00000010UL)) +#define MASK_BIT_3 ((uint32_t)(0x00000008UL)) +#define MASK_BIT_2 ((uint32_t)(0x00000004UL)) +#define MASK_BIT_1 ((uint32_t)(0x00000002UL)) +#define MASK_BIT_0 ((uint32_t)(0x00000001UL)) + +/* + * Multi Bit Mask + */ +#define BIT_MASK_32_BITS ((uint32_t)(0xFFFFFFFFUL)) +#define BIT_MASK_31_BITS ((uint32_t)(0x7FFFFFFFUL)) +#define BIT_MASK_30_BITS ((uint32_t)(0x3FFFFFFFUL)) +#define BIT_MASK_29_BITS ((uint32_t)(0x1FFFFFFFUL)) +#define BIT_MASK_28_BITS ((uint32_t)(0x0FFFFFFFUL)) +#define BIT_MASK_27_BITS ((uint32_t)(0x07FFFFFFUL)) +#define BIT_MASK_26_BITS ((uint32_t)(0x03FFFFFFUL)) +#define BIT_MASK_25_BITS ((uint32_t)(0x01FFFFFFUL)) +#define BIT_MASK_24_BITS ((uint32_t)(0x00FFFFFFUL)) +#define BIT_MASK_23_BITS ((uint32_t)(0x007FFFFFUL)) +#define BIT_MASK_22_BITS ((uint32_t)(0x003FFFFFUL)) +#define BIT_MASK_21_BITS ((uint32_t)(0x001FFFFFUL)) +#define BIT_MASK_20_BITS ((uint32_t)(0x000FFFFFUL)) +#define BIT_MASK_19_BITS ((uint32_t)(0x0007FFFFUL)) +#define BIT_MASK_18_BITS ((uint32_t)(0x0003FFFFUL)) +#define BIT_MASK_17_BITS ((uint32_t)(0x0001FFFFUL)) +#define BIT_MASK_16_BITS ((uint32_t)(0x0000FFFFUL)) +#define BIT_MASK_15_BITS ((uint32_t)(0x00007FFFUL)) +#define BIT_MASK_14_BITS ((uint32_t)(0x00003FFFUL)) +#define BIT_MASK_13_BITS ((uint32_t)(0x00001FFFUL)) +#define BIT_MASK_12_BITS ((uint32_t)(0x00000FFFUL)) +#define BIT_MASK_11_BITS ((uint32_t)(0x000007FFUL)) +#define BIT_MASK_10_BITS ((uint32_t)(0x000003FFUL)) +#define BIT_MASK_9_BITS ((uint32_t)(0x000001FFUL)) +#define BIT_MASK_8_BITS ((uint32_t)(0x000000FFUL)) +#define BIT_MASK_7_BITS ((uint32_t)(0x0000007FUL)) +#define BIT_MASK_6_BITS ((uint32_t)(0x0000003FUL)) +#define BIT_MASK_5_BITS ((uint32_t)(0x0000001FUL)) +#define BIT_MASK_4_BITS ((uint32_t)(0x0000000FUL)) +#define BIT_MASK_3_BITS ((uint32_t)(0x00000007UL)) +#define BIT_MASK_2_BITS ((uint32_t)(0x00000003UL)) + + + +#ifdef __cplusplus +} +#endif + +#endif /* UNIT_32_BIT_MASKS_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreGPIO/core_gpio.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c similarity index 99% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreGPIO/core_gpio.c rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c index 63cd377..1a0073f 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreGPIO/core_gpio.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.c @@ -1,6 +1,8 @@ /******************************************************************************* - * (c) Copyright 2008-2021 Microchip FPGA Embedded Systems Solutions. + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. * + * SPDX-License-Identifier: MIT + * * @file core_gpio.c * @author Microchip FPGA Embedded Systems Solutions * @brief CoreGPIO bare metal driver implementation. diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreGPIO/core_gpio.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h similarity index 60% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreGPIO/core_gpio.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h index 3491d68..88ba178 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreGPIO/core_gpio.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreGPIO/core_gpio.h @@ -1,5 +1,5 @@ /******************************************************************************* - * (c) Copyright 2008-2021 Microchip FPGA Embedded Systems Solutions. + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -31,18 +31,18 @@ @mainpage CoreGPIO Bare Metal Driver. @section intro_sec Introduction - The CoreGPIO hardware IP includes up to 32 general purpose input output GPIOs. + The CoreGPIO hardware IP includes up to 32 general-purpose input/output GPIOs. This driver provides a set of functions for controlling the GPIOs 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 + bare-metal system where no operating system is available. These drivers + can be adapted for use as part of an operating system, but the implementation of the adaptation layer between this driver and the operating system's driver model is outside the scope of this driver. @section driver_configuration Driver Configuration - The CoreGPIO individual IOs can be configured either in the hardware flow or - as part of the software application through calls to the GPIO_config() function. - GPIOs configured as as part of the hardware is fixed and cannot be modified - using a call to the GPI_config() function. + The individual IOs of CoreGPIO can be configured either in the hardware flow + or as part of the software application through calls to the GPIO_config() + function. GPIOs configured as part of the hardware are fixed and cannot be + modified using a call to the GPI_config() function. @section theory_op Theory of Operation The CoreGPIO driver uses the Actel Hardware Abstraction Layer (HAL) to access @@ -61,14 +61,14 @@ can be called. Each GPIO port is individually configured through a call to the - GPIO_config() function. Configuration includes deciding if a GPIO port - will be used as input, 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. - Please note that a CoreGPIO hardware instance can be generated, as part of the - hardware flow, with a fixed configuration for some or all of its IOs. Attempting - to modify the configuration of such a hardware configured IO using the - GPIO_config() function has no effect. + GPIO_config() function. Configuration includes deciding if a GPIO port is + going to be used as input, output, or both. GPIO ports configured as inputs + are further configured to generate interrupts based on the state of input. + Interrupts is either level- or edge-sensitive. + Note that a CoreGPIO hardware instance is generated as part of the hardware + flow with a fixed configuration for some or all of its IOs. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. The state of the GPIO ports can be read and written using the following functions: @@ -96,6 +96,10 @@ #include "hal.h" #endif +#ifdef __cplusplus +extern "C" { +#endif + /*-------------------------------------------------------------------------*//** The gpio_id_t enumeration is used to identify GPIOs as part of the parameter to functions: @@ -141,6 +145,9 @@ typedef enum __gpio_id_t GPIO_31 = 31 } gpio_id_t; +/*-------------------------------------------------------------------------*//** + Possible width of the APB bus + */ typedef enum __gpio_apb_width_t { GPIO_APB_8_BITS_BUS = 0, @@ -150,6 +157,7 @@ typedef enum __gpio_apb_width_t } gpio_apb_width_t; /*-------------------------------------------------------------------------*//** + Structure instance holding all data regarding the CoreGPIO */ typedef struct __gpio_instance_t { @@ -159,9 +167,41 @@ typedef struct __gpio_instance_t /*-------------------------------------------------------------------------*//** GPIO ports definitions used to identify GPIOs as part of the parameter to - function GPIO_set_outputs(). - These definitions can also be used to identity GPIO through logical - operations on the return value of function GPIO_get_inputs(). + function GPIO_set_outputs(). + These definitions are also be used to identity GPIO through logical operations + on the return value of function GPIO_get_inputs(). + # GPIO_0_MASK + # GPIO_1_MASK + # GPIO_2_MASK + # GPIO_3_MASK + # GPIO_4_MASK + # GPIO_5_MASK + # GPIO_6_MASK + # GPIO_7_MASK + # GPIO_8_MASK + # GPIO_9_MASK + # GPIO_10_MASK + # GPIO_11_MASK + # GPIO_12_MASK + # GPIO_13_MASK + # GPIO_14_MASK + # GPIO_15_MASK + # GPIO_16_MASK + # GPIO_17_MASK + # GPIO_18_MASK + # GPIO_19_MASK + # GPIO_20_MASK + # GPIO_21_MASK + # GPIO_22_MASK + # GPIO_23_MASK + # GPIO_24_MASK + # GPIO_25_MASK + # GPIO_26_MASK + # GPIO_27_MASK + # GPIO_28_MASK + # GPIO_29_MASK + # GPIO_30_MASK + # GPIO_31_MASK */ #define GPIO_0_MASK 0x00000001UL #define GPIO_1_MASK 0x00000002UL @@ -198,6 +238,9 @@ typedef struct __gpio_instance_t /*-------------------------------------------------------------------------*//** * GPIO modes + * # GPIO_INPUT_MODE + * # GPIO_OUTPUT_MODE + * # GPIO_INOUT_MODE */ #define GPIO_INPUT_MODE 0x0000000002UL #define GPIO_OUTPUT_MODE 0x0000000005UL @@ -205,6 +248,11 @@ typedef struct __gpio_instance_t /*-------------------------------------------------------------------------*//** * Possible GPIO inputs interrupt configurations. + * # GPIO_IRQ_LEVEL_HIGH + * # GPIO_IRQ_LEVEL_LOW + * # GPIO_IRQ_EDGE_POSITIVE + * # GPIO_IRQ_EDGE_NEGATIVE + * # GPIO_IRQ_EDGE_BOTH */ #define GPIO_IRQ_LEVEL_HIGH 0x0000000000UL #define GPIO_IRQ_LEVEL_LOW 0x0000000020UL @@ -213,7 +261,7 @@ typedef struct __gpio_instance_t #define GPIO_IRQ_EDGE_BOTH 0x0000000080UL /*-------------------------------------------------------------------------*//** - * Possible states for GPIO configured as INOUT. + * Possible states for GPIO configured as INOUT */ typedef enum gpio_inout_state { @@ -223,29 +271,29 @@ typedef enum gpio_inout_state } gpio_inout_state_t; /*-------------------------------------------------------------------------*//** - The GPIO_init() function initialises a CoreGPIO hardware instance and the data - structure associated with the CoreGPIO hardware instance. - Please note that a CoreGPIO hardware instance can be generated with a fixed - configuration for some or all of its IOs as part of the hardware flow. Attempting - to modify the configuration of such a hardware configured IO using the - GPIO_config() function has no effect. + The GPIO_init() function initializes a CoreGPIO hardware instance and the data + structure associated with the CoreGPIO hardware instance. + Note that a CoreGPIO hardware instance is generated with a fixed configuration + for some or all of its IOs as part of the hardware flow. + Attempting to modify the configuration of such a hardware-configured IO using + the GPIO_config() function has no effect. @param this_gpio Pointer to the gpio_instance_t data structure instance holding all data regarding the CoreGPIO hardware instance being initialized. A pointer to the - same data structure will be used in subsequent calls to the CoreGPIO driver - functions in order to identify the CoreGPIO instance that should perform the + same data structure is used in subsequent calls to the CoreGPIO driver + functions in order to identify the CoreGPIO instance that must perform the operation implemented by the called driver function. @param base_addr - The base_addr parameter is the base address in the processor's memory map for - the registers of the GPIO instance being initialized. + The base_addr parameter is the base address in the memory map of the + processor for the registers of the GPIO instance being initialized. @param bus_width - The bus_width parameter informs the driver of the APB bus width selected during - the hardware flow configuration of the CoreGPIO hardware instance. It indicates - to the driver whether the CoreGPIO hardware registers will be visible as 8, 16 - or 32 bits registers. Allowed value are: + The bus_width parameter informs the driver of the APB bus width selected + during the hardware flow configuration of the CoreGPIO hardware instance. It + indicates to the driver whether the CoreGPIO hardware registers are visible + as 8, 16, or 32-bits registers. Allowed values are: - GPIO_APB_8_BITS_BUS - GPIO_APB_16_BITS_BUS - GPIO_APB_32_BITS_BUS @@ -253,7 +301,7 @@ typedef enum gpio_inout_state @return none. - Example: + @example @code #define COREGPIO_BASE_ADDR 0xC2000000 @@ -276,36 +324,38 @@ void GPIO_init The GPIO_config() function is used to configure an individual GPIO port. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @param port_id The port_id parameter identifies the GPIO port to be configured. - An enumeration item of the form GPIO_n where n is the number of the GPIO - port is used to identify the GPIO port. For example GPIO_0 identifies the + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the first GPIO port and GPIO_31 the last one. @param config The config parameter specifies the configuration to be applied to the GPIO port identified by the first parameter. It is a logical OR of GPIO mode and - the interrupt mode. The interrupt mode is only relevant if the GPIO is - configured as input. - Possible modes are: - - GPIO_INPUT_MODE, - - GPIO_OUTPUT_MODE, - - GPIO_INOUT_MODE. - Possible interrupt modes are: - - GPIO_IRQ_LEVEL_HIGH, - - GPIO_IRQ_LEVEL_LOW, - - GPIO_IRQ_EDGE_POSITIVE, - - GPIO_IRQ_EDGE_NEGATIVE, - - GPIO_IRQ_EDGE_BOTH + interrupt mode. The interrupt mode is only relevant if the GPIO is + configured as an input. + - Possible modes are: + - GPIO_INPUT_MODE, + - GPIO_OUTPUT_MODE, + - GPIO_INOUT_MODE. + - Possible interrupt modes are: + - GPIO_IRQ_LEVEL_HIGH, + - GPIO_IRQ_LEVEL_LOW, + - GPIO_IRQ_EDGE_POSITIVE, + - GPIO_IRQ_EDGE_NEGATIVE, + - GPIO_IRQ_EDGE_BOTH @return none. - - For example the following call will configure GPIO 4 as an input generating - interrupts on a low to high transition of the input: + + @example + For example, the following call configures GPIO 4 as an input that generates + interrupts on a low-to-high transition of the input: @code GPIO_config( &g_gpio, GPIO_4, GPIO_INPUT_MODE | GPIO_IRQ_EDGE_POSITIVE ); @endcode @@ -322,28 +372,29 @@ void GPIO_config configured as outputs. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @param value The value parameter specifies the state of the GPIO ports configured as - outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK) where n - and m are numbers identifying GPIOs. - For example (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the - first, second and third GPIOs' must be set high and all other outputs set + outputs. It is a bit mask of the form (GPIO_n_MASK | GPIO_m_MASK), where n + and m are numbers identifying GPIOs. + For example, (GPIO_0_MASK | GPIO_1_MASK | GPIO_2_MASK ) specifies that the + first, second, and third GPIO must be set high and all other outputs set low. @return none. - - Example 1: - Set GPIOs outputs 0 and 8 high and all other GPIO outputs low. + + @example + Set GPIO 0 and 8 outputs high and all other GPIO outputs low. @code GPIO_set_outputs( &g_gpio, GPIO_0_MASK | GPIO_8_MASK ); @endcode - Example 2: - Set GPIOs outputs 2 and 4 low without affecting other GPIO outputs. + @example + Set GPIO 2 and 4 outputs low without affecting the other GPIO outputs. @code uint32_t gpio_outputs; gpio_outputs = GPIO_get_outputs( &g_gpio ); @@ -360,20 +411,21 @@ void GPIO_set_outputs ); /*-------------------------------------------------------------------------*//** - The GPIO_set_output() function is used to set the state of a single GPIO - port configured as output. + The GPIO_set_output() function is used to set the state of a single GPIO port + configured as an output. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @param port_id - The port_id parameter specifies the GPIO port that will have its output set - by a call to this function. + The port_id parameter specifies the GPIO port that has its output set by a + call to this function. @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 port high. + of 0 sets the output low, and a value of 1 sets the port high. @return none. @@ -390,13 +442,14 @@ void GPIO_set_output configured as inputs. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @return - This function returns a 32 bit unsigned integer where each bit represents - the state of an input. The least significant bit representing the state of - GPIO 0 and the most significant bit the state of GPIO 31. + This function returns a 32-bit unsigned integer, where each bit represents + the state of an input. The least significant bit represents the state of + GPIO 0, and the most significant bit represents the state of GPIO 31. */ uint32_t GPIO_get_inputs ( @@ -408,13 +461,14 @@ uint32_t GPIO_get_inputs GPIO outputs. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @return - This function returns a 32 bit unsigned integer where each bit represents - the state of an output. The least significant bit representing the state - of GPIO 0 and the most significant bit the state of GPIO 31. + This function returns a 32-bit unsigned integer where each bit represents + the state of an output. The least significant bit represents the state + of GPIO 0, and the most significant bit represents the state of GPIO 31. */ uint32_t GPIO_get_outputs ( @@ -423,28 +477,30 @@ uint32_t GPIO_get_outputs /*-------------------------------------------------------------------------*//** The GPIO_drive_inout() function is used to set the output state of a - GPIO configured as INOUT. An INOUT GPIO can be in one of three states: + GPIO configured as INOUT. An INOUT GPIO is 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 signal. The high and low states are equivalent to the high and low - states of a GPIO configured as output. The high impedance state is used to - prevent the GPIO from driving the state of the output and therefore allow - reading the state of the GPIO as an input. - Please note that the GPIO port you wish to use as INOUT through this function - must be configurable through software. Therefore the GPIO ports used as INOUT + - high impedance + + An INOUT output is typically be used where several devices drive the state of + a signal. 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 the state of the output and therefore allow reading the + state of the GPIO as an input. + Note that the GPIO port you wish to use as INOUT through this function + must be configurable through software. Therefore, the GPIO ports used as INOUT must not have a fixed configuration selected as part of the hardware flow. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @param port_id The port_id parameter identifies the GPIO for which this function will - change the output state. - An enumeration item of the form GPIO_n where n is the number of the GPIO - port is used to identify the GPIO port. For example GPIO_0 identifies the + change the output state. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the first GPIO port and GPIO_31 the last one. @param inout_state @@ -457,7 +513,7 @@ uint32_t GPIO_get_outputs @return none. - Example: + @example The call to GPIO_drive_inout() below will set the GPIO 7 output to high impedance state. @code @@ -473,25 +529,26 @@ void GPIO_drive_inout /*-------------------------------------------------------------------------*//** The GPIO_enable_irq() function is used to enable an interrupt to be - generated based on the state of the input identified as parameter. + generated based on the state of the input identified as a parameter. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @param port_id - The port_id parameter identifies the GPIO input the call to - GPIO_enable_irq() will enable to generate interrupts. - An enumeration item of the form GPIO_n where n is the number of the GPIO - port is used to identify the GPIO port. For example GPIO_0 identifies the + The port_id parameter identifies the GPIO input that the call to + GPIO_enable_irq() enables to generate interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the first GPIO port and GPIO_31 the last one. @return none. - Example: - The call to GPIO_enable_irq() below will allow GPIO 8 to generate - interrupts. + @example + The call to GPIO_enable_irq() below allows GPIO 8 to generate interrupts. + @code GPIO_enable_irq( &g_gpio, GPIO_8 ); @endcode @@ -503,25 +560,26 @@ void GPIO_enable_irq ); /*-------------------------------------------------------------------------*//** - The GPIO_disable_irq() function is used to disable interrupt from being - generated based on the state of the input specified as parameter. + The GPIO_disable_irq() function is used to disable interrupts from being + generated based on the state of the input specified as a parameter. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @param port_id - The port_id parameter identifies the GPIO input the call to - GPIO_disable_irq() will disable from generating interrupts. - An enumeration item of the form GPIO_n where n is the number of the GPIO - port is used to identify the GPIO port. For example GPIO_0 identifies the + The port_id parameter identifies the GPIO input that the call to + GPIO_disable_irq() disables from generating interrupts. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the first GPIO port and GPIO_31 the last one. @return none. - Example: - The call to GPIO_disable_irq() below will prevent GPIO 8 from generating + @example + The call to GPIO_disable_irq() below prevents GPIO 8 from generating interrupts. @code GPIO_disable_irq( &g_gpio, GPIO_8 ); @@ -535,29 +593,30 @@ void GPIO_disable_irq /*-------------------------------------------------------------------------*//** The GPIO_clear_irq() function is used to clear the interrupt generated by - the GPIO specified as parameter. The GPIO_clear_irq() function must be + the GPIO specified as a parameter. The GPIO_clear_irq() function must be called as part of a GPIO interrupt service routine (ISR) in order to prevent - the same interrupt event re-triggering a call to the GPIO ISR. - Please note that interrupts may also need to be cleared in the processor's + the same interrupt event from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's interrupt controller. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @param port_id The port_id parameter identifies the GPIO input for which to clear the - interrupt. - An enumeration item of the form GPIO_n where n is the number of the GPIO - port is used to identify the GPIO port. For example GPIO_0 identifies the + interrupt. + An enumeration item of the form GPIO_n, where n is the number of the GPIO + port, is used to identify the GPIO port. For example, GPIO_0 identifies the first GPIO port and GPIO_31 the last one. @return none. - Example: + @example The example below demonstrates the use of the GPIO_clear_irq() function as - part of the GPIO 9 interrupt service routine. + part of the GPIO-9 interrupt service routine. @code void GPIO9_IRQHandler( void ) { @@ -576,22 +635,25 @@ void GPIO_clear_irq ); /*-------------------------------------------------------------------------*//** - The GPIO_get_irq_sources() function is used to identify the source of - interrupt. i.e. the GPIO input line whose state change triggered the interrupt. - The GPIO_get_irq_sources() function must be called as part of a GPIO - interrupt service routine (ISR) in order to determine the interrupt source. + The GPIO_get_irq_sources() function is used to identify the source of the + interrupt. i.e. to That is the GPIO input line, whose state change triggered + the interrupt. The GPIO_get_irq_sources() function must be called as part of + a GPIO interrupt service routine (ISR) in order to determine the interrupt + source. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @return - This function returns a 32 bit unsigned integer where each bit represents - the pin number of GPIO. + This function returns a 32-bit unsigned integer, where each bit represents + the pin number of a GPIO. + + @example + The example below demonstrates the use of the GPIO_get_irq_sources() + function as part of the GPIO-9 interrupt service routine. - Example: - The example below demonstrates the use of the GPIO_get_irq_sources() function - as part of the GPIO 9 interrupt service routine. @code void GPIO9_IRQHandler( void ) { @@ -609,30 +671,31 @@ uint32_t GPIO_get_irq_sources ); /*-------------------------------------------------------------------------*//** - The GPIO_clear_all_irq_sources() function is used to clear the all the active - interrupt generated by the GPIO specified as parameter. The - GPIO_clear_all_irq_sources() function must be called as part of a GPIO interrupt - service routine (ISR) in order to prevent the same interrupt event - re-triggering a call to the GPIO ISR. - Please note that interrupts may also need to be cleared in the processor's + The GPIO_clear_all_irq_sources() function is used to clear all the active + interrupts generated by the GPIO specified as a parameter. The + GPIO_clear_all_irq_sources() function must be called as part of a GPIO + interrupt service routine (ISR) in order to prevent the same interrupt event + from re-triggering a call to the GPIO ISR. + Note that interrupts may also need to be cleared in the processor's interrupt controller. @param this_gpio - The this_gpio parameter is a pointer to the gpio_instance_t structure holding - all data regarding the CoreGPIO instance controlled through this function call. + The this_gpio parameter is a pointer to the gpio_instance_t structure + holding all the data regarding the CoreGPIO instance controlled through this + function call. @param bitmask - This bitmask parameter is a 32 bit unsigned integer where each bit represents - the GPIO pin used to clears the interrupt bit register of the corresponding - GPIO bit. The least significant bit representing the status of GPIO 0 and - the most significant bit the status of GPIO 31. + This bitmask parameter is a 32-bit unsigned integer where each bit + represents the GPIO pin used to clear the interrupt bit register of the + corresponding GPIO bit. The least significant bit represents the status of + GPIO 0, and the most significant bit represents the status of GPIO 31. @return none. - Example: - The example below demonstrates the use of the GPIO_clear_all_irq_sources() function as - part of the GPIO 9 interrupt service routine. + @example + The example below demonstrates the use of the GPIO_clear_all_irq_sources() + function as part of the GPIO-9 interrupt service routine. @code void GPIO9_IRQHandler( void ) { @@ -651,4 +714,9 @@ void GPIO_clear_all_irq_sources gpio_instance_t * this_gpio, uint32_t bitmask ); + +#ifdef __cplusplus +} +#endif + #endif /* CORE_GPIO_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreGPIO/coregpio_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h similarity index 92% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreGPIO/coregpio_regs.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h index 0c13e28..41f5b7c 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreGPIO/coregpio_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreGPIO/coregpio_regs.h @@ -1,6 +1,8 @@ /******************************************************************************* - * (c) Copyright 2008-2021 Microchip FPGA Embedded Systems Solutions. + * (c) Copyright 2008-2023 Microchip FPGA Embedded Systems Solutions. * + * SPDX-License-Identifier: MIT + * * @file coregpio_regs.h * @author Microchip FPGA Embedded Systems Solutions * @brief CoreGPIO register definitions diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c new file mode 100644 index 0000000..1fd3dd6 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.c @@ -0,0 +1,1495 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C software driver implementation. + * + */ + +#include "core_smbus_regs.h" +#include "core_i2c.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------------ + * I2C transaction direction. + */ +#define WRITE_DIR 0u +#define READ_DIR 1u + +/* -- TRANSACTIONS TYPES -- */ +#define NO_TRANSACTION 0u +#define MASTER_WRITE_TRANSACTION 1u +#define MASTER_READ_TRANSACTION 2u +#define MASTER_RANDOM_READ_TRANSACTION 3u +#define WRITE_SLAVE_TRANSACTION 4u +#define READ_SLAVE_TRANSACTION 5u + +/* -- SMBUS H/W STATES -- */ +/* -- MASTER STATES -- */ +#define ST_BUS_ERROR 0x00u /* Bus error during MST or selected slave modes */ +#define ST_I2C_IDLE 0xF8u /* No activity and no interrupt either... */ +#define ST_START 0x08u /* start condition sent */ +#define ST_RESTART 0x10u /* repeated start */ +#define ST_SLAW_ACK 0x18u /* SLA+W sent, ack received */ +#define ST_SLAW_NACK 0x20u /* SLA+W sent, nack received */ +#define ST_TX_DATA_ACK 0x28u /* Data sent, ACK'ed */ +#define ST_TX_DATA_NACK 0x30u /* Data sent, NACK'ed */ +#define ST_LOST_ARB 0x38u /* Master lost arbitration */ +#define ST_SLAR_ACK 0x40u /* SLA+R sent, ACK'ed */ +#define ST_SLAR_NACK 0x48u /* SLA+R sent, NACK'ed */ +#define ST_RX_DATA_ACK 0x50u /* Data received, ACK sent */ +#define ST_RX_DATA_NACK 0x58u /* Data received, NACK sent */ +#define ST_RESET_ACTIVATED 0xD0u /* Master reset is activated */ +#define ST_STOP_TRANSMIT 0xE0u /* Stop has been transmitted */ + +/* -- SLAVE STATES -- */ +#define ST_SLAVE_SLAW 0x60u /* SLA+W received */ +#define ST_SLAVE_SLAR_ACK 0xA8u /* SLA+R received, ACK returned */ +#define ST_SLV_LA 0x68u /* Slave lost arbitration */ +#define ST_GCA 0x70u /* GCA received */ +#define ST_GCA_LA 0x78u /* GCA lost arbitration */ +#define ST_RDATA 0x80u /* Data received */ +#define ST_SLA_NACK 0x88u /* Slave addressed, NACK returned */ +#define ST_GCA_ACK 0x90u /* Previously addresses with GCA, data ACKed */ +#define ST_GCA_NACK 0x98u /* GCA addressed, NACK returned */ +#define ST_RSTOP 0xA0u /* Stop received */ +#define ST_SLARW_LA 0xB0u /* Arbitration lost */ +#define ST_RACK 0xB8u /* Byte sent, ACK received */ +#define ST_SLAVE_RNACK 0xC0u /* Byte sent, NACK received */ +#define ST_FINAL 0xC8u /* Final byte sent, ACK received */ +#define ST_SLV_RST 0xD8u /* Slave reset state */ + + +/* I2C Channel base offset */ +#define CHANNEL_BASE_SHIFT 5u +#define CHANNEL_MASK 0x1E0u + +/* + * Maximum address offset length in slave write-read transactions. + * A maximum of two bytes will be interpreted as address offset within the slave + * tx buffer. + */ +#define MAX_OFFSET_LENGTH 2u + +/*------------------------------------------------------------------------------ + * I2C interrupts control functions implemented "i2c_interrupt.c". + * the implementation of these functions depend on the underlying hardware + * design and how the CoreI2C interrupt line is connected to the system's + * interrupt controller. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ); +void I2C_disable_irq( i2c_instance_t * this_i2c ); +static void enable_slave_if_required(i2c_instance_t * this_i2c); + +/*------------------------------------------------------------------------------ + * I2C_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + /* + * We need to disable ints while doing this as there is no guarantee we + * have not been called already and the ISR is active. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize all items of the this_i2c data structure to zero. This + * initializes all state variables to their init value. It relies on + * the fact that NO_TRANSACTION, I2C_SUCCESS and I2C_RELEASE_BUS all + * have an actual value of zero. + */ + memset(this_i2c, 0, sizeof(i2c_instance_t)); + + /* + * Set base address of I2C hardware used by this instance. + */ + this_i2c->base_address = base_address; + + /* + * Update Serial address of the device + */ + this_i2c->ser_address = ((uint_fast8_t)ser_address << 1u); + + /* + * Configure hardware. + */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x00); /* Reset I2C hardware. */ + HAL_set_8bit_reg_field(this_i2c->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c->base_address, CR0, ( clock_speed & 0x01) ); + + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS, this_i2c->ser_address); + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); + + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); +} +/*------------------------------------------------------------------------------ + * I2C_channel_init() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +) +{ + psr_t saved_psr; + uint_fast16_t clock_speed = (uint_fast16_t)ser_clock_speed; + + HAL_ASSERT(channel_number < I2C_MAX_CHANNELS); + HAL_ASSERT(I2C_CHANNEL_0 != channel_number); + + /* + * Cannot allow channel 0 in this function as we will trash the hardware + * base address and slave address. + */ + if ((channel_number < I2C_MAX_CHANNELS) && + (I2C_CHANNEL_0 != channel_number)) + { + /* + * We need to disable ints while doing this as the hardware should already + * be active at this stage. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Initialize channel data. + */ + memset(this_i2c_channel, 0, sizeof(i2c_instance_t)); + + this_i2c_channel->base_address = + ((this_i2c->base_address) & ~((addr_t)CHANNEL_MASK)) + | (((addr_t)channel_number) << CHANNEL_BASE_SHIFT); + + this_i2c_channel->ser_address = this_i2c->ser_address; + + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x00); /* Reset I2C channel hardware. */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, ENS1, 0x01); /* set enable bit */ + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR2, ( (clock_speed >> 2) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR1, ( (clock_speed >> 1) & 0x01) ); + HAL_set_8bit_reg_field(this_i2c_channel->base_address, CR0, ( clock_speed & 0x01) ); + /* + * Finally safe to enable interrupts. + */ + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_write() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_WRITE_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_WRITE_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + this_i2c->dir = WRITE_DIR; + this_i2c->master_tx_buffer = write_buffer; + this_i2c->master_tx_size = write_size; + this_i2c->master_tx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = READ_DIR; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_write_read() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +) +{ + HAL_ASSERT(offset_size > 0u); + HAL_ASSERT(addr_offset != (uint8_t *)0); + HAL_ASSERT(read_size > 0u); + HAL_ASSERT(read_buffer != (uint8_t *)0); + + this_i2c->master_status = I2C_FAILED; + + if((read_size > 0u) && (offset_size > 0u)) + { + psr_t saved_psr; + volatile uint8_t stat_ctrl; + + saved_psr = HAL_disable_interrupts(); + + /* Update the transaction only when there is no transaction going on I2C */ + if( this_i2c->transaction == NO_TRANSACTION) + { + this_i2c->transaction = MASTER_RANDOM_READ_TRANSACTION; + } + + /* Update the Pending transaction information so that transaction can restarted */ + this_i2c->pending_transaction = MASTER_RANDOM_READ_TRANSACTION ; + + /* Update target address */ + this_i2c->target_addr = (uint_fast8_t)serial_addr << 1u; + + this_i2c->dir = WRITE_DIR; + + this_i2c->master_tx_buffer = addr_offset; + this_i2c->master_tx_size = offset_size; + this_i2c->master_tx_idx = 0u; + + this_i2c->master_rx_buffer = read_buffer; + this_i2c->master_rx_size = read_size; + this_i2c->master_rx_idx = 0u; + + /* Set I2C status in progress */ + this_i2c->master_status = I2C_IN_PROGRESS; + this_i2c->options = options; + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->is_transaction_pending = 1u; + } + else + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Clear interrupts if required (depends on repeated starts). + * Since the Bus is on hold, only then prior status needs to + * be cleared. + */ + if ( I2C_HOLD_BUS == this_i2c->bus_status ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + stat_ctrl = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + stat_ctrl = stat_ctrl; /* Avoids lint warning. */ + + /* Enable the interrupt. ( Re-enable) */ + I2C_enable_irq( this_i2c ); + + HAL_restore_interrupts( saved_psr ); + } +} + +/*------------------------------------------------------------------------------ + * I2C_get_status() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +) +{ + i2c_status_t i2c_status ; + + i2c_status = this_i2c->master_status ; + + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_wait_complete() + * See "core_i2c.h" for details of how to use this function. + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +) +{ + i2c_status_t i2c_status; + psr_t saved_psr; + /* + * Because we have no idea of what CPU we are supposed to be running on + * we need to guard this write to the timeout value to avoid ISR/user code + * interaction issues. Checking the status below should be fine as only a + * single byte should change in that. + */ + saved_psr = HAL_disable_interrupts(); + this_i2c->master_timeout_ms = timeout_ms; + HAL_restore_interrupts( saved_psr ); + + /* Run the loop until state returns I2C_FAILED or I2C_SUCESS*/ + do { + i2c_status = this_i2c->master_status; + } while(I2C_IN_PROGRESS == i2c_status); + return i2c_status; +} + +/*------------------------------------------------------------------------------ + * I2C_system_tick() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +) +{ + if(this_i2c->master_timeout_ms != I2C_NO_TIMEOUT) + { + if(this_i2c->master_timeout_ms > ms_since_last_tick) + { + this_i2c->master_timeout_ms -= ms_since_last_tick; + } + else + { + psr_t saved_psr; + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* + * Mark current transaction as having timed out. + */ + this_i2c->master_status = I2C_TIMED_OUT; + this_i2c->transaction = NO_TRANSACTION; + this_i2c->is_transaction_pending = 0; + + HAL_restore_interrupts( saved_psr ); + + /* + * Make sure we do not incorrectly signal a timeout for subsequent + * transactions. + */ + this_i2c->master_timeout_ms = I2C_NO_TIMEOUT; + } + } +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_tx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_tx_buffer = tx_buffer; + this_i2c->slave_tx_size = tx_size; + this_i2c->slave_tx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_rx_buffer() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_rx_buffer = rx_buffer; + this_i2c->slave_rx_size = rx_size; + this_i2c->slave_rx_idx = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_mem_offset_length() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +) +{ + HAL_ASSERT(offset_length <= MAX_OFFSET_LENGTH); + + /* + * Single byte update, should be interrupt safe + */ + if(offset_length > MAX_OFFSET_LENGTH) + { + this_i2c->slave_mem_offset_length = MAX_OFFSET_LENGTH; + } + else + { + this_i2c->slave_mem_offset_length = offset_length; + } +} + +/*------------------------------------------------------------------------------ + * I2C_register_write_handler() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * shared data without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + this_i2c->slave_write_handler = handler; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register and slave mode flag without the I2C ISR interrupting + * us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Set the Assert Acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Enable slave mode */ + this_i2c->is_slave_enabled = 1u; + + HAL_restore_interrupts( saved_psr ); + + /* Enable I2C IRQ*/ + I2C_enable_irq( this_i2c ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the I2C ISR interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + /* Reset the assert acknowledge bit. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + + /* Disable slave mode with IRQ blocked to make whole change atomic */ + this_i2c->is_slave_enabled = 0u; + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * + */ +static void enable_slave_if_required +( + i2c_instance_t * this_i2c +) +{ + /* + * This function is only called from within the ISR and so does not need + * guarding on the register access. + */ + if( 0 != this_i2c->is_slave_enabled ) + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } +} +/*------------------------------------------------------------------------------ + * I2C_set_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +) +{ + uint8_t second_slave_address; + + /* + This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + With the programmable configuration, ADDR1[0] and ADDR0[0] both control + enable/disable of GCA recognition, as an effective OR of the 2 bit fields. + Therefore we set ADDR1[0] to 0 here, so that only ADDR0[0] controls GCA. + */ + second_slave_address = (uint8_t)((second_slave_addr << 1u) & (~SLAVE1_EN_MASK)); + + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, second_slave_address); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_slave_second_addr() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +) +{ + /* + We are disabling the second slave address by setting the value of the 2nd + slave address to the primary slave address. The reason for using this method + of disabling 2nd slave address is that ADDRESS1[0] has different meaning + depending on hardware configuration. Its use would likely interfere with + the intended GCA setting. + */ + /* + * Single byte register write, should be interrupt safe + */ + HAL_set_8bit_reg(this_i2c->base_address, ADDRESS1, this_i2c->ser_address); +} + +/*------------------------------------------------------------------------------ + * i2C_set_gca() + * See "i2c.h" for details of how to use this function. + */ + +void I2C_set_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* accept GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x01u); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_gca() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_gca +( + i2c_instance_t * this_i2c +) +{ + /* + * This read modify write access should be interrupt safe as the address + * register is not written to in the ISR. + */ + /* Clear GC addressing. */ + HAL_set_8bit_reg_field(this_i2c->base_address, GC, 0x00u); +} + +/*------------------------------------------------------------------------------ + * I2C_isr() + * See "core_i2c.h" for details of how to use this function. + */ +void I2C_isr +( + i2c_instance_t * this_i2c +) +{ + volatile uint8_t status; + uint8_t data; + uint8_t hold_bus; + uint8_t clear_irq = 1u; + + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); + + switch( status ) + { + /************** MASTER TRANSMITTER / RECEIVER *******************/ + + case ST_START: /* start has been xmt'd */ + case ST_RESTART: /* repeated start has been xmt'd */ + HAL_set_8bit_reg_field( this_i2c->base_address, STA, 0x00u); + HAL_set_8bit_reg( this_i2c->base_address, DATA, this_i2c->target_addr); /* write call address */ + HAL_set_8bit_reg_field( this_i2c->base_address, DIR, this_i2c->dir); /* set direction bit */ + if(this_i2c->dir == WRITE_DIR) + { + this_i2c->master_tx_idx = 0u; + } + else + { + this_i2c->master_rx_idx = 0u; + } + + /* + * Clear the pending transaction. This condition will be true if the slave + * has acquired the bus to carry out pending master transaction which + * it had received during its slave transmission or reception mode. + */ + if(this_i2c->is_transaction_pending) + { + this_i2c->is_transaction_pending = 0u; + } + + /* + * Make sure to update proper transaction after master START + * or RESTART + */ + if(this_i2c->transaction != this_i2c->pending_transaction) + { + this_i2c->transaction = this_i2c->pending_transaction; + } + break; + + case ST_LOST_ARB: + /* Set start bit. Let's keep trying! Don't give up! */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + break; + + case ST_STOP_TRANSMIT: + /* Stop has been transmitted. Do nothing */ + break; + + /******************* MASTER TRANSMITTER *************************/ + case ST_SLAW_NACK: + /* SLA+W has been transmitted; not ACK has been received - let's stop. */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_SLAW_ACK: + case ST_TX_DATA_ACK: + /* data byte has been xmt'd with ACK, time to send stop bit or repeated start. */ + if (this_i2c->master_tx_idx < this_i2c->master_tx_size) + { + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->master_tx_buffer[this_i2c->master_tx_idx++]); + } + else if ( this_i2c->transaction == MASTER_RANDOM_READ_TRANSACTION ) + { + /* We are finished sending the address offset part of a random read transaction. + * It is is time to send a restart in order to change direction. */ + this_i2c->dir = READ_DIR; + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + else /* done sending. let's stop */ + { + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + this_i2c->master_status = I2C_SUCCESS; + } + break; + + case ST_TX_DATA_NACK: + /* data byte SENT, ACK to be received + * In fact, this means we've received a NACK (This may not be + * obvious, but if we've rec'd an ACK then we would be in state + * 0x28!) hence, let's send a stop bit + */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u);/* xmt stop condition */ + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + /********************* MASTER (or slave?) RECEIVER *************************/ + + /* STATUS codes 08H, 10H, 38H are all covered in MTX mode */ + case ST_SLAR_ACK: /* SLA+R tx'ed. */ + /* Let's make sure we ACK the first data byte received (set AA bit in CTRL) unless + * the next byte is the last byte of the read transaction. + */ + if(this_i2c->master_rx_size > 1u) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + } + else if(1u == this_i2c->master_rx_size) + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + else /* this_i2c->master_rx_size == 0u */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_SUCCESS; + this_i2c->transaction = NO_TRANSACTION; + } + break; + + case ST_SLAR_NACK: /* SLA+R tx'ed; let's release the bus (send a stop condition) */ + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); + this_i2c->master_status = I2C_FAILED; + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + enable_slave_if_required(this_i2c); + break; + + case ST_RX_DATA_ACK: /* Data byte received, ACK returned */ + /* First, get the data */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx++] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + if( this_i2c->master_rx_idx >= (this_i2c->master_rx_size - 1u)) + { + /* If we're at the second last byte, let's set AA to 0 so + * we return a NACK at the last byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RX_DATA_NACK: /* Data byte received, NACK returned */ + /* Get the data, then send a stop condition */ + this_i2c->master_rx_buffer[this_i2c->master_rx_idx] = HAL_get_8bit_reg(this_i2c->base_address, DATA); + + hold_bus = this_i2c->options & I2C_HOLD_BUS; + + /* Store the information of current I2C bus status in the bus_status*/ + this_i2c->bus_status = hold_bus; + if ( hold_bus == 0u ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STO, 0x01u); /*xmt stop condition */ + + /* Bus is released, now we can start listening to bus, if it is slave */ + enable_slave_if_required(this_i2c); + } + else + { + I2C_disable_irq( this_i2c ); + clear_irq = 0u; + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + this_i2c->master_status = I2C_SUCCESS; + break; + + /******************** SLAVE RECEIVER **************************/ + case ST_GCA_NACK: /* NACK after, GCA addressing */ + case ST_SLA_NACK: /* Re-enable AA (assert ack) bit for future transmissions */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + this_i2c->transaction = NO_TRANSACTION; + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + break; + + case ST_GCA_LA: /* Arbitr. lost (GCA rec'd) */ + case ST_SLV_LA: /* Arbitr. lost (SLA rec'd) */ + /* + * We lost arbitration and either the GCE or our address was the + * one received so pend the master operation we were starting. + */ + this_i2c->is_transaction_pending = 1u; + /* Fall through to normal ST processing as we are now in slave mode */ + + case ST_GCA: /* General call address received, ACK returned */ + case ST_SLAVE_SLAW: /* SLA+W received, ACK returned */ + this_i2c->transaction = WRITE_SLAVE_TRANSACTION; + this_i2c->slave_rx_idx = 0u; + this_i2c->random_read_addr = 0u; + /* + * If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + this_i2c->slave_status = I2C_IN_PROGRESS; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + /* Fall through to put address as first byte in payload buffer */ +#else + /* Only break from this case if the slave address must NOT be included at the + * beginning of the received write data. */ + break; +#endif + case ST_GCA_ACK: /* DATA received; ACK sent after GCA */ + case ST_RDATA: /* DATA received; must clear DATA register */ + if((this_i2c->slave_rx_buffer != (uint8_t *)0) + && (this_i2c->slave_rx_idx < this_i2c->slave_rx_size)) + { + data = HAL_get_8bit_reg(this_i2c->base_address, DATA); + this_i2c->slave_rx_buffer[this_i2c->slave_rx_idx++] = data; + +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + if((ST_RDATA == status) || (ST_GCA_ACK == status)) + { + /* Ignore the slave address byte in the random read address + computation in the case where INCLUDE_SLA_IN_RX_PAYLOAD + is defined. */ +#endif + this_i2c->random_read_addr = (this_i2c->random_read_addr << 8) + data; +#ifdef INCLUDE_SLA_IN_RX_PAYLOAD + } +#endif + } + + if(this_i2c->slave_rx_idx >= this_i2c->slave_rx_size) + { + /* Rx buffer is full. NACK next received byte. */ + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + } + break; + + case ST_RSTOP: + /* STOP or repeated START occurred. */ + /* We cannot be sure if the transaction has actually completed as + * this hardware state reports that either a STOP or repeated START + * condition has occurred. We assume that this is a repeated START + * if the transaction was a write from the master to this point.*/ + if ( this_i2c->transaction == WRITE_SLAVE_TRANSACTION ) + { + if ( this_i2c->slave_rx_idx == this_i2c->slave_mem_offset_length ) + { + this_i2c->slave_tx_idx = this_i2c->random_read_addr; + } + /* Call the slave's write transaction handler if it exists. */ + if ( this_i2c->slave_write_handler != 0u ) + { + i2c_slave_handler_ret_t h_ret; + h_ret = this_i2c->slave_write_handler( this_i2c, this_i2c->slave_rx_buffer, (uint16_t)this_i2c->slave_rx_idx ); + if ( I2C_REENABLE_SLAVE_RX == h_ret ) + { + /* There is a small risk that the write handler could + * call I2C_disable_slave() but return + * I2C_REENABLE_SLAVE_RX in error so we only enable + * ACKs if still in slave mode. */ + enable_slave_if_required(this_i2c); + } + else + { + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x0u ); + /* Clear slave mode flag as well otherwise in mixed + * master/slave applications, the AA bit will get set by + * subsequent master operations. */ + this_i2c->is_slave_enabled = 0u; + } + } + else + { + /* Re-enable address acknowledge in case we were ready to nack the next received byte. */ + HAL_set_8bit_reg_field( this_i2c->base_address, AA, 0x01u ); + } + } + else /* A stop or repeated start outside a write/read operation */ + { + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * See if we need to re-enable acknowledgement as some error conditions, such + * as a master prematurely ending a transfer, can see us get here with AA set + * to 0 which will disable slave operation if we are not careful. + */ + enable_slave_if_required(this_i2c); + } + + /* Mark any previous master write transaction as complete. */ + this_i2c->slave_status = I2C_SUCCESS; + + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + case ST_SLV_RST: /* SMBUS ONLY: timeout state. must clear interrupt */ + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear status to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + enable_slave_if_required(this_i2c); /* Make sure AA is set correctly */ + + break; + + /****************** SLAVE TRANSMITTER **************************/ + case ST_SLAVE_SLAR_ACK: /* SLA+R received, ACK returned */ + case ST_SLARW_LA: /* Arbitration lost, and: */ + case ST_RACK: /* Data tx'ed, ACK received */ + if ( status == ST_SLAVE_SLAR_ACK ) + { + this_i2c->transaction = READ_SLAVE_TRANSACTION; + this_i2c->random_read_addr = 0u; + this_i2c->slave_status = I2C_IN_PROGRESS; + /* If Start Bit is set clear it, but store that information since it is because of + * pending transaction + */ + if(HAL_get_8bit_reg_field(this_i2c->base_address, STA)) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + this_i2c->is_transaction_pending = 1u; + } + } + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) + { + /* Ensure 0xFF is returned to the master when the slave specifies + * an empty transmit buffer. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, 0xFFu); + } + else + { + /* Load the data the data byte to be sent to the master. */ + HAL_set_8bit_reg(this_i2c->base_address, DATA, (uint_fast8_t)this_i2c->slave_tx_buffer[this_i2c->slave_tx_idx++]); + } + /* Determine if this is the last data byte to send to the master. */ + if (this_i2c->slave_tx_idx >= this_i2c->slave_tx_size) /* last byte? */ + { + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x00u); + /* Next read transaction will result in slave's transmit buffer + * being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + } + break; + + case ST_SLAVE_RNACK: /* Data byte has been transmitted; not-ACK has been received. */ + case ST_FINAL: /* Last Data byte tx'ed, ACK received */ + /* We assume that the transaction will be stopped by the master. + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. */ + this_i2c->slave_tx_idx = 0u; + HAL_set_8bit_reg_field(this_i2c->base_address, AA, 0x01u); + + /* Mark previous state as complete */ + this_i2c->slave_status = I2C_SUCCESS; + /* Check if transaction was pending. If yes, set the START bit */ + if(this_i2c->is_transaction_pending) + { + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x01u); + } + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction + */ + this_i2c->transaction = NO_TRANSACTION; + + break; + + /* Master Reset has been activated Wait 35 ms for interrupt to be set, + * clear interrupt and proceed to 0xF8 state. */ + case ST_RESET_ACTIVATED: + case ST_BUS_ERROR: /* Bus error during MST or selected slave modes */ + default: + /* Some undefined state has encountered. Clear Start bit to make + * sure, next good transaction happen */ + HAL_set_8bit_reg_field(this_i2c->base_address, STA, 0x00u); + /* + * Set the transaction back to NO_TRANSACTION to allow user to do further + * transaction. + */ + this_i2c->transaction = NO_TRANSACTION; + /* + * Reset slave_tx_idx so that a subsequent read will result in the slave's + * transmit buffer being sent from the first byte. + */ + this_i2c->slave_tx_idx = 0u; + /* + * Clear statuses to I2C_FAILED only if there was an operation in progress. + */ + if(I2C_IN_PROGRESS == this_i2c->master_status) + { + this_i2c->master_status = I2C_FAILED; + } + + if(I2C_IN_PROGRESS == this_i2c->slave_status) + { + this_i2c->slave_status = I2C_FAILED; + } + + break; + } + + if ( clear_irq ) + { + /* clear interrupt. */ + HAL_set_8bit_reg_field(this_i2c->base_address, SI, 0x00u); + } + + /* Read the status register to ensure the last I2C registers write took place + * in a system built around a bus making use of posted writes. */ + status = HAL_get_8bit_reg( this_i2c->base_address, STATUS); +} + +/*------------------------------------------------------------------------------ + * I2C_smbus_init() + * See "i2c.h" for details of how to use this function. + */ + +/* + * SMBSUS_NO = 1 + * SMBALERT_NO = 1 + * SMBus enable = 1 + */ +#define INIT_AND_ENABLE_SMBUS 0x54u +void I2C_smbus_init +( + i2c_instance_t * this_i2c +) +{ + /* + * Single byte register write, should be interrupt safe + */ + /* Enable SMBUS */ + HAL_set_8bit_reg(this_i2c->base_address, SMBUS, INIT_AND_ENABLE_SMBUS); +} + +/*------------------------------------------------------------------------------ + * I2C_enable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x01u); + } + if ( irq_type & I2C_SMBSUS_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x01u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_disable_smbus_irq() + * See "i2c.h" for details of how to use this function. + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + if ( irq_type & I2C_SMBALERT_IRQ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_IE, 0x00u); + } + if (irq_type & I2C_SMBSUS_IRQ ) + { + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_IE, 0x00u); + } + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_suspend_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_resume_smbus_slave() + * See "i2c.h" for details of how to use this function. + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBSUS_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_reset_smbus() + * See "i2c.h" for details of how to use this function. + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBUS_MST_RESET, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_set_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x00u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_clear_smbus_alert() + * See "i2c.h" for details of how to use this function. + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +) +{ + psr_t saved_psr; + + /* + * We need to disable interrupts here to ensure we can update the + * hardware register without the SMBUS IRQs interrupting us. + */ + saved_psr = HAL_disable_interrupts(); + + HAL_set_8bit_reg_field(this_i2c->base_address, SMBALERT_NO_CONTROL, 0x01u); + + HAL_restore_interrupts( saved_psr ); +} + +/*------------------------------------------------------------------------------ + * I2C_get_irq_status() + * See "i2c.h" for details of how to use this function. + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +) +{ + uint8_t status ; + uint8_t irq_type = I2C_NO_IRQ ; + + status = HAL_get_8bit_reg(this_i2c->base_address, SMBUS); + + if( status & (uint8_t)SMBALERT_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBALERT_IRQ ; + } + + if( status & (uint8_t)SMBSUS_NI_STATUS_MASK ) + { + irq_type |= I2C_SMBSUS_IRQ ; + } + + status = HAL_get_8bit_reg(this_i2c->base_address, CONTROL); + + if( status & (uint8_t)SI_MASK ) + { + irq_type |= I2C_INTR_IRQ ; + } + return(irq_type); +} + +/*------------------------------------------------------------------------------ + * I2C_set_slave_addr2() + * See "i2c.h" for details of how to use this function. + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +) +{ + this_i2c->p_user_data = p_user_data ; +} + +/*------------------------------------------------------------------------------ + * I2C_get_user_data() + * See "i2c.h" for details of how to use this function. + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +) +{ + return( this_i2c->p_user_data); +} + +#ifdef __cplusplus +} +#endif + diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h new file mode 100644 index 0000000..3891ce0 --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_i2c.h @@ -0,0 +1,2306 @@ +/***************************************************************************//** + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * CoreI2C software driver Application Programming Interface. + * This file contains defines and function declarations allowing to interface + * with the CoreI2C software driver. + * + */ +/*=========================================================================*//** + @mainpage CoreI2C Bare Metal Driver. + The CoreI2C bare metal software driver supports I2C master and slave + operations. + + ============================================================================== + Introduction + ============================================================================== + The CoreI2C driver provides a set of functions for controlling the Microchip + CoreI2C hardware IP. The driver supports up to 16 separate I2C channels per + CoreI2C instance, with common slave address settings shared between channels + on a device. + + Optional features of the CoreI2C allow it to operate with I2C based protocols + such as System Management Bus (SMBus), Power Management Bus (PMBus), and + Intelligent Platform Management Interface (IPMI). This driver provides support + for these features when enabled in the CoreI2C IP. + + The major features provided by CoreI2C driver: + - Provides support to configuring the I2C channels of each CoreI2C peripheral device. + - I2C master operations. + - I2C slave operations. + - SMBus related operations. + + This driver is used as part of a bare metal system where no operating + system is available. The driver gets adapted as a 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 this driver. + + ============================================================================== + Hardware Flow Dependencies + ============================================================================== + Your application software should configure the CoreI2C driver through + calls to the I2C_init() function for each CoreI2C instance in the + hardware design. The configuration parameters include the CoreI2C hardware + instance base address and other runtime parameters, such as the I2C serial + clock frequency and the I2C device address. + + Once channel 0 of a CoreI2C peripheral has been initialized by I2C_init(), + any additional channels present should be configured by calling + I2C_channel_init() for each of the remaining channels. + + Apart from the CoreI2C hardware instance base address, no CoreI2C hardware configuration + parameters are used by the driver. Hence, no additional configuration files are required + to use the driver. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver has to enable and disable the generation of interrupts by + CoreI2C at various times when it is operating. This enabling and disabling of + interrupts must be done through the system’s interrupt controller. For that + reason, the method of controlling the CoreI2C interrupt is system specific + and it is necessary to customize the I2C_enable_irq() and I2C_disable_irq() + functions. These functions are available in the i2c_interrupt.c file. + The default implementation calls HAL_ASSERT(0) to indicate to the application + developer that a suitable implementations for these functions must be provided. + + The implementation of the I2C_enable_irq() function should permit interrupts + generated by a CoreI2C instance to interrupt the processor. The implementation + of the I2C_disable_irq() function should prevent interrupts generated by a + CoreI2C instance from interrupting the processor. See the provided example + projects for a working implementation of these functions. + + The I2C_register_write_handler() function registers a write handler + function with the CoreI2C driver that calls on completion of an I2C write + transaction by the CoreI2C slave. It is your responsibility to create and + register the implementation of this handler function that processes or + trigger the processing of the received data. + + The SMBSUS and SMBALERT interrupts are related to the SMBus interface and are + enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. It is your responsibility to create + interrupt handler functions in your application to get the desired response + for the SMBus interrupts. + + Note: You must include the path to any application header files that are + included in the i2c_interrupt.c file, as an include path in your + project's compiler settings. The details of how to do this will depend + on your development software. + + -------------------------------- + SMBus Logic Options + -------------------------------- + SMBus related APIs does not have any effect if the "Generate SMBus Logic" + is not enabled in the CoreI2C hardware configuration. Following are API's + that does not give the desired results if SMBus Logic is disabled. + + - I2C_smbus_init() + - I2C_reset_smbus() + - I2C_enable_smbus_irq() + - I2C_disable_smbus_irq() + - I2C_suspend_smbus_slave() + - I2C_resume_smbus_slave() + - I2C_set_smsbus_alert() + - I2C_clear_smsbus_alert() + - I2C_get_irq_status() + + -------------------------------- + Fixed Baud Rate Values + -------------------------------- + The serial clock frequency parameter passed to the I2C_init() and + I2C_channel_init() functions may not have any effect if fixed values were + selected for Baud rate in the hardware configuration of CoreI2C. When fixed + values are selected for these baud rates, the driver cannot overwrite + the fixed values. + + ----------------------------------- + Fixed Slave Address Options Values + ----------------------------------- + The primary slave address parameter passed to the I2C_init() function and + secondary address value passed to the I2C_set_slave_second_addr() function, + may not have the desired effect if fixed values were selected for the slave 0 + address and slave 1 address respectively. Proper operation of this version of + the driver requires the slave addresses to be programmable. + + ============================================================================== + Theory of Operation + ============================================================================== + The CoreI2C software driver is designed to allow the control of multiple + instances of CoreI2C with one or more I2C channels. Each channel in an + instance of CoreI2C in the hardware design is associated with a single + instance of the i2c_instance_t structure in the software. You must allocate + memory for one unique i2c_instance_t structure instance for each channel of + each CoreI2C hardware instance. The contents of these data structures are + initialised by calling I2C_init() and if necessary I2C_channel_init(). + A pointer to the structure is passed to the subsequent driver functions in order + to identify the CoreI2C hardware instance and channel to perform the + requested operation. + + Note: Do not attempt to directly manipulate the contents of i2c_instance_t + structures. These structures are only intended to be modified by the driver + functions. + + The CoreI2C driver functions are grouped into the following categories: + - Initialization and configuration functions + - Interrupt control + - I2C slave addressing functions + - I2C master operations functions to handle write, read, and write-read + transactions + - I2C slave operations functions to handle write, read, and write-read + transactions + - Mixed master-slave operations + - SMBus interface configuration and control + + -------------------------------- + Initialization and Configuration + -------------------------------- + The CoreI2C device is first initialized by calling the I2C_init() + function. Since each CoreI2C peripheral supports up to 16 channels, an + additional function, I2C_channel_init(), is required to initialize the + remaining channels with their own data structures. + + I2C_init() function initializes channel 0 of a CoreI2C and the i2c_instance_t + for channel 0 acts as the basis for further channel initialization as the + hardware base address and I2C serial address are same across all the channels. + Ensure to call I2C_init() function before calling any other I2C driver function + calls. The I2C_init() call for each CoreI2C takes the I2C serial address assigned + to the I2C and the serial clock divider to generate its I2C clock as configuration + parameters. + + I2C_channel_init() function takes as input parameters a pointer to the CoreI2C + i2c_instance_t which has been initialized by calling the I2C_init() and a pointer + to a separate i2c_instance_t which represents this new channel. Another input + parameter which is required by this function is serial clock divider which generates + its I2C clock. + + -------------------------------- + Interrupt Control + -------------------------------- + The CoreI2C driver is interrupt driven and it uses each channels INT + interrupt to drive the state machine which is at the heart of the driver. + The application is responsible for providing the link between the interrupt + generating hardware and the CoreI2C interrupt handler and must ensure that + the I2C_isr() function is called with the correct i2c_instance_t structure + pointer for the CoreI2C channel initiating the interrupt. + + The driver enables and disables the generation of INT interrupts by CoreI2C + at various times when it is operating through the user supplied + I2C_enable_irq() and I2C_disable_irq() functions. + + The I2C_register_write_handler() function is used to register a write + handler function with the CoreI2C driver which is called on completion + of an I2C write transaction by the CoreI2C slave. It is the user + applications responsibility to create and register the implementation of + this handler function that processes or triggers the processing of the + received data. + + The other two interrupt sources in the CoreI2C are related to SMBus + operation and are enabled and disabled through I2C_enable_smbus_irq() and + I2C_disable_smbus_irq() respectively. Due to the application specific + nature of the response to SMBus interrupts, you must design interrupt + handler functions in the application to get the desired behaviour for + SMBus related interrupts. + + If enabled, the SMBA_INT signal from the CoreI2C is asserted if an + SMBALERT condition is signalled on the SMBALERT_NI input for the channel. + + If enabled, the SMBS_INT signal from the CoreI2C is asserted if an + SMBSUSPEND condition is signalled on the SMBSUS_NI input for the channel. + + ## I2C Slave Addressing Functions + A CoreI2C peripheral responds to the following three slave addresses: + - Slave address 0 - This is the primary slave address that accesses + a CoreI2C channel when it acts as a slave in + I2C transactions. You must configure the primary slave + address using I2C_init(). + + - Slave address 1 - This is the secondary slave address which might be + required in certain application specific scenarios. + The secondary slave address is configured by + I2C_set_slave_second_addr() and is disabled by + I2C_disable_slave_second_addr(). + + - General call address - A CoreI2C slave can be configured to respond to + a broadcast command by a master transmitting the + general call address of 0x00. Use the I2C_set_gca() + function to enable the slave to respond to the general + call address. If the CoreI2C slave is not required to + respond to the general call address, disable this + address by calling I2C_clear_gca(). + + Note: All channels on a CoreI2C instance share the same slave address logic. + This means that they cannot have separate slave addresses and rely on + the separate physical I2C bus connections to distinguish them. + + -------------------------------- + Transaction Types + -------------------------------- + The I2C driver is designed to handle three types of I2C transaction: + - Write transactions + - Read transactions + - Write-read transactions + + ## Write Transaction + The master I2C device initiates a write transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's address with an acknowledge bit. The master sends data one + byte at a time to the slave, which must acknowledge the receipt of each byte + for the next byte to be sent. The master sends a STOP bit to complete the + transaction. The slave can abort the transaction by replying with a + non-acknowledge bit instead of an acknowledge bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Read Transaction + The master I2C device initiates a read transaction by sending a START bit + as soon as the bus becomes free. The START bit is followed by the 7-bit + serial address of the target slave device followed by the read/write bit + indicating the direction of the transaction. The slave acknowledges the + receipt of it's slave address with an acknowledge bit. The slave sends + data one byte at a time to the master, which must acknowledge the receipt of + each byte for the next byte to be sent. The master sends a non-acknowledge + bit following the last byte it wishes to read followed by a STOP bit. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Write-Read Transaction + The write-read transaction is a combination of a write transaction + immediately followed by a read transaction. There is no STOP bit in between + the write and read phases of a write-read transaction. A repeated START + bit is sent between the write and read phases. + + Whilst the write handler is being executed, the slave holds the clock line + low to stretch the clock until the response is ready. + + The write-read transaction is typically used to send a command or offset + in the write transaction specifying the logical data to be transferred + during the read phase. + + The application programmer can choose not to send a STOP bit at the end of + the transaction causing the next transaction to begin with a repeated + START bit. + + ## Master Operations + The application can use the I2C_write(), I2C_read(), and I2C_write_read() + functions to initiate an I2C bus transaction. The application can then wait + for the transaction to complete using the I2C_wait_complete() function + or poll the status of the I2C transaction using the I2C_get_status() + function until it returns a value different from I2C_IN_PROGRESS. The + I2C_system_tick() function is used to set a time base for the + I2C_wait_complete() function's time out delay. + + ## Slave Operations + To configure the I2C driver to operate as an I2C slave requires the use + of the following functions: + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_set_slave_mem_offset_length() + - I2C_register_write_handler() + - I2C_enable_slave() + + Use of all functions is not required if the slave I2C does not need to support + all types of I2C read transactions. The subsequent sections list the functions + that must be used to support each transaction type. + + ## Responding to Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to I2C read transactions: + • I2C_set_slave_tx_buffer() + • I2C_enable_slave() + + The I2C_set_slave_tx_buffer() function specifies the data buffer that + is transmitted when the I2C slave is the target of an I2C read + transaction. It is then up to the application to manage the content of + that buffer to control the data that will be transmitted to the I2C + master as a result of the read transaction. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to the I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write Transactions + The following functions are used to configure the I2C driver to respond + to I2C write transactions: + • I2C_set_slave_rx_buffer() + • I2C_register_write_handler() + • I2C_enable_slave() + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stored the data received by the I2C slave when it targets an I2C write + transaction. + + The I2C_register_write_handler() function specifies the handler function + that must be called on completion of the I2C write transaction. It is this + handler function that processes or triggers the processing of the received + data. + + The I2C_enable_slave() function enables the I2C hardware instance + to respond to I2C transactions. It must be called after the I2C driver + has been configured to respond to the required transaction types. + + ## Responding to Write-Read Transactions + The following functions are used to configure the CoreI2C driver to + respond to write-read transactions: + - I2C_set_slave_mem_offset_length() + - I2C_set_slave_tx_buffer() + - I2C_set_slave_rx_buffer() + - I2C_register_write_handler() + - I2C_enable_slave() + + The I2C_set_slave_mem_offset_length() function specifies the number of + bytes expected by the I2C slave during the write phase of the write-read + transaction. + + The I2C_set_slave_tx_buffer() function specifies the data that is + transmitted to the I2C master during the read phase of the write-read + transaction. The value received by the I2C slave during the write phase of + the transaction will be used as an index into the transmit buffer + specified by this function. It decides which part of the transmit buffer + will be transmitted to the I2C master as part of the read phase of the + write-read transaction. + + The I2C_set_slave_rx_buffer() function specifies the data buffer that + stores the data received by the I2C slave during the write phase of + the write-read transaction. This buffer must be large enough to accommodate + the number of bytes specified through the I2C_set_slave_mem_offset_length() + function. + + The I2C_register_write_handler() function can optionally be used to + specify a handler function that is called on completion of the write phase + of the I2C write-read transaction. If a handler function is registered, it + is responsible for processing the received data in the slave receive + buffer and populating the slave transmit buffer with the data that will be + transmitted to the I2C master as part of the read phase of the write-read + transaction. + + The I2C_enable_slave() function enables the CoreI2C hardware instance to + respond to the I2C transactions. It must be called after configuring the + CoreI2C driver to respond to the required transaction types. + + ## Mixed Master-Slave Operations + The CoreI2C device supports mixed master and slave operations. If the + CoreI2C slave has a transaction in progress and your application attempts to + begin a master mode transaction, the CoreI2C driver queues the master mode + transaction until the bus is released and the CoreI2C can switch to master + mode and acquire the bus. The CoreI2C master then starts the previously + queued master transaction. + + ## SMBus Control + The CoreI2C driver enables the CoreI2C peripheral’s SMBus functionality + using the I2C_smbus_init() function. + + The I2C_suspend_smbus_slave() function is used with a master mode CoreI2C + to force slave devices on the SMBus to enter their Power-Down/Suspend mode. + The I2C_resume_smbus_slave() function is used to end the suspend operation + on the SMBus. + + The I2C_reset_smbus() function is used with a master mode CoreI2C to force + all devices on the SMBus to reset their SMBUs interface. + + The I2C_set_smsbus_alert() function is used by a slave mode CoreI2C to + force communication with the SMBus master. Once communications with the + master is initiated, the I2C_clear_smsbus_alert() function clears the alert + condition. + + The I2C_enable_smbus_irq() and I2C_disable_smbus_irq() functions are used to + enable and disable the SMBSUS and SMBALERT SMBus interrupts. + + *//*=========================================================================*/ + +#ifndef CORE_I2C_H_ +#define CORE_I2C_H_ + +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*-------------------------------------------------------------------------*//** + I2C_RELEASE_BUS + ======================================= + The I2C_RELEASE_BUS constant is used to specify the options parameter to + functions I2C_read(), I2C_write() and I2C_write_read() to indicate + that a STOP bit must be generated at the end of the I2C transaction to release + the bus. + */ +#define I2C_RELEASE_BUS 0x00u + +/*-------------------------------------------------------------------------*//** + I2C_HOLD_BUS + ======================================= + The I2C_HOLD_BUS constant specify the options parameter to functions I2C_read(), + I2C_write(), and I2C_write_read() to indicate that a STOP bit must not be + generated at the end of the I2C transaction in order to retain the bus ownership. + This causes the next transaction to begin with a repeated START bit and no STOP + bit between the transactions. + */ +#define I2C_HOLD_BUS 0x01u + +/*-------------------------------------------------------------------------*//** + Interrupt Identifier Number + ======================================= + The following constants specify the interrupt identifier number which is + solely used by the driver API. This has nothing to do with hardware interrupt + line. I2C_INTR_IRQ is the primary interrupt signal which drives the state machine + of the CoreI2C driver. The I2C_SMBALERT_IRQ and I2C_SMBSUS_IRQ are used by + SMBus interrupt enable and disable functions. These IRQ numbers are also used + by I2C_get_irq_status(). + + | Constant | Description | + |--------------------|--------------------------------------------------------| + | I2C_NO_IRQ | No interrupt | + | I2C_SMBALERT_IRQ | Used by SMBus interrupt enable functions | + | I2C_SMBSUS_IRQ | Used by SMBus interrupt disable functions | + | I2C_INTR_IRQ | Primary interrupt signal which drives the state machine| + + */ +#define I2C_NO_IRQ 0x00u +#define I2C_SMBALERT_IRQ 0x01u +#define I2C_SMBSUS_IRQ 0x02u +#define I2C_INTR_IRQ 0x04u + +/*-------------------------------------------------------------------------*//** + I2C_NO_TIMEOUT + ======================================= + The I2C_wait_complete() function uses I2C_NO_TIMEOUT constant as a parameter + to indicate that the wait for completion of the transaction should not time out. + */ +#define I2C_NO_TIMEOUT 0u + +/***************************************************************************//** + The i2c_channel_number_t type is used to specify the channel number of a + CoreI2C instance. + */ +typedef enum i2c_channel_number { + I2C_CHANNEL_0 = 0u, + I2C_CHANNEL_1, + I2C_CHANNEL_2, + I2C_CHANNEL_3, + I2C_CHANNEL_4, + I2C_CHANNEL_5, + I2C_CHANNEL_6, + I2C_CHANNEL_7, + I2C_CHANNEL_8, + I2C_CHANNEL_9, + I2C_CHANNEL_10, + I2C_CHANNEL_11, + I2C_CHANNEL_12, + I2C_CHANNEL_13, + I2C_CHANNEL_14, + I2C_CHANNEL_15, + I2C_MAX_CHANNELS = 16u +} i2c_channel_number_t; + +/***************************************************************************//** + The i2c_clock_divider_t type specifies the divider to be applied + to the I2C PCLK or BCLK signal in order to generate the I2C clock. + The I2C_BCLK_DIV_8 value selects a clock frequency based on division of BCLK, + all other values select a clock frequency based on division of PCLK. + */ +typedef enum i2c_clock_divider { + I2C_PCLK_DIV_256 = 0u, + I2C_PCLK_DIV_224, + I2C_PCLK_DIV_192, + I2C_PCLK_DIV_160, + I2C_PCLK_DIV_960, + I2C_PCLK_DIV_120, + I2C_PCLK_DIV_60, + I2C_BCLK_DIV_8 +} i2c_clock_divider_t; + +/***************************************************************************//** + The i2c_status_t type is used to report the status of I2C transactions. + */ +typedef enum i2c_status +{ + I2C_SUCCESS = 0u, + I2C_IN_PROGRESS, + I2C_FAILED, + I2C_TIMED_OUT +} i2c_status_t; + +/***************************************************************************//** + The i2c_slave_handler_ret_t type is used by slave write handler functions + to indicate whether or not the received data buffer should be released. + */ +typedef enum i2c_slave_handler_ret { + I2C_REENABLE_SLAVE_RX = 0u, + I2C_PAUSE_SLAVE_RX = 1u +} i2c_slave_handler_ret_t; + +/***************************************************************************//** + This structure identifies various CoreI2C hardware instances in the system + and the I2C channels within them. The application software should declare + one instance of this structure for each channel of each instance of CoreI2C + in your system. I2C_init() and I2C_channel_init() functions initialize this + structure depending on whether it is channel 0 or one of the additional + channels, respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify which + CoreI2C hardware instance to use. + */ +typedef struct i2c_instance i2c_instance_t ; +/***************************************************************************//* + Slave write handler functions prototype +/***************************************************************************//** + This defines the function prototype that must be followed by I2C slave write + handler functions. These functions are registered with the CoreI2C driver + through the I2C_register_write_handler() function. + + Declaring and Implementing Slave Write Handler Functions: + + Slave write handler functions should follow the following prototype: + @code + i2c_slave_handler_ret_t write_handler + ( + i2c_instance_t *instance, uint8_t * data, uint16_t size + ); + @endcode + + The instance parameter is a pointer to the i2c_instance_t for which this + slave write handler has been declared. + + The data parameter is a pointer to a buffer (received data buffer) holding + the data written to the I2C slave. + + Define the INCLUDE_SLA_IN_RX_PAYLOAD macro for the driver to insert the + actual address used to access the slave as the first byte in the buffer. + This allows the applications to tailor their response based on the actual + address used to access the slave (primary address, secondary address, or GCA). + + The size parameter is the number of bytes held in the received data buffer. + Handler functions must return one of the following values: + - I2C_REENABLE_SLAVE_RX + - I2C_PAUSE_SLAVE_RX + + If the handler function returns I2C_REENABLE_SLAVE_RX, the driver releases + the received data buffer and allows further I2C write transactions to the + I2C slave. + + If the handler function returns I2C_PAUSE_SLAVE_RX, the I2C slave responds + to subsequent write requests with a non-acknowledge bit (NACK), until the + received data buffer content gets processed by some other part of the + software application. + + Call the I2C_enable_slave() after returning the I2C_PAUSE_SLAVE_RX to release + the received data buffer in order to store the data received by the subsequent + I2C write transactions. + */ +typedef i2c_slave_handler_ret_t (*i2c_slave_wr_handler_t)(i2c_instance_t *instance, uint8_t *, uint16_t ); + +/***************************************************************************//** + This structure is used to identify the various CoreI2C hardware instances in + your system and the I2C channels within them. Your application software should + declare one instance of this structure for each channel of each instance of + CoreI2C in your system. The functions I2C_init() and I2C_channel_init() + initialize this structure depending on whether it is channel 0 or one of the + additional channels respectively. A pointer to an initialized instance of the + structure should be passed as the first parameter to the CoreI2C driver + functions, to identify which CoreI2C hardware instance and channel should + perform the requested operation. + + The contents of this data structure should not be modified or used outside of + the CoreI2C driver. Software using the CoreI2C driver should only need to + create one single instance of this data structure for each channel of each + CoreI2C hardware instance in the system then pass a pointer to these data + structures with each call to the CoreI2C driver in order to identify the + CoreI2C hardware instance it wishes to use. + */ +struct i2c_instance +{ + addr_t base_address; + uint_fast8_t ser_address; + + /* Transmit related info:*/ + uint_fast8_t target_addr; + + /* Current transaction type (WRITE, READ, RANDOM_READ)*/ + uint8_t transaction; + + uint_fast16_t random_read_addr; + + uint8_t options; + + /* Master TX INFO: */ + const uint8_t * master_tx_buffer; + uint_fast16_t master_tx_size; + uint_fast16_t master_tx_idx; + uint_fast8_t dir; + + /* Master RX INFO: */ + uint8_t * master_rx_buffer; + uint_fast16_t master_rx_size; + uint_fast16_t master_rx_idx; + + /* Master Status */ + volatile i2c_status_t master_status; + uint32_t master_timeout_ms; + + /* Slave TX INFO */ + const uint8_t * slave_tx_buffer; + uint_fast16_t slave_tx_size; + uint_fast16_t slave_tx_idx; + + /* Slave RX INFO */ + uint8_t * slave_rx_buffer; + uint_fast16_t slave_rx_size; + uint_fast16_t slave_rx_idx; + /* Slave Status */ + volatile i2c_status_t slave_status; + + /* Slave data: */ + uint_fast8_t slave_mem_offset_length; + i2c_slave_wr_handler_t slave_write_handler; + uint8_t is_slave_enabled; + + /* user specific data */ + void *p_user_data ; + + /* I2C bus status */ + uint8_t bus_status; + + /* Is transaction pending flag */ + uint8_t is_transaction_pending; + + /* I2C Pending transaction */ + uint8_t pending_transaction; +}; + +/*------------------------Public Function-------------------------------------*/ + +/***************************************************************************//** + The I2C_init() function configures channel 0 of a CoreI2C instance. It sets + the base hardware address which is used to locate the CoreI2C instance + in memory and also used internally by I2C_channel_init() to calculate the + register addresses for any additional channels. The slave serial address set + is shared by all channels on a CoreI2C instance. + + If only one channel is configured in a CoreI2C, the address of the + i2c_instance_t used in I2C_Init() will also be used in subsequent calls to the + CoreI2C driver functions. If more than one channel is configured in the + CoreI2C, I2C_channel_init() will be called after I2C_init(), which initializes + the i2c_instance_t data structure for a specific channel. + + @param this_i2c + Pointer to the i2c_instance_t data structure that holds all the data + related to channel 0 of the CoreI2C instance is initialized. A pointer + to this structure is used in all subsequent calls to the CoreI2C driver + functions which operates on channel 0 of this CoreI2C instance. + + @param base_address + Base address in the processor's memory map of the registers of the CoreI2C + instance being initialized. + + @param ser_address + This parameter sets the primary I2C serial address (SLAVE0 address) for the + CoreI2C to initialize. It is the principal I2C bus address to which the + CoreI2C instance will respond. CoreI2C can operate in master mode or slave + mode and the serial address is significant only in the case of I2C slave + mode. In master mode, CoreI2C does not require a serial address and the + value of this parameter is not important. If you do not intend to use the + CoreI2C device in slave mode, then provide any dummy slave address value + to this parameter. However, in systems where the CoreI2C is expected to + switch from master mode to slave mode, it is advisable to initialize the + CoreI2C device with a valid serial slave address. Call the I2C_init() + function whenever it is required to change the primary slave address as + there is no separate function to set the primary slave address of the + I2C device. The serial address initialized through this function is + basically the primary slave address or slave address0. + I2C_set_slave_second_addr() is used to set the secondary slave address + or slave address 1. + Note : ser_address parameter does not have any affect if fixed slave + address is enabled in CoreI2C hardware design. CoreI2C will + be always addressed with the hardware configured fixed slave + address. + Note : ser_address parameter will not have any affect if the CoreI2C + instance is only used in master mode. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that generates the serial clock from the APB PCLK or from the BCLK. + It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value overrides the value passed + as parameter in this function. + Note: serial_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + } + @endcode + */ +void I2C_init +( + i2c_instance_t * this_i2c, + addr_t base_address, + uint8_t ser_address, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_channel_init() function initializes and configures hardware and data + structures of one of the additional channels of a CoreI2C instance. + I2C_init() must be called before calling this function to set the CoreI2C + instance hardware base address and I2C serial address. I2C_channel_init() also + initializes I2C serial clock divider to set the serial clock baud rate. + The pointer to data structure i2c_instance_t used for a particular channel + is used as an input parameter to subsequent CoreI2C driver functions + which operate on this channel. + + @param this_i2c_channel + Pointer to the i2c_instance_t data structure that holds all data related to + the CoreI2C channel gets initialized. A pointer to the same data structure + is used in subsequent calls to the CoreI2C driver functions in order to + identify the CoreI2C channel instance that should perform the operation + implemented by the called driver function. + + @param this_i2c + This is a pointer to an i2c_instance_t structure, previously initialized by + I2C_init(). It holds information regarding the hardware base address and + I2C serial address for the CoreI2C containing the channel to be + initialized. This information is required by I2C_channel_init() to + initialize the i2c_instance_t structure pointed by this_i2c_channel as + all channels in a CoreI2C instance share the same base address and serial + address. It is very important that the i2c_instance_t structure pointed + by this_i2c must be previously initialized by calling I2C_init(). + + @param channel_number + This parameter of type i2c_channel_number_t identifies the channel to be + initialized. + + @param ser_clock_speed + This parameter sets the I2C serial clock frequency. It selects the divider + that is used to generate the serial clock from the APB PCLK or from + the BCLK. It can be one of the following: + - I2C_PCLK_DIV_256 + - I2C_PCLK_DIV_224 + - I2C_PCLK_DIV_192 + - I2C_PCLK_DIV_160 + - I2C_PCLK_DIV_960 + - I2C_PCLK_DIV_120 + - I2C_PCLK_DIV_60 + - I2C_BCLK_DIV_8 + Note: serial_clock_speed value does not have any affect if the fixed baud + rate is enabled in CoreI2C hardware instance configuration dialogue + window. The fixed baud rate divider value will supersede the value + passed as parameter in this function. + Note: ser_clock_speed value is not critical for devices that only operate + as slaves and can be set to any of the above values. + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_SER_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + i2c_instance_t g_i2c_channel_1_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void system_init( void ) + { + uint8_t target_slave_addr = 0x12; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize CoreI2C channel 1 with different clock speed + I2C_channel_init( &g_i2c_channel_1_inst, &g_i2c_inst, I2C_CHANNEL_1, + I2C_PCLK_DIV_224 ); + + // Write data to Channel 1 of CoreI2C instance. + I2C_write( &g_i2c_channel_1_inst, target_slave_addr, tx_buffer, + write_length, I2C_RELEASE_BUS ); + } + @endcode + +*/ +void I2C_channel_init +( + i2c_instance_t * this_i2c_channel, + i2c_instance_t * this_i2c, + i2c_channel_number_t channel_number, + i2c_clock_divider_t ser_clock_speed +); + +/***************************************************************************//** + The I2C_isr function is the CoreI2C interrupt service routine. User must + call this function from their application level CoreI2C interrupt handler + function. This function runs the I2C state machine based on previous and + current status. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREINTERRUPT_BASE_ADDR 0xCC000000u + #define COREI2C_SER_ADDR 0x10u + #define I2C_IRQ_NB 2u + + i2c_instance_t g_i2c_inst; + + void core_i2c_isr( void ) + { + I2C_isr( &g_i2c_inst ); + } + + void main( void ) + { + CIC_init( COREINTERRUPT_BASE_ADDR ); + NVIC_init(); + CIC_set_irq_handler( I2C_IRQ_NB, core_i2c_isr ); + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_SER_ADDR, + I2C_PCLK_DIV_256 ); + NVIC_enable_interrupt( NVIC_IRQ_0 ); + } + @endcode + */ +void I2C_isr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #Master Specific Functions + + The following functions are only used within an I2C master's implementation. +/***************************************************************************//** + This function initiates an I2C master write transaction. This function returns + immediately after initiating the transaction. The content of the write buffer + passed as parameter should not be modified until the write transaction + completes. It also means that the memory allocated for the write buffer should + not be freed or should not go out of scope before the write completes. You can + check for the write transaction completion using the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param write_buffer + This parameter is a pointer to a buffer holding the data to be written to + the target I2C device. Do not to release the memory used by this buffer + before the write transaction completes. For example, it is not appropriate + to return from a function allocating this buffer as an auto array variable + before the write transaction completes as this would result in the buffer's + memory being de-allocated from the stack when the function returns. This + memory could then be subsequently reused and modified causing unexpected + data to be written to the target I2C device. + + @param write_size + Number of bytes held in the write_buffer to be written to the target I2C + device. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t tx_buffer[DATA_LENGTH]; + uint8_t write_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Write data to Channel 0 of CoreI2C instance. + I2C_write( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * write_buffer, + uint16_t write_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C master read transaction. This function returns + immediately after initiating the transaction. + The contents of the read buffer passed as parameter should not be modified + until the read transaction completes. It also means that the memory allocated + for the read buffer should not be freed or should not go out of scope before + the read completes. You can check for the read transaction completion using + the I2C_status() function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param read_buffer + This is a pointer to a buffer where the data received from the target device + gets stored. Do not to release the memory used by this buffer before the read + transaction completes. For example, it is not appropriate to return from a + function allocating this buffer as an auto array variable before the read + transaction completes as this would result in the buffer's memory being + de-allocated from the stack when the function returns. This memory could + then be subsequently reallocated resulting in the read transaction + corrupting the newly allocated memory. + + @param read_size + This parameter specifies the number of bytes to read from the target device. + This size must not exceed the size of the read_buffer buffer. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the read transaction causing the bus to be released for other I2C + devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the read transaction, + preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from target slave Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function initiates an I2C write-read transaction where data is first + written to the target device before issuing a restart condition and changing + the direction of the I2C transaction in order to read from the target device. + + The same warnings about buffer allocation in I2C_write() and I2C_read() + applies to this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param serial_addr + This parameter specifies the serial address of the target I2C device. + + @param addr_offset + This parameter is a pointer to the buffer containing the data that is sent + to the slave during the write phase of the write-read transaction. This + data is typically used to specify an address offset specifying to the I2C + slave device what data it must return during the read phase of the + write-read transaction. + + @param offset_size + This parameter specifies the number of offset bytes to be written during the + write phase of the write-read transaction. This is typically the size of the + buffer pointed by the addr_offset parameter. + + @param read_buffer + This parameter is a pointer to the buffer where the data read from the I2C + slave will be stored. + + @param read_size + This parameter specifies the number of bytes to read from the target I2C + slave device. This size must not exceed the size of the buffer pointed by + the read_buffer parameter. + + @param options + The options parameter is used to indicate if the I2C bus should be released + on completion of the write-read transaction. Using the I2C_RELEASE_BUS + constant for the options parameter causes a STOP bit to be generated at the + end of the write-read transaction causing the bus to be released for other + I2C devices to use. Using the I2C_HOLD_BUS constant as options parameter + prevents a STOP bit from being generated at the end of the write-read + transaction, preventing other I2C devices from initiating a bus transaction. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define TX_LENGTH 16u + #define RX_LENGTH 8u + + i2c_instance_t g_i2c_inst; + uint8_t rx_buffer[RX_LENGTH]; + uint8_t read_length = RX_LENGTH; + uint8_t tx_buffer[TX_LENGTH]; + uint8_t write_length = TX_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + I2C_write_read( &g_i2c_inst, target_slave_addr, tx_buffer, write_length, + rx_buffer, read_length, I2C_RELEASE_BUS ); + + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +void I2C_write_read +( + i2c_instance_t * this_i2c, + uint8_t serial_addr, + const uint8_t * addr_offset, + uint16_t offset_size, + uint8_t * read_buffer, + uint16_t read_size, + uint8_t options +); + +/***************************************************************************//** + This function indicates the current state of a CoreI2C channel. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + The return value indicates the current state of a CoreI2C channel or the + outcome of the previous transaction if no transaction is in progress. + Following are the return values are: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_IN_PROGRESS + There is an I2C transaction in progress. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The request has failed to complete in the allotted time. + + @example + @code + i2c_instance_t g_i2c_inst; + + while( I2C_IN_PROGRESS == I2C_get_status( &g_i2c_inst ) ) + { + // Do something useful while waiting for I2C operation to complete + our_i2c_busy_task(); + } + + if( I2C_SUCCESS != I2C_get_status( &g_i2c_inst ) ) + { + // Something went wrong... + our_i2c_error_recovery( &g_i2c_inst ); + } + @endcode + */ +i2c_status_t I2C_get_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function waits for the current I2C transaction to complete. The return + value indicates whether the last I2C transaction was successful or not. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param timeout_ms + The timeout_ms parameter specifies the delay within which the current I2C + transaction should complete. The time out delay is given in + milliseconds. I2C_wait_complete() will return I2C_TIMED_OUT if the current + transaction has not completed after the time out delay has expired. This + parameter can be set to I2C_NO_TIMEOUT to indicate that I2C_wait_complete() + must not time out. + + @return + The return value indicates the outcome of the last I2C transaction. It can + be one of the following: + - I2C_SUCCESS + The last I2C transaction has completed successfully. + - I2C_FAILED + The last I2C transaction failed. + - I2C_TIMED_OUT + The last transaction failed to complete within the time out delay given + as second parameter. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define COREI2C_DUMMY_ADDR 0x10u + #define DATA_LENGTH 16u + + i2c_instance_t g_i2c_inst; + + uint8_t rx_buffer[DATA_LENGTH]; + uint8_t read_length = DATA_LENGTH; + + void main( void ) + { + uint8_t target_slave_addr = 0x12; + i2c_status_t status; + + // Initialize base CoreI2C instance + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, COREI2C_DUMMY_ADDR, + I2C_PCLK_DIV_256 ); + + // Read data from Channel 0 of CoreI2C instance. + I2C_read( &g_i2c_inst, target_slave_addr, rx_buffer, read_length, + I2C_RELEASE_BUS ); + + // Wait for completion and record the outcome + status = I2C_wait_complete( &g_i2c_inst, I2C_NO_TIMEOUT ); + } + @endcode + */ +i2c_status_t I2C_wait_complete +( + i2c_instance_t * this_i2c, + uint32_t timeout_ms +); + +/***************************************************************************//** + This function is used to control the expiration of the time out delay + specified as a parameter to the I2C_wait_complete() function. It must be + called from the interrupt service routine of a periodic interrupt source such + as the SysTick timer interrupt. It takes the period of the interrupt + source as its ms_since_last_tick parameter and uses it as the time base for + the I2C_wait_complete() function's time out delay. + + Note: This function does not need to be called if the I2C_wait_complete() + function is called with a timeout_ms value of I2C_NO_TIMEOUT. + + Note: If this function is not called then the I2C_wait_complete() function + will behave as if its timeout_ms was specified as I2C_NO_TIMEOUT and it + will not time out. + + Note: If this function is being called from an interrupt handler (for example, + SysTick) it is important that the calling interrupt have a lower priority + than the CoreI2C interrupt(s) to ensure any updates to the shared data are + protected. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + @param ms_since_last_tick + The ms_since_last_tick parameter specifies the number of milliseconds that + elapsed since the last call to I2C_system_tick(). This parameter would + typically be a constant specifying the interrupt rate of a timer used to + generate system ticks. + + @return None. + + @example + The following example shows how the I2C_system_tick() function. I2C_system_tick() + is called for each I2C channel from the SysTick timer interrupt service routine. + The following example shows how the SysTick is configured to generate an interrupt + in every 10 milliseconds. + @code + #define SYSTICK_INTERVAL_MS 10 + + void SysTick_Handler(void) + { + I2C_system_tick(&g_core_i2c0, SYSTICK_INTERVAL_MS); + I2C_system_tick(&g_core_i2c2, SYSTICK_INTERVAL_MS); + } + @endcode + */ +void I2C_system_tick +( + i2c_instance_t * this_i2c, + uint32_t ms_since_last_tick +); + +/***************************************************************************//* + #Slave Specific Functions + + The following functions are only used within the implementation of an I2C slave device. + +/***************************************************************************//** + This function specifies the memory buffer holding the data that will be sent + to the I2C master when this CoreI2C channel is the target of an I2C read or + write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param tx_buffer + This parameter is a pointer to the memory buffer holding the data to be + returned to the I2C master when this CoreI2C channel is the target of an + I2C read or write-read transaction. + + @param tx_size + Size of the transmit buffer pointed by the tx_buffer parameter. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the transmit buffer containing the data that will be + // returned to the master during read and write-read transactions. + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + } + @endcode + */ +void I2C_set_slave_tx_buffer +( + i2c_instance_t * this_i2c, + const uint8_t * tx_buffer, + uint16_t tx_size +); + +/***************************************************************************//** + This function specifies the memory buffer that is used by the CoreI2C channel + to receive data when it is a slave. This buffer is the memory where data gets + stored when the CoreI2C channel is the target of an I2C master write + transaction (that is, when it is the slave). + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param rx_buffer + This parameter is a pointer to the memory buffer allocated by the caller + software to be used as a slave receive buffer. + + @param rx_size + Size of the slave receive buffer. This is the amount of memory allocated + to the buffer pointed by rx_buffer. + Note: Indirectly, this buffer size specifies the maximum I2C write + transaction length this CoreI2C channel targets. This is because + this CoreI2C channel responds to further received bytes with + a non-acknowledge bit (NACK) as soon as its receive buffer is + full. This causes the write transaction to fail. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_RX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_rx_buffer[SLAVE_RX_BUFFER_SIZE]; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Specify the buffer used to store the data written by the I2C master. + I2C_set_slave_rx_buffer( &g_i2c_inst, g_slave_rx_buffer, + sizeof(g_slave_rx_buffer) ); + } + @endcode + */ +void I2C_set_slave_rx_buffer +( + i2c_instance_t * this_i2c, + uint8_t * rx_buffer, + uint16_t rx_size +); + +/***************************************************************************//** + This function is used as part of the configuration of a CoreI2C channel to + operate as a slave supporting write-read transactions. It specifies the + number of bytes expected as part of the write phase of a write-read + transaction. The bytes received during the write phase of a write-read + transaction will be interpreted as an offset into the slave's transmit buffer. + This allows random access into the I2C slave transmit buffer from a remote + I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param offset_length + The offset_length parameter configures the number of bytes to be interpreted + by the CoreI2C slave as a memory offset value during the write phase of + write-read transactions. The maximum value for the offset_length parameter + is two. The value of offset_length has the following effect on the + interpretation of the received data. + • If offset_length is 0, the offset into the transmit buffer is fixed at 0. + • If offset_length is 1, a single byte of received data is interpreted as an + unsigned 8-bit offset value in the range 0 to 255. + • If offset_length is 2, 2 bytes of received data are interpreted as an + unsigned 16-bit offset value in the range 0 to 65535. The first byte + received in this case provides the high order bits of the offset and + the second byte provides the low order bits. + If the number of bytes received does not match the non 0 value of + offset_length, the transmit buffer offset is set to 0. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + } + @endcode + */ +void I2C_set_slave_mem_offset_length +( + i2c_instance_t * this_i2c, + uint8_t offset_length +); + +/***************************************************************************//** + Register the function that is called to process the data written to this + CoreI2C channel when it is the slave in an I2C write transaction. + + Note: If a write handler is registered, it is called on completion of the + write phase of a write-read transaction and responsible for processing + the received data in the slave receive buffer and populating the slave + transmit buffer with the data that is transmitted to the I2C master + as part of the read phase of the write-read transaction. If a write + handler is not registered, the write data of a write-read transaction is + interpreted as an offset into the slave’s transmit buffer and handled by + the driver. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param handler + Pointer to the function that processes the I2C write request. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SLAVE_TX_BUFFER_SIZE 10u + + i2c_instance_t g_i2c_inst; + + uint8_t g_slave_tx_buffer[SLAVE_TX_BUFFER_SIZE] = { 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10 }; + + // local function prototype + void slave_write_handler + ( + i2c_instance_t * this_i2c, + uint8_t * p_rx_data, + uint16_t rx_size + ); + + void main( void ) + { + // Initialize the CoreI2C driver with its base address, I2C serial + // address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_tx_buffer( &g_i2c_inst, g_slave_tx_buffer, + sizeof(g_slave_tx_buffer) ); + I2C_set_slave_mem_offset_length( &g_i2c_inst, 1 ); + I2C_register_write_handler( &g_i2c_inst, slave_write_handler ); + } + @endcode +*/ +void I2C_register_write_handler +( + i2c_instance_t * this_i2c, + i2c_slave_wr_handler_t handler +); + +/***************************************************************************//** + This function enables slave mode operation for a CoreI2C channel. It enables + the CoreI2C slave to receive data when it is the target of an I2C read, write, + or write-read transaction. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Enable I2C slave + I2C_enable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_enable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + This function disables the slave mode operation for a CoreI2C channel. It stops + the CoreI2C slave that acknowledges the I2C read, write, or write-read + transactions targeted at it. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + // Disable I2C slave + I2C_disable_slave( &g_i2c_inst ); + @endcode + */ +void I2C_disable_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_slave_second_addr() function sets the secondary slave address for + a CoreI2C slave device. This is an additional slave address required in certain + applications, for example, to enable fail-safe operation in a system. As the + CoreI2C device supports 7-bit addressing, the highest value assigned to second + slave address is 127 (0x7F). + + Note: This function does not support CoreI2C hardware configured with a fixed + second slave address. The current implementation of the ADDR1[0] register + bit makes it difficult for the driver to support both programmable and + fixed second slave address, so we choose to support programmable only. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param second_slave_addr + The second_slave_addr parameter is the secondary slave address of the I2C + device. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + #define SECOND_SLAVE_ADDR 0x20u + + i2c_instance_t g_i2c_inst; + void main( void ) + { + // Initialize the CoreI2C driver with its base address, primary I2C + // serial address and serial clock divider. + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + I2C_set_slave_second_addr( &g_i2c_inst, SECOND_SLAVE_ADDR ); + } + @endcode + */ +void I2C_set_slave_second_addr +( + i2c_instance_t * this_i2c, + uint8_t second_slave_addr +); + +/***************************************************************************//** + The I2C_disable_slave_second_addr() function disables the secondary slave + address of the CoreI2C slave device. + + Note: This version of the driver only supports CoreI2C hardware configured + with a programmable second slave address. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + I2C_disable_slave_second_addr( &g_i2c_inst); + @endcode + */ +void I2C_disable_slave_second_addr +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_gca() function is used to set the general call acknowledgement bit + of a CoreI2C slave device. This allows all channels of the CoreI2C slave + device to respond to a general call or broadcast message from an I2C master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Enable recognition of the General Call Address + I2C_set_gca( &g_i2c_inst ); + @endcode + */ +void I2C_set_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_gca() function is used to clear the general call acknowledgement + bit of a CoreI2C slave device. This will stop all channels of the I2C slave + device responding to any general call or broadcast message from the master. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + i2c_instance_t g_i2c_inst; + + // Disable recognition of the General Call Address + I2C_clear_gca( &g_i2c_inst ); + @endcode + */ + +void I2C_clear_gca +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//* + #I2C SMBUS Specific APIs + +/***************************************************************************//** + The I2C_smbus_init() function enables SMBus timeouts and status logic for a + CoreI2C channel. + + Note: This and any of the other SMBus related functionality will only have an + effect if the CoreI2C was instantiated with the Generate SMBus Logic + option checked. + + Note: If the CoreI2C was instantiated with the Generate IPMI Logic option + checked this function then enables the IPMI 3mS SCL low timeout but + none of the other SMBus functions will have any effect. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void system_init( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst); + } + @endcode + */ +void I2C_smbus_init +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_enable_smbus_irq() function is used to enable the CoreI2C channel’s + SMBSUS and SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specify the SMBUS interrupt(s) which will be enabled. + The two possible interrupts are: + - I2C_SMBALERT_IRQ + - I2C_SMBSUS_IRQ + To enable both interrupts in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ) ); + } + @endcode + */ +void I2C_enable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_disable_smbus_irq() function disable the CoreI2C channel’s SMBSUS and + SMBALERT SMBus interrupts. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param irq_type + The irq_type specifies the SMBUS interrupt(s) which are disabled. + The two possible interrupts are: + • I2C_SMBALERT_IRQ + • I2C_SMBSUS_IRQ + To disable both ints in one call, use I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both SMBALERT & SMBSUS interrupts + I2C_enable_smbus_irq( &g_i2c_inst, + (uint8_t)(I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ)); + + ... + + // Disable the SMBALERT interrupt + I2C_disable_smbus_irq( &g_i2c_inst, I2C_SMBALERT_IRQ ); + } + @endcode + */ +void I2C_disable_smbus_irq +( + i2c_instance_t * this_i2c, + uint8_t irq_type +); + +/***************************************************************************//** + The I2C_suspend_smbus_slave() function forces any SMBUS slave devices + connected to a CoreI2C channel into Power-Down or Suspend mode by asserting + the channel's SMBSUS signal. The CoreI2C channel is the SMBus master in this + case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_suspend_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_resume_smbus_slave() function de-asserts the CoreI2C channel's SMBSUS + signal to take any connected slave devices out of the Suspend mode. The CoreI2C + channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // suspend SMBus slaves + I2C_suspend_smbus_slave( &g_i2c_inst ); + + ... + + // Re-enable SMBus slaves + I2C_resume_smbus_slave( &g_i2c_inst ); + } + @endcode + */ +void I2C_resume_smbus_slave +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_reset_smbus() function resets the CoreI2C channel's SMBus connection + by forcing SCLK low for 35 mS. The reset that automatically cleares after 35 ms + gets elapsed. The CoreI2C channel is the SMBus master in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Make sure the SMBus channel is in a known state by resetting it + I2C_reset_smbus( &g_i2c_inst ); + } + @endcode + */ +void I2C_reset_smbus +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_smbus_alert() function is used to force master communication with + an I2C slave device by asserting the CoreI2C channel's SMBALERT signal. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_set_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_clear_smbus_alert() function is used to de-assert the CoreI2C channel's + SMBALERT signal once a slave device gets a response from the master. The + CoreI2C channel is the SMBus slave in this case. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Get the SMBus masters attention + I2C_set_smbus_alert( &g_i2c_inst ); + + ... + + // Once we are happy, drop the alert + I2C_clear_smbus_alert( &g_i2c_inst ); + } + @endcode + */ +void I2C_clear_smbus_alert +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_get_irq_status function returns information about which interrupts are + currently pending in a CoreI2C channel. + The interrupts supported by CoreI2C are: + • SMBUSALERT + • SMBSUS + • INTR + + The macros I2C_NO_IRQ, I2C_SMBALERT_IRQ, I2C_SMBSUS_IRQ, and I2C_INTR_IRQ are + provided to use with this function. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns the status of the CoreI2C channel's interrupts as a + single byte bitmap where a bit is set to indicate a pending interrupt. + The following are the bit positions associated with each interrupt type: + Bit 0 - SMBUS_ALERT_IRQ + Bit 1 - SMBSUS_IRQ + Bit 2 - INTR_IRQ + It returns 0, if there are no pending interrupts. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + + void main( void ) + { + uint8_t irq_to_enable = I2C_SMBALERT_IRQ | I2C_SMBSUS_IRQ; + uint8_t pending_irq = 0u; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Initialize SMBus feature + I2C_smbus_init( &g_i2c_inst ); + + // Enable both I2C_SMBALERT_IRQ & I2C_SMBSUS_IRQ irq + I2C_enable_smbus_irq( &g_i2c_inst, irq_to_enable ); + + // Get I2C IRQ type + pending_irq = I2C_get_irq_status( &g_i2c_inst ); + + // Let's assume, in system, INTR and SMBALERT IRQ is pending. + // So pending_irq will return status of both the IRQs + + if( pending_irq & I2C_SMBALERT_IRQ ) + { + // if true, it means SMBALERT_IRQ is there in pending IRQ list + } + if( pending_irq & I2C_INTR_IRQ ) + { + // if true, it means I2C_INTR_IRQ is there in pending IRQ list + } + } + @endcode + */ +uint8_t I2C_get_irq_status +( + i2c_instance_t * this_i2c +); + +/***************************************************************************//** + The I2C_set_user_data() function allows the association of a block of application + specific data with a CoreI2C channel. The composition of the data block is an + application matter and the driver simply provides the means for the application + to set and retrieve the pointer. For example, this is used to provide additional + channel specific information to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @param p_user_data + The p_user_data parameter is a pointer to the user specific data block for + this channel. It is defined as void * as the driver does not know the actual + type of data being pointed to and simply stores the pointer for later + retrieval by the application. + + @return + None. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void I2C_set_user_data +( + i2c_instance_t * this_i2c, + void * p_user_data +); + +/***************************************************************************//** + The I2C_get_user_data() function is used to allows the retrieval of the address + of a block of application specific data associated with a CoreI2C channel. + The composition of the data block is an application matter and the driver + simply provides the means for the application to set and retrieve the pointer. + For example, this is used to provide additional channel specific information + to the slave write handler. + + @param this_i2c + The this_i2c parameter is a pointer to the i2c_instance_t data structure + holding all data related to a specific CoreI2C channel. For example, if only + one channel is initialized, this data structure holds the information of + channel 0 of the instantiated CoreI2C hardware. + + @return + This function returns a pointer to the user specific data block for this + channel. It is defined as void * as the driver does not know the actual type + of data being pointed. If no user data has been registered for this channel + a NULL pointer is returned. + + @example + @code + #define COREI2C_BASE_ADDR 0xC0000000u + #define SLAVE_SER_ADDR 0x10u + + i2c_instance_t g_i2c_inst; + app_data_t channel_xdata; + + void main( void ) + { + app_data_t *p_xdata; + + I2C_init( &g_i2c_inst, COREI2C_BASE_ADDR, SLAVE_SER_ADDR, + I2C_PCLK_DIV_256 ); + + // Store location of user data in instance structure + I2C_set_user_data( &g_i2c_inst, (void *)&channel_xdata ); + + ... + + // Retrieve location of user data and do some work on it + p_xdata = (app_data_t *)I2C_get_user_data( &g_i2c_inst ); + if( NULL != p_xdata ) + { + p_xdata->foo = 123; + } + } + @endcode + */ +void * I2C_get_user_data +( + i2c_instance_t * this_i2c +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h new file mode 100644 index 0000000..b1d872d --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/core_smbus_regs.h @@ -0,0 +1,190 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + */ + +#ifndef __CORE_SMBUS_REGISTERS +#define __CORE_SMBUS_REGISTERS 1 + +/*------------------------------------------------------------------------------ + * CONTROL register details + */ +#define CONTROL_REG_OFFSET 0x00u + +/* + * CR0 bits. + */ +#define CR0_OFFSET 0x00u +#define CR0_MASK 0x01u +#define CR0_SHIFT 0u + +/* + * CR1 bits. + */ +#define CR1_OFFSET 0x00u +#define CR1_MASK 0x02u +#define CR1_SHIFT 1u + +/* + * AA bits. + */ +#define AA_OFFSET 0x00u +#define AA_MASK 0x04u +#define AA_SHIFT 2u + +/* + * SI bits. + */ +#define SI_OFFSET 0x00u +#define SI_MASK 0x08u +#define SI_SHIFT 3u + +/* + * STO bits. + */ +#define STO_OFFSET 0x00u +#define STO_MASK 0x10u +#define STO_SHIFT 4u + +/* + * STA bits. + */ +#define STA_OFFSET 0x00u +#define STA_MASK 0x20u +#define STA_SHIFT 5u + +/* + * ENS1 bits. + */ +#define ENS1_OFFSET 0x00u +#define ENS1_MASK 0x40u +#define ENS1_SHIFT 6u + +/* + * CR2 bits. + */ +#define CR2_OFFSET 0x00u +#define CR2_MASK 0x80u +#define CR2_SHIFT 7u + +/*------------------------------------------------------------------------------ + * STATUS register details + */ +#define STATUS_REG_OFFSET 0x04u + +/*------------------------------------------------------------------------------ + * DATA register details + */ +#define DATA_REG_OFFSET 0x08u + +/* + * TARGET_ADDR bits. + */ +#define TARGET_ADDR_OFFSET 0x08u +#define TARGET_ADDR_MASK 0xFEu +#define TARGET_ADDR_SHIFT 1u + +/* + * DIR bit. + */ +#define DIR_OFFSET 0x08u +#define DIR_MASK 0x01u +#define DIR_SHIFT 0u + + +/*------------------------------------------------------------------------------ + * ADDRESS register details + */ +#define ADDRESS_REG_OFFSET 0x0Cu + +/* + * GC bits. + */ +#define GC_OFFSET 0x0Cu +#define GC_MASK 0x01u +#define GC_SHIFT 0u + +/* + * ADR bits. + */ +#define OWN_SLAVE_ADDR_OFFSET 0x0Cu +#define OWN_SLAVE_ADDR_MASK 0xFEu +#define OWN_SLAVE_ADDR_SHIFT 1u + +/*------------------------------------------------------------------------------ + * SMBUS register details + */ +#define SMBUS_REG_OFFSET 0x10u + +/* + * SMBALERT_IE bits. + */ +#define SMBALERT_IE_OFFSET 0x10u +#define SMBALERT_IE_MASK 0x01u +#define SMBALERT_IE_SHIFT 0u + +/* + * SMBSUS_IE bits. + */ +#define SMBSUS_IE_OFFSET 0x10u +#define SMBSUS_IE_MASK 0x02u +#define SMBSUS_IE_SHIFT 1u + +/* + * SMB_IPMI_EN bits. + */ +#define SMB_IPMI_EN_OFFSET 0x10u +#define SMB_IPMI_EN_MASK 0x04u +#define SMB_IPMI_EN_SHIFT 2u + +/* + * SMBALERT_NI_STATUS bits. + */ +#define SMBALERT_NI_STATUS_OFFSET 0x10u +#define SMBALERT_NI_STATUS_MASK 0x08u +#define SMBALERT_NI_STATUS_SHIFT 3u + +/* + * SMBALERT_NO_CONTROL bits. + */ +#define SMBALERT_NO_CONTROL_OFFSET 0x10u +#define SMBALERT_NO_CONTROL_MASK 0x10u +#define SMBALERT_NO_CONTROL_SHIFT 4u + +/* + * SMBSUS_NI_STATUS bits. + */ +#define SMBSUS_NI_STATUS_OFFSET 0x10u +#define SMBSUS_NI_STATUS_MASK 0x20u +#define SMBSUS_NI_STATUS_SHIFT 5u + +/* + * SMBSUS_NO_CONTROL bits. + */ +#define SMBSUS_NO_CONTROL_OFFSET 0x10u +#define SMBSUS_NO_CONTROL_MASK 0x40u +#define SMBSUS_NO_CONTROL_SHIFT 6u + +/* + * SMBUS_MST_RESET bits. + */ +#define SMBUS_MST_RESET_OFFSET 0x10u +#define SMBUS_MST_RESET_MASK 0x80u +#define SMBUS_MST_RESET_SHIFT 7u + +/*------------------------------------------------------------------------------ + * SLAVE ADDRESS 1 register details + */ + +#define ADDRESS1_REG_OFFSET 0x1Cu + +/* + * SLAVE1_EN bit of Slave Address 1 . + */ +#define SLAVE1_EN_OFFSET 0x1Cu +#define SLAVE1_EN_MASK 0x01u +#define SLAVE1_EN_SHIFT 0u + +#endif /* __CORE_SMBUS_REGISTERS */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c new file mode 100644 index 0000000..12e352d --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreI2C/i2c_interrupt.c @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright 2009-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * CoreI2C driver interrupt control. + * + */ +#include "core_i2c.h" + +/*------------------------------------------------------------------------------ + * This function must be modified to enable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_enable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} + +/*------------------------------------------------------------------------------ + * This function must be modified to disable interrupts generated from the + * CoreI2C instance identified as parameter. + */ +void I2C_disable_irq( i2c_instance_t * this_i2c ) +{ + HAL_ASSERT(0) +} diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSPI/core_spi.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c similarity index 83% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSPI/core_spi.c rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c index 926b758..2e11750 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSPI/core_spi.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSPI/core_spi.c @@ -1,10 +1,17 @@ -/******************************************************************************* - * (c) Copyright 2007-2022 Microchip FPGA Embedded Systems Solutions. +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT * - * @file core_uart_apb.c + * CoreSPI bare metal driver implementation for CoreSPI. + * + * This Core SPI driver provides functions for implementing SPI master or + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. + * + * @file core_spi.c * @author Microchip FPGA Embedded Systems Solutions - * @brief CoreSPI driver implementation. See "core_spi.h" for description of - * the functions implemented in this file. + * @brief CoreSPI software configuration * */ @@ -486,6 +493,206 @@ void SPI_transfer_block } } +/***************************************************************************//** + * SPI_transfer_block_store_all_resp() + * See "core_spi.h" for details of how to use this function. + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +) +{ + uint32_t transfer_size = 0U; /* Total number of bytes to transfer. */ + uint16_t transfer_idx = 0U; /* Number of bytes transferred so far */ + uint16_t tx_idx = 0u; /* Number of valid data bytes sent */ + uint16_t rx_idx = 0u; /* Number of valid response bytes received */ + uint16_t transit = 0U; /* Number of bytes "in flight" to avoid FIFO errors */ + + HAL_ASSERT( NULL_INSTANCE != this_spi ); + + if( NULL_INSTANCE != this_spi ) + { + /* This function is only intended to be used with an SPI master. */ + if( ( DISABLE != HAL_get_8bit_reg_field(this_spi->base_addr, CTRL1_MASTER ) ) && + /* Check for empty transfer as well */ + ( 0u != ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) ) ) + { + /* + * tansfer_size is one less than the real amount as we have to write + * the last frame separately to trigger the slave deselect in case + * the SPS option is in place. + */ + transfer_size = ( (uint32_t)cmd_byte_size + (uint32_t)rx_byte_size ) - 1u; + /* Flush the receive and transmit FIFOs */ + HAL_set_8bit_reg(this_spi->base_addr, CMD, (uint32_t)(CMD_TXFIFORST_MASK | CMD_RXFIFORST_MASK )); + + /* Recover from receiver overflow because of previous slave */ + if( ENABLE == HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXOVFLOW) ) + { + recover_from_rx_overflow( this_spi ); + } + + /* Disable the Core SPI for a little bit, while we load the TX FIFO */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, DISABLE ); + + while( ( tx_idx < transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out 0s to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + } + ++transit; + ++tx_idx; + } + + /* If room left to put last frame in before the off, then do it */ + if( ( tx_idx == transfer_size ) && ( tx_idx < this_spi->fifo_depth ) ) + { + if( tx_idx < cmd_byte_size ) + { + /* Push out valid data, not expecting any reply this time */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + /* Push out last 0 to get data back from slave */ + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + } + + ++transit; + ++tx_idx; + } + + /* FIFO is all loaded up so enable Core SPI to start transfer */ + HAL_set_8bit_reg_field( this_spi->base_addr, CTRL1_ENABLE, ENABLE ); + + /* Perform the remainder of the transfer by sending a byte every time a byte + * has been received. This should ensure that no Rx overflow can happen in + * case of an interrupt occurring during this function. + * + * We break the transfer down into stages to minimise the processing in + * each loop as the SPI interface is very demanding at higher clock rates. + * This works well with FIFOs but might be less efficient if there is only + * a single frame buffer. + * + * First stage transfers remaining command bytes (if any). + * At this stage anything in the RX FIFO can be discarded as it is + * not part of a valid response. + */ + while( tx_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + /* Send another byte. */ + if( tx_idx == transfer_size ) /* Last frame is special... */ + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, (uint32_t)cmd_buffer[tx_idx] ); + } + else + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, (uint32_t)cmd_buffer[tx_idx] ); + } + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now, we are writing dummy bytes to push through the response from + * the slave, which we store in the command response buffer. + */ + while( transfer_idx < cmd_byte_size ) + { + if( transit < this_spi->fifo_depth ) + { + if( tx_idx < transfer_size ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received command byte. */ + cmd_response_buffer[transfer_idx] = HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++transfer_idx; + --transit; + } + } + /* + * Now we are now only sending dummy data to push through the + * valid response data which we store in the data response buffer. + */ + while( tx_idx < transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXDATA, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* If we still need to send the last frame */ + while( tx_idx == transfer_size ) + { + if( transit < this_spi->fifo_depth ) + { + HAL_set_32bit_reg( this_spi->base_addr, TXLAST, 0U ); + ++tx_idx; + ++transit; + } + if( !HAL_get_8bit_reg_field( this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + --transit; + } + } + /* + * Finally, we are now finished sending data and are only reading + * valid response data which we store in the data response buffer. + */ + while( transfer_idx <= transfer_size ) + { + if( !HAL_get_8bit_reg_field(this_spi->base_addr, STATUS_RXEMPTY ) ) + { + /* Process received data byte. */ + rx_data_buffer[rx_idx] = (uint8_t)HAL_get_32bit_reg( this_spi->base_addr, RXDATA ); + ++rx_idx; + ++transfer_idx; + } + } + } + } +} /***************************************************************************//** * SPI_set_frame_rx_handler() * See "core_spi.h" for details of how to use this function. diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSPI/core_spi.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h similarity index 67% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSPI/core_spi.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h index 4ae077e..c6873f7 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSPI/core_spi.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSPI/core_spi.h @@ -1,5 +1,5 @@ -/******************************************************************************* - * (c) Copyright 2007-2022 Microchip FPGA Embedded Systems Solutions. +/***************************************************************************//** + * Copyright 2013-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -21,39 +21,45 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * - * @file core_spi.h - * @author Microchip FPGA Embedded Systems Solutions - * @brief This file contains the application programming interface for the - * CoreSPI bare metal driver. + * Core SPI bare metal software driver public API. * * This Core SPI driver provides functions for implementing SPI master or - * SPI slave operations with the CoreSPI v4.2. It is not compatible with the - * CoreSPI v3.0. + * SPI slave operations with the CoreSPI version 4.2.xxx It is not compatible + * with CoreSPI version 3.0.xxx. * * The Core SPI driver supports two classes of data transfer operation: * SPI frame operation or SPI block transfer operations. * - * Frame operations allow transferring individual SPI frames from 4 to 32 bits + * Frame operations allow transferring individual SPI frames from 4 to 32-bits * in length. Block operations allow transferring blocks of data organized as - * 8 bit frames. + * 8-bit frames. * + * @file core_spi.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief CoreSPI prototypes + * */ + /*=========================================================================*//** @mainpage Core SPI Bare Metal Driver. - @section intro_sec Introduction + ============================================================================== + Introduction + ============================================================================== CoreSPI is an IP component that implements a full-duplex, synchronous, and configurable serial peripheral interface (SPI) with frame sizes from 4 to 32 - bits and bus interface sizes of 8-, 16-, or 32-bit . Each CoreSPI instance - can communicate with up to 8 slave devices. + bits and bus interface sizes of 8-, 16-, or 32-bit. Each CoreSPI instance + communicates with up to eight slave devices. This driver provides a set of functions for controlling CoreSPI as part of the bare metal system where no operating system is available. These drivers can be adapted to be used as a part of an operating system, but the implementation of the adaptation layer between driver and the operating - system's driver model is outside the scope of this User�s Guide. + system's driver model is outside the scope of this User's Guide. - @section driver_configuration Driver Configuration + ============================================================================== + Driver Configuration + ============================================================================== Your application software should configure the CoreSPI driver through calls to the SPI_init() function for each CoreSPI instance in the hardware design. This function configures a default set of parameters that include a CoreSPI @@ -61,36 +67,39 @@ The CoreSPI instance is configured at the time of instantiation in hardware design for APB width, frame size, FIFO depth, serial clock speed, serial - clock polarity, serial clock phase and slave select state parameters. + clock polarity, serial clock phase, and slave select state parameters. - CoreSPI can communicate with up to 8 different slave devices that match - the CoreSPI configuration done at the time of hardware instantiation. + CoreSPI can communicate with up to eight different slave devices that match + the CoreSPI configuration at the time of hardware instantiation. The functions SPI_configure_slave_mode() and SPI_configure_master_mode() are - used to configure the CoreSPI instance as a master or as a slave as required by + used to configure the CoreSPI instance as a master or slave as required by the application. - When CoreSPI wishes to communicate with a specific slave device, the - function SPI_set_slave_select() is called with the slave number as an - argument. This function selects the slave device. A previously selected - slave can be unselected by calling the function SPI_clear_slave_select(). + When CoreSPI wishes to communicate with a specific slave device, call + the SPI_set_slave_select() function with the slave number as an argument. + This function selects the slave device. A previously selected slave gets + unselected by calling the SPI_clear_slave_select() function. - @section theory_op Theory of Operation - The CoreSPI driver functions are grouped into the following categories: - � Initialization - � Configuration for either master or slave operations - � SPI master frame transfer control - � SPI master block transfer control - � SPI slave frame transfer control - � SPI slave block transfer control - Frame transfers allow CoreSPI to write or read up to 32 bits of data in a - single SPI transaction. For example, a frame transfer of 12 bits might be used + ============================================================================== + Theory of Operation + ============================================================================== + The CoreSPI driver functions are grouped into the following categories: + • Initialization + • Configuration for either master or slave operations + • SPI master frame transfer control + • SPI master block transfer control + • SPI slave frame transfer control + • SPI slave block transfer control + + Frame transfers allow CoreSPI to write or read up to 32-bits of data in a + single SPI transaction. For example, a frame transfer of 12-bits might be used to read the result of an ADC conversion from a SPI analog to digital converter. Block transfers allow CoreSPI to write and/or read a number of bytes in a single SPI transaction. With the driver as is, block transfer transactions allow data - transfers in multiples of 8 bits (8, 16, 24, 32, 40�) and the CoreSPI instance - has to be configured for 8 bit frames. For other frame sizes, the + transfers in multiples of 8-bits (8, 16, 24, 32, 40,...) and the CoreSPI instance + has to be configured for 8-bit frames. For other frame sizes, the SPI_transfer_block() code can act as a template for developing a frame block transfer function. Block transfers are typically used with byte oriented devices like SPI @@ -100,7 +109,9 @@ the frame size required by the application; configuration by driver is not possible. + -------------------------------- Initialization + -------------------------------- The CoreSPI driver is initialized through a call to the SPI_init() function. The SPI_init() function takes a pointer to the global CoreSPI instance data structure of type spi_instance_t and the base address of the CoreSPI instance @@ -117,56 +128,64 @@ The SPI_init() function must be called before any other CoreSPI driver functions can be called. + ---------------------------------------------------- Configuration + ---------------------------------------------------- A CoreSPI instance can operate either as a master or as a slave SPI device. There are two distinct functions for configuring a CoreSPI instance for master or slave operations. - Master configuration + ## Master Configuration The SPI_configure_master_mode() function configures the specified CoreSPI - block for operations as a SPI master. This function must be called once - before the CoreSPI block communicates with a SPI slave device. + block for operations as an SPI master. This function must be called once + before the CoreSPI block communicates with an SPI slave device. - Slave configuration + ## Slave Configuration The SPI_configure_slave_mode() function configures the specified CoreSPI block for operations as a SPI slave. This function must be called after - SPI_init() call to configure the CoreSPI instance referred by this_spi - parameter to operate in slave mode. - - SPI master frame transfer control - The following functions are used as a part of the SPI master frame transfers: - � SPI_set_slave_select() - � SPI_transfer_frame() - � SPI_clear_slave_select() - The master must first select the target slave or slaves to be addressed through - a call to SPI_set_slave_select(). This causes the relevant select line(s) to - become asserted while data is clocked out onto the SPI data line. + calling the SPI_init() to configure the CoreSPI instance referred by this_spi + parameter to operate in the slave mode. + + ------------------------------------- + SPI Master Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master frame transfers: + • SPI_set_slave_select() + • SPI_transfer_frame() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves to be addressed by + calling the SPI_set_slave_select() function. This causes the relevant select + line(s) to become asserted while data is clocked out onto the SPI data line. A function call is then made to SPI_transfer_frame() specifying the value of the data frame to be sent and returning the value read. - The function SPI_clear_slave_select() can be used after the transfer is - complete to prevent this slave select line from being asserted during - subsequent SPI transactions. A call to this function is required only if - the master is communicating with multiple slave devices. - - SPI master block transfer control - The following functions are used as a part of the SPI master block transfers: - � SPI_set_slave_select() - � SPI_transfer_block() - � SPI_clear_slave_select() - The master must first select the target slave or slaves through a call to + After the transfer is complete, use the SPI_clear_slave_select() function + to prevent this slave select line from being asserted during subsequent SPI + transactions. A call to this function is required only if the master is + communicating with multiple slave devices. + + ------------------------------------- + SPI Master Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI master block transfers: + • SPI_set_slave_select() + • SPI_transfer_block() + • SPI_clear_slave_select() + + The master must first select the target slave or slaves by calling SPI_set_slave_select(). This causes the relevant slave select line(s) to become asserted while data is clocked out onto the SPI data line. Alternatively, a general purpose input/output (GPIO) can be used to control - the state of the target slave device�s chip select signal. + the state of the target slave device's chip select signal. A call is then made to the SPI_transfer_block() function. The parameters of this function specify the following: - � The number of bytes to be transmitted - � A pointer to the buffer containing the data to be transmitted - � The number of bytes to be received - � A pointer to the buffer where received data will be stored + • The number of bytes to be transmitted + • A pointer to the buffer containing the data to be transmitted + • The number of bytes to be received + • A pointer to the buffer where the received data gets stored The number of bytes to be transmitted can be set to zero to indicate that the transfer is purely a block read transfer. The number of bytes to be received @@ -175,7 +194,7 @@ Block mode transfers as implemented by the driver are effectively half duplex as we do not store the values received from the slave device whilst we are - transmitting. If full duplex operation is required the driver + transmitting. If full duplex operation is required, the driver SPI_transfer_block() function can serve as a starting point for implementing full duplex block transfers. @@ -184,59 +203,63 @@ subsequent SPI transactions. A call to this function is only required if the master is communicating with multiple slave devices. - SPI slave frame transfer control - The following functions are used as a part of the SPI slave frame transfers: - � SPI_set_frame_rx_handler() - � SPI_set_slave_tx_frame() + ------------------------------------- + SPI Slave Frame Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave frame transfers: + • SPI_set_frame_rx_handler() + • SPI_set_slave_tx_frame() The SPI_set_frame_rx_handler() function specifies the receive handler - function that will be called when a frame of data has been received by the + function that is called when a frame of data has been received by the SPI when it is configured as a slave. The receive handler function specified through this call processes the frame data written over the SPI bus to the SPI slave by the remote SPI master. The receive handler function must be implemented as part of the application. It is only required if the SPI slave is the target of SPI frame write transactions. - The SPI_set_slave_tx_frame() function specifies the frame data that will be + The SPI_set_slave_tx_frame() function specifies the frame data that is returned to the SPI master. The frame data specified through this function is the value that will be read over the SPI bus by the remote SPI master, - when it initiates a transaction. A call to SPI_set_slave_tx_frame() is only - required if the SPI slave is the target of SPI read transactions, i.e., if + when it initiates a transaction. Call the SPI_set_slave_tx_frame() function + only if the SPI slave is the target of SPI read transactions. That is, if data is meant to be read over CoreSPI. - If both frame handlers are required, the call to SPI_set_frame_rx_handler() - should be made first otherwise the initial TX frame will be discarded when - SPI_set_frame_rx_handler() clears the FIFOs as part of its initialization. - - SPI slave block transfer control - The following functions are used as a part of the SPI slave block transfers: - � SPI_set_slave_block_buffers() - � SPI_set_cmd_handler() - � SPI_set_cmd_response() + If both frame handlers are required, call the SPI_set_frame_rx_handler() + first, otherwise the initial TX frame gets discarded when SPI_set_frame_rx_handler() + clears the FIFOs as part of its initialization. + + ------------------------------------- + SPI Slave Block Transfer Control + ------------------------------------- + The following functions are used as a part of the SPI slave block transfers: + • SPI_set_slave_block_buffers() + • SPI_set_cmd_handler() + • SPI_set_cmd_response() The SPI_set_slave_block_buffers() function is used to configure an SPI slave for block transfer operations. It specifies the following: - � The buffer containing the data that will be returned to the remote SPI + • The buffer containing the data that will be returned to the remote SPI master - � The buffer where data received from the remote SPI master will be + • The buffer where data received from the remote SPI master will be stored - � The optional handler function that will be called after the receive - buffer is filled. + • The optional handler function that will be called after the receive + buffer is filled The SPI_set_cmd_handler() function specifies a command handler function that - will be called by the driver once a specific number of frames have been - received after the SPI chip select signal becoming active. The number of + is called by the driver once a specific number of frames have been + received after the SPI chip select signal becomes active. The number of bytes making up the command part of the transaction is specified as part of the parameters to the SPI_set_cmd_handler() function. The command handler function is implemented as a part of the application making use of the SPI driver and typically calls the SPI_set_cmd_response() function. - The SPI_set_cmd_response() function specifies the data that will be returned + The SPI_set_cmd_response() function specifies the data that gets returned to the master. Typically, the SPI_set_slave_block_buffers() function is called as a part of the system initialisation to specify the data sent to the master while the command bytes are being received. The transmit buffer - specified though the call to the SPI_set_slave_block_buffers() function - would also typically include one or more bytes allowing the turn around time + specified through calling the SPI_set_slave_block_buffers() function would + also typically include one or more bytes allowing the turn around time for the command handler function to execute and call the SPI_set_cmd_response() function. @@ -249,22 +272,31 @@ #else #include "hal.h" +#include "hal_assert.h" #endif #ifdef __cplusplus extern "C" { #endif -/***************************************************************************//** - These constants define the maximum and minimum FIFO depths allowed for the - CoreSPI instance. User need to inform the driver of the FIFO depth for each - CoreSPI instance to ensure that the FIFOs are managed correctly. +/*-------------------------------------------------------------------------*//** + SPI FIFO Depth + ======================================= + SPI_MAX_FIFO_DEPTH & SPI_MIN_FIFO_DEPTH constants define the maximum and minimum + FIFO depths allowed for the CoreSPI instance. User need to inform the driver of + the FIFO depth for each CoreSPI instance to ensure that the FIFOs are managed correctly. + + | Constant | Description | + |--------------------|----------------------------------------------------| + | SPI_MAX_FIFO_DEPTH | Maximum FIFO depth allowed for the CoreSPI instance| + | SPI_MIN_FIFO_DEPTH | Minimum FIFO depth allowed for the CoreSPI instance| + */ #define SPI_MAX_FIFO_DEPTH 32u #define SPI_MIN_FIFO_DEPTH 1u /***************************************************************************//** - Instances of this structure are used to identify specific CoreSPI hardware + Instances of this structure are used to identify the specific CoreSPI hardware instances. A pointer to an instance of the spi_instance_t structure is passed as the first parameter to the CoreSPI driver functions to identify which SPI performs the requested operation. @@ -273,17 +305,18 @@ typedef struct spi_instance spi_instance_t; /***************************************************************************//** This function pointer type is to assign a callback function for TX interrupt - when slave wants send the next updated frame. + when slave wants to send the next updated frame. - Declaring and Implementing Slave Frame Receive Handler Functions: + Declaring and Implementing Slave Frame Transmit Handler Functions: Slave transmit frame update handler functions should follow the following prototype: - void slave_txframe_update_handler ( spi_instance_t * this_spi ); - The actual name of the receive handler is unimportant. You can use any name + void slave_tx_frame_update_handler ( spi_instance_t * this_spi ); + The actual name of the transmit handler is unimportant. You can use any name of your choice for the frame update handler. - A common handler may be used for more than one slave instance as the particular - slave device currently requiring service is indicated. + A common handler function may be used when multiple CoreSPI instances are + configured as slave, as the particular slave device currently requiring + service is indicated by the function parameter. */ typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); @@ -295,10 +328,10 @@ typedef void (*spi_slave_frame_tx_handler_t)( spi_instance_t * this_spi ); Declaring and Implementing the Slave Frame Receive Handler Functions: The Slave frame receive handler functions should follow the following prototype: - void slave_frame_receive_handler(uint32_t rx_frame); + void slave_frame_receive_handler(uint32_t rx_frame); The actual name of the receive handler is unimportant. You can use any name - of your choice for the receive frame handler. The rx_frame parameter will - contain the value of the received frame. + of your choice for the receive frame handler. The rx_frame parameter contains + the value of the received frame. Separate handler functions are required for each slave instance as there is no indication of the slave requiring service passed to the handler. @@ -311,13 +344,13 @@ typedef void (*spi_frame_rx_handler_t)( uint32_t rx_frame ); block receive handler functions. These functions are registered with the SPI driver through the SPI_set_slave_block_buffers() function. - Declaring and Implementing Slave Block Receive Handler Functions + Declaring and Implementing Slave Block Receive Handler Functions: Slave block receive handler functions should follow the following prototype: - void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); + void spi_block_rx_handler ( uint8_t * rx_buff, uint16_t rx_size ); The actual name of the receive handler is unimportant. You can use any name - of your choice for the receive frame handler. The rx_buff parameter will - contain a pointer to the start of the received block. The rx_size parameter - will contain the number of bytes of the received block. + of your choice for the receive frame handler. The rx_buff parameter contains + a pointer to the start of the received block. The rx_size parameter contains + the number of bytes of the received block. Separate handler functions are required for each slave instance as there is no indication of the slave requiring service passed to the handler. @@ -357,57 +390,54 @@ typedef enum __spi_sxfer_mode_t /***************************************************************************//** There is one instance of this structure for each of the core SPIs. Instances of this structure are used to identify a specific SPI. A pointer to an - instance of the spi_instance_t structure is passed as - the first parameter to SPI driver functions to identify which SPI should - perform the requested operation. - */ + instance of the spi_instance_t structure is passed as the first parameter to + SPI driver functions to identify which SPI should perform the requested operation. + */ struct spi_instance{ - /** Base address in the processor's memory map for the - * registers of the CoreSPI instance being initialized. */ - addr_t base_addr; /*!< Base address of SPI hardware instance. */ + /* Base address in the processor's memory map for the + registers of the CoreSPI instance being initialized */ + addr_t base_addr; /* Base address of SPI hardware instance */ - uint32_t rx_frame; /*!< received data */ + uint32_t rx_frame; /* received data */ /* Internal transmit state: */ - const uint8_t * slave_tx_buffer; /*!< Pointer to slave transmit buffer. */ - uint32_t slave_tx_size; /*!< Size of slave transmit buffer. */ - uint32_t slave_tx_idx; /*!< Current index into slave transmit buffer. */ + const uint8_t * slave_tx_buffer; /* Pointer to slave transmit buffer */ + uint32_t slave_tx_size; /* Size of slave transmit buffer */ + uint32_t slave_tx_idx; /* Current index into slave transmit buffer */ /* Slave command response buffer: */ const uint8_t * resp_tx_buffer; uint32_t resp_buff_size; uint32_t resp_buff_tx_idx; spi_block_rx_handler_t cmd_handler; - uint32_t cmd_done; /*!< Flag which indicates response has been set up and - it is safe to pad with 0s once the response is sent. */ + uint32_t cmd_done; /* Flag which indicates response has been set up and + it is safe to pad with 0s once the response is sent */ /* Internal receive state: */ - uint8_t * slave_rx_buffer; /*!< Pointer to buffer where data received by a slave will be stored. */ - uint32_t slave_rx_size; /*!< Slave receive buffer size. */ - uint32_t slave_rx_idx; /*!< Current index into slave receive buffer. */ - - /** Slave received frame handler: */ - spi_frame_rx_handler_t frame_rx_handler; /*!< Pointer to function that will be called when a frame - is received when the SPI block is configured as slave. */ - /** Slave transmitted frame handler: */ - uint32_t slave_tx_frame; /*!< Value of the data frame that will be transmitted - when the SPI block is configured as slave. */ - spi_slave_frame_tx_handler_t slave_tx_frame_handler; /*!< Callback function pointer to update slave_tx_frame */ + uint8_t * slave_rx_buffer; /* Pointer to buffer where data received by a slave will be stored */ + uint32_t slave_rx_size; /* Slave receive buffer size */ + uint32_t slave_rx_idx; /* Current index into slave receive buffer */ + + /* Slave received frame handler: */ + spi_frame_rx_handler_t frame_rx_handler; /* Pointer to function that will be called when a frame + is received when the SPI block is configured as slave */ + /* Slave transmitted frame handler: */ + uint32_t slave_tx_frame; /* Value of the data frame that will be transmitted + when the SPI block is configured as slave */ + spi_slave_frame_tx_handler_t slave_tx_frame_handler; /* Callback function pointer to update slave_tx_frame */ /* Slave block rx handler: */ - spi_block_rx_handler_t block_rx_handler; /*!< Pointer to the function that will be called when a data block has been received. */ + spi_block_rx_handler_t block_rx_handler; /* Pointer to the function that will be called when a data block has been received */ /* Per instance specific hardware information that the driver needs to know */ - uint16_t fifo_depth; /*!< Depth of RX and TX FIFOs in frames. */ + uint16_t fifo_depth; /* Depth of RX and TX FIFOs in frames */ /* How we are expecting to deal with slave transfers */ - spi_sxfer_mode_t slave_xfer_mode; /*!< Current slave mode transfer configuration. */ + spi_sxfer_mode_t slave_xfer_mode; /* Current slave mode transfer configuration */ }; -/*============================================================================== - * Public functions - *============================================================================*/ +/*------------------------Public Function-------------------------------------*/ /***************************************************************************//** The SPI_init() function initializes the hardware and data structures of a @@ -416,11 +446,11 @@ struct spi_instance{ parameter combination. The SPI_init() function must be called before any other CoreSPI driver functions are called. - After SPI_init() has been called, the CoreSPI will be configured as a master, - all interrupt sources will be masked and all slaves deselected. + After calling the SPI_init() the CoreSPI is configured as a master, + all interrupt sources will be masked and all the slaves are deselected. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to be initialized. This parameter must point to the g_core_spi global data structure defined within the application code. @@ -438,7 +468,7 @@ struct spi_instance{ @return This function does not return any value. - Example: + @example @code #define SPI0_BASE_ADDR 0xC2000000 @@ -458,14 +488,14 @@ void SPI_init to be configured as a SPI slave. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to be configured. This parameter must point to the g_core_spi global data structure defined within the application code. @return This function does not return any value. - Example: + @example @code #define SPI0_BASE_ADDR 0xC2000000 @@ -488,14 +518,14 @@ void SPI_configure_slave_mode to be configured as a SPI master. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to be configured. This parameter must point to a g_core_spi global data structure defined within the application code. @return This function does not return any value. - Example: + @example @code #define SPI0_BASE_ADDR 0xC2000000 @@ -519,7 +549,7 @@ void SPI_configure_master_mode asserted while data is clocked out onto the SPI data line. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to a g_core_spi global data structure defined within the application code. @@ -530,7 +560,7 @@ void SPI_configure_master_mode @return This function does not return any value. - Example: + @example @code #define SPI0_BASE_ADDR 0xC2000000 @@ -558,7 +588,7 @@ void SPI_set_slave_select signal to be de-asserted. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to a g_core_spi global data structure defined within the application code. @@ -569,7 +599,7 @@ void SPI_set_slave_select @return This function does not return any value. - Example: + @example @code #define SPI0_BASE_ADDR 0xC2000000 @@ -598,23 +628,23 @@ void SPI_clear_slave_select are not divisible by 8 or where full duplex exchange of frames is required. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to a g_core_spi global data structure defined within the application code. @param tx_bits The tx_bits parameter is a 32-bit word containing the value that will be - transmitted. If the frame size configured for the CoreSPI in question is - less that 32 bits, the upper bits will be ignored. - Note: The bit length of the value to be transmitted to the slave is + transmitted. If the frame size configured for the CoreSPI is less than 32-bits, + the upper bits will be ignored. + Note: The bit length of the value to be transmitted to the slave is set when the CoreSPI is instantiated in the hardware design. @return This function returns a 32-bit word containing the value that is received from the slave. If the frame size configured for the CoreSPI in question is - less that 32 bits, the upper bits will be 0. + less that 32-bits, the upper bits will be 0. - Example: + @example @code #define SPI0_BASE_ADDR 0xC2000000 @@ -637,44 +667,41 @@ uint32_t SPI_transfer_frame /***************************************************************************//** The SPI_transfer_block() function is used by the SPI master to transmit and - receive blocks of data organized as a specified number of 8 bit frames. It - can be used for the following: - � Writing a data block to a slave - � Reading a data block from a slave - � Sending a command to a slave followed by reading the outcome of - the command in a single SPI transaction. + receive blocks of data organized as a specified number of 8-bit frames. It + can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to a g_core_spi global data structure defined within the application code. @param cmd_buffer - The cmd_buffer parameter is a pointer to the buffer containing the data that - will be sent by the master from the beginning of the transfer. This pointer - can be null (0) if the master does not need to send a command before reading - data. + The cmd_buffer parameter is a pointer to the buffer that contains the data + sent by the master from the beginning of the transfer. This pointer can be + null (0) if the master does not need to send a command before reading data. @param cmd_byte_size - The cmd_byte_size parameter specifies the number of bytes contained in - cmd_buffer that will be sent. A value �0� indicates that no data needs - to be sent to the slave. + The cmd_byte_size parameter specifies the number of bytes in cmd_buffer that + will be sent. A value ‘0’ indicates that no data needs to be sent to the slave. @param rx_buffer - The rx_buffer parameter is a pointer to the buffer where the data received - from the slave after the command has been sent will be stored. This pointer - can be null (0) if the master does not need to receive any data from the - slave. + The rx_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. @param rx_byte_size - The rx_byte_size parameter specifies the number of bytes to be received from - the slave and stored in the rx_buffer. A value �0� indicates that no data is + The rx_byte_size parameter specifies the number of bytes received from + the slave and stored in the rx_buffer. A value ‘0’ indicates that no data is to be read from the slave. @return This function does not return any value. - Example: + @example @code Polled write transfer example #define SPI0_BASE_ADDR 0xC2000000 @@ -704,19 +731,102 @@ uint32_t SPI_transfer_frame void SPI_transfer_block ( spi_instance_t * this_spi, - const uint8_t * tx_buffer, - uint16_t tx_byte_size, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, uint8_t * rx_buffer, uint16_t rx_byte_size ); +/***************************************************************************//** + The SPI_transfer_block_store_all_resp() function is used by the SPI master + to transmit and receive blocks of data organized as a specified number + of 8-bit frames. It can be used for the following: + • Writing a data block to a slave + • Reading a data block from a slave + • Sending a command to a slave followed by reading the outcome of + the command in a single SPI transaction + + @param this_spi + The this_spi parameter is a pointer to a spi_instance_t structure that identifies + the CoreSPI hardware block to operate on. This parameter must point to + a g_core_spi global data structure defined within the application code. + + @param cmd_buffer + The cmd_buffer parameter is a pointer to the buffer that contains the data sent by + the master from the beginning of the transfer. This pointer can be null (0) + if the master does not need to send a command before reading data. + + @param cmd_byte_size + The cmd_byte_size parameter specifies the number of bytes contained in + cmd_buffer that will be sent. A value ‘0’ indicates that no data needs + to be sent to the slave. + + @param rx_data_buffer + The rx_data_buffer parameter is a pointer to the buffer that stores the data received + from the slave after sending the command. This pointer can be null (0) if the + master does not receive any data from the slave. + + @param rx_byte_size + The rx_byte_size parameter specifies the number of bytes received from + the slave and stores in the rx_buffer. A value ‘0’ indicates that no data is + to be read from the slave. + + @param cmd_response_buffer + The cmd_response_buffer parameter is a pointer to the buffer which stores the + command response from the slave, while the master is transmitting the number + of bytes indicated by cmd_byte_size parameter. + + @return + This function does not return any value. + + @example + @code + Polled write transfer example + #define SPI0_BASE_ADDR 0xC2000000 + + spi_instance_t g_spi0 ; + + uint8_t master_tx_buffer[MASTER_TX_BUFFER] = + { + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A + }; + + uint8_t cmd_rx_buffer[CMD_RX_BUFFER]={0}; + + SPI_init( &g_spi0, SPI0_BASE_ADDR, 8 ); + + SPI_configure_master_mode( &g_spi0 ); + + SPI_set_slave_select( &g_spi0, SPI_SLAVE_0) ; + SPI_transfer_block_store_all_resp + ( + &g_spi0, + master_tx_buffer, + sizeof(master_tx_buffer), + 0, + 0, + cmd_response_buffer + ); + SPI_clear_slave_select(&g_spi0, SPI_SLAVE_0 ); + @endcode + */ +void SPI_transfer_block_store_all_resp +( + spi_instance_t * this_spi, + const uint8_t * cmd_buffer, + uint16_t cmd_byte_size, + uint8_t * rx_data_buffer, + uint16_t rx_byte_size, + uint8_t * cmd_response_buffer +); + /***************************************************************************//** The SPI_set_frame_rx_handler() function is used by the SPI slaves to specify - the receive handler function that will be called by the SPI driver interrupt + the receive handler function that is called by the SPI driver interrupt handler when a frame of data is received by the SPI slave. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to a g_core_spi global data structure defined within the application code. @@ -724,12 +834,12 @@ void SPI_transfer_block The rx_handler parameter is a pointer to the frame receive handler that must be called when a frame is received by the CoreSPI slave. Passing in a NULL pointer disables the receive handler but does enable the receive interrupt to - ensure the RX FIFO is emptied each time a frame is received. + ensure the RX FIFO is empty each time a frame is received. @return This function does not return any value. - Example: + @example @code #define SPI0_BASE_ADDR 0xC2000000 @@ -756,24 +866,23 @@ void SPI_set_frame_rx_handler /***************************************************************************//** The SPI_set_slave_tx_frame() function is used by the SPI slaves to specify - the frame that will be transmitted, when a transaction is initiated by - the SPI master. This function allows you to assign a slave_tx_frame_handler - function which will be executed upon transmit interrupt when the SPI is - in slave mode. + the frame that gets transmitted when a transaction is initiated by the SPI + master. This function allows you to assign a slave_tx_frame_handler function, + which will be executed upon transmit interrupt when the SPI is in slave mode. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to a g_core_spi global data structure defined within the application code. @param frame_value The frame_value parameter contains the value of the frame to be sent to the - master. + master. Note: The bit length of the value to be transmitted to the master is set when the CoreSPI is instantiated in the hardware design. @param slave_tx_frame_handler - The slave_tx_frame_handler function pointer will be executed upon occurrence of + The slave_tx_frame_handler function pointer is executed upon occurrence of transmit interrupt when CoreSPI is operating in slave mode. This parameter is optional and if set to NULL it is assumed that the frame value is static or updated asynchronously. @@ -781,7 +890,7 @@ void SPI_set_frame_rx_handler @return This function does not return any value. - Example: + @example @code #define SPI0_BASE_ADDR 0xC2000000 @@ -814,55 +923,55 @@ void SPI_set_slave_tx_frame /***************************************************************************//** The SPI_set_slave_block_buffers() function is used to configure an SPI slave - for block transfer operations. It specifies one or more of the following: - � The data that will be transmitted when accessed by a master. - � The buffer where the data received from a master will be stored. - � The handler function that must be called after the receive buffer has - been filled. - � The number of bytes that must be received from the master before the - receive handler function is called. - These parameters allow the following use cases: - � Slave performing an action after receiving a block of data from a - master containing a command. This action will be performed by the - receive handler based on the content of the receive data buffer. - � Slave returning a block of data to the master. The type of information + for block transfer operations. It specifies one or more of the following: + • The data that is transmitted when accessed by a master. + • The buffer where the data received from a master is stored. + • The handler function that must be called after the receive buffer has + been filled. + • The number of bytes that must be received from the master before calling + the recieve handler function. + These parameters allow the following use cases: + • Slave performing an action after receiving a block of data from a + master containing a command. This action is performed by the + receive handler based on the content of the receive data buffer. + • Slave returning a block of data to the master. The type of information is always the same but the actual values change over time. For example, - returning the voltage of a predefined set of analog inputs. - � Slave returning data based on a command contained in the first part of + returning the voltage of a predefined set of analog inputs. + • Slave returning data based on a command contained in the first part of the SPI transaction. For example, reading the voltage of the analog input specified by the first data byte by the master. This is achieved by using the SPI_set_slave_block_buffers() function in conjunction with - functions SPI_set_cmd_handler() and SPI_set_cmd_response(). + functions SPI_set_cmd_handler() and SPI_set_cmd_response(). - Refer to the SPI_set_cmd_handler() function description for details of + See the SPI_set_cmd_handler() function description for details of this use case. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to a g_core_spi global data structure defined within the application code. @param tx_buffer The tx_buffer parameter is a pointer to a buffer containing the data that - will be sent to the master. This parameter can be set to �0� if the SPI + will be sent to the master. This parameter can be set to ‘0’ if the SPI slave is not intended to be the target of SPI read transactions. @param tx_buff_size - The tx_buff_size parameter specifies the number of bytes that will be + The tx_buff_size parameter specifies the number of bytes that are transmitted by the SPI slave. It is the number of bytes contained in the - tx_buffer. This parameter can be set to �0� if the SPI slave is not + tx_buffer. This parameter can be set to ‘0’ if the SPI slave is not intended to be the target of SPI read transactions. The driver returns 0s to the master if there is no buffer specified or the master reads beyond the - end of the buffer. - Note. If SPI_transfer_block() is used to read from this slave and there - is no command handler involved, the buffer size here must be at least the - combined length of the command and response specified by the master and the - bytes at the start corresponding to the command will be discarded by the - master. + end of the buffer. + Note: If SPI_transfer_block() is used to read from this slave and there is + no command handler involved, the buffer size here must be at least the + combined length of the command and response specified by the master. + On receiving this data, the master discards the data bytes equal to + command length bytes from the start of the received buffer. @param rx_buffer The rx_buffer parameter is a pointer to the buffer where data received - from the master will be stored. This parameter can be set to �0� if the + from the master is stored. This parameter can be set to ‘0’ if the SPI slave is not intended to be the target of SPI write or write-read transactions. @@ -870,20 +979,21 @@ void SPI_set_slave_tx_frame The rx_buff_size parameter specifies the size of the receive buffer. It is also the number of bytes that must be received before the receive handler is called, if a receive handler is specified using the block_rx_handler - parameter. Any bytes received in excess of this are discarded. - This parameter can be set to �0� if the SPI slave is not intended - to be the target of SPI write or write-read transactions. + parameter. Any bytes received in excess of the size specified by the + rx_buff_size parameter are discarded. This parameter can be set to ‘0’ + if the SPI slave is not intended to be the target of SPI write or + write-read transactions. @param block_rx_handler - The block_rx_handler parameter is a pointer to a function that will be called + The block_rx_handler parameter is a pointer to a function that is called when receive buffer has been filled or the slave select has been de-asserted. - This parameter can be set to �0� if the SPI slave is not intended to be the + This parameter can be set to ‘0’ if the SPI slave is not intended to be the target of SPI write or write-read transactions. @return This function does not return any value. - Example: + @example @code Slave Performing Operation Based on Master Command: In this example the SPI slave is configured to receive 10 bytes of data @@ -948,19 +1058,19 @@ void SPI_set_slave_block_buffers abstracts CoreSPI command interrupt and slave mode transmit interrupt handling by calling lower level handler functions specific to each type of CoreSPI interrupt. You must create the lower level handler functions to suit your - application and register them with the driver through calls to the - SPI_set_cmd_handler(), SPI_set_cmd_response() and SPI_set_slave_tx_frame() + application and register them with the driver through calling the + SPI_set_cmd_handler(), SPI_set_cmd_response(), and SPI_set_slave_tx_frame() functions. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to the g_core_spi global data structure defined within the application code. @return This function does not return any value. - Example: + @example @code Example of configuring a CoreInterrupt connected to the Fabric Interrupt on a @@ -1010,17 +1120,17 @@ void SPI_isr /***************************************************************************//** The SPI_set_cmd_handler() function specifies a command handler function that will be called when the number of bytes received reaches the command size - specified as parameter cmd_size. + specified as cmd_size parameter. This function is used by the SPI slaves performing block transfers. Its - purpose is to allow a SPI slave to decide the data that will be returned to - the master while a SPI transaction is taking place. Typically, one or more + purpose is to allow an SPI slave to decide the data that will be returned to + the master while an SPI transaction is taking place. Typically, one or more command bytes are sent by the master to request some specific data. The slave interprets the command byte(s) while one or more turn-around bytes are transmitted. The slave adjusts its transmit data buffer based on the command during the turn around time. - The diagram below provides an example of the use of this function where the + The following table provides an example of the use of this function where the SPI slave returns data bytes D0 to D6 based on the value of a command. The 3 bytes long command is made up of a command opcode byte followed by an address byte followed by a size byte. The cmd_handler() function specified @@ -1034,21 +1144,14 @@ void SPI_isr transport layer so that master and slave agree on the number of turn around bytes. - t0 t1 t2 t3 t4 - | | | | | - |------------------------------------------------------------------| - | COMMAND | TURN-AROUND | DATA | - |------------------------------------------------------------------| - | C | A | S | T0 | T1 | T2 | T3 | D0 | D1 | D2 | D3 | D4 | D5 | D6 | - |------------------------------------------------------------------| - | - | - --> cmd_handler() called here. - | - | - --> SPI_set_cmd_response() called here by - implementation of cmd_handler() to set the data - that will be transmitted by the SPI slave. +|Timestamp| SPI Transaction | Bytes | Comments | +|---------|-------------|----------------------|---------------| +| t0|COMMAND|C A S |C - command opcode byte, A - address byte, S - size byte| +|t1| TURN-AROUND|T0 T1 |cmd_handler() called here (T0 to T3 are TURN-AROUND bytes)| +|t2|TURN-AROUND|T2 T3|SPI_set_cmd_response() called here by implementation of cmd_handler() +|| | |to set the data that will be transmitted by the SPI slave.| +|t3| DATA | D0 D1 D2 D3 D4 D5 D6 |Data transmition (SPI slave return data bytes)| + @param this_spi The this_spi parameter is a pointer to a spi_instance_t structure identifying @@ -1057,19 +1160,19 @@ void SPI_isr @param cmd_handler The cmd_handler parameter is a pointer to a function with the prototype: - void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); + void cmd_handler(uint8_t * rx_buff, uint32_t rx_size); It specifies the function that will be called when the number of bytes - specified by the parameter cmd_size has been received. + specified by the cmd_size parameter has been received. @param cmd_size The cmd_size parameter specifies the number of bytes that must be received - before the command handler function specified by cmd_handler is called. The - CoreSPI supports cmd_size values in the range 1 to 7. + before calling the command handler function specified by the cmd_handler. + The CoreSPI supports cmd_size values in the range 1 to 7. @return This function does not return any value. - Example: + @example @code The following example demonstrates how to configure CoreSPI to implement the protocol given as an example above. The configure_slave() function @@ -1156,17 +1259,17 @@ void SPI_set_cmd_handler to the master. See the description of SPI_set_cmd_handler() for details. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to a g_core_spi global data structure defined within the application code. @param resp_tx_buffer The resp_tx_buffer parameter is a pointer to the buffer containing the data - that must be returned to the host in the data phase of a SPI transaction. + that must be returned to the host in the data phase of an SPI transaction. @param resp_buff_size - The resp_buff_size parameter specifies the size of the buffer pointed to - by the resp_tx_buffer parameter. + The resp_buff_size parameter specifies the size of the buffer pointed by the + resp_tx_buffer parameter. @return This function does not return any value. @@ -1179,13 +1282,13 @@ void SPI_set_cmd_response ); /***************************************************************************//** - The SPI_enable() function enables the CoreSPI and allows it respond to external + The SPI_enable() function enables the CoreSPI and allows it to respond to the external signals. It is usually called to re-enable a CoreSPI instance which has been - disabled previously via a call to SPI_disable() as the normal state of a CoreSPI - after initialization is enabled. + disabled previously via by calling the SPI_disable() as the normal state of a CoreSPI + after enabling the initialization. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to the g_core_spi global data structure defined within the application code. @@ -1198,11 +1301,11 @@ void SPI_enable ); /***************************************************************************//** - The SPI_disable() function disables the CoreSPI and stops it responding to + The SPI_disable() function disables the CoreSPI and stops responding to the external signals. @param this_spi - The this_spi parameter is a pointer to a spi_instance_t structure identifying + The this_spi parameter is a pointer to a spi_instance_t structure that identifies the CoreSPI hardware block to operate on. This parameter must point to the g_core_spi global data structure defined within the application code. diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSPI/corespi_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h similarity index 98% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSPI/corespi_regs.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h index d92fb80..a3e5b2a 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSPI/corespi_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSPI/corespi_regs.h @@ -1,11 +1,14 @@ -/******************************************************************************* - * (c) Copyright 2008-2022 Microchip FPGA Embedded Systems Solutions. - * +/***************************************************************************//** + * Copyright 2011-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * * @file corespi_regs.h * @author Microchip FPGA Embedded Systems Solutions - * @brief CoreSPI register definitions - * + * @brief CoreSPI memory map + * */ + #ifndef CORESPI_REGS_H_ #define CORESPI_REGS_H_ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSysServices_PF/core_sysservices_pf.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c similarity index 91% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSysServices_PF/core_sysservices_pf.c rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c index 82ab53f..b8adaed 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSysServices_PF/core_sysservices_pf.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.c @@ -1,21 +1,16 @@ /******************************************************************************* - * (c) Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT * * PF_System_Services driver implementation. See file "core_syservices_pf.h" for * description of the functions implemented in this file. * */ -#ifndef LEGACY_DIR_STRUCTURE -#include "hal/hal.h" -#include "core_sysservices_pf.h" -#include "coresysservicespf_regs.h" -#else -#include "hal.h" #include "core_sysservices_pf.h" #include "coresysservicespf_regs.h" -#include "hal_assert.h" -#endif +#include #ifdef __cplusplus extern "C" { @@ -416,18 +411,26 @@ uint8_t SYS_secure_nvm_write uint8_t status = SYS_PARAM_ERR; HAL_ASSERT(!(NULL_BUFFER == p_data)); - HAL_ASSERT(!(NULL_BUFFER == p_user_key)); HAL_ASSERT(!(snvm_module >= 221u)); + if (format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + { + HAL_ASSERT(!(NULL_BUFFER == p_user_key)); + } + + if ((p_data == NULL_BUFFER) || (snvm_module >= 221)) + { + return status; + } - if((p_data == NULL_BUFFER) || (p_user_key == NULL_BUFFER) - || (snvm_module >= 221)) + if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) + && (p_user_key == NULL_BUFFER)) { return status; } if ((format != SNVM_NON_AUTHEN_TEXT_REQUEST_CMD) - || (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) - || (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) + && (format != SNVM_AUTHEN_TEXT_REQUEST_CMD) + && (format != SNVM_AUTHEN_CIPHERTEXT_REQUEST_CMD)) { return status; } @@ -681,24 +684,66 @@ uint8_t SYS_digest_check_service uint8_t SYS_iap_service ( uint8_t iap_cmd, - uint32_t spiaddr + uint32_t spiaddr, + uint16_t mb_offset ) { uint8_t status = SYS_PARAM_ERR; - uint32_t l_spiaddr = spiaddr; + uint16_t l_mb_offset = 0u; + uint16_t cmd_data_size = 0u; + uint8_t* cmd_data = NULL_BUFFER; + bool invalid_param = false; - if ((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + if (((IAP_PROGRAM_BY_SPIIDX_CMD == iap_cmd) + || (IAP_VERIFY_BY_SPIIDX_CMD == iap_cmd)) + && (1u == spiaddr)) { - HAL_ASSERT(!(1u == spiaddr)); + invalid_param = true; + HAL_ASSERT(!invalid_param); } - status = execute_ss_command(iap_cmd, - (uint8_t*)&l_spiaddr, - 4u, - NULL_BUFFER, - 0u, - spiaddr, - 0u); + if (!invalid_param) + { + switch(iap_cmd) + { + case IAP_PROGRAM_BY_SPIIDX_CMD: + case IAP_VERIFY_BY_SPIIDX_CMD: + /*In SPI_IDX based program and verify commands, + * Mailbox is not Required. Instead of mailbox offset + * SPI_IDX is passed as parameter.*/ + l_mb_offset = (uint16_t)(0xFFu & spiaddr); + break; + + case IAP_PROGRAM_BY_SPIADDR_CMD: + case IAP_VERIFY_BY_SPIADDR_CMD: + /*In SPI_ADDR based program and verify commands, + * Mailbox is Required*/ + l_mb_offset = mb_offset; + /*command data size is four bytes holding the + * SPI Address in it.*/ + cmd_data_size = 4u; + cmd_data = (uint8_t*)&spiaddr; + break; + + case IAP_AUTOUPDATE_CMD: + /*In auto update command Mailbox is not Required*/ + l_mb_offset = 0u; + break; + + default: + l_mb_offset = 0u; + + } + + status = execute_ss_command( + (uint8_t)iap_cmd, + cmd_data, + cmd_data_size, + NULL_BUFFER, + 0, + (uint16_t)l_mb_offset, + 0); + } return status; } diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSysServices_PF/core_sysservices_pf.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h similarity index 69% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSysServices_PF/core_sysservices_pf.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h index aa1c82b..8e0ebb6 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSysServices_PF/core_sysservices_pf.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSysServices_PF/core_sysservices_pf.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -29,41 +29,43 @@ @section intro_sec Introduction The PolarFire System Services (PF_SYSTEM_SERVICES) SgCore enables executing - system services on the PolarFire and PolarFire SoC device. The System services - are System Controller actions initiated via the System Controller’s System - Service Interface (SSI). The PolarFire System Services SgCore provides a + the system services on the PolarFire and PolarFire SoC device. The system services + are the system controller actions initiated by the System Controller's System + Service Interface (SSI). The PolarFire System Services "SgCore" provides a method to initiate these system services. The PF_SYSTEM_SERVICES interacts with the system controller on SSI and Mailbox interface to initiate system - services, exchange data required for that services and to know the successful + services, exchange data required for that services, and to know the successful completion or error status. The PF_SYSTEM_SERVICES provides an APB interface for controlling the registers functions for controlling the PF_SYSTEM_SERVICES as part of a bare metal system - implemented within it. This software driver provides a set of where no + register implemented within it. This software driver provides a set of where no part of an operating system but the implementation of the adaptation layer - operating system is available. This driver can be adapted for use as + operating system is available. This driver is adapted for use in between this driver and the operating system's driver model is outside the scope of this driver. - Features + ## Features The CoreSysServices_PF driver provides the following features: - - Executing device and design information services. - - Executing design services. + - Executing device and design information services + - Executing design services - Executing data security services - - Executing Fabric services. + - Executing Fabric services The CoreSysServices_PF driver is provided as C source code. @section Driver Configuration - Your application software should configure the CoreSysServices_PF driver, through - call to the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is + The application software should configure the CoreSysServices_PF driver through + calling the SYS_init() function. Only one instance of PF_SYSTEM_SERVICES SgCore is supported. No additional configuration files are required to use the driver. + If using this driver on RT PolarFire device FPGA, define RT_DEVICE_FAMILY + macro in application. @section theory_op Theory of Operation The CoreSysServices_PF driver provides access to the PolarFire system services. These system services are grouped into the following categories: - Device & Design Information Service + Device and Design Information Service - Serial Number Service - USERCODE Service - Design Info Service @@ -73,27 +75,29 @@ - Read Debug Info - Read eNVM param - Design services + Design Services - Bitstream authentication service - IAP bitstream authentication service - Data Security services + Data Security Services - Digital Signature Service - Secure NVM (SNVM) Functions - PUF Emulation Service - Nonce Service - Fabric services + Fabric Services - Digest Check Service - - In Application programming(IAP)/ Auto-Update service + - In Application programming(IAP)/Auto-Update service Initialization and Configuration - The CoreSysServices_PF driver is initialized through a call to the SYS_init() - function. The SYS_init() function must be called before any other - CoreSysServices_PF driver functions is called. - Device and design information services - The CoreSysServices_PF driver can be used to read information about the device + The CoreSysServices_PF driver is initialized by calling the SYS_init() + function. The SYS_init() function must be called before calling any other + CoreSysServices_PF driver functions. + + Device and Design Information Services + + The CoreSysServices_PF driver is used to read information about the device and the design using the following functions: - SYS_get_serial_number() - SYS_get_user_code() @@ -103,14 +107,16 @@ - SYS_query_security() - SYS_read_debug_info() - Design Authentication services - The CoreSysServices_PF driver can be used to execute design services using the + Design Authentication Services + + The CoreSysServices_PF driver is used to execute design services using the following functions: - SYS_bitstream_authenticate_service() - SYS_IAP_image_authenticate_service() - Data security services - The CoreSysServices_PF driver can be used to execute data security services + Data Security Services + + The CoreSysServices_PF driver is used to execute data security services using the following functions: - SYS_digital_signature_service() - SYS_secure_nvm_write() @@ -118,79 +124,88 @@ - SYS_puf_emulation_service () - SYS_nonce_service () - Executing Fabric services - The CoreSysServices_PF driver can be used to execute fabric services using the + Executing Fabric Services + + The CoreSysServices_PF driver is used to execute fabric services using the following functions: - SYS_digest_check_service() - SYS_iap_service() - All the service execution functions return the 8 bit status returned by - system controller on executing the given service. A '0' value indicates + All the service execution functions return the 8-bit status, which is returned + by the system controller on executing the given service. A '0' value indicates successful execution of that service. A non-zero value indicates error. - The error codes for each service are different. Please see individual function + The error codes for each service are different. See individual function description to know the exact meanings of the error codes for each service. - The function descriptions in this file will mainly focus on details required + The function descriptions in this file mainly focus on the details required by the user to use the APIs provided by this driver to execute the services. - To know the complete details of the system services, please refer to the - PolarFire® FPGA and PolarFire SoC FPGA System Services document. Link below: - https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html - + To know the complete details of the system services, see the + PolarFire FPGA and PolarFire SoC FPGA System Services [document](https://onlinedocs.microchip.com/pr/GUID-1409CF11-8EF9-4C24-A94E-70979A688632-en-US-3/index.html) + *//*=========================================================================*/ #ifndef __CORE_SYSSERV_PF_H #define __CORE_SYSSERV_PF_H 1 +#ifndef LEGACY_DIR_STRUCTURE +#include "hal/hal.h" + +#else +#include "hal.h" +#include "hal_assert.h" +#endif + #ifdef __cplusplus extern "C" { #endif /***************************************************************************//** - * Service execution success and error status codes: - * The status codes below are the return values from the system service functions. - * For any service, a return value '0' indicates that the service was executed - * successfully. A non-zero return value indicates that the service was not - * executed successfully. For all the services, the return value represents the - * status code returned by the system controller for the respective service, - * except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT and SS_USER_RDVLD_TIMEOUT. - * These three values indicate the error conditions detected by this driver and - * they do not overlap with the status code returned by the system controller for - * any of the system service. - */ -/* - * SYS_SUCCESS - * System service executed successfully. - * - * SYS_PARAM_ERR - * System service cannot be executed as one or more parameters are not as - * expected by this driver. No read/write access will be performed with the - * IP. - * - * SS_USER_BUSY_TIMEOUT - * The System service request was initiated and the driver timed-out while - * waiting for the system service to complete. The System Service - * completion is indicated by de-assertion of the SS_USER_BUSY bit by the - * IP. - * - * SS_USER_RDVLD_TIMEOUT - * The System service request was initiated and the driver timed-out while - * waiting for SS_USER_RDVLD bit, which indicates availability of data to - * be read from the mailbox, to become active. +* # Service Execution Success and Error Status Codes +* +* The following status codes are the return values from the system service functions. +* For any service, a return value '0' indicates that the service was executed +* successfully. A non-zero return value indicates that the service was not +* executed successfully. For all the services, the return value represents the +* status code returned by the system controller for the respective service, +* except the values SYS_PARAM_ERR, SS_USER_BUSY_TIMEOUT, and SS_USER_RDVLD_TIMEOUT. +* These three values indicate the error conditions detected by this driver and +* they do not overlap with the status code returned by the system controller for +* any of the system service. +* +* SYS_SUCCESS +* System service executed successfully +* +* SYS_PARAM_ERR +* System service cannot be executed as one or more parameters are not as +* expected by this driver. No read/write access is performed with the +* IP. +* +* SS_USER_BUSY_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for the system service to complete. The System Service +* completion is indicated by de-assertion of the SS_USER_BUSY bit by the +* IP. +* +* SS_USER_RDVLD_TIMEOUT +* The System service request is initiated and the driver timed-out while +* waiting for SS_USER_RDVLD bit, which indicates availability of data to +* be read from the mailbox, to become active. */ #define SYS_SUCCESS 0u #define SYS_PARAM_ERR 0xFFu #define SS_USER_BUSY_TIMEOUT 0xFAu #define SS_USER_RDVLD_TIMEOUT 0xFBu -/* - * SS_TIMEOUT_COUNT - * The SS_TIMEOUT_COUNT value will be used by the driver as a timeout count - * while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical - * value is sufficiently large so that the operations will not falsely - * timeout in the normal circumstance. It is provided as a way to provide - * more debug information to the application in case there are some - * unforeseen issues. You may change this value for your need based on your - * system design. - */ +/** +* # System Service Timeout Count +* +* The SS_TIMEOUT_COUNT value is used by the driver as a timeout count +* while waiting for either the SS_USER_BUSY or SS_USER_RDVLD. This empirical +* value is sufficiently large so that the operations are falsely +* timeout in the normal circumstance. It is provided as a way to provide +* more debug information to the application in case there are some +* unforeseen issues. You may change this value for your need based on your +* system design. +*/ #define SS_TIMEOUT_COUNT 40000u /* * SYS_DCF_DEVICE_MISMATCH @@ -217,18 +232,19 @@ extern "C" { #define SYS_NONCE_PUK_FETCH_ERROR 1u #define SYS_NONCE_SEED_GEN_ERROR 2u -/* Secure NVM write error codes +/** + * # Secure Nvm Write Error Codes * - * SNVM_WRITE_INVALID_SNVMADDR + * SNVM_WRITE_INVALID_SNVMADDR * Illegal page address * - * SNVM_WRITE_FAILURE + * SNVM_WRITE_FAILURE * PNVM program/verify failed * - * SNVM_WRITE_SYSTEM_ERROR + * SNVM_WRITE_SYSTEM_ERROR * PUF or storage failure * - * SNVM_WRITE_NOT_PERMITTED + * SNVM_WRITE_NOT_PERMITTED * Write is not permitted */ #define SNVM_WRITE_INVALID_SNVMADDR 1u @@ -236,15 +252,16 @@ extern "C" { #define SNVM_WRITE_SYSTEM_ERROR 3u #define SNVM_WRITE_NOT_PERMITTED 4u -/* Secure NVM read error codes +/** + * # Secure Nvm Read Error Codes * - * SNVM_READ_INVALID_SNVMADDR + * SNVM_READ_INVALID_SNVMADDR * Illegal page address * - * SNVM_READ_AUTHENTICATION_FAILURE + * SNVM_READ_AUTHENTICATION_FAILURE * Storage corrupt or incorrect USK * - * SNVM_READ_SYSTEM_ERROR + * SNVM_READ_SYSTEM_ERROR * PUF or storage failure * */ @@ -252,62 +269,64 @@ extern "C" { #define SNVM_READ_AUTHENTICATION_FAILURE 2u #define SNVM_READ_SYSTEM_ERROR 3u -/* Digital Signature Service error code +/** + * # Digital Signature Service Error Codes * - * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR + * DIGITAL_SIGNATURE_FEK_FAILURE_ERROR * Error retrieving FEK * - * DIGITAL_SIGNATURE_DRBG_ERROR + * DIGITAL_SIGNATURE_DRBG_ERROR * Failed to generate nonce * - * DIGITAL_SIGNATURE_ECDSA_ERROR + * DIGITAL_SIGNATURE_ECDSA_ERROR * ECDSA failed */ #define DIGITAL_SIGNATURE_FEK_FAILURE_ERROR 1u #define DIGITAL_SIGNATURE_DRBG_ERROR 2u #define DIGITAL_SIGNATURE_ECDSA_ERROR 3u -/*Digest Check error code +/** + * # Digest Check Error Codes * - * NOTE: when these error occur, the DIGEST tamper flag is triggered + * NOTE: When these error occur, the DIGEST tamper flag is triggered. * - * DIGEST_CHECK_FABRICERR + * DIGEST_CHECK_FABRICERR * Fabric digest check error * - * DIGEST_CHECK_CCERR + * DIGEST_CHECK_CCERR * UFS Fabric Configuration (CC) segment digest check error * - * DIGEST_CHECK_SNVMERR + * DIGEST_CHECK_SNVMERR * ROM digest in SNVM segment digest check error * - * DIGEST_CHECK_ULERR + * DIGEST_CHECK_ULERR * UFS UL segment digest check error * - * DIGEST_CHECK_UK0ERR + * DIGEST_CHECK_UK0ERR * UKDIGEST0 in User Key segment digest check error * - * DIGEST_CHECK_UK1ERR + * DIGEST_CHECK_UK1ERR * UKDIGEST1 in User Key segment digest check error * - * DIGEST_CHECK_UK2ERR + * DIGEST_CHECK_UK2ERR * UKDIGEST2 in User Key segment (UPK1) digest check error * - * DIGEST_CHECK_UK3ERR + * DIGEST_CHECK_UK3ERR * UKDIGEST3 in User Key segment (UK1) digest check error * - * DIGEST_CHECK_UK4ERR + * DIGEST_CHECK_UK4ERR * UKDIGEST4 in User Key segment (DPK) digest check error * - * DIGEST_CHECK_UK5ERR + * DIGEST_CHECK_UK5ERR * UKDIGEST5 in User Key segment (UPK2) digest check error * - * DIGEST_CHECK_UK6ERR + * DIGEST_CHECK_UK6ERR * UKDIGEST6 in User Key segment (UK2) digest check error * - * DIGEST_CHECK_UPERR + * DIGEST_CHECK_UPERR * UFS Permanent Lock (UPERM) segment digest check error * - * DIGEST_CHECK_SYSERR + * DIGEST_CHECK_SYSERR * M3 ROM, Factory and Factory Key Segments digest check error * */ @@ -325,113 +344,114 @@ extern "C" { #define DIGEST_CHECK_UPERR 0x11u #define DIGEST_CHECK_SYSERR 0x12u -/* bitstream authentication and IAP bitstream authentication Return status +/** + * # Bitstream Authentication and Iap Bitstream Authentication Return Status * - * BSTREAM_AUTH_CHAINING_MISMATCH_ERR + * BSTREAM_AUTH_CHAINING_MISMATCH_ERR * Validator or hash chaining mismatch. Incorrectly constructed bitstream or * wrong key used. * - * BSTREAM_AUTH_UNEXPECTED_DATA_ERR + * BSTREAM_AUTH_UNEXPECTED_DATA_ERR * Unexpected data received. - * Additional data received after end of EOB component + * Additional data received after end of EOB component. * - * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR + * BSTREAM_AUTH_INVALID_ENCRY_KEY_ERR * Invalid/corrupt encryption key. - * The requested key mode is disabled or the key could not be read/reconstructed + * The requested key mode is disabled or the key could not be read/reconstructed. * - * BSTREAM_AUTH_INVALID_HEADER_ERR + * BSTREAM_AUTH_INVALID_HEADER_ERR * Invalid component header * - * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR + * BSTREAM_AUTH_BACK_LEVEL_NOT_SATISFIED_ERR * Back level not satisfied * - * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR + * BSTREAM_AUTH_ILLEGAL_BITSTREAM_MODE_ERR * Illegal bitstream mode. - * Requested bitstream mode is disabled by user security + * Requested bitstream mode is disabled by user security. * - * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR + * BSTREAM_AUTH_DNS_BINDING_MISMATCH_ERR * DSN binding mismatch * - * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR + * BSTREAM_AUTH_ILLEGAL_COMPONENT_SEQUENCE_ERR * Illegal component sequence * - * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR + * BSTREAM_AUTH_INSUFF_DEVICE_CAPAB_ERR * Insufficient device capabilities * - * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR + * BSTREAM_AUTH_INCORRECT_DEVICEID_ERR * Incorrect DEVICEID * - * BSTREAM_AUTH_PROTOCOL_VERSION_ERR + * BSTREAM_AUTH_PROTOCOL_VERSION_ERR * Unsupported bitstream protocol version (regeneration required) * - * BSTREAM_AUTH_VERIFY_ERR + * BSTREAM_AUTH_VERIFY_ERR * Verify not permitted on this bitstream * - * BSTREAM_AUTH_INVALID_DEV_CERT_ERR + * BSTREAM_AUTH_INVALID_DEV_CERT_ERR * Invalid Device Certificate. - * Device SCAC is invalid or not present + * Device SCAC is invalid or not present. * - * BSTREAM_AUTH_INVALID_DIB_ERR + * BSTREAM_AUTH_INVALID_DIB_ERR * Invalid DIB * - * BSTREAM_AUTH_SPI_NOT_MASTER_ERR + * BSTREAM_AUTH_SPI_NOT_MASTER_ERR * Device not in SPI Master Mode. - * Error may occur only when bitstream is executed through IAP mode + * Error may occur only when bitstream is executed through IAP mode. * - * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR + * BSTREAM_AUTH_AUTOIAP_NO_VALID_IMAGE_ERR * No valid images found. * Error may occur when bitstream is executed through Auto Update mode. - * Occurs when No valid image pointers are found. + * Occurs when no valid image pointers are found. * - * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR + * BSTREAM_AUTH_INDEXIAP_NO_VALID_IMAGE_ERR * No valid images found. * Error may occur when bitstream is executed through IAP mode via Index Mode. * Occurs when No valid image pointers are found. * - * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR + * BSTREAM_AUTH_NEWER_DESIGN_VERSION_ERR * Programmed design version is newer than AutoUpdate image found. - * Error may occur when bitstream is executed through Auto Update mode + * Error may occur when bitstream is executed through Auto Update mode. * - * BSTREAM_AUTH_INVALID_IMAGE_ERR + * BSTREAM_AUTH_INVALID_IMAGE_ERR * Selected image was invalid and no recovery was performed due to valid design * in device. * Error may occur only when bitstream is executed through Auto Update or IAP mode * (This error is here for completeness but only can be observed by running the - * READ_DEBUG_INFO instruction and looking at IAP Error code field) + * READ_DEBUG_INFO instruction and looking at IAP Error code field). * - * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR + * BSTREAM_AUTH_IMAGE_PROGRAM_FAILED_ERR * Selected and Recovery image failed to program. * Error may occur only when bitstream is executed through Auto Update or * IAP mode * (This error is here for completeness but only can be observed by running the - * READ_DEBUG_INFO instruction and looking at IAP Error code field) + * READ_DEBUG_INFO instruction and looking at IAP Error code field). * - * BSTREAM_AUTH_ABORT_ERR + * BSTREAM_AUTH_ABORT_ERR * Abort. * Non-bitstream instruction executed during bitstream loading. * - * BSTREAM_AUTH_NVMVERIFY_ERR + * BSTREAM_AUTH_NVMVERIFY_ERR * Fabric/UFS verification failed (min or weak limit) * - * BSTREAM_AUTH_PROTECTED_ERR + * BSTREAM_AUTH_PROTECTED_ERR * Device security prevented modification of non-volatile memory * - * BSTREAM_AUTH_NOTENA + * BSTREAM_AUTH_NOTENA * Programming mode not enabled * - * BSTREAM_AUTH_PNVMVERIFY + * BSTREAM_AUTH_PNVMVERIFY * pNVM verify operation failed * - * BSTREAM_AUTH_SYSTEM + * BSTREAM_AUTH_SYSTEM * System hardware error (PUF or DRBG) * - * BSTREAM_AUTH_BADCOMPONENT + * BSTREAM_AUTH_BADCOMPONENT * An internal error was detected in a component payload * - * BSTREAM_AUTH_HVPROGERR + * BSTREAM_AUTH_HVPROGERR * HV programming subsystem failure (pump failure) * - * BSTREAM_AUTH_HVSTATE + * BSTREAM_AUTH_HVSTATE * HV programming subsystem in unexpected state (internal error) * */ @@ -467,11 +487,11 @@ extern "C" { #define BSTREAM_AUTH_HVSTATE 135 /***************************************************************************//** - * Mailbox ECC status - * Provides ECC status when the mailbox is read. The values are as follows: - * 00: No ECC errors detected, data is correct. - * 01: Exactly one bit error occurred and has been corrected. - * 10: Exactly two bits error occurred and no correction performed. + * # Mailbox ECC Status + * Provides ECC status when the mailbox is read. The values are as follows: + * 00: No ECC errors detected, data is correct. + * 01: Exactly one bit error occurred and has been corrected. + * 10: Exactly two bits error occurred and no correction performed. * 11: Reserved. */ #define SYS_MBOX_ECC_NO_ERROR_MASK 0x00u @@ -539,53 +559,61 @@ extern "C" { #define QUERY_SECURITY_MPFS_RESP_LEN 33u /* SNVM Input data length from sNVM write. */ - +#ifndef RT_DEVICE_FAMILY /* SNVMADDR + RESERVED + PT + USK */ #define NON_AUTHENTICATED_TEXT_DATA_LEN 256u /* SNVMADDR + RESERVED + PT */ #define AUTHENTICATED_TEXT_DATA_LEN 252u +#else +/* SNVMADDR + RESERVED + PT + USK */ +#define NON_AUTHENTICATED_TEXT_DATA_LEN 224u -/* Digest Check Input options +/* SNVMADDR + RESERVED + PT */ +#define AUTHENTICATED_TEXT_DATA_LEN 220u +#endif + +/** + * # Digest Check Input Options * - * DIGEST_CHECK_FABRIC + * DIGEST_CHECK_FABRIC * Carry out digest check on Fabric * - * DIGEST_CHECK_CC + * DIGEST_CHECK_CC * Carry out digest check on UFS Fabric Configuration (CC) segment * - * DIGEST_CHECK_SNVM + * DIGEST_CHECK_SNVM * Carry out digest check on ROM digest in SNVM segment * - * DIGEST_CHECK_UL + * DIGEST_CHECK_UL * Carry out digest check on UFS UL segment * - * DIGEST_CHECK_UKDIGEST0 + * DIGEST_CHECK_UKDIGEST0 * Carry out digest check on UKDIGEST0 in User Key segment * - * DIGEST_CHECK_UKDIGEST1 + * DIGEST_CHECK_UKDIGEST1 * Carry out digest check on UKDIGEST1 in User Key segment * - * DIGEST_CHECK_UKDIGEST2 + * DIGEST_CHECK_UKDIGEST2 * Carry out digest check on UKDIGEST2 in User Key segment (UPK1) * - * DIGEST_CHECK_UKDIGEST3 + * DIGEST_CHECK_UKDIGEST3 * Carry out digest check on UKDIGEST3 in User Key segment (UK1) * - * DIGEST_CHECK_UKDIGEST4 + * DIGEST_CHECK_UKDIGEST4 * Carry out digest check on UKDIGEST4 in User Key segment (DPK) * - * DIGEST_CHECK_UKDIGEST5 + * DIGEST_CHECK_UKDIGEST5 * Carry out digest check on UKDIGEST5 in User Key segment (UPK2) * - * DIGEST_CHECK_UKDIGEST6 + * DIGEST_CHECK_UKDIGEST6 * Carry out digest check on UKDIGEST6 in User Key segment (UK2) * - * DIGEST_CHECK_UPERM + * DIGEST_CHECK_UPERM * Carry out digest check on UFS Permanent lock (UPERM) segment * - * DIGEST_CHECK_SYS - * Carry out digest check on Factory and Factory Key Segments. + * DIGEST_CHECK_SYS + * Carry out digest check on Factory and Factory Key Segments * */ #define DIGEST_CHECK_FABRIC (0x01<<0x00u) /*Fabric digest*/ @@ -622,14 +650,14 @@ SYS_init * service. * * @param p_serial_number The p_serial_number parameter is a pointer to a buffer - * in which the data returned by system controller will - * be copied. + * in which the data returned by system controller + * is copied. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * * @return This function returns the status code returned by the @@ -647,14 +675,14 @@ SYS_get_serial_number * The function SYS_get_user_code() is used to execute "USERCODE" system * service. * @param p_user_code The p_user_code parameter is a pointer to a buffer - * in which the data returned by system controller will be + * in which the data returned by system controller is * copied. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * * @return This function returns the status code returned by the @@ -673,17 +701,17 @@ SYS_get_user_code * service. * * @param p_design_info The p_design_info parameter is a pointer to a buffer - * in which the data returned by system controller will be + * in which the data returned by system controller is * copied. Total size of debug information is 36 bytes. * The data from the system controller includes the 256-bit - * user-defined design ID, 16-bit design version and 16-bit + * user-defined design ID, 16-bit design version, and 16-bit * design back level. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * * @return This function returns the status code returned by the @@ -703,13 +731,13 @@ SYS_get_design_info * * @param p_device_certificate The p_device_certificate parameter is a pointer * to a buffer in which the data returned by the - * system controller will be copied. + * system controller is copied. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * * @return This function returns the status code returned by the @@ -728,14 +756,14 @@ SYS_get_device_certificate * The function SYS_read_digest() is used to execute "Read Digest" system service. * * @param p_digest The p_digest parameter is a pointer to a buffer - * in which the data returned by system controller will be + * in which the data returned by system controller is * copied. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * * @return This function returns the status code returned by the @@ -753,14 +781,13 @@ uint8_t SYS_read_digest * service. * * @param p_security_locks The p_security_locks parameter is a pointer to a buffer - * in which the data returned by system controller will - * be copied. + * in which the data returned by system controller is copied. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * * @return This function returns the status code returned by the @@ -778,14 +805,14 @@ uint8_t SYS_query_security * service. * * @param p_debug_info The p_debug_info parameter is a pointer to a buffer - * in which the data returned by system controller will be + * in which the data returned by system controller is * copied. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * * @return This function returns the status code returned by the @@ -800,25 +827,25 @@ uint8_t SYS_read_debug_info #ifdef CORESYSSERVICES_PFSOC /***************************************************************************//** - * The function SYS_read_envm_param() is used to retrieve all parameters needed - * for eNVM operation and programming. + * The function SYS_read_envm_parameter() is used to retrieve all parameters needed + * for the eNVM operation and programming. * * NOTE: This service is available only on PolarFire SoC Platform. * This service is not yet supported by PF_SYSTEM_SERVICES 3.0.100. * * @param p_envm_param The p_envm_param parameter is a pointer to a buffer - * in which the data returned by system controller will be copied. - * This buffer will store all the eNVM parameters. + * in which the data returned by system controller is copied. + * This buffer stores all the eNVM parameters. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * - * @return The SYS_read_envm_param service will return zero if the - * service executed successfully otherwise it will return + * @return The SYS_read_envm_parameter service will return zero if the + * service executed successfully, otherwise, it will return * one indicating error. */ uint8_t SYS_read_envm_parameter @@ -828,33 +855,31 @@ uint8_t SYS_read_envm_parameter ); #endif /***************************************************************************//** - * The function SYS_puf_emulation_service() is used to authenticating a device. + * The function SYS_puf_emulation_service() is used to authenticate a device. * * The SYS_puf_emulation_service() function accept a challenge comprising a * 8-bit optype and 128-bit challenge and return a 256-bit response unique to * the given challenge and the device. * * @param p_challenge The p_challenge parameter specifies the 128-bit challenge - * to be used to generate the unique 256-bits unique - * response. + * to generate the 256-bits unique response. * * @param op_type The op_type parameter specifies the operational parameter - * to be used to generate the unique 256-bits unique - * response. + * to generate the 256-bits unique response. * - * @param p_response The p_response parameter is a pointer to a buffer in - * which the data returned i.e. response by system controller will - * be copied. + * @param p_response The p_response parameter is a pointer to a buffer where + * the data returned which is the response by system controller + * is copied. * - * @param mb_offset The mb_offset parameter specifies the offset from - * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service - * starts from 11th word (offset 10) in the Mailbox. + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. * * @return The SYS_puf_emulation_service function will return zero - * if the service executed successfully otherwise it will + * if the service executed successfully, otherwise, it will * return one indicating error. */ uint8_t SYS_puf_emulation_service @@ -870,7 +895,7 @@ uint8_t SYS_puf_emulation_service * signature based on SHA384 hash value. * * @param p_hash The p_hash parameter is a pointer to the buffer which - * contain the 48 bytes SHA384 Hash value(input value). + * contain the 48 bytes SHA384 Hash value (input value). * * @param format The format parameter specifies the output format of * generated SIGNATURE field. The different types of output @@ -878,20 +903,20 @@ uint8_t SYS_puf_emulation_service * - DIGITAL_SIGNATURE_RAW_FORMAT * - DIGITAL_SIGNATURE_DER_FORMAT * - * @param p_response The p_response parameter is a pointer to a buffer which - * contain the generated ECDSA signature. The field may be + * @param p_response The p_response parameter is a pointer to a buffer that + * contains the generated ECDSA signature. The field may be * 96 bytes or 104 bytes depending upon the output format. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * - * @return The SYS_digital_signature_service function will return - * zero if the service executed successfully otherwise - * non-zero values indicating error. + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. */ uint8_t SYS_digital_signature_service ( @@ -902,18 +927,18 @@ uint8_t SYS_digital_signature_service ); /***************************************************************************//** - * The SYS_secure_nvm_write() function is used to provide write access/write the - * data in the sNVM region. Data can be stored in the following format: - * Non-authenticated plaintext, - * Authenticated plaintext - * Authenticated ciphertext + * The SYS_secure_nvm_write() function writes data in the sNVM region. + * Data gets stored in the following format: + * - Non-authenticated plaintext + * - Authenticated plaintext + * - Authenticated ciphertext * * Note: If you are executing this function with Authenticated plaintext * or Authenticated ciphertext on a device whose sNVM was never previously * written to, then the service may fail. For it to work, you must first write * Authenticated data to the sNVM using Libero along with USK client and - * custom security. This flow generates the SMK. Refer UG0753 PolarFire FPGA - * security User Guide for further details. + * custom security. This flow generates the SMK. See UG0753 PolarFire FPGA + * Security User Guide for further details. * @param format The format parameter specifies the format used to write * data in sNVM region. The different type of text formats @@ -927,27 +952,27 @@ uint8_t SYS_digital_signature_service * * @param p_data The p_data parameter is a pointer to a buffer which * contains the data to be stored in sNVM region. The data - * length to be written is if fixed depending on the format + * length to be written is fixed depending on the format * parameter. If NON_AUTHENTICATED_PLAINTEXT_FORMAT is - * selected then you can write 252 bytes in the sNVM module. + * selected, then you can write 252 bytes in the sNVM module. * For other two formats the data length is 236 bytes. * * @param p_user_key The p_user_key parameter is a pointer to a buffer which * contain the 96-bit key USK (user secret key). This user * secret key will enhance the security when authentication - * is used.(i.e. When Authenticated plaintext and - * Authenticated ciphertext format is selected). + * is used. That is, when Authenticated plaintext and + * Authenticated ciphertext format is selected. * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * - * @return The SYS_secure_nvm_write function will return - * zero if the service executed successfully otherwise - * non-zero values indicating error. + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. */ uint8_t SYS_secure_nvm_write ( @@ -963,12 +988,12 @@ uint8_t SYS_secure_nvm_write * User should provide USK key, if the data was programmed using authentication. * If the data was written in the sNVM using the authenticated plaintext or the * authenticated ciphertext service option then this service will return the - * valid data only when authentication is successful. Please also refer the - * SYS_secure_nvm_write() function for more details. If the data was written in + * valid data only when authentication is successful. For more details, see + * SYS_secure_nvm_write() function. If the data was written in * the sNVM using the authenticated plaintext or the authenticated ciphertext * service option then this service will return the valid data only when - * authentication is successful. Please also refer the SYS_secure_nvm_write() - * function and its parameter description for more details. + * authentication is successful. For more details, see SYS_secure_nvm_write() + * function and its parameter description. * * @param snvm_module The snvm_module parameter specifies the sNVM module * from which the data need to be read. @@ -979,7 +1004,7 @@ uint8_t SYS_secure_nvm_write * authentication while writing data in sNVM region. * * @param p_admin The p_admin parameter is a pointer to the buffer where - * the output page admin data will be stored. The page admin + * the output page admin data is stored. The page admin * data is 4 bytes long. * * @param p_data The p_data parameter is a pointer to a buffer which @@ -996,14 +1021,14 @@ uint8_t SYS_secure_nvm_write * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * - * @return The SYS_secure_nvm_read function will return - * zero if the service executed successfully otherwise - * non-zero values indicating error. + * @return The SYS_digital_signature_service function returns + * zero if the service executed successfully, otherwise, it + * returns non-zero values indicating error. */ uint8_t SYS_secure_nvm_read ( @@ -1020,19 +1045,19 @@ uint8_t SYS_secure_nvm_read * service to the system controller. * * @param p_nonce The p_nonce parameter is a pointer to a buffer - * in which the data returned by system controller will be copied. + * in which the data returned by system controller is copied. * - * @param mb_offset The mb_offset parameter specifies the offset from - * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service - * starts from 11th word (offset 10) in the Mailbox. + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. * * @return This function returns the status code returned by the * system controller for this service. A '0' status code means * that the service was executed successfully and a non-zero - * value indicates error. Please refer to the document link + * value indicates error. See the document link * provided in the theory of operation section to know more * about the service and service response. */ @@ -1057,15 +1082,15 @@ uint8_t SYS_nonce_service * * @param mb_offset The mb_offset parameter specifies the offset from * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service * starts from 11th word (offset 10) in the Mailbox. * * @return The SYS_bitstream_authenticate_service function will return - * zero if the service executed successfully the non-zero - * response from system controller indicates error. Please - * refer to the document link provided in the theory of + * zero if the service executed successfully and the non-zero + * response from system controller indicates error. See + * the document link provided in the theory of * operation section to know more about the service and service * response. */ @@ -1086,11 +1111,10 @@ uint8_t SYS_bitstream_authenticate_service * * @param spi_idx * The spi_idx parameter specifies the index in the SPI directory to - * be used where the IAP bit-stream is stored. - * + * be used where the IAP bit-stream is stored. * Note: To support recovery SPI_IDX=1 should be an empty slot and the recovery * image should be located in SPI_IDX=0. Since SPI_IDX=1 should be an - * empty slot it shouldn’t be passed into the system service. + * empty slot, it shouldn’t be passed into the system service. * * @return The SYS_IAP_image_authenticate_service function will return * zero if the service executed successfully the non-zero @@ -1108,45 +1132,42 @@ uint8_t SYS_IAP_image_authenticate_service * The SYS_digest_check_service() function is used to Recalculates and compares * digests of selected non-volatile memories. If the fabric digest is to be * checked, then the user design must follow all prerequisite steps for the - * FlashFreeze service before invoking this service. - * + * FlashFreeze service before invoking this service. * This service is applicable to bitstreams stored in SPI Flash memory only. - * * @param options * The options parameter specifies the digest check options which * indicate the area on which the digest check should be performed. * Below is the list of options. You can OR these options to indicate - * to perform digest check on multiple segments. - * - * Note: The options parameter will be of 2 bytes when used with PF - * device and 4 bytes when used with PolarFire SoC device. - * - * Options[i] Description - * 0x01 Fabric digest - * 0x02 Fabric Configuration (CC) segment - * 0x04 ROM digest in SNVM segment - * 0x08 UL segment - * 0x10 UKDIGEST0 in User Key segment - * 0x20 UKDIGEST1 in User Key segment - * 0x40 UKDIGEST2 in User Key segment (UPK1) - * 0x80 UKDIGEST3 in User Key segment (UK1) - * 0x100 UKDIGEST4 in User Key segment (DPK) - * 0x200 UKDIGEST5 in User Key segment (UPK2) - * 0x400 UKDIGEST6 in User Key segment (UK2) - * 0x800 UFS Permanent lock (UPERM) segment - * 0x1000 Factory and Factory Key Segments. - * 0x2000 UKDIGEST7 in User Key segment (HWM) (PFSoC) - * 0x4000 ENVMDIGEST (PFSoC only) - * 0x8000 UKDIGEST8 for MSS Boot Info (PFSoC only) - * 0x10000 SNVM_RW_ACCESS_MAP Digest (PFSoC only) - * 0x20000 SBIC revocation digest (PFSoC only) + * to perform digest check on multiple segments. + * Note: The options parameter is of 2 bytes when used with PF + * device and 4 bytes when used with PolarFire SoC device. + * Options[i] | Description + * ---------------|---------------------------------- + * 0x01 | Fabric digest + * 0x02 | Fabric Configuration (CC) segment + * 0x04 | ROM digest in SNVM segment + * 0x08 | UL segment + * 0x10 | UKDIGEST0 in User Key segment + * 0x20 | UKDIGEST1 in User Key segment + * 0x40 | UKDIGEST2 in User Key segment (UPK1) + * 0x80 | UKDIGEST3 in User Key segment (UK1) + * 0x100 | UKDIGEST4 in User Key segment (DPK) + * 0x200 | UKDIGEST5 in User Key segment (UPK2) + * 0x400 | UKDIGEST6 in User Key segment (UK2) + * 0x800 | UFS Permanent lock (UPERM) segment + * 0x1000 | Factory and Factory Key Segments. + * 0x2000 | UKDIGEST7 in User Key segment (HWM) (PFSoC) + * 0x4000 | ENVMDIGEST (PFSoC only) + * 0x8000 | UKDIGEST8 for MSS Boot Info (PFSoC only) + * 0x10000 | SNVM_RW_ACCESS_MAP Digest (PFSoC only) + * 0x20000 | SBIC revocation digest (PFSoC only) * - * @param mb_offset The mb_offset parameter specifies the offset from - * the start of Mailbox where the data related to this service - * will be available. Note that all accesses to the mailbox - * are of word length(4 bytes). A Value '10' of this parameter - * would mean that the data access area for this service - * starts from 11th word (offset 10) in the Mailbox. + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. * * @return The SYS_digest_check_service function will return * zero if the service executed successfully the non-zero @@ -1162,8 +1183,8 @@ uint8_t SYS_digest_check_service ); /***************************************************************************//** - * The SYS_iap_service() function is used to IAP service. The IAP service allows t - * he user to reprogram the device without the need for an external master. The + * The SYS_iap_service() function is used to IAP service. The IAP service allows + * the user to reprogram the device without the need for an external master. The * user design writes the bitstream to be programmed into a SPI Flash connected * to the SPI port. When the service is invoked, the System Controller * automatically reads the bitstream from the SPI flash and programs the device. @@ -1175,28 +1196,33 @@ uint8_t SYS_digest_check_service * @param iap_cmd * The iap_cmd parameter specifies the specific IAP command which * depends upon VERIFY or PROGRAM modes and the SPI address method. - * - * iap_cmd Description - * IAP_PROGRAM_BY_SPIIDX_CMD IAP program. - * IAP_VERIFY_BY_SPIIDX_CMD Fabric Configuration (CC) segment - * IAP_PROGRAM_BY_SPIADDR_CMD ROM digest in SNVM segment - * IAP_VERIFY_BY_SPIADDR_CMD UL segment - * IAP_AUTOUPDATE_CMD UKDIGEST0 in User Key segment + * iap_cmd | Description + * -----------------------|------------ + * IAP_PROGRAM_BY_SPIIDX_CMD | IAP program. + * IAP_VERIFY_BY_SPIIDX_CMD | Fabric Configuration (CC) segment + * IAP_PROGRAM_BY_SPIADDR_CMD | ROM digest in SNVM segment + * IAP_VERIFY_BY_SPIADDR_CMD | UL segment + * IAP_AUTOUPDATE_CMD | UKDIGEST0 in User Key segment * * @param spiaddr - * The spiaddr parameter specifies the either the either the index + * The spiaddr parameter specifies either the index * in the SPI directory or the SPI address in the SPI Flash memory. * Below is the list of the possible meaning of spiaddr parameter * in accordance with the iap_cmd parameter. + * iap_cmd | spiaddr + * ----------------------|----------------- + * IAP_PROGRAM_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_VERIFY_BY_SPIIDX_CMD | Index in the SPI directory. + * IAP_PROGRAM_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_VERIFY_BY_SPIADDR_CMD | SPI address in the SPI Flash memory + * IAP_AUTOUPDATE_CMD | spiaddr is ignored as No index/address required for this command. * - * iap_cmd spiaddr - * IAP_PROGRAM_BY_SPIIDX_CMD Index in the SPI directory. - * IAP_VERIFY_BY_SPIIDX_CMD Index in the SPI directory. - * IAP_PROGRAM_BY_SPIADDR_CMD SPI address in the SPI Flash memory - * IAP_VERIFY_BY_SPIADDR_CMD SPI address in the SPI Flash memory - * IAP_AUTOUPDATE_CMD spiaddr is ignored as No index/address - * required for this command. - * + * @param mb_offset The mb_offset parameter specifies the offset from + * the start of Mailbox where the data related to this service + * is available. Note that all accesses to the mailbox + * are of word length (4 bytes). Value '10' of this parameter + * means that the data access area for this service + * starts from 11th word (offset 10) in the Mailbox. * Note: For the IAP services with command IAP_PROGRAM_BY_SPIIDX_CMD and * IAP_VERIFY_BY_SPIIDX_CMD To support recovery SPI_IDX=1 should be an * empty slot and the recovery image should be located in SPI_IDX=0. @@ -1212,7 +1238,8 @@ uint8_t SYS_digest_check_service uint8_t SYS_iap_service ( uint8_t iap_cmd, - uint32_t spiaddr + uint32_t spiaddr, + uint16_t mb_offset ); #ifdef __cplusplus diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSysServices_PF/coresysservicespf_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h similarity index 97% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSysServices_PF/coresysservicespf_regs.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h index c978968..8b14b7e 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreSysServices_PF/coresysservicespf_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreSysServices_PF/coresysservicespf_regs.h @@ -1,5 +1,7 @@ /******************************************************************************* - * (c) Copyright 2019-2021 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT * * Register bit offsets and masks definitions for CoreSysServices_PF driver. */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreUARTapb/core_uart_apb.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c similarity index 98% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreUARTapb/core_uart_apb.c rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c index 2b2087a..0c0a866 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreUARTapb/core_uart_apb.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.c @@ -1,6 +1,8 @@ /******************************************************************************* - * (c) Copyright 2007-2021 Microchip FPGA Embedded Systems Solutions. + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. * + * SPDX-License-Identifier: MIT + * * @file core_uart_apb.c * @author Microchip FPGA Embedded Systems Solutions * @brief CoreUARTapb driver implementation. See file "core_uart_apb.h" for diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreUARTapb/core_uart_apb.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h similarity index 50% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreUARTapb/core_uart_apb.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h index 2ce0b88..c016403 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreUARTapb/core_uart_apb.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreUARTapb/core_uart_apb.h @@ -1,5 +1,5 @@ /******************************************************************************* - * (c) Copyright 2007-2021 Microchip FPGA Embedded Systems Solutions. + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -32,72 +32,70 @@ @section intro_sec Introduction CoreUARTapb is an implementation of the Universal Asynchronous - Receiver/Transmitter aimed at a minimal FPGA tile usage within an Microsemi - FPGA. The CoreUARTapb bare metal software driver is designed for use in - systems with no operating system. + Receiver/Transmitter aimed at minimal FPGA tile usage within a Microchip FPGA. + The CoreUARTapb bare metal software driver is designed to be used in systems + with no operating system. The CoreUARTapb driver provides functions for basic polled transmitting and - receiving operations. It also provides functions allowing use of the - CoreUARTapb in interrupt-driven mode, but leaves the management of interrupts - to the calling application, as interrupt enabling and disabling cannot be + receiving operations. It also provide functions that allow the use of the + CoreUARTapb in interrupt-driven mode but leaves the management of interrupts + to the calling application, as interrupt enabling and disabling are not controlled through the CoreUARTapb registers. The CoreUARTapb driver is provided as C source code. @section driver_configuration Driver Configuration - Your application software should configure the CoreUARTapb driver, through - calls to the UART_init() function for each CoreUARTapb instance in the - hardware design. The configuration parameters include the CoreUARTapb - hardware instance base address and other runtime parameters, such as baud - rate, bit width, and parity. No CoreUARTapb hardware configuration parameters - are needed by the driver, apart from the CoreUARTapb hardware instance base - address. Hence, no additional configuration files are required to use the driver. + Your application software should configure the CoreUARTapb driver by calling + the UART_init() function for each CoreUARTapb instance in the hardware design. + The configuration parameters include the CoreUARTapb hardware instance base + address and other runtime parameters, such as baud rate, bit width, and + parity. No CoreUARTapb hardware configuration parameters are needed by the + driver, apart from the CoreUARTapb hardware instance base address. Hence, no + additional configuration files are required to use the driver. - A CoreUARTapb hardware instance can be generated with fixed baud value, - character size and parity configuration settings as part of the hardware flow. - The baud_value and line_config parameter values passed to the UART_init() - function will not have any effect if fixed values were selected for the - baud value, character size and parity in the hardware configuration of - CoreUARTapb. When fixed values are selected for these hardware configuration - parameters, the driver cannot overwrite the fixed values in the CoreUARTapb - control registers, CTRL1 and CTRL2. + A CoreUARTapb hardware instance is generated with fixed baud rate, character + size, and parity configuration settings as part of the hardware flow. The + baud_value and line_config parameter values passed to the UART_init() function + have no effect if fixed values were selected for the baud rate, character + size, and parity in the hardware configuration of CoreUARTapb. When fixed + values are selected for these hardware configuration parameters, the driver is + unable to overwrite the fixed values in the CoreUARTapb control registers, + CTRL1 and CTRL2. @section theory_op Theory of Operation The CoreUARTapb software driver is designed to allow the control of multiple instances of CoreUARTapb. Each instance of CoreUARTapb in the hardware design is associated with a single instance of the UART_instance_t structure in the - software. You need to allocate memory for one unique UART_instance_t - structure instance for each CoreUARTapb hardware instance. The contents of - these data structures are initialized during calls to function UART_init(). - A pointer to the structure is passed to subsequent driver functions in order - to identify the CoreUARTapb hardware instance you wish to perform the - requested operation on. + software. You need to allocate memory for one unique UART_instance_t structure + instance for each CoreUARTapb hardware instance. The contents of these data + structures are initialized while calling the UART_init() function. A pointer + to the structure is passed to the subsequent driver functions in order to + identify the CoreUARTapb hardware instance you wish to perform the requested + operation on. Note: Do not attempt to directly manipulate the content of UART_instance_t structures. This structure is only intended to be modified by the driver function. - The driver can be used to transmit and receive data once initialized. - Transmit can be performed using the UART_send() function. This function - is blocking, meaning that it will only return once the data passed to - the function has been sent to the CoreUARTapb hardware. Data received - by the CoreUARTapb hardware can be read by the user application using - the UART_get_rx() function. + Once initialized, the driver transmits and receives data. Transmit is + performed using the UART_send() function. If this function blocks, then it + returns only when the data passed to it has been sent to the CoreUARTapb + hardware. Data received by the CoreUARTapb hardware is read by the user + application using the UART_get_rx() function. - The function UART_fill_tx_fifo() is also provided to be used as part of + The UART_fill_tx_fifo() function is also provided as a part of the interrupt-driven transmit. This function fills the CoreUARTapb hardware transmit FIFO with the content of a data buffer passed as a parameter before returning. The control of the interrupts must be implemented outside the - driver as the CoreUARTapb hardware does not provide the ability to enable + driver, as the CoreUARTapb hardware does not provide the ability to enable or disable its interrupt sources. - The function UART_polled_tx_string() is provided to transmit a NULL - 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 - CoreUARTapb hardware. + The UART_polled_tx_string() function is provided to transmit a NULL-terminated + string in polled mode. If this function blocks, then it returns only when the + data passed to it has been sent to the CoreUARTapb hardware. - The function UART_get_rx_status() returns the error status of the CoreUARTapb - receiver. This can be used by applications to take appropriate action in case - of receiver errors. + The UART_get_rx_status() function returns the error status of the CoreUARTapb + receiver. This is used by applications to take appropriate action in case of + receiver errors. *//*=========================================================================*/ #ifndef __CORE_UART_APB_H #define __CORE_UART_APB_H 1 @@ -114,20 +112,43 @@ extern "C" { #endif /***************************************************************************//** - * Data bits length defines: + Data Bits Length Defines + ======================== + These constants define the data length in a UART packet. + | Constant | Description | + |-------------|---------------------------------------| + | DATA_7_BITS | Data length is 7-bits | + | DATA_8_BITS | Data length is 8-bits | */ #define DATA_7_BITS 0x00u #define DATA_8_BITS 0x01u /***************************************************************************//** - * Parity defines: + Parity Defines + ============== + These constants define parity check options. + | Constant | Description | + |-------------|---------------------------------------| + | NO_PARITY | No Parity bit | + | EVEN_PARITY | Even Parity bit | + | ODD_PARITY | ODD Parity bit | */ #define NO_PARITY 0x00u #define EVEN_PARITY 0x02u #define ODD_PARITY 0x06u /***************************************************************************//** - * Error Status definitions: + Error Status Definitions + ======================== + These constants define the different types of possible errors in UART + transmission of data. + | Constant | Description | + |-------------------------|---------------------------------------| + | UART_APB_PARITY_ERROR | Data parity error | + | UART_APB_OVERFLOW_ERROR | Data overflow error | + | UART_APB_FRAMING_ERROR | Data framing error | + | UART_APB_NO_ERROR | No error | + | UART_APB_INVALID_PARAM | Invalid parameter | */ #define UART_APB_PARITY_ERROR 0x01u #define UART_APB_OVERFLOW_ERROR 0x02u @@ -135,54 +156,50 @@ extern "C" { #define UART_APB_NO_ERROR 0x00u #define UART_APB_INVALID_PARAM 0xFFu -/***************************************************************************//** - * UART_instance_t - * - * There should be one instance of this structure for each instance of CoreUARTapb - * in your system. This structure instance is used to identify the various UARTs - * in a system and should be passed as first parameter to UART functions to - * identify which UART should perform the requested operation. The 'status' - * element in the structure is used to provide sticky status information. +/***************************************************************************//** + * There should be one instance of this structure for each instance of + * CoreUARTapb in your system. This structure instance identifies various UARTs + * in a system and should be passed as first parameter to UART functions to + * identify which UART performs the requested operation. The 'status' element in + * the structure is used to provide sticky status information. */ -typedef struct +typedef struct { addr_t base_address; uint8_t status; } UART_instance_t; /***************************************************************************//** - * The function UART_init() initializes the UART with the configuration passed - * as parameters. The configuration parameters are the baud_value used to - * generate the baud rate and the line configuration (bit length and parity). + * The UART_init() function initializes the UART with the configuration passed + * as parameters. The configuration parameters are the baud_value that generates + * the baud rate and the line configuration (bit length and parity). * - * @param this_uart The this_uart parameter is a pointer to a UART_instance_t - * structure which holds all data regarding this instance of - * the CoreUARTapb. This pointer will be used to identify - * the target CoreUARTapb hardware instance in subsequent - * calls to the CoreUARTapb functions. + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data regarding + * this instance of the CoreUARTapb. This pointer is used to + * identify the target CoreUARTapb hardware instance in + * subsequent calls to the CoreUARTapb functions. * @param base_addr The base_address parameter is the base address in the * processor's memory map for the registers of the * CoreUARTapb instance being initialized. - * @param baud_value The baud_value parameter is used to select the baud rate - * for the UART. The baud value is calculated from the - * frequency of the system clock in hertz and the desired - * baud rate using the following equation: - * - * baud_value = (clock /(baud_rate * 16)) - 1. - * + * @param baud_value The baud_value parameter selects the baud rate for the + * UART. The baud value is calculated from the frequency of + * the system clock in hertz and the desired baud rate using + * the following equation: + * baud_value = (clock / (baud_rate * 16)) - 1. * The baud_value parameter must be a value in the range 0 * to 8191 (or 0x0000 to 0x1FFF). - * @param line_config This parameter is the line configuration specifying the - * bit length and parity settings. This is a logical OR of: - * - DATA_7_BITS - * - DATA_8_BITS - * - NO_PARITY - * - EVEN_PARITY - * - ODD_PARITY + * @param line_config This parameter is the line configuration, specifies the + * bit length and parity settings. This is the logical OR of: + * - DATA_7_BITS + * - DATA_8_BITS + * - NO_PARITY + * - EVEN_PARITY + * - ODD_PARITY * For example, 8 bits even parity would be specified as * (DATA_8_BITS | EVEN_PARITY). * @return This function does not return a value. - * Example: + * @example * @code * #define BAUD_VALUE_57600 25 * @@ -206,28 +223,28 @@ UART_init ); /***************************************************************************//** - * The function UART_send() is used to transmit data. It transfers the contents + * The UART_send() function is used to transmit data. It transfers the content * 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 * transmitter data buffer has been transferred to the UART's transmitter FIFO. * - * Note: you cannot assume that the data you are sending using this function has - * been received at the other end by the time this function returns. The actual - * transmit over the serial connection will still be taking place at the time of - * the function return. It is safe to release or reuse the memory used as the - * transmit buffer once this function returns. + * Note: You should not assume that the data you are sending using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. It is safe to release or reuse the memory + * used as the transmit buffer once this function returns. * - * @param this_uart The this_uart parameter is a pointer to a - * UART_instance_t structure which holds all data regarding - * this instance of the CoreUARTapbUART. - * @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. + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the CoreUARTapbUART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. * * @return This function does not return a value. * - * Example: + * @example * @code * uint8_t testmsg1[] = {"\n\r\n\r\n\rUART_send() test message 1"}; * UART_send(&g_uart,(const uint8_t *)&testmsg1,sizeof(testmsg1)); @@ -242,7 +259,7 @@ UART_send ); /***************************************************************************//** - * The function UART_fill_tx_fifo() fills the UART's transmitter hardware FIFO + * The UART_fill_tx_fifo() function fills the UART's transmitter hardware FIFO * with the data found in the transmitter buffer that is passed in as a * function parameter. The function returns either when the FIFO is full or * when the complete contents of the transmitter buffer have been copied into @@ -250,22 +267,22 @@ UART_send * hardware FIFO. This function is intended to be used as part of * interrupt-driven transmission. * - * Note: You cannot assume that the data you transmit using this function has - * been received at the other end by the time this function returns. - * The actual transmission over the serial connection will still be - * taking place at the time of the function return. + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. * - * @param this_uart The this_uart parameter is a pointer to a UART_instance_t - * structure which holds all data regarding this instance of - * the UART. - * @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 hardware FIFO. + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param tx_buffer The tx_buffer parameter is a pointer to a buffer that + * contains the data to be transmitted. + * @param tx_size The tx_size parameter is the size in bytes of the + * transmitted data. + * @return This function returns the number of bytes copied into + * the UART's transmitter hardware FIFO. * - * Example: + * @example * @code * void send_using_interrupt * ( @@ -287,40 +304,41 @@ UART_fill_tx_fifo ); /***************************************************************************//** - * The function UART_get_rx() reads the content of the UART's receiver hardware + * The UART_get_rx() function reads the content of the UART's receiver hardware * FIFO and stores it in the receiver buffer that is passed in as a function * parameter. It copies either the full contents of the FIFO into the receiver * buffer, or just enough data from the FIFO to fill the receiver buffer, - * dependent upon the size of the receiver buffer. The size of the receiver + * depending on the size of the receiver buffer. The size of the receiver * buffer is passed in as a function parameter. UART_get_rx() returns the number * of bytes copied into the receiver buffer. If no data was received at the time * the function is called, the function returns 0. * - * Note: This function reads and accumulates the receiver status of the - * CoreUARTapb 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 UART_get_rx_status() - * function returns any receiver errors accumulated during the execution - * of the UART_get_rx() function. - * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, - * the driver accumulates a sticky record of any parity errors, framing - * errors or overflow errors. When FIFO mode is enabled, the driver - * accumulates a sticky record of overflow errors only; in this case - * interrupts must be used to handle parity errors or framing errors. + * Note: This function reads and accumulates the receiver status of the + * CoreUARTapb 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 UART_get_rx_status() + * function returns any receiver errors accumulated during the execution + * of the UART_get_rx() function. + * + * Note: When FIFO mode is disabled in the CoreUARTapb hardware configuration, + * the driver accumulates a sticky record of any parity errors, framing + * errors, or overflow errors. When FIFO mode is enabled, the driver + * accumulates a sticky record of overflow errors only; in this case, + * interrupts must be used to handle parity errors or framing errors. * - * @param this_uart The this_uart parameter is a pointer to a UART_instance_t - * structure which holds all data regarding this instance of - * the UART. - * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where the - * received data will be copied. - * @param buff_size The buff_size parameter is the size of the receive buffer - * in bytes. - * @return This function returns the number of bytes copied into the - * receive buffer. + * @param this_uart The this_uart parameter is a pointer to the + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. + * @param rx_buffer The rx_buffer parameter is a pointer to a buffer where + * the received data is copied. + * @param buff_size The buff_size parameter is the size of the receive + * buffer in bytes. + * @return This function returns the number of bytes copied into + * the receive buffer. * - * Example: + * @example * @code * #define MAX_RX_DATA_SIZE 256 * @@ -339,27 +357,27 @@ UART_get_rx ); /***************************************************************************//** - * The function UART_polled_tx_string() is used to transmit a NULL ('\0') + * The UART_polled_tx_string() function is used to transmit a NULL ('\0') * terminated string. Internally, it polls for the transmit ready status and - * transfers the text starting at the address pointed to by p_sz_string into + * transfers the text starting at the address pointed by p_sz_string into * the UART's hardware transmitter FIFO. It is a blocking function and returns * only when the complete string has been transferred to the UART's transmit * FIFO. * - * Note: You cannot assume that the data you transmit using this function - * has been received at the other end by the time this function - * returns. The actual transmission over the serial connection will - * still be taking place at the time of the function return. + * Note: You should not assume that the data you transmit using this function + * has been received at the other end by the time this function returns. The + * actual transmission over the serial connection is still be taking place at + * the time of the function return. * - * @param this_uart The this_uart parameter is a pointer to a - * UART_instance_t structure which holds - * all data regarding this instance of the UART. + * @param this_uart The this_uart parameter is the pointer to a + * UART_instance_t structure, which holds all data + * regarding this instance of the UART. * @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: + * @example * @code * uint8_t testmsg1[] = {"\r\n\r\nUART_polled_tx_string() test message 1\0"}; * UART_polled_tx_string(&g_uart,(const uint8_t *)&testmsg1); @@ -377,36 +395,37 @@ UART_polled_tx_string * CoreUARTapb instance. It reads both the current error status of the receiver * and the accumulated error status from preceding calls to the UART_get_rx() * function and combines them using a bitwise OR. It returns the cumulative - * parity, framing and overflow error status of the receiver, since the - * previous call to UART_get_rx_status(), as an 8-bit encoded value. + * parity, framing, and overflow error status of the receiver, since the + * previous call to UART_get_rx_status() as an 8-bit encoded value. * - * Note: The UART_get_rx() function reads and accumulates the receiver status - * of the CoreUARTapb instance before reading each byte from the - * receiver's data register/FIFO. The driver maintains a sticky record - * of the cumulative error status, which persists after the - * UART_get_rx() function returns. The UART_get_rx_status() function - * clears this accumulated record of receiver errors before returning. + * Note: The UART_get_rx() function reads and accumulates the receiver status + * of the CoreUARTapb instance before reading each byte from the receiver's data + * register/FIFO. The driver maintains a sticky record of the cumulative error + * status, which persists after the UART_get_rx() function returns. The + * UART_get_rx_status() function clears this accumulated record of receiver + * errors before returning. * - * @param this_uart The this_uart parameter is a pointer to a UART_instance_t - * structure which holds all data regarding this instance - * of the UART. - * @return This function returns the UART receiver error status as - * an 8-bit encoded value. The returned value is 0 if no - * receiver errors occurred. The driver provides a set of - * bit mask constants which should be compared with and/or - * used to mask the returned value to determine the - * receiver error status. + * @param this_uart The this_uart parameter is a pointer to a + * UART_instance_t structure which holds all data regarding + * this instance of the UART. + * @return This function returns the UART receiver error status as + * an 8-bit encoded value. The return value is 0, if there + * are no receiver errors occurred. The driver provides a + * set of bit mask constants, which 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: - * UART_APB_PARITY_ERROR (bit mask = 0x01) - * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) - * UART_APB_FRAMING_ERROR (bit mask = 0x04) + * corresponding error occurred: + * UART_APB_PARITY_ERROR (bit mask = 0x01) + * UART_APB_OVERFLOW_ERROR (bit mask = 0x02) + * UART_APB_FRAMING_ERROR (bit mask = 0x04) * When the return value is compared to the following bit - * mask, a non-zero result indicates that no error occurred: + * mask, a non-zero result indicates that no error + * occurred: * UART_APB_NO_ERROR (0x00) * - * Example: + * @example * @code * UART_instance_t g_uart; * uint8_t rx_data[MAX_RX_DATA_SIZE]; diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreUARTapb/coreuartapb_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h similarity index 95% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreUARTapb/coreuartapb_regs.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h index 8651f0c..c123cc3 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/CoreUARTapb/coreuartapb_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/CoreUARTapb/coreuartapb_regs.h @@ -1,7 +1,9 @@ /******************************************************************************* - * (c) Copyright 2007-2021 Microchip FPGA Embedded Systems Solutions. - * - * @file coreuartapb_regs.h + * (c) Copyright 2007-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file coreuartapb_regs.h * @author Microchip FPGA Embedded Systems Solutions * @brief CoreUARTapb register definitions */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/miv_i2c.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c similarity index 98% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/miv_i2c.c rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c index a2115c9..a2f4911 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/miv_i2c.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.c @@ -10,13 +10,6 @@ #include "miv_i2c.h" -#ifdef __cplusplus -extern "C" { -#endif - -void MIV_I2C_enable_irq(void); -void MIV_I2C_disable_irq(void); - #define MIV_I2C_ERROR 0xFFu /*------------------------------------------------------------------------------ @@ -39,6 +32,24 @@ void MIV_I2C_disable_irq(void); #define MIV_I2C_TX_DATA 0x02u #define MIV_I2C_RX_DATA 0x03u +/*-------------------------------------------------------------------------*//** + The MIV_I2C_disable_irq() disables the Mi-V I2C interrupt. + */ +void +MIV_I2C_disable_irq +( + void +); + +/*-------------------------------------------------------------------------*//** + The MIV_I2C_enable_irq() enables the Mi-V I2C interrupt. + */ +void +MIV_I2C_enable_irq +( + void +); + /* * Please refer to miv_i2c.h for more info */ @@ -752,7 +763,3 @@ MIV_I2C_get_status return i2c_status; } - -#ifdef __cplusplus -} -#endif diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/miv_i2c.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h similarity index 99% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/miv_i2c.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h index 688a16c..c5e704d 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/miv_i2c.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c.h @@ -178,7 +178,7 @@ extern "C" { #endif -#include "mivi2c_regs.h" +#include "miv_i2c_regs.h" #include #ifndef LEGACY_DIR_STRUCTURE @@ -847,4 +847,8 @@ MIV_I2C_get_status miv_i2c_instance_t *this_i2c ); +#ifdef __cplusplus +} +#endif + #endif /* MIV_I2C_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/miv_i2c_interrupt.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c similarity index 100% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/miv_i2c_interrupt.c rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_interrupt.c diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/mivi2c_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h similarity index 99% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/mivi2c_regs.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h index ee6770a..9a4bfbf 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_i2c/mivi2c_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_i2c/miv_i2c_regs.h @@ -150,5 +150,9 @@ extern "C" { #define STAT_RXACK_MASK 0x80u #define STAT_RXACK_SHIFT 7u + +#ifdef __cplusplus +} +#endif #endif /* MIV_I2C_APB_REGISTERS */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_plic/miv_plic.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c similarity index 99% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_plic/miv_plic.c rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c index 7eb9637..903f029 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_plic/miv_plic.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_plic/miv_plic.c @@ -10,10 +10,6 @@ #include "miv_plic.h" -#ifdef __cplusplus -extern "C" { -#endif - /***************************************************************************//** * Mi-V PLIC interrupt handler function declaration. * These functions are called by the external interrupt handler of the MIV_RV32 diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_plic/miv_plic.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h similarity index 99% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_plic/miv_plic.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h index 3e893c3..f5d64cd 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_plic/miv_plic.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_plic/miv_plic.h @@ -100,6 +100,14 @@ interrupt 1 will be serviced first, followed by interrupt 6. */ + +#ifndef MIV_PLIC_H_ +#define MIV_PLIC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + #include #include "miv_plic_regs.h" @@ -409,3 +417,9 @@ MIV_PLIC_disable_irq HAL_set_32bit_reg((this_plic->base_addr + (IRQn/32) + (hart_id * 128)), INT_ENABLE, current); } + +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_plic/miv_plic_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h similarity index 82% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_plic/miv_plic_regs.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h index d2fc15f..76cbc0b 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_plic/miv_plic_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_plic/miv_plic_regs.h @@ -5,11 +5,11 @@ * * This file contains Register bit offsets and masks definitions for MI-V Soft * IP PLIC module driver. This module is delivered as a part of Mi-V extended - * Sub-System(ESS). + * Sub-System(MIV_ESS). */ -#ifndef ESS_PLIC_REGISTERS -#define ESS_PLIC_REGISTERS 1 +#ifndef MIV_PLIC_REGISTERS +#define MIV_PLIC_REGISTERS 1 #ifdef __cplusplus extern "C" { @@ -24,4 +24,8 @@ extern "C" { /* Interrupt claim complete register */ #define INT_CLAIM_COMPLETE_REG_OFFSET 0x200004u -#endif /* ESS_PLIC_REGISTERS */ +#ifdef __cplusplus +} +#endif + +#endif /* MIV_PLIC_REGISTERS */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_timer/miv_timer.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h similarity index 89% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_timer/miv_timer.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h index 66e8f24..5f00889 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_timer/miv_timer.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_timer/miv_timer.h @@ -121,11 +121,9 @@ extern "C" { #ifndef LEGACY_DIR_STRUCTURE #include "hal/hal.h" -#include "miv_rv32_hal/miv_rv32_hal.h" #else #include "hal.h" -#include "miv_rv32_hal.h" #endif /*-------------------------------------------------------------------------*//** MIV_TIMER_SUCCESS @@ -146,12 +144,12 @@ configuring the Mi-V Timer module. #define MIV_TIMER_ERROR 1u /*-------------------------------------------------------------------------*//* -MASK_32BIT +MIV_TIMER_MASK_32BIT ===================== 32-bit mask constant used in calculation of 64-bit register value. */ -#define MASK_32BIT 0xFFFFFFFFu +#define MIV_TIMER_MASK_32BIT 0xFFFFFFFFu /*-------------------------------------------------------------------------*//* Mi-V Timer register offsets @@ -160,29 +158,29 @@ The MTIMECMP is the 64-bit timer compare register, it pre-sets the threshold which needs to be reached by the timer count register. This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits and higher 32-bits. - - MTIMECMP_L_REG_OFFSET - - MTIMECMP_H_REG_OFFSET + - MIV_TIMER_MTIMECMP_L_REG_OFFSET + - MIV_TIMER_MTIMECMP_H_REG_OFFSET The MTIME is the 64-bit register that contains the 64-bit timer count. The count increments by 1 every time the prescaler ticks. This 64-bit register is accessed with 2 32-bit address offset, lower 32-bits and higher 32-bits. - - MTIME_L_REG_OFFSET - - MTIME_H_REG_OFFSET + - MIV_TIMER_MTIME_L_REG_OFFSET + - MIV_TIMER_MTIME_H_REG_OFFSET The PRESCALE register is used to determine the amount of clock cycles the selected clock needs to go through, for MTIME register to increment count. - - PRESCALAR_REG_OFFSET + - MIV_TIMER_PRESCALAR_REG_OFFSET */ /// @cond private -#define MTIMECMP_L_REG_OFFSET 0x4000u -#define MTIMECMP_H_REG_OFFSET 0x4004u +#define MIV_TIMER_MTIMECMP_L_REG_OFFSET 0x4000u +#define MIV_TIMER_MTIMECMP_H_REG_OFFSET 0x4004u -#define MTIME_L_REG_OFFSET 0xBFF8u -#define MTIME_H_REG_OFFSET 0xBFFCu +#define MIV_TIMER_MTIME_L_REG_OFFSET 0xBFF8u +#define MIV_TIMER_MTIME_H_REG_OFFSET 0xBFFCu -#define PRESCALAR_REG_OFFSET 0x5000u +#define MIV_TIMER_PRESCALAR_REG_OFFSET 0x5000u /// @endcond /*-------------------------------------------------------------------------*//** @@ -241,10 +239,10 @@ MIV_TIMER_read_current_time /* when mtime lower word is 0xFFFFFFFF, there will be rollover and * returned value could be wrong. */ do { - mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MTIME_H); - mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MTIME_L); + mtime_hi = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H); + mtime_lo = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_L); - } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MTIME_H)); + } while(mtime_hi != HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIME_H)); read_data = mtime_hi; @@ -272,13 +270,13 @@ MIV_TIMER_write_compare_time uint64_t compare_reg_value ) { - HAL_set_32bit_reg(this_timer->base_addr, MTIMECMP_H, MASK_32BIT); + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, MIV_TIMER_MASK_32BIT); - HAL_set_32bit_reg(this_timer->base_addr, MTIMECMP_L, - (compare_reg_value & MASK_32BIT)); + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_L, + (compare_reg_value & MIV_TIMER_MASK_32BIT)); - HAL_set_32bit_reg(this_timer->base_addr, MTIMECMP_H, - ((compare_reg_value >> 32u) & MASK_32BIT)); + HAL_set_32bit_reg(this_timer->base_addr, MIV_TIMER_MTIMECMP_H, + ((compare_reg_value >> 32u) & MIV_TIMER_MASK_32BIT)); } /** The MIV_TIMER_config() is used to configure the MIV_ESS Timer module. The @@ -308,7 +306,7 @@ MIV_TIMER_config uint32_t prescalar = 0u; uint64_t miv_timer_increment = 0U; - prescalar = HAL_get_32bit_reg(this_timer->base_addr, PRESCALAR); + prescalar = HAL_get_32bit_reg(this_timer->base_addr, MIV_TIMER_PRESCALAR); miv_timer_increment = (uint64_t)(ticks) / prescalar; @@ -323,5 +321,9 @@ MIV_TIMER_config return ret_val; } + +#ifdef __cplusplus +} +#endif #endif /* MIV_TIMER_H */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_udma/miv_udma.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c similarity index 96% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_udma/miv_udma.c rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c index d57f2ae..cbd9652 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_udma/miv_udma.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_udma/miv_udma.c @@ -1,5 +1,7 @@ /******************************************************************************* - * (c) Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * (c) Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT * * Mi-V uDMA Soft IP bare-metal driver. This module is delivered as part of * Mi-V Extended Sub System(MIV_ESS) diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_udma/miv_udma.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h similarity index 57% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_udma/miv_udma.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h index e3ad5da..efa8731 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_udma/miv_udma.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_udma/miv_udma.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2022 Microchip FPGA Embedded Systems Solutions. + * Copyright 2022-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -32,11 +32,11 @@ @section intro_sec Introduction The Mi-V uDMA driver provides a set of functions to control the Mi-V uDMA - module in the Mi-V Extended Sub System(MIV_ESS) soft-IP. The Mi-V uDMA module + module in the Mi-V Extended Subsystem (MIV_ESS) soft-IP. The Mi-V uDMA module allows peripherals with AHB interfaces to transfer data independently of the MIV_RV32 RISC-V processor. - The major features provided by the Mi-V uDMA driver are: + Following are the major features provided by the Mi-V uDMA driver: - Initialization and configuration - Start and reset the transaction @@ -48,61 +48,63 @@ @section hw_dependencies Hardware Flow Dependency The application software should initialize and configure the Mi-V uDMA through - the call to MIV_uDMA_init(), MIV_uDMA_config() function for Mi-V uDMA - instance in the design. - The μDMA can operate in two possible transfer configurations: + calling the MIV_uDMA_init() and MIV_uDMA_config() functions for each Mi-V + uDMA instance in the design. + + The uDMA can operate in two possible transfer configurations: - AHBL Read –> AHBL Write: - In this configuration, the μDMA reads data from the source memory over an - AHBL (Mirrored Main/Initiator) read interface and writes data to the - destination memory over an AHBL (Mirrored Main/Initiator) write interface. + - AHBL Read -> AHBL Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over an AHBL (mirrored main/initiator) write interface. - AHBL Read –> TAS Write: - In this configuration, the μDMA reads data from the source memory over an - AHBL (Mirrored Main/Initiator) read interface and writes data to the - destination memory over the TAS (Mirrored Main/Initiator) write interface. + - AHBL Read -> TAS Write: + In this configuration, the uDMA reads data from the source memory over an + AHBL (mirrored main/initiator) read interface and writes data to the + destination memory over the TAS (mirrored main/initiator) write interface. - The AHBL Read -> TAS Write configuration is out of scope for this driver. + Note: The AHBL Read -> TAS Write configuration is out of scope for this + driver. @section theory_op Theory of Operation - The uDMA module in the Mi-V Extended Sub System(MIV_ESS) is a single channel - uDMA module that allows peripherals to perform read write operations between - source and destination memory. The Mi-V uDMA driver is generally used in - interrupt driven mode and uses the Mi-V uDMA IRQ signal to drive the - interrupt service routine(ISR) which signifies a transfer has completed. + The uDMA module in the Mi-V Extended Sub System (MIV_ESS) is a single-channel + uDMA module that allows peripherals to perform read-write operations between + source and destination memory. The Mi-V uDMA driver is used in + interrupt-driven mode and uses the Mi-V uDMA IRQ signal to drive the + interrupt service routine (ISR), which signifies a transfer has completed. The status is checked in the ISR to ensure the transfer is completed - successfully. - The reset operation in the ISR will reset the Mi-V uDMA controller. - Once the Mi-V uDMA transfer completes, Mi-V uDMA retires. To - initiate another transaction, Mi-V uDMA will have to be configured again. + successfully. + The reset operation in the ISR resets the Mi-V uDMA controller. Once the Mi-V + uDMA transfer is complete, Mi-V uDMA retires. To initiate another + transaction, Mi-V uDMA needs to be configured again. - The operation of the Mi-V uDMA driver can be divided into following + The operation of the Mi-V uDMA driver is divided into the following categories: - Initialization - Configuration - - Start and reset transfer + - Start and reset the transfer - ### Initialization and configuration - Mi-V uDMA is first initialized by a call to MIV_uDMA_init(). This function - initializes the instance of Mi-V uDMA with base address. The MIV_uDMA_init() - function must be called before calling any other Mi-V uDMA driver functions. + Initialization and configuration: + Mi-V uDMA is first initialized by calling MIV_uDMA_init() function. This + function initializes the instance of Mi-V uDMA with the base address. The + MIV_uDMA_init() function must be called before calling any other Mi-V uDMA + driver functions. - The Mi-V uDMA is configured by a call to MIV_uDMA_config(). This function - will configure the source_addr and dest_addr registers of the Mi-V uDMA with - source and destination addresses for Mi-V uDMA transfers. + The Mi-V uDMA is configured by calling MIV_uDMA_config() function. This + function configures the source_addr and dest_addr registers of the Mi-V + uDMA with source and destination addresses for Mi-V uDMA transfers. This function also configures the transfer size and interrupt preference for - successful transfer of Mi-V uDMA. - - ### Start and Reset transfer - Once the Mi-V uDMA is configured, the transfers can be started with a call to - MIV_uDMA_start(). Once the Mi-V uDMA transfer is started, it can not be - aborted and the status of the transfer should be read from the ISR by a call - to MIV_uDMA_read_status(). - - The Mi-V uDMA can be reset to the default state by calling MIV_uDMA_reset() - function. After performing reset operation, the Mi-V uDMA should be - re-configured to perform transfer since MIV_uDMA_reset() resets the Mi-V uDMA - controller. + successful transfers using Mi-V uDMA. + + Start and reset the transfer: + Once the Mi-V uDMA is configured, initiate the transfers by calling the + MIV_uDMA_start() function. Once the Mi-V uDMA transfer is started, it cannot + be aborted, and the status of the transfer should be read from the ISR by + calling the MIV_uDMA_read_status() function. + + Reset the Mi-V uDMA to the default state by calling the MIV_uDMA_reset() + function. After performing the reset operation, reconfigure the Mi-V uDMA to + perform transfers as MIV_uDMA_reset() resets the Mi-V uDMA controller. */ #ifndef MIV_uDMA_H_ @@ -149,9 +151,8 @@ extern "C" { #define MIV_uDMA_STATUS_ERROR 2u /***************************************************************************//** - * Mi-V uDMA instant structure. - * This structure will hold the base of Mi-V uDMA module which is used in the - * other functions in the driver to access the uDMA registers. + * This structure holds the base of the Mi-V uDMA module, which is used in the + * other functions of the driver to access the uDMA registers. */ typedef struct miv_udma_instance { @@ -159,9 +160,10 @@ typedef struct miv_udma_instance } miv_udma_instance_t; /***************************************************************************//** - * The MIV_uDMA_init() assigns the base address of Mi-V uDMA module to the - * uDMA instance structure. - * This address is used in later part of the driver to access the uDMA registers. + * The MIV_uDMA_init() function assigns the base address of the Mi-V uDMA module + * to the uDMA instance structure. + * This address is used in a later part of the driver to access the uDMA + * registers. * * @param this_udma * This parameter is a pointer to the miv_udma_instance_t structure. @@ -180,34 +182,32 @@ MIV_uDMA_init ); /***************************************************************************//** - * The MIV_uDMA_config() is used to configure the Mi-V uDMA controller. - * This function will set the source address, destination address, block size - * and IRQ config register. + * The MIV_uDMA_config() function is used to configure the Mi-V uDMA controller. + * This function will set the source address, destination address, block size, + * and IRQ configuration register. * * @param this_udma - * This parameter is a pointer to the miv_udma_instance_t structure which - * holds the base address of Mi-V uDMA module. + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. * * @param base_addr - * Base address of the Mi-V uDMA + * Base address of the Mi-V uDMA. * * @param src_addr - * Source address of memory from which the uDMA will read the data. + * Source address of memory from where the uDMA reads the data. * * @param dest_addr - * Destination address where the data will be written from src_addr. + * Destination address where the data is written from src_addr. * * @param transfer_size - * Number of 32-bit words to transfer + * Number of 32-bit words to transfer. * * @param irq_config - * uDMA IRQ Configuration. - * - * When set, the IRQ is asserted when and error occurs during a uDMA - * transfer or on the completion of the uDMA transfer. - * - * When clear, the IRQ is only asserted when an error occurs during a uDMA - * transfer. + * uDMA IRQ configuration + * - When set, the IRQ is asserted when an error occurs during a uDMA + * transfer or on the completion of the uDMA transfer. + * - When clear, the IRQ is only asserted when an error occurs during a + * uDMA transfer. * * @return * This function does not return any value. @@ -223,11 +223,11 @@ MIV_uDMA_config ); /***************************************************************************//** - * The MIV_uDMA_start() is used to start the uDMA transfer. + * The MIV_uDMA_start() function is used to start the uDMA transfer. * * @param this_udma - * This parameter is a pointer to the miv_udma_instance_t structure which - * holds the base address of Mi-V uDMA module. + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. * * @return * This function does not return any value. @@ -239,15 +239,15 @@ MIV_uDMA_start ); /***************************************************************************//** - * The MIV_uDMA_reset() is used to clear the uDMA interrupt and reset the uDMA - * transfer. + * The MIV_uDMA_reset() function is used to clear the uDMA interrupt and reset + * the uDMA transfer. * - * This function should be called from interrupt handler and it will reset the - * values set during MIV_uDMA_config(). + * This function should be called from the interrupt handler to reset the values + * set during MIV_uDMA_config(). * * @param this_udma - * This parameter is a pointer to the miv_udma_instance_t structure which - * holds the base address of Mi-V uDMA module. + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. * * @return * This function does not return any value. @@ -259,16 +259,17 @@ MIV_uDMA_reset ); /***************************************************************************//** - * The MIV_uDMA_read_status() will be used to status of the uDMA transfer. When - * Interrupt is enabled this function can be called from the interrupt handler - * to know the reason of uDMA interrupt. + * The MIV_uDMA_read_status() function is used to read the status of the uDMA + * transfer. When interrupt is enabled, this function can be called from the + * interrupt handler to know the reason for a uDMA interrupt. * * @param this_udma - * This parameter is a pointer to the miv_udma_instance_t structure which - * holds the base address of Mi-V uDMA module. + * This parameter is a pointer to the miv_udma_instance_t structure, which + * holds the base address of the Mi-V uDMA module. * * @return - * Return value will indicate error of busy status of the uDMA channel. + * The return value indicates an error due to the busy status of the uDMA + * channel. * * |Bit Number| Name | Description | * |----------|---------|------------------------------------------------------| @@ -282,4 +283,8 @@ MIV_uDMA_read_status miv_udma_instance_t* this_pdma ); +#ifdef __cplusplus +} +#endif + #endif /* MIV_uDMA_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_udma/miv_udma_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h similarity index 99% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_udma/miv_udma_regs.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h index 359055e..14d0759 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_udma/miv_udma_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_udma/miv_udma_regs.h @@ -87,5 +87,8 @@ extern "C" { #define BLK_SIZE_MASK 0xFFFFFFFFu #define BLK_SIZE_SHIFT 0x0u +#ifdef __cplusplus +} +#endif #endif /* MIV_UDMA_APB_REGISTERS */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_watchdog/miv_watchdog.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c similarity index 97% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_watchdog/miv_watchdog.c rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c index 2aa8061..525928a 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_watchdog/miv_watchdog.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.c @@ -10,10 +10,6 @@ #include "miv_watchdog.h" -#ifdef __cplusplus -extern "C" { -#endif - addr_t g_this_wdog; /***************************************************************************//* @@ -96,6 +92,3 @@ void MIV_WDOG_get_config } } -#ifdef __cplusplus -} -#endif diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_watchdog/miv_watchdog.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h similarity index 100% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_watchdog/miv_watchdog.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog.h diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_watchdog/miv_watchdog_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h similarity index 95% rename from bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_watchdog/miv_watchdog_regs.h rename to bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h index 2cc9441..2fca983 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/fabric_ip/miv_watchdog/miv_watchdog_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/fpga_ip/miv_watchdog/miv_watchdog_regs.h @@ -11,6 +11,10 @@ #ifndef MIV_WDOG_REGISTERS #define MIV_WDOG_REGISTERS 1u +#ifdef __cplusplus +extern "C" { +#endif + /*------------------------------------------------------------------------------ * Refresh register details */ @@ -38,8 +42,8 @@ /* Control register next enforbidden bit */ #define WDOGCNTL_NEXT_ENFORBIDDEN_OFFSET 0x04u -#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x04u -#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 2u +#define WDOGCNTL_NEXT_ENFORBIDDEN_MASK 0x10u +#define WDOGCNTL_NEXT_ENFORBIDDEN_SHIFT 4u /*------------------------------------------------------------------------------ * Watchdog status register @@ -111,4 +115,8 @@ #define WDOGFORCE_MASK 0xFFFFFFFFu #define WDOGFORCE_SHIFT 0u +#ifdef __cplusplus +} #endif + +#endif /* MIV_WATCHDOG_REGS_H_ */ diff --git a/bootloaders/miv-rv32-bootloader/src/platform/drivers/off_chip/spi_flash/spi_flash.c b/bootloaders/miv-rv32-bootloader/src/platform/drivers/off_chip/spi_flash/spi_flash.c index 81f2c93..97625f7 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/drivers/off_chip/spi_flash/spi_flash.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/drivers/off_chip/spi_flash/spi_flash.c @@ -23,7 +23,7 @@ #else #include "hal.h" #endif -#include "drivers/fabric_ip/CoreSPI/core_spi.h" +#include "drivers/fpga_ip/CoreSPI/core_spi.h" #include "spi_flash.h" #define READ_ARRAY_OPCODE 0x1B diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_assert.h b/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_assert.h index 2b4c3fb..1e18b54 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_assert.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_assert.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -9,7 +9,6 @@ */ #ifndef __HAL_ASSERT_HEADER #define __HAL_ASSERT_HEADER 1 -#define NDEBUG 1 #ifdef __cplusplus extern "C" { diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_irq.c b/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_irq.c index a799ca8..95a0775 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_irq.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hal_irq.c @@ -1,5 +1,5 @@ /***************************************************************************//** - * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_macros.h b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_macros.h index 95396ee..189609c 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_macros.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_macros.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.S b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.S index 6d99e80..dd29223 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.S +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.S @@ -1,5 +1,5 @@ /***************************************************************************//** - * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.h b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.h index 010e698..1a24309 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/hal/hw_reg_access.h @@ -1,5 +1,5 @@ /***************************************************************************//** - * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * diff --git a/bootloaders/miv-rv32-bootloader/src/platform/hal/readme.md b/bootloaders/miv-rv32-bootloader/src/platform/hal/readme.md deleted file mode 100644 index c756b34..0000000 --- a/bootloaders/miv-rv32-bootloader/src/platform/hal/readme.md +++ /dev/null @@ -1,38 +0,0 @@ -# hal folder - - -The HAL folder hardware abstraction for the bare metal drivers for the fabric -IP cores. The HAL folder contains files using a combination of C and assembly -source code. This layer allows the fabric ip drivers to be used with any of the -soft processors or the MSS hardened processors. - -The hal folder should be included in a your project under the platform directory. -See location in the drawing below. - -The hal folder contains: - -* register access functions -* assert macros - -### Project directory strucutre, showing where hal folder sits. - - +---------+ +-----------+ - | src +----->|application| - +---------+ | +-----------+ - | - | +-----------+ - +-->|middleware | - | +-----------+ - | - | +-----------+ +---------+ - +-->|platform +---->|drivers | - +-----------+ | +---------+ - | - | +---------+ - +->|hal | - | +---------+ - | - | +---------+ - +->|mpfs_hal | - +---------+ - \ No newline at end of file diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/Jenkinsfile b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/Jenkinsfile new file mode 100644 index 0000000..fb8e72f --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/Jenkinsfile @@ -0,0 +1,2 @@ +@Library('automated-testing-library') _ +pipelineSoftIPSrc() diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_entry.S b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_entry.S index b16a86e..c625844 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_entry.S +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_entry.S @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -17,6 +17,7 @@ #define MTIMEH_ADDR 0x200BFFCu + #if __riscv_xlen == 64 # define LREG ld # define SREG sd @@ -27,6 +28,84 @@ # define REGBYTES 4 #endif +#if defined(MIV_FP_CONTEXT_SAVE) && defined(__riscv_flen) +#define SP_SHIFT_OFFSET 64 +#else +#define SP_SHIFT_OFFSET 32 +#endif + +.macro STORE_CONTEXT + addi sp, sp, -SP_SHIFT_OFFSET*REGBYTES + SREG x1, 0 * REGBYTES(sp) + SREG x2, 1 * REGBYTES(sp) + SREG x3, 2 * REGBYTES(sp) + SREG x4, 3 * REGBYTES(sp) + SREG x5, 4 * REGBYTES(sp) + SREG x6, 5 * REGBYTES(sp) + SREG x7, 6 * REGBYTES(sp) + SREG x8, 7 * REGBYTES(sp) + SREG x9, 8 * REGBYTES(sp) + SREG x10, 9 * REGBYTES(sp) + SREG x11, 10 * REGBYTES(sp) + SREG x12, 11 * REGBYTES(sp) + SREG x13, 12 * REGBYTES(sp) + SREG x14, 13 * REGBYTES(sp) + SREG x15, 14 * REGBYTES(sp) + SREG x16, 15 * REGBYTES(sp) + SREG x17, 16 * REGBYTES(sp) + SREG x18, 17 * REGBYTES(sp) + SREG x19, 18 * REGBYTES(sp) + SREG x20, 19 * REGBYTES(sp) + SREG x21, 20 * REGBYTES(sp) + SREG x22, 21 * REGBYTES(sp) + SREG x23, 22 * REGBYTES(sp) + SREG x24, 23 * REGBYTES(sp) + SREG x25, 24 * REGBYTES(sp) + SREG x26, 25 * REGBYTES(sp) + SREG x27, 26 * REGBYTES(sp) + SREG x28, 27 * REGBYTES(sp) + SREG x29, 28 * REGBYTES(sp) + SREG x30, 29 * REGBYTES(sp) + SREG x31, 30 * REGBYTES(sp) + + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + fsw f0, 31*REGBYTES(sp) + fsw f1, 32*REGBYTES(sp) + fsw f2, 33*REGBYTES(sp) + fsw f3, 34*REGBYTES(sp) + fsw f4, 35*REGBYTES(sp) + fsw f5, 36*REGBYTES(sp) + fsw f6, 37*REGBYTES(sp) + fsw f7, 38*REGBYTES(sp) + fsw f8, 39*REGBYTES(sp) + fsw f9, 40*REGBYTES(sp) + fsw f10, 41*REGBYTES(sp) + fsw f11, 42*REGBYTES(sp) + fsw f12, 43*REGBYTES(sp) + fsw f13, 44*REGBYTES(sp) + fsw f14, 45*REGBYTES(sp) + fsw f15, 46*REGBYTES(sp) + fsw f16, 47*REGBYTES(sp) + fsw f17, 48*REGBYTES(sp) + fsw f18, 49*REGBYTES(sp) + fsw f19, 50*REGBYTES(sp) + fsw f20, 51*REGBYTES(sp) + fsw f21, 52*REGBYTES(sp) + fsw f22, 53*REGBYTES(sp) + fsw f23, 54*REGBYTES(sp) + fsw f24, 55*REGBYTES(sp) + fsw f25, 56*REGBYTES(sp) + fsw f26, 57*REGBYTES(sp) + fsw f27, 58*REGBYTES(sp) + fsw f28, 59*REGBYTES(sp) + fsw f29, 60*REGBYTES(sp) + fsw f30, 61*REGBYTES(sp) + fsw f31, 62*REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ +.endm + .section .entry, "ax" .globl _start @@ -91,205 +170,98 @@ MGECI_trap_entry: .word 0 .word 0 .word 0 - .word 0 - .word 0 -MSYS_EI0_trap_entry: +#ifndef MIV_RV32_V3_0 +MSYS_MIE22_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_SUBSYSR_IRQHandler +#endif /*MIV_RV32_V3_0*/ +#ifdef __riscv_compressed + .2byte 0 +#endif + +MSYS_MIE23_trap_entry: + j vector_SUBSYS_IRQHandler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /*MIV_RV32_V3_0*/ + +MSYS_MIE24_trap_entry: j vector_MSYS_EI0_trap_handler #ifdef __riscv_compressed .2byte 0 #endif -MSYS_EI1_trap_entry: +MSYS_MIE25_trap_entry: j vector_MSYS_EI1_trap_handler #ifdef __riscv_compressed .2byte 0 #endif -MSYS_EI2_trap_entry: +MSYS_MIE26_trap_entry: j vector_MSYS_EI2_trap_handler #ifdef __riscv_compressed .2byte 0 #endif -MSYS_EI3_trap_entry: +MSYS_MIE27_trap_entry: j vector_MSYS_EI3_trap_handler #ifdef __riscv_compressed .2byte 0 #endif -MSYS_EI4_trap_entry: +MSYS_MIE28_trap_entry: j vector_MSYS_EI4_trap_handler #ifdef __riscv_compressed .2byte 0 #endif -MSYS_EI5_trap_entry: +MSYS_MIE29_trap_entry: j vector_MSYS_EI5_trap_handler #ifdef __riscv_compressed .2byte 0 #endif +MSYS_MIE30_trap_entry: +#ifndef MIV_RV32_V3_0 + j vector_MSYS_EI6_trap_handler +#else + j vector_SUBSYS_IRQHandler +#endif #ifdef __riscv_compressed .2byte 0 #endif -OPSRV_trap_entry: - j vector_OPSRV_IRQHandler -#endif /* MIV_LEGACY_RV32 */ +#ifndef MIV_RV32_V3_0 +MSYS_MIE31_trap_entry: + j vector_MSYS_EI7_trap_handler +#ifdef __riscv_compressed + .2byte 0 +#endif +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ .align 4 generic_trap_handler: - addi sp, sp, -32*REGBYTES -.align 4 - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT csrr a0, mcause csrr a1, mepc jal handle_trap j generic_restore vector_sw_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT jal handle_m_soft_interrupt j generic_restore vector_tmr_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT jal handle_m_timer_interrupt j generic_restore vector_ext_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT #ifdef MIV_LEGACY_RV32 jal handle_m_ext_interrupt #else @@ -299,346 +271,68 @@ vector_ext_trap_handler: #ifndef MIV_LEGACY_RV32 vector_MGEUI_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT jal MGEUI_IRQHandler j generic_restore vector_MGECI_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT jal MGECI_IRQHandler j generic_restore vector_MSYS_EI0_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT jal MSYS_EI0_IRQHandler j generic_restore vector_MSYS_EI1_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT jal MSYS_EI1_IRQHandler j generic_restore vector_MSYS_EI2_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT jal MSYS_EI2_IRQHandler j generic_restore vector_MSYS_EI3_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT jal MSYS_EI3_IRQHandler j generic_restore vector_MSYS_EI4_trap_handler: - addi sp, sp, -32*REGBYTES - - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - + STORE_CONTEXT jal MSYS_EI4_IRQHandler j generic_restore vector_MSYS_EI5_trap_handler: - addi sp, sp, -32*REGBYTES + STORE_CONTEXT + jal MSYS_EI5_IRQHandler + j generic_restore - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) +vector_SUBSYS_IRQHandler: + STORE_CONTEXT + jal SUBSYS_IRQHandler + j generic_restore - jal MSYS_EI5_IRQHandler +#ifndef MIV_RV32_V3_0 +vector_MSYS_EI6_trap_handler: + STORE_CONTEXT + jal MSYS_EI6_IRQHandler j generic_restore -vector_OPSRV_IRQHandler: - addi sp, sp, -32*REGBYTES +vector_MSYS_EI7_trap_handler: + STORE_CONTEXT + jal MSYS_EI7_IRQHandler + j generic_restore - SREG x1, 0 * REGBYTES(sp) - SREG x2, 1 * REGBYTES(sp) - SREG x3, 2 * REGBYTES(sp) - SREG x4, 3 * REGBYTES(sp) - SREG x5, 4 * REGBYTES(sp) - SREG x6, 5 * REGBYTES(sp) - SREG x7, 6 * REGBYTES(sp) - SREG x8, 7 * REGBYTES(sp) - SREG x9, 8 * REGBYTES(sp) - SREG x10, 9 * REGBYTES(sp) - SREG x11, 10 * REGBYTES(sp) - SREG x12, 11 * REGBYTES(sp) - SREG x13, 12 * REGBYTES(sp) - SREG x14, 13 * REGBYTES(sp) - SREG x15, 14 * REGBYTES(sp) - SREG x16, 15 * REGBYTES(sp) - SREG x17, 16 * REGBYTES(sp) - SREG x18, 17 * REGBYTES(sp) - SREG x19, 18 * REGBYTES(sp) - SREG x20, 19 * REGBYTES(sp) - SREG x21, 20 * REGBYTES(sp) - SREG x22, 21 * REGBYTES(sp) - SREG x23, 22 * REGBYTES(sp) - SREG x24, 23 * REGBYTES(sp) - SREG x25, 24 * REGBYTES(sp) - SREG x26, 25 * REGBYTES(sp) - SREG x27, 26 * REGBYTES(sp) - SREG x28, 27 * REGBYTES(sp) - SREG x29, 28 * REGBYTES(sp) - SREG x30, 29 * REGBYTES(sp) - SREG x31, 30 * REGBYTES(sp) - jal OPSRV_IRQHandler +vector_SUBSYSR_IRQHandler: + STORE_CONTEXT + jal SUBSYSR_IRQHandler j generic_restore + +#endif /*MIV_RV32_V3_0*/ #endif /* MIV_LEGACY_RV32 */ generic_restore: @@ -674,7 +368,44 @@ generic_restore: LREG x30, 29 * REGBYTES(sp) LREG x31, 30 * REGBYTES(sp) - addi sp, sp, 32*REGBYTES + #ifdef __riscv_flen + #ifdef MIV_FP_CONTEXT_SAVE + flw f0, 0 * REGBYTES(sp) + flw f1, 1 * REGBYTES(sp) + flw f2, 2 * REGBYTES(sp) + flw f3, 3 * REGBYTES(sp) + flw f4, 4 * REGBYTES(sp) + flw f5, 5 * REGBYTES(sp) + flw f6, 6 * REGBYTES(sp) + flw f7, 7 * REGBYTES(sp) + flw f8, 8 * REGBYTES(sp) + flw f9, 9 * REGBYTES(sp) + flw f10, 10 * REGBYTES(sp) + flw f11, 11 * REGBYTES(sp) + flw f12, 12 * REGBYTES(sp) + flw f13, 13 * REGBYTES(sp) + flw f14, 14 * REGBYTES(sp) + flw f15, 15 * REGBYTES(sp) + flw f16, 16 * REGBYTES(sp) + flw f17, 17 * REGBYTES(sp) + flw f18, 18 * REGBYTES(sp) + flw f19, 19 * REGBYTES(sp) + flw f20, 20 * REGBYTES(sp) + flw f21, 21 * REGBYTES(sp) + flw f22, 22 * REGBYTES(sp) + flw f23, 23 * REGBYTES(sp) + flw f24, 24 * REGBYTES(sp) + flw f25, 25 * REGBYTES(sp) + flw f26, 26 * REGBYTES(sp) + flw f27, 27 * REGBYTES(sp) + flw f28, 28 * REGBYTES(sp) + flw f29, 29 * REGBYTES(sp) + flw f30, 30 * REGBYTES(sp) + flw f31, 31 * REGBYTES(sp) + #endif /* __riscv_flen */ + #endif /* MIV_FP_CONTEXT_SAVE */ + + addi sp, sp, SP_SHIFT_OFFSET*REGBYTES mret .section .text, "ax" @@ -683,6 +414,7 @@ handle_reset: .option push .option norelax +#ifndef MIV_RV32_V3_0 csrwi mstatus, 0 csrwi mie, 0 la ra, _start @@ -697,8 +429,12 @@ handle_reset: andi t0, t0, A_EXTENSION_MASK bnez t0, ima_cores_setup /* Jump to IMA core handling */ + /* For MIV_RV32 cores the mtvec exception base address is fixed at Reset vector address + 0x4. Check the mode bits. */ +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec andi t0, t0, MTVEC_MODE_BIT_MASK li t1, MTVEC_VECTORED_MODE_VAL @@ -712,12 +448,36 @@ handle_reset: bne t0, t1, vector_address_not_matching j generic_reset_handling +#else /* MIV_RV32_V3_0 */ + +/* Clearnig this to be on safer side as RTL doesnt seem to clear it on reset. */ +#ifndef MIV_LEGACY_RV32 + li t0, MTIMEH_ADDR + sw x0, 0(t0) +#endif + +/* In the MIV_RV32 v3.1, the MTVEC exception base address is WARL, and can be + configured by the user at runtime */ + csrr t0, mtvec + andi t0, t0, MTVEC_MODE_BIT_MASK + li t1, MTVEC_VECTORED_MODE_VAL + bne t0, t1, ima_cores_setup /* Jump to IMA core handling */ + +/* When mode = 1 => this is vectored mode on MIV_RV32 core. + Verify that the trap_handler address matches the configuration in MTVEC */ + csrr t0, mtvec + andi t0, t0, 0xFFFFFFFC + la t1, trap_entry + bne t0, t1, vector_address_not_matching + j generic_reset_handling +#endif /*MIV_RV32_V3_0*/ + ima_cores_setup: la t0, trap_entry #ifdef MIV_LEGACY_RV32_VECTORED_INTERRUPTS addi t0, t0, 0x01 /* Set the mode bit for IMA cores. - For MIV_RV32 cores this is done by configurator. */ + For both MIV_RV32 v3.1 and v3.0 cores this is done by configurator. */ #endif csrw mtvec, t0 diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.c b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.c index 2f73a63..bdb05a1 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -88,7 +88,7 @@ uint8_t External_31_IRQHandler(void); /*------------------------------------------------------------------------------ * RISC-V interrupt handler for external interrupts. */ -uint8_t (* const ext_irq_handler_table[32])(void) = +uint8_t (* const mrv_ext_irq_handler_table[32])(void) = { Invalid_IRQHandler, @@ -129,6 +129,7 @@ uint8_t (* const ext_irq_handler_table[32])(void) = /*------------------------------------------------------------------------------ * Interrupt handlers as mapped into the MIE register of the MIV_RV32 */ +extern void Reserved_IRQHandler(void); extern void External_IRQHandler(void); extern void MGEUI_IRQHandler(void); extern void MGECI_IRQHandler(void); @@ -138,7 +139,13 @@ extern void MSYS_EI2_IRQHandler(void); extern void MSYS_EI3_IRQHandler(void); extern void MSYS_EI4_IRQHandler(void); extern void MSYS_EI5_IRQHandler(void); -extern void OPSRV_IRQHandler(void); +extern void SUBSYS_IRQHandler(void); + +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +extern void MSYS_EI6_IRQHandler(void); +extern void MSYS_EI7_IRQHandler(void); +extern void SUBSYSR_IRQHandler(void); // @suppress("Unused function declaration") +#endif /*MIV_RV32_V3_0*/ #endif /* MIV_LEGACY_RV32 */ @@ -156,6 +163,8 @@ uint32_t MRV_systick_config(uint64_t ticks) { uint32_t ret_val = ERROR; uint64_t remainder = ticks; + g_systick_increment = 0U; + g_systick_cmp_value = 0U; while (remainder >= MTIME_PRESCALER) { @@ -170,7 +179,6 @@ uint32_t MRV_systick_config(uint64_t ticks) WRITE_MTIMECMP(g_systick_cmp_value); set_csr(mie, MIP_MTIP); MRV_enable_interrupts(); - ret_val = SUCCESS; } @@ -197,20 +205,19 @@ void handle_m_timer_interrupt(void) d_tick += 1; #endif } - +/***************************************************************************//** /* - * Note: If d_tick > 1 it means, that a system timer interrupt has been missed. - * + * Note: If d_tick > 1 it means, that a system timer interrupt has been + * missed. * Please ensure that interrupt handlers are as short as possible to prevent * them stopping other interrupts from being handled. For example, if a * system timer interrupt occurs during a software interrupt, the system * timer interrupt will not be handled until the software interrupt handling - * is complete. If the software interrupt handling time is more than one systick - * interval, it will result in d_tick > 1. - * - * If you are running the program using the debugger and halt the CPU at a breakpoint, - * MTIME will continue to increment and interrupts will be missed; resulting - * in d_tick > 1. + * is complete. If the software interrupt handling time is more than one + * systick interval, it will result in d_tick > 1. + * If you are running the program using the debugger and halt the CPU at a + * breakpoint, MTIME will continue to increment and interrupts will be + * missed; resulting in d_tick > 1. */ WRITE_MTIMECMP(g_systick_cmp_value); @@ -220,6 +227,11 @@ void handle_m_timer_interrupt(void) set_csr(mie, MIP_MTIP); } +void handle_m_soft_interrupt(void) +{ + Software_IRQHandler(); + MRV_clear_soft_irq(); +} /*------------------------------------------------------------------------------ * RISC-V interrupt handler for software interrupts. */ @@ -232,7 +244,7 @@ void handle_m_ext_interrupt(void) if (0u !=int_num) { - disable = ext_irq_handler_table[int_num](); + disable = mrv_ext_irq_handler_table[int_num](); PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; @@ -242,74 +254,99 @@ void handle_m_ext_interrupt(void) } } } -#endif /* MIV_LEGACY_RV32 */ +#else -void handle_m_soft_interrupt(void) +/*------------------------------------------------------------------------------ + * MSYS local interrupts table + */ +void (* const local_irq_handler_table[16])(void) = { - Software_IRQHandler(); - MRV_clear_soft_irq(); +#ifndef MIV_RV32_V3_0 + MGEUI_IRQHandler, + MGECI_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYSR_IRQHandler, + MSYS_EI6_IRQHandler, + MSYS_EI7_IRQHandler +#else + MGEUI_IRQHandler, + MGECI_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + Reserved_IRQHandler, + MSYS_EI0_IRQHandler, + MSYS_EI1_IRQHandler, + MSYS_EI2_IRQHandler, + MSYS_EI3_IRQHandler, + MSYS_EI4_IRQHandler, + MSYS_EI5_IRQHandler, + SUBSYS_IRQHandler, + Reserved_IRQHandler, +#endif +}; + +/*------------------------------------------------------------------------------ + * Jump to interrupt table containing local interrupts + */ +void handle_local_ei_interrupts(uint8_t irq_no) +{ + uint64_t mhart_id = read_csr(mhartid); + ASSERT(irq_no <= MIV_LOCAL_IRQ_MAX) + ASSERT(irq_no >= MIV_LOCAL_IRQ_MIN) + + uint8_t ei_no = (uint8_t)(irq_no - MIV_LOCAL_IRQ_MIN); + (*local_irq_handler_table[ei_no])(); } +#endif /* MIV_LEGACY_RV32 */ + /*------------------------------------------------------------------------------ * Trap handler. This function is invoked in the non-vectored mode. */ void handle_trap(uintptr_t mcause, uintptr_t mepc) -{ - if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT)) - { - handle_m_soft_interrupt(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER)) - { - handle_m_timer_interrupt(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT)) +{ + uint64_t is_interrupt = mcause & MCAUSE_INT; + + if (is_interrupt) { -#ifdef MIV_LEGACY_RV32 - handle_m_ext_interrupt(); +#ifndef MIV_LEGACY_RV32 + if (((mcause & MCAUSE_CAUSE) >= MIV_LOCAL_IRQ_MIN) && ((mcause & MCAUSE_CAUSE) <= MIV_LOCAL_IRQ_MAX)) + { + handle_local_ei_interrupts((uint8_t)(mcause & MCAUSE_CAUSE)); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) #else - External_IRQHandler(); + if ((mcause & MCAUSE_CAUSE) == IRQ_M_EXT) #endif - } + { #ifndef MIV_LEGACY_RV32 - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI0)) - { - MSYS_EI0_IRQHandler(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI1)) - { - MSYS_EI1_IRQHandler(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI2)) - { - MSYS_EI2_IRQHandler(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI3)) - { - MSYS_EI3_IRQHandler(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI4)) - { - MSYS_EI4_IRQHandler(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MSYS_EI5)) - { - MSYS_EI5_IRQHandler(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == OPSRV_REG)) - { - OPSRV_IRQHandler(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MGEUI)) - { - MGEUI_IRQHandler(); - } - else if ((mcause & MCAUSE_INT) && ((mcause & MCAUSE_CAUSE) == MGECI)) - { - MGECI_IRQHandler(); + External_IRQHandler(); +#else + handle_m_ext_interrupt(); +#endif + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_SOFT) + { + handle_m_soft_interrupt(); + } + else if ((mcause & MCAUSE_CAUSE) == IRQ_M_TIMER) + { + handle_m_timer_interrupt(); + } } -#endif /* MIV_LEGACY_RV32 */ - else { #ifndef NDEBUG @@ -341,7 +378,7 @@ void handle_trap(uintptr_t mcause, uintptr_t mepc) # See: https://github.com/riscv/riscv-gcc/issues/133 */ - /* interrupt pending */ + /* interrupt pending */ uintptr_t mip = read_csr(mip); /* additional info and meaning depends on mcause */ @@ -370,3 +407,4 @@ void handle_trap(uintptr_t mcause, uintptr_t mepc) #ifdef __cplusplus } #endif + diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.h b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.h index c4e071d..0af53c8 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_hal.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -27,12 +27,174 @@ * */ +/*=========================================================================*//** + @mainpage MIV_RV32 Hardware Abstraction Layer + + ============================================================================== + Introduction + ============================================================================== + This document describes the Hardware Abstraction Layer (HAL) for the MIV_RV32 + Soft IP Core. This release of the HAL corresponds to the Soft IP core MIV_RV32 + v3.1 release. It also supports earlier versions of the MIV_RV32 as well as the + legacy RV32 IP cores. + The preprocessor macros provided with the MIV_RV32 HAL are used to customize + it to target the Soft Processor IP version being used in your project. + + The term "MIV_RV32" represents following two cores: + - MIV_RV32 v3.0 and later (the latest and greatest Mi-V soft processor) + - MIV_RV32IMC v2.1 (MIV_RV32 v3.0 is a drop in replacement for this core) + It is highly recommended to migrate your design to MIV_RV32 v3.1 + + The term, Legacy RV32 IP cores, represents following IP cores: + - MIV_RV32IMA_L1_AHB + - MIV_RV32IMA_L1_AXI + - MIV_RV32IMAF_L1_AHB + + These legacy RV32 IP cores are deprecated. It is highly recommended to migrate + your designs to MIV_RV32 v3.1 (and subsequent IP releases) for the latest + enhancements, bug fixes, and support. + + -------------------------------- + MIV_RV32 V3.1 + -------------------------------- + This is the latest release of the MIV_RV32 Soft IP core. For more details, + refer to the MIV_RV32 User [Guide](https://www.microchip.com/en-us/products/fpgas-and-plds/ip-core-tools/miv-rv32) + + The MIV_RV32 Core as well as this document use the terms defined below: + + -------------------------------- + - SUBSYS - Processor Subsystem for RISC-V + - OPSRV - Offload Processor Subsystem for RISC-V + - GPR - General Purpose Registers + - MGECIE - Machine GPR ECC Correctable Interrupt Enable + - MGEUIE - Machine GPR ECC Uncorrectable Interrupt Enable + - MTIE - Machine Timer Interrupt Enable + - MEIE - Machine External Interrupt Enable + - MSIE - Machine Software Interrupt Enable + - ISR - Interrupt Service Routine + + ============================================================================== + Customizing MIV_RV32 HAL + ============================================================================== + To use the HAL with older releases of MIV_RV32, preprocessor macros have been + provided. Using these macros, any of the IP version is targeted. + The HAL is used to target any of the mentioned platforms by adding the + following macros in the way : + Project Properties > C/C++ Build > Settings > Preprocessor in Assembler and + Compiler settings. + The table below shows the macros corresponding to the MIV Core being used in + your libero project. By default, the HAL targets v3.1 of the IP core and no + macros need to be set for this configutation. + + | Libero MI-V Soft IP Version | SoftConsole Macro | + |-----------------------------|-------------------| + | MIV_RV32 v3.1 | no macro required | + | MIV_RV32 v3.0 | MIV_CORE_V3_0 | + | Legacy RV32 Cores | MIV_LEGACY_RV32 | + + -------------------------------- + Interrupt Handling + -------------------------------- + The MIE Register is defined as a enum in the HAL, and the table below is used + as a reference when the vectored interrupts are enabled in the GUI core + configurator. + + The MIE register is a RISC-V Control and Status Register (CSR), which stands + for the Machine Interrupt Enable. This is used to enable the machine mode + interrupts in the MIV_RV32 hart. Refer to the RISC-V Priv spec for more details. + + The following table shows the trap entry addresses when an interrupt occurs and + the vectored interrupts are enabled in the GUI configurator. + + | MIE Register Bit | Interrupt Enable | Vector Address | + |-------------------|------------------|----------------| + | 31 | MSYS_IE7 | mtvec.BASE + 0x7C | + | 30 | MSYS_IE6 | mtvec.BASE + 0x78 | + | 29 | MSYS_IE5 | mtvec.BASE + 0x74 | + | 28 | MSYS_IE4 | mtvec.BASE + 0x70 | + | 27 | MSYS_IE3 | mtvec.BASE + 0x6C | + | 26 | MSYS_IE2 | mtvec.BASE + 0x68 | + | 25 | MSYS_IE1 | mtvec.BASE + 0x64 | + | 24 | MSYS_IE0 | mtvec.BASE + 0x60 | + | 23 | SUBSYS_EI | mtvec.BASE + 0x5C | + | 22 | SUBSYSR | mtvec.BASE + 0x58 | + | 17 | MGECIE | mtvec.BASE + 0x44 | + | 16 | MGEUIE | mtvec.BASE + 0x40 | + | 11 | MEIE | mtvec.BASE + 0x2C | + | 7 | MTIE | mtvec.BASE + 0x1C | + | 3 | MSIE | mtvec.BASE + 0x0C | + + + For changes in MIE register map, see the [MIE Register Map for MIV_RV32 v3.0] + (#mie-register-map-for-miv_rv32-v3.0) section. + + SUBSYSR is currently not being used by the core and is Reserved for future use. + + The mtvec.BASE field corresponds to the bits [31:2], where mtvec stands for + Machine Trap Vector, and all traps set the PC to the the value stored in the + mtvec.BASE field when in Non-Vectored mode. In this case, a generic trap + handler is as an interrupt service routine. + + When Vectored interrupts are enabled, use this formula to calculate the trap + address: (mtvec.BASE + 4*cause), where cause comes from the mcause CSR. The + mcause register is written with a code indicating the event that caused the trap. + For more details, see the RISC-V priv specification. + + The MIV_RV32 Soft IP core does not contain a Platfrom Level Interrup Controller + (PLIC). It is advised to use the PLIC contained within the MIV_ESS sub-system. + Connect the PLIC interrupt output of the MIV_ESS to the EXT_IRQ pin on the + MIV_RV32. + + The following table is the MIE register map for the MIV_RV32 Core V3.0. It only + highlights the differences between the V3.0 and V3.1 of the core. + + -------------------------------- + MIE Register Map for MIV_RV32 V3.0 + -------------------------------- + + | MIE Register Bit | Target Interrupt | Vector Address | + |-------------------|------------------|----------------| + | 31 | Not in use | top table | + | 30 | SUBSYS_EI | addr + 0x78 | + | 23 | Not in use | Not in use | + | 22 | Not in use | Not in use | + + Other interrupt bit postions like the MGEUIE and MSYS_IE5 to MSYS_IE0 remain + unchanged. + + -------------------------------- + Floating Point Interrupt Support + -------------------------------- + When an interrupt is taken and Floating Point instructions are used in the + ISR, the floating point register context must be saved to resume the application + correctly. To use this feature, enable the provided macro in the + Softconsole build settings. + This feature is turned off by default as it adds overhead which is not required + when the ISR does not used FP insturctions and saving the general purpose + register context is sufficient. + + | Macro Name | Definition | + |--------------------------|-------------------------------------------------| + | MIV_FP_CONTEXT_SAVE | Define to save the FP register file | + + + -------------------------------- + SUBSYS - SubSystem for RISC-V + -------------------------------- + SUBSYS stands for SubSystem for RISC-V. This was previously (MIV_RV32 v3.0) + known as OPSRV, which stands for "Offload Processor Subsystem + for RISC-V". See the earlier versions of the handbook for more details. + In the latest release of the MIV_RV32 IP core v3.1, OPSRV has been renamed to + SUBSYS. The MIV_RV32 HAL now uses SUBSYS instead of OPSRV. + + *//*=========================================================================*/ #ifndef RISCV_HAL_H #define RISCV_HAL_H #include "miv_rv32_regs.h" #include "miv_rv32_plic.h" #include "miv_rv32_assert.h" +#include "miv_rv32_subsys.h" #ifndef LEGACY_DIR_STRUCTURE #include "fpga_design_config/fpga_design_config.h" @@ -43,43 +205,106 @@ #ifdef __cplusplus extern "C" { #endif - -/***************************************************************************//** - * Return value from External IRQ handler. This will be used to disable the - * External interrupt. +/*-------------------------------------------------------------------------*//** + SUBSYS Backwards Compatibility + ======================================= + For application code using the older macro names and API functions, these macros + act as a compatibility layer and applications which use OPSRV API features work + due to these macro definitions. However, it is adviced to update your + application code to use the SUBSYS macros and API functions. + + | Macro Name | Now Called | + |-------------------------|--------------------------| + | OPSRV_TCM_ECC_CE_IRQ | SUBSYS_TCM_ECC_CE_IRQ | + | OPSRV_TCM_ECC_UCE_IRQ | SUBSYS_TCM_ECC_UCE_IRQ | + | OPSRV_AXI_WR_RESP_IRQ | SUBSYS_AXI_WR_RESP_IRQ | + | MRV32_MSYS_OPSRV_IRQn | MRV32_SUBSYS_IRQn | + | MRV32_opsrv_enable_irq | MRV32_subsys_enable_irq | + | MRV32_opsrv_disable_irq | MRV32_subsys_disable_irq | + | MRV32_opsrv_clear_irq | MRV32_subsys_clear_irq | + | OPSRV_IRQHandler | SUBSYS_IRQHandler | */ -#define EXT_IRQ_KEEP_ENABLED 0U -#define EXT_IRQ_DISABLE 1U -/***************************************************************************//** - * System tick handler. This handler function gets called when the Machine - * timer interrupt asserts. An implementation of this function should be - * provided by the application to implement the application specific machine - * timer interrupt handling. If application does not provide such implementation - * the weakly linked handler stub function implemented in riscv_hal_stubs.c gets - * linked. +/*-------------------------------------------------------------------------*//** + MTIME Timer Interrupt Constants + ======================================= + These values contain the register addresses for the registers used by the + machine timer interrupt + + MTIME_PRESCALER is not defined on the MIV_RV32IMC v2.0 and v2.1. By using this + definition the system crashes. For those core, use the following definition: + + #define MTIME_PRESCALER 100u + + MTIME and MTIMECMP + -------------------------------- + MIV_RV32 core offers flexibility in terms of generating MTIME and MTIMECMP + registers internal to the core or using external time reference. There four + possible combinations: + + - Internal MTIME and Internal MTIME IRQ enabled Generate the MTIME and MTIMECMP + registers internally. (The only combination available on legacy RV32 cores) + + - Internal MTIME enabled and Internal MTIME IRQ disabled Generate the MTIME + internally and have a timer interrupt input to the core as external pin. In + this case, 1 pin port will be available on MIV_RV32 for timer interrupt. + + - When the internal MTIME is disabled, and the Internal MTIME IRQ is enabled, the + system generates the time value externally and generates the mtimecmp and + interrupt internally (for example, a multiprocessor system with a shared time + between all cores). In this case, a 64-bit port is available on the MIV_RV32 + core as input. + + - Internal MTIME and Internal MTIME IRQ disabled Generate both the time and + timer interrupts externally. In this case a 64 bit port will be available on + the MIV_RV32 core as input, and a 1 pin port will be available for timer + interrupt. + + To handle all these combinations in the firmware, the following constants must + be defined in accordance with the configuration that you have made on your + MIV_RV32 core design. + + MIV_RV32_EXT_TIMER + -------------------------------- + When defined, it means that the MTIME register is not available internal to + the core. In this case, a 64 bit port will be available on the MIV_RV32 core as + input. When this macro is not defined, it means that the MTIME register is + available internally to the core. + + MIV_RV32_EXT_TIMECMP + -------------------------------- + When defined, it means the MTIMECMP register is not available internally to + the core and the Timer interrupt input to the core comes as an external pin. + When this macro is not defined it means the that MTIMECMP register exists + internal to the core and that the timer interrupt is generated internally. + +NOTE: All these macros must not be defined if you are using a MIV_RV32 core. */ -void SysTick_Handler(void); -/***************************************************************************//** - * System timer tick configuration. - * Configures the machine timer to generate a system tick interrupt at regular - * intervals. - * Takes the number of system clock ticks between interrupts. - * - * Though this function can take any valid ticks value as parameter, we expect - * that, for all practical purposes, a small tick value (to generate periodic - * interrupts every few miliseconds) will be passed. If you need to generate - * periodic events in the range of seconds or more, you may use the SysTick_Handler() - * to further count the number of interrupts and hence the larger time intervals. - * - * Returns 0 if successful. - * Returns 1 if the interrupt interval cannot be achieved. +#define OPSRV_TCM_ECC_CE_IRQ SUBSYS_TCM_ECC_CE_IRQ +#define OPSRV_TCM_ECC_UCE_IRQ SUBSYS_TCM_ECC_UCE_IRQ +#define OPSRV_AXI_WR_RESP_IRQ SUBSYS_AXI_WR_RESP_IRQ +#define MRV32_MSYS_OPSRV_IRQn MRV32_SUBSYS_IRQn +#define MRV32_opsrv_enable_irq MRV32_subsys_enable_irq +#define MRV32_opsrv_disable_irq MRV32_subsys_disable_irq +#define MRV32_opsrv_clear_irq MRV32_subsys_clear_irq +#define OPSRV_IRQHandler SUBSYS_IRQHandler + +/*-------------------------------------------------------------------------*//** + External IRQ + ======================================= + Return value from External IRQ handler. This is used to disable the + External Interrupt. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | EXT_IRQ_KEEP_ENABLED | 0 | Keep external interrupts enabled | + | EXT_IRQ_DISABLE | 1 | Disable external interrupts | */ -uint32_t MRV_systick_config(uint64_t ticks); +#define EXT_IRQ_KEEP_ENABLED 0U +#define EXT_IRQ_DISABLE 1U #define MTIME_DELTA 5 - #ifdef MIV_LEGACY_RV32 #define MSIP (*(uint32_t*)0x44000000UL) #define MTIMECMP (*(uint32_t*)0x44004000UL) @@ -89,38 +314,11 @@ uint32_t MRV_systick_config(uint64_t ticks); /* To maintain backward compatibility with FreeRTOS config code */ #define PRCI_BASE 0x44000000UL - -#else +#else /* MIV_LEGACY_RV32 */ /* To maintain backward compatibility with FreeRTOS config code */ #define PRCI_BASE 0x02000000UL -/* OPSRV stands for "Offload Processor Subsystem for RISC-V" (OPSRV) on the - * MIV_RV32 IP core. Please see the handbook for more details. */ - -/* TCM ECC correctable error irq enable mask value */ -#define OPSRV_TCM_ECC_CE_IRQ 0x01u - -/* TCMECC uncorrectable error irq enable */ -#define OPSRV_TCM_ECC_UCE_IRQ 0x02u - -/* AXI write response error irq enable */ -#define OPSRV_AXI_WR_RESP_IRQ 0x10u - -#define OPSRV_BASE_ADDR 0x00006000UL - -typedef struct -{ - volatile uint32_t cfg; /*Parity is not being supported by MIV_RV32 v3.0*/ - volatile uint32_t reserved0[3]; - volatile uint32_t irq_en; /*offset 0x10*/ - volatile uint32_t irq_pend; - volatile uint32_t reserved1[2]; - volatile uint32_t soft_reg; /*offset 0x20*/ -} OPSRV_Type; - -#define OPSRV ((OPSRV_Type *)OPSRV_BASE_ADDR) - #ifndef MIV_RV32_EXT_TIMECMP #define MTIMECMP (*(volatile uint32_t*)0x02004000UL) #define MTIMECMPH (*(volatile uint32_t*)0x02004004UL) @@ -129,71 +327,103 @@ typedef struct #define MTIMECMPH (0u) #endif -/* On MIV_RV32IMC v2.0 and v2.1 MTIME_PRESCALER is not defined and using this - * definition will result in crash. For those core use the definition as below - * #define MTIME_PRESCALER 100u - */ #define MTIME_PRESCALER (*(volatile uint32_t*)0x02005000UL) #ifndef MIV_RV32_EXT_TIMER #define MTIME (*(volatile uint32_t*)0x0200BFF8UL) #define MTIMEH (*(volatile uint32_t*)0x0200BFFCUL) + +/***************************************************************************//** + MIMPID Register + The MIMPID register is a RISC-V Control and Status Register In the v3.0 of + MIV_RV32, the value of `MIMPID = 0x000540AD`. In the v3.1 of MIV_RV32, the + value if `MIMPID = 0xE5010301` corresponding to (E)mbedded (5)ystem(01) core + version (03).(01) this terminology will be followed in the subsequent releases + of the core read the csr value and store it in a varible which may be used to + check the MIV_RV32 core version during runtime. + + Future releases of the core will increment the 03 and 01 as major and minor + releases respectively and the register can be read at runtime to find the + Soft IP core version. + + | Core Version | Register | Value | Notes | + |----------------|------------|---------|---------| + | MIV_RV32 V3.1 | mimpid | 0xE5010301 | implimentation ID | + | MIV_RV32 V3.0 | mimpid | 0x000540AD | implimentation ID | + */ +#define MIMPID read_csr(mimpid) + +/*Used as a mask to read and write to mte mtvec.BASE address*/ +#define MTVEC_BASE_ADDR_MASK 0xFFFFFFFC + #else #define MTIME (0u) #define MTIMEH (0u) #endif /*MIV_RV32_EXT_TIMER*/ -/* These definitions are provided for convenient identification of the interrupts - * in the MIE/MIP registers. - * Apart from the standard software, timer and external interrupts, the names - * of the additional interrupts correspond to the names as used in the MIV_RV32 - * handbook. Please refer the MIV_RV32 handbook for more details. - * */ +/*-------------------------------------------------------------------------*//** + RISC-V Specification Interrupts + ======================================= + These definitions are provided for easy identification of the interrupt + in the MIE/MIP registers. + Apart from the standard software, timer, and external interrupts, the names + of the additional interrupts correspond to the names as used in the MIV_RV32 + handbook. Please refer the MIV_RV32 handbook for more details. + + All the interrups, provided by the MIV_RV32 core, follow the interrupt priority + order and register description as mentioned in the RISC-V spec. + + | Macro Name | Value | Description| + |-------------------|--------|----------------| + | MRV32_SOFT_IRQn | MIE_3_IRQn | Software interrupt enable | + | MRV32_TIMER_IRQn | MIE_7_IRQn | Timer interrupt enable | + | MRV32_EXT_IRQn | MIE_11_IRQn | External interrupt enable | + + */ #define MRV32_SOFT_IRQn MIE_3_IRQn #define MRV32_TIMER_IRQn MIE_7_IRQn #define MRV32_EXT_IRQn MIE_11_IRQn -/*============================================================================== - * Interrupt numbers: - * This enum represents the interrupt enable bits in the MIE register. +/***************************************************************************//** + Interrupt numbers: + This enum represents the interrupt enable bits in the MIE register. */ enum { MIE_0_IRQn = (0x01u), MIE_1_IRQn = (0x01u<<1u), MIE_2_IRQn = (0x01u<<2u), - MIE_3_IRQn = (0x01u<<3u), /*MSIE*/ + MIE_3_IRQn = (0x01u<<3u), /*MSIE 0xC*/ MIE_4_IRQn = (0x01u<<4u), MIE_5_IRQn = (0x01u<<5u), MIE_6_IRQn = (0x01u<<6u), - MIE_7_IRQn = (0x01u<<7u), /*MTIE*/ + MIE_7_IRQn = (0x01u<<7u), /*MTIE 0x1C*/ MIE_8_IRQn = (0x01u<<8u), MIE_9_IRQn = (0x01u<<9u), MIE_10_IRQn = (0x01u<<10u), - MIE_11_IRQn = (0x01u<<11u), /*MEIE*/ + MIE_11_IRQn = (0x01u<<11u), /*MEIE 0x2C*/ MIE_12_IRQn = (0x01u<<12u), MIE_13_IRQn = (0x01u<<13u), MIE_14_IRQn = (0x01u<<14u), MIE_15_IRQn = (0x01u<<15u), - MIE_16_IRQn = (0x01u<<16u), /*MGEUIE*/ - MIE_17_IRQn = (0x01u<<17u), /*MGECIE*/ + MIE_16_IRQn = (0x01u<<16u), /*MGEUIE ECC Uncorrectable 0x40*/ + MIE_17_IRQn = (0x01u<<17u), /*MGECIE ECC Correctable 0x44*/ MIE_18_IRQn = (0x01u<<18u), MIE_19_IRQn = (0x01u<<19u), MIE_20_IRQn = (0x01u<<20u), MIE_21_IRQn = (0x01u<<21u), - MIE_22_IRQn = (0x01u<<22u), - MIE_23_IRQn = (0x01u<<23u), - MIE_24_IRQn = (0x01u<<24u), /*MSYS_EIE0*/ - MIE_25_IRQn = (0x01u<<25u), /*MSYS_EIE1*/ - MIE_26_IRQn = (0x01u<<26u), /*MSYS_EIE2*/ - MIE_27_IRQn = (0x01u<<27u), /*MSYS_EIE3*/ - MIE_28_IRQn = (0x01u<<28u), /*MSYS_EIE4*/ - MIE_29_IRQn = (0x01u<<29u), /*MSYS_EIE5*/ - MIE_30_IRQn = (0x01u<<30u) /*OPSRV_IRQ_IE*/ - + MIE_22_IRQn = (0x01u<<22u), /*SUBSYSR 0x58 (R)eserved*/ + MIE_23_IRQn = (0x01u<<23u), /*SUBSYS_IE 0x5C for MIV_RV32 v3.1*/ + MIE_24_IRQn = (0x01u<<24u), /*MSYS_IE0 0x60*/ + MIE_25_IRQn = (0x01u<<25u), /*MSYS_IE1 0x64*/ + MIE_26_IRQn = (0x01u<<26u), /*MSYS_IE2 0x68*/ + MIE_27_IRQn = (0x01u<<27u), /*MSYS_IE3 0x6C*/ + MIE_28_IRQn = (0x01u<<28u), /*MSYS_IE4 0x70*/ + MIE_29_IRQn = (0x01u<<29u), /*MSYS_IE5 0x74*/ + MIE_30_IRQn = (0x01u<<30u), /*MSYS_IE6 0x78, read comment below*/ + MIE_31_IRQn = (0x01u<<31u) /*MSYS_IE7 0x7C*/ } MRV_LOCAL_IRQn_Type; - #define MRV32_MGEUIE_IRQn MIE_16_IRQn #define MRV32_MGECIE_IRQn MIE_17_IRQn #define MRV32_MSYS_EIE0_IRQn MIE_24_IRQn @@ -202,74 +432,33 @@ enum #define MRV32_MSYS_EIE3_IRQn MIE_27_IRQn #define MRV32_MSYS_EIE4_IRQn MIE_28_IRQn #define MRV32_MSYS_EIE5_IRQn MIE_29_IRQn -#define MRV32_MSYS_OPSRV_IRQn MIE_30_IRQn - -/***************************************************************************//** - Enable OPSRV interrupt. Parameter takes logical OR of following values - #define OPSRV_TCM_ECC_CE_IRQ 0x01u - #define OPSRV_TCM_ECC_UCE_IRQ 0x02u - #define OPSRV_AXI_WR_RESP_IRQ 0x10u - */ -static inline void MRV32_opsrv_enable_irq(uint32_t irq_mask) -{ - OPSRV->irq_en = irq_mask; -} - -/***************************************************************************//** - Disable OPSRV interrupt. Parameter takes logical OR of following values - #define OPSRV_TCM_ECC_CE_IRQ 0x01u - #define OPSRV_TCM_ECC_UCE_IRQ 0x02u - #define OPSRV_AXI_WR_RESP_IRQ 0x10u - */ -static inline void MRV32_opsrv_disable_irq(uint32_t irq_mask) -{ - OPSRV->irq_en &= ~irq_mask; -} - -/***************************************************************************//** - Clear OPSRV interrupt. Parameter takes logical OR of following values - #define OPSRV_TCM_ECC_CE_IRQ 0x01u - #define OPSRV_TCM_ECC_UCE_IRQ 0x02u - #define OPSRV_AXI_WR_RESP_IRQ 0x10u - */ -static inline void MRV32_opsrv_clear_irq(uint32_t irq_mask) -{ - OPSRV->irq_pend |= irq_mask; -} - -/***************************************************************************//** - * The function MRV32_is_gpr_ded() returns the core_gpr_ded_reset_reg bit value. - * When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was - * reset due to GPR DED error. - */ -static inline uint32_t MRV32_is_gpr_ded(void) -{ - return((OPSRV->soft_reg & 0x04u) >> 0x02u); -} +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define MRV32_SUBSYSR_IRQn MIE_22_IRQn +#define MRV32_SUBSYS_IRQn MIE_23_IRQn +#define MRV32_MSYS_EIE6_IRQn MIE_30_IRQn +#define MRV32_MSYS_EIE7_IRQn MIE_31_IRQn +#else +#define MRV32_SUBSYS_IRQn MIE_30_IRQn +#endif /*MIV_RV32_V3_0*/ -/***************************************************************************//** - * The function MRV32_clear_gpr_ded() can be used to clear the - * core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg - * is set when the core was previously reset due to GPR DED error. - */ -static inline void MRV32_clear_gpr_ded(void) -{ - OPSRV->soft_reg &= ~0x04u; - -} +/*--------------------------------Public APIs---------------------------------*/ /***************************************************************************//** - When ECC is enabled for the GPRs and if that data has a single bit error then - the data coming out of the ECC block will be corrected and will not have the - error but the data source will still have the error. - The ECC block does not write back corrected data to memory. - Therefore, if data has a single bit error, then the corrected data should be - written back to prevent the single bit error from becoming a double bit error. - The MRV32_clear_gpr_ecc_errors() can be used for that. - - Clear the pending interrupt bit after this using MRV32_mgeci_clear_irq() - function to complete the ECC error handling. - */ + The MRV32_clear_gpr_ecc_errors() function clears single bit ECC errors on the + GPRs. The ECC block does not write back corrected data to memory. Hence, when + ECC is enabled for the GPRs and if that data has a single bit error then the + data coming out of the ECC block is corrected and will not have the error, but + the data source will still have the error. Therefore, if data has a single bit + error, then the corrected data must be written back to prevent the single bit + error from becoming a double bit error. Clear the pending interrupt bit after + this using MRV32_mgeci_clear_irq() function to complete the ECC error handling. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ static inline void MRV32_clear_gpr_ecc_errors(void) { uint32_t temp; @@ -375,89 +564,163 @@ static inline void MRV32_clear_gpr_ecc_errors(void) :"m" (temp)); } + /***************************************************************************//** - * The function MRV32_enable_parity_check() is used to enable parity check on - * the TCM and it's interface transactions. This feature is not available on - * MIV_RV32 v3.0.100 soft processor core. + The MRV32_mgeui_clear_irq() function clears the GPR ECC Uncorrectable + Interrupt. MGEUI interrupt is available only when ECC is enabled in the MIV_RV32 + IP configurator. + + @return + This function does not return any value. */ -static inline void MRV32_enable_parity_check(void) +static inline void MRV32_mgeui_clear_irq(void) { - OPSRV->cfg |= 0x01u; + clear_csr(mip, MRV32_MGEUIE_IRQn); } /***************************************************************************//** - * The function MRV32_disable_parity_check() is used to disable parity check on - * the TCM and it's interface transactions. + The MRV32_mgeci_clear_irq() function clears the GPR ECC Correctable Interrupt + MGECI interrupt is available only when ECC is enabled in the MIV_RV32 IP + configurator. + + @return + This function does not return any value. */ -static inline void MRV32_disable_parity_check(void) +static inline void MRV32_mgeci_clear_irq(void) { - OPSRV->cfg &= ~0x01u; + clear_csr(mip, MRV32_MGECIE_IRQn); } /***************************************************************************//** - * The function MRV32_cpu_soft_reset() is used to cause a soft cpu reset on - * the MIV_RV32 soft processor core. + The MRV_enable_local_irq() function enables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is enabled. + + MRV_enable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); */ -static inline void MRV32_cpu_soft_reset(void) +static inline void MRV_enable_local_irq(uint32_t mask) { - OPSRV->soft_reg &= ~0x01u; + set_csr(mie, mask); } /***************************************************************************//** - Clear GPR ECC Uncorrectable interrupt. MGEUI interrupt is available only when - ECC is enabled in MIV_RV32 IP configurator. + The MRV_disable_local_irq() function disables the local interrupts. It takes a + mask value as input. For each set bit in the mask value, the corresponding + interrupt bit in the MIE register is disabled. + + MRV_disable_local_irq( MRV32_SOFT_IRQn | MRV32_TIMER_IRQn | MRV32_EXT_IRQn | + MRV32_MSYS_EIE0_IRQn | + MRV32_MSYS_SUBSYS_IRQn); */ -static inline void MRV32_mgeui_clear_irq(uint32_t irq_mask) +static inline void MRV_disable_local_irq(uint32_t mask) { - clear_csr(mip, MRV32_MGEUIE_IRQn); + clear_csr(mie, mask); } +#endif /* MIV_LEGACY_RV32 */ /***************************************************************************//** - Clear GPR ECC correctable interrupt. MGECI interrupt is available only when - ECC is enabled in MIV_RV32 IP configurator. + The MRV_enable_interrupts() function enables all interrupts by setting the + machine mode interrupt enable bit in MSTATUS register. + + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. */ -static inline void MRV32_mgeci_clear_irq(uint32_t irq_mask) +static inline void MRV_enable_interrupts(void) { - clear_csr(mip, MRV32_MGECIE_IRQn); + set_csr(mstatus, MSTATUS_MIE); } /***************************************************************************//** - * Enable interrupts. - This function takes a mask value as input. For each set bit in the mask value, - corresponding interrupt bit in the MIE register is enabled. - - MRV_enable_local_irq(MRV32_SOFT_IRQn | - MRV32_TIMER_IRQn | - MRV32_EXT_IRQn | - MRV32_MSYS_EIE0_IRQn | - MRV32_MSYS_OPSRV_IRQn); + The MRV_disable_interrupts() function disables all interrupts by clearing the + machine mode interrupt enable bit in MSTATUS register. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. */ -static inline void MRV_enable_local_irq(uint32_t mask) +static inline void MRV_disable_interrupts(void) { - set_csr(mie, mask); + clear_csr(mstatus, MSTATUS_MPIE); + clear_csr(mstatus, MSTATUS_MIE); } /***************************************************************************//** - * Disable interrupts. - This function takes a mask value as input. For each set bit in the mask value, - corresponding interrupt bit in the MIE register is disabled. + The MRV_read_mtvec_base() function reads the mtvec base value, which is the + addr used when an interrupt/trap occurs. In the mtvec register, [31:2] is the + BASE address. NOTE: The BASE address must be aligned on a 4B boundary. - MRV_disable_local_irq(MRV32_SOFT_IRQn | - MRV32_TIMER_IRQn | - MRV32_EXT_IRQn | - MRV32_MSYS_EIE0_IRQn | - MRV32_MSYS_OPSRV_IRQn); + @param + The function does not take any parameters. + + @return + The function returns the value of the BASE field [31:2] as an unsigned 32-bit + value. */ -static inline void MRV_disable_local_irq(uint32_t mask) + +#ifndef MIV_LEGACY_RV32 +#ifndef MIV_RV32_v3_0 +static inline uint32_t MRV_read_mtvec_base (void) { - clear_csr(mie, mask); + uint32_t mtvec_addr_base = read_csr(mtvec); + return mtvec_addr_base & MTVEC_BASE_ADDR_MASK; } -#endif /* MIV_LEGACY_RV32 */ +/***************************************************************************//** + The MRV_set_mtvec_base() function takes the mtvec_base address as a unsigned int + and writes the value into the BASE field [31:2] in the mtvec CSR, MODE[1:0] + is Read-only. BASE is 4B aligned, so the lowest 2 bits of mtvec_base are + ignored. + + @param mtvec_base + Any legal value is passed into the function, and it is used as the trap_entry + for interrupts. The PC jumps to this address provided when an interrupt occurs. + In case of vectored interrupts, the address value mentioned in the vector + table under the MIE Register Map is updated to the value passed to this + function parameter. + + @return + This function does not return any value. + */ +static inline void MRV_set_mtvec_base (uint32_t mtvec_base) +{ + mtvec_base = mtvec_base & MTVEC_BASE_ADDR_MASK; + write_csr(mtvec, mtvec_base); +} +#endif /*MIV_RV32_v3_0*/ +#endif /*MIV_LEGACY_RV32*/ + +/***************************************************************************//** + The MRV_read_mtime() function returns the current MTIME register value. + */ +static inline uint64_t MRV_read_mtime(void) +{ + volatile uint32_t hi = 0u; + volatile uint32_t lo = 0u; + + /* when mtime lower word is 0xFFFFFFFF, there will be rollover and + * returned value could be wrong. */ + do { + hi = MTIMEH; + lo = MTIME; + } while(hi != MTIMEH); + + return((((uint64_t)MTIMEH) << 32u) | lo); +} /***************************************************************************//** - * The function MRV_raise_soft_irq() raises a synchronous software interrupt - * by writing into the MSIP register. + The MRV_raise_soft_irq() function raises a synchronous software interrupt + by writing into the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. */ static inline void MRV_raise_soft_irq(void) { @@ -468,13 +731,18 @@ static inline void MRV_raise_soft_irq(void) MSIP = 0x01; /* raise soft interrupt */ #else /* Raise soft IRQ on MIV_RV32 processor */ - OPSRV->soft_reg |= (1u << 1u); + SUBSYS->soft_reg |= SUBSYS_SOFT_IRQ; #endif } /***************************************************************************//** - * The function MRV_clear_soft_irq() clears a synchronous software interrupt - * by clearing the MSIP register. + The MRV_clear_soft_irq() function clears a synchronous software interrupt + by clearing the MSIP register. + @param + This function does not take any parameters. + + @return + This function does not return any value. */ static inline void MRV_clear_soft_irq(void) { @@ -482,50 +750,42 @@ static inline void MRV_clear_soft_irq(void) MSIP = 0x00u; /* clear soft interrupt */ #else /* Clear soft IRQ on MIV_RV32 processor */ - OPSRV->soft_reg &= ~(1u << 1u); + SUBSYS->soft_reg &= ~SUBSYS_SOFT_IRQ; #endif } /***************************************************************************//** - * The function MRV_enable_interrupts() enables all interrupts setting the - * machine mode interrupt enable bit in MSTATUS register. - */ -static inline void MRV_enable_interrupts(void) -{ - set_csr(mstatus, MSTATUS_MIE); -} - -/***************************************************************************//** - * The function MRV_disable_interrupts() disables all interrupts clearing the - * machine mode interrupt enable bit in MSTATUS register. + System tick handler. This handler function gets called when the Machine + timer interrupt asserts. An implementation of this function must be provided + by the application to implement the application specific machine timer + interrupt handling. If application does not provide such implementation, the + weakly linked handler stub function implemented in riscv_hal_stubs.c gets + linked. */ -static inline void MRV_disable_interrupts(void) -{ - clear_csr(mstatus, MSTATUS_MPIE); - clear_csr(mstatus, MSTATUS_MIE); -} +void SysTick_Handler(void); /***************************************************************************//** - * The function MRV_read_mtime() returns the current MTIME register value. + System timer tick configuration. + Configures the machine timer to generate a system tick interrupt at regular + intervals. Takes the number of system clock ticks between interrupts. + + Though this function can take any valid ticks value as parameter, we expect + that, for all practical purposes, a small tick value (to generate periodic + interrupts every few miliseconds) is passed. If you need to generate periodic + events in the range of seconds or more, you may use the SysTick_Handler() to + further count the number of interrupts and hence the larger time intervals. + + @param ticks + This is the number of ticks or clock cycles which are counted down from the + interrupt to be triggered. + + @return + Returns 0 if successful. + Returns 1 if the interrupt interval is not achieved. */ -static inline uint64_t MRV_read_mtime(void) -{ - volatile uint32_t hi = 0u; - volatile uint32_t lo = 0u; - - /* when mtime lower word is 0xFFFFFFFF, there will be rollover and - * returned value could be wrong. */ - do { - hi = MTIMEH; - lo = MTIME; - } while(hi != MTIMEH); - - return((((uint64_t)MTIMEH) << 32u) | lo); -} +uint32_t MRV_systick_config(uint64_t ticks); #ifdef __cplusplus } #endif - -#endif /* RISCV_HAL_H */ - +#endif /* RISCV_HAL_H */ \ No newline at end of file diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_plic.h b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_plic.h index e3b1401..1e250f2 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_plic.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_plic.h @@ -27,7 +27,7 @@ extern "C" { #ifdef MIV_LEGACY_RV32 typedef enum { - NoInterrupt_IRQn = 0, + MRV_NoInterrupt_IRQn = 0, External_1_IRQn = 1, External_2_IRQn = 2, External_3_IRQn = 3, @@ -73,12 +73,12 @@ typedef struct volatile uint32_t PRIORITY_THRESHOLD; volatile uint32_t CLAIM_COMPLETE; volatile uint32_t reserved[1022]; -} IRQ_Target_Type; +} MRV_IRQ_Target_Type; typedef struct { volatile uint32_t ENABLES[32]; -} Target_Enables_Type; +} MRV_Target_Enables_Type; typedef struct { @@ -90,12 +90,12 @@ typedef struct volatile uint32_t RESERVED1[992]; /*-------------------- Target enables --------------------*/ - volatile Target_Enables_Type TARGET_ENABLES[15808]; + volatile MRV_Target_Enables_Type TARGET_ENABLES[15808]; volatile uint32_t RESERVED2[16384]; /*--- Target Priority threshold and claim/complete---------*/ - IRQ_Target_Type TARGET[15872]; + MRV_IRQ_Target_Type TARGET[15872]; } PLIC_Type; @@ -192,7 +192,7 @@ static inline void MRV_PLIC_clear_pending_irq(void) volatile uint32_t int_num = PLIC->TARGET[hart_id].CLAIM_COMPLETE; volatile int32_t wait_possible_int; - while (NoInterrupt_IRQn != int_num) + while (MRV_NoInterrupt_IRQn != int_num) { PLIC->TARGET[hart_id].CLAIM_COMPLETE = int_num; wait_possible_int = 0xFU; diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_regs.h b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_regs.h index 9e21bd7..967f4f2 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_regs.h +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_regs.h @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -8,8 +8,8 @@ * @brief Mi-V soft processor register bit mask and shift constants encodings. * */ -#ifndef RISCV_REGS_H -#define RISCV_REGS_H +#ifndef MIV_RV32_REGS_H +#define MIV_RV32_REGS_H #ifdef __cplusplus extern "C" { @@ -53,30 +53,6 @@ extern "C" { #define MIP_HEIP (1u << IRQ_H_EXT) #define MIP_MEIP (1u << IRQ_M_EXT) -#ifndef MIV_LEGACY_RV32 -#define MGEUI 16U -#define MGECI 17U -#define MSYS_EI0 24U -#define MSYS_EI1 25U -#define MSYS_EI2 26U -#define MSYS_EI3 27U -#define MSYS_EI4 28U -#define MSYS_EI5 29U -#define OPSRV_REG 30U - -#define MGEUI_MEIP (1u << MGEUI) -#define MGECI_MEIP (1u << MGECI) -#define MSYS_EI0IP (1u << MSYS_EI0) -#define MSYS_EI1IP (1u << MSYS_EI1) -#define MSYS_EI2IP (1u << MSYS_EI2) -#define MSYS_EI3IP (1u << MSYS_EI3) -#define MSYS_EI4IP (1u << MSYS_EI4) -#define MSYS_EI5IP (1u << MSYS_EI5) -#define MSYS_EXTERNAL_INT (0x3Fu << MSYS_EI0) -#define MIP_OPSRV_REG (1u << OPSRV_REG) - -#endif /* MIV_LEGACY_RV32 */ - #define PRV_M 3U #define VM_MBARE 0U diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_stubs.c b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_stubs.c index a7a02d0..d300848 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_stubs.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_stubs.c @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright 2019-2022 Microchip FPGA Embedded Systems Solutions. + * Copyright 2019-2023 Microchip FPGA Embedded Systems Solutions. * * SPDX-License-Identifier: MIT * @@ -191,47 +191,51 @@ __attribute__((weak)) uint8_t External_31_IRQHandler(void) } #else - __attribute__((weak)) void External_IRQHandler(void) { } - __attribute__((weak)) void MGECI_IRQHandler(void) { } - __attribute__((weak)) void MGEUI_IRQHandler(void) { } - -__attribute__((weak)) void OPSRV_IRQHandler(void) +__attribute__((weak)) void SUBSYS_IRQHandler(void) { } - -__attribute__((weak)) void MSYS_EI5_IRQHandler(void) +__attribute__((weak)) void MSYS_EI0_IRQHandler(void) { } - -__attribute__((weak)) void MSYS_EI4_IRQHandler(void) +__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI2_IRQHandler(void) { } - __attribute__((weak)) void MSYS_EI3_IRQHandler(void) { } - -__attribute__((weak)) void MSYS_EI2_IRQHandler(void) +__attribute__((weak)) void MSYS_EI4_IRQHandler(void) { } - -__attribute__((weak)) void MSYS_EI1_IRQHandler(void) +__attribute__((weak)) void MSYS_EI5_IRQHandler(void) { } - -__attribute__((weak)) void MSYS_EI0_IRQHandler(void) +__attribute__((weak)) void Reserved_IRQHandler(void) { + _exit(10); } - +#ifndef MIV_RV32_V3_0 /* For MIV_RV32 v3.0 */ +__attribute__((weak)) void MSYS_EI6_IRQHandler(void) +{ +} +__attribute__((weak)) void MSYS_EI7_IRQHandler(void) +{ +} +__attribute__((weak)) void SUBSYSR_IRQHandler(void) +{ +} +#endif /* MIV_RV32_V3_0 */ #endif /* MIV_LEGACY_RV32 */ #ifdef __cplusplus diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_subsys.h b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_subsys.h new file mode 100644 index 0000000..509f13b --- /dev/null +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_subsys.h @@ -0,0 +1,293 @@ +/******************************************************************************* + * Copyright 2023 Microchip FPGA Embedded Systems Solutions. + * + * SPDX-License-Identifier: MIT + * + * @file miv_rv32_subsys.h + * @author Microchip FPGA Embedded Systems Solutions + * @brief Mi-V soft processor SUBSYS regsiter description and API fuctions. + * + */ +#ifndef MIV_RV32_SUBSYS_H +#define MIV_RV32_SUBSYS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MIV_LEGACY_RV32 +#define MGEUI 16U +#define MGECI 17U +#define MSYS_EI0 24U +#define MSYS_EI1 25U +#define MSYS_EI2 26U +#define MSYS_EI3 27U +#define MSYS_EI4 28U +#define MSYS_EI5 29U + +#define MGEUI_MEIP (1u << MGEUI) +#define MGECI_MEIP (1u << MGECI) +#define MSYS_EI0IP (1u << MSYS_EI0) +#define MSYS_EI1IP (1u << MSYS_EI1) +#define MSYS_EI2IP (1u << MSYS_EI2) +#define MSYS_EI3IP (1u << MSYS_EI3) +#define MSYS_EI4IP (1u << MSYS_EI4) +#define MSYS_EI5IP (1u << MSYS_EI5) + +#define MIV_LOCAL_IRQ_MIN 16 +#ifndef MIV_RV32_V3_0 /*For MIV_RV32 v3.1*/ +#define SUBSYSR 22U +#define SUBSYS_EI 23U +#define MSYS_EI6 30U +#define MSYS_EI7 31U +#define MIV_SUBSYSR (1u << SUBSYSR) +#define MIV_SUBSYS (1u << SUBSYS_EI) +#define MSYS_EI6IP (1u << MSYS_EI6) +#define MSYS_EI7IP (1u << MSYS_EI7) +#define MIV_LOCAL_IRQ_MAX 31 + +#else /* MIV_RV32_V3_0 */ +#define MIV_LOCAL_IRQ_MAX 29 +#define SUBSYS_EI 30U +#define MIP_SUBSYS_REG (1u << SUBSYS_EI) + +#endif /* MIV_RV32_V3_0 */ +#endif /* MIV_LEGACY_RV32 */ + +#ifdef MIV_LEGACY_RV32 +#define MIV_LOCAL_IRQ_MAX 0U +#define MIV_LOCAL_IRQ_MIN 0U +#endif /* MIV_LEGACY_RV32 */ + +#ifdef __cplusplus +} +#endif + +/*-------------------------------------------------------------------------*//** + SUBSYS Register Configuration + ======================================= + For the SUBSYS registers configutation, the following definitions are used in + the SUBSUS API functions. For example, to raise soft interrupts, enable parity + checks, soft reset, and so on. + + | Configuration | Value | Description | + |--------------------------|-------|------------------------------------------------| + | SUBSYS_SOFT_REG_GRP_DED | 0x04 | Mask for the Core GPR DED Reset Register | + | SUBSYS_CFG_PARITY_CHECK | 0x01 | Use to set or clear the parity check on the TCM | + | SUBSYS_SOFT_RESET | 0x01 | Use the SUBSYS soft reset the MIV_RV32 IP core | + | SUBSYS_SOFT_IRQ | 0x02 | Use to raise a software interrupt through SUBSYS| + */ +/*Mask for the Core GPR DED Reset Register*/ +#define SUBSYS_SOFT_REG_GRP_DED 0x04U + +/*Use to set or clear the parity check on the TCM*/ +#define SUBSYS_CFG_PARITY_CHECK 0x01U + +/*Use the SUBSYS soft reset the MIV_RV32 IP core*/ +#define SUBSYS_SOFT_RESET 0x01U + +/*Use to raise a software interrupt through SUBSYS*/ +#define SUBSYS_SOFT_IRQ 0x02U + +/*-------------------------------------------------------------------------*//** + SUBSYS Interrupt Request Masks + ======================================= + The following values correspond to the bit value of the SUBSYS interrupt + enable and interrupt pending register. + + | Interrupt Mask | Value | Description | + |----------------------------|---------|-------------------------------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | TCM ECC controllable error irq enable | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | TCM ECC uncontrollable error irq enable | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | AXI write response error irq enable | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | Icache ECC Correctable error irq | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | Icache ECC Uncorrectable error irq | + | SUBSYS_BASE_ADDR | 0x6000u | Base address of the SUBSYS | + */ +/* TCM ECC correctable error irq enable mask value */ +#define SUBSYS_TCM_ECC_CE_IRQ 0x01u + +/* TCMECC uncorrectable error irq enable */ +#define SUBSYS_TCM_ECC_UCE_IRQ 0x02u + +/* AXI write response error irq enable */ +#define SUBSYS_AXI_WR_RESP_IRQ 0x10u + +/*Icache ECC Correctable error irq*/ +#define SUBSYS_ICACHE_ECC_CE_IRQ 0x40u + +/*Icache ECC Uncorrectable error irq*/ +#define SUBSYS_ICACHE_ECC_UCE_IRQ 0x80u + +/*Base address of the SUBSYS*/ +#define SUBSYS_BASE_ADDR 0x00006000UL + +/***************************************************************************//** + Subsys contains interrupt enable, interrupt pending and Subsys registers + which can be used to enable SUBSYS specific features such as ECC for vaious + memories. For more available features refer to the MIV_RV32 User Guide +*/ +typedef struct +{ + volatile uint32_t cfg; /*Parity is not supported by MIV_RV32 v3.1 and MIV_RV32 v3.0.100*/ + volatile uint32_t reserved0[3]; + volatile uint32_t irq_en; /*offset 0x10*/ + volatile uint32_t irq_pend; + volatile uint32_t reserved1[2]; + volatile uint32_t soft_reg; /*offset 0x20*/ +} SUBSYS_Type; + +#define SUBSYS ((SUBSYS_Type *)SUBSYS_BASE_ADDR) + +/***************************************************************************//** + The MRV32_subsys_enable_irq() function initializes the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to enable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_enable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_disable_irq() function disables the SUBSYS interrupts. It + takes the logical OR of the following defined IRQ masks as a parameter. + + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_disable_irq(uint32_t irq_mask) +{ + SUBSYS->irq_en &= ~irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_clear_irq() function clears the SUBSYS interrupts, which was + triggered. It takes the logical OR of the following defined IRQ masks as a + parameter. + @param irq_mask + | irq_mask | Value | + |------------------------|------------| + | SUBSYS_TCM_ECC_CE_IRQ | 0x01u | + | SUBSYS_TCM_ECC_UCE_IRQ | 0x02u | + | SUBSYS_AXI_WR_RESP_IRQ | 0x10u | + | SUBSYS_ICACHE_ECC_CE_IRQ | 0x40u | + | SUBSYS_ICACHE_ECC_UCE_IRQ | 0x80u | + Use logical OR values of one or more interrupts to disable them in the SUBSYS + @return + This function does not return any value. + */ +static inline void MRV32_subsys_clear_irq(uint32_t irq_mask) +{ + SUBSYS->irq_pend |= irq_mask; +} + +/***************************************************************************//** + The MRV32_subsys_irq_cause() function returns the irq_pend register value which + is present in the SUBSYS. This is be used to check which irq_mask value + caused the SUBSYS interrupt to occur. + @param + This function does not take any parameters + + @return + This function returns the irq_pend regsiter value. +*/ +static inline uint32_t MRV32_subsys_irq_cause() +{ + return SUBSYS->irq_pend; +} + +/***************************************************************************//** + The MRV32_is_gpr_ded() function returns the core_gpr_ded_reset_reg bit value. + When ECC is enabled, the core_gpr_ded_reset_reg is set when the core was + reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This functions returns the CORE_GPR_DED_RESET_REG bit value. + */ +static inline uint32_t MRV32_is_gpr_ded(void) +{ + return((SUBSYS->soft_reg & SUBSYS_SOFT_REG_GRP_DED) >> 0x02u); +} + +/***************************************************************************//** + The MRV32_clear_gpr_ded() function must be used to clear the + core_gpr_ded_reset_reg bit. When ECC is enabled, the core_gpr_ded_reset_reg is + set when the core was previously reset due to GPR DED error. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_clear_gpr_ded(void) +{ + SUBSYS->soft_reg &= ~SUBSYS_SOFT_REG_GRP_DED; +} + +/***************************************************************************//** + The MRV32_enable_parity_check() function is used to enable parity check on + the TCM and it's interface transactions. This feature is not available on + MIV_RV32 v3.1 and MIV_RV32 v3.0.100 + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_enable_parity_check(void) +{ + SUBSYS->cfg |= SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_disable_parity_check() function is used to disable parity check on + the TCM and it's interface transactions. + @param + This function does not take any parameters + + @return + This function does not return any value. + + */ +static inline void MRV32_disable_parity_check(void) +{ + SUBSYS->cfg &= ~SUBSYS_CFG_PARITY_CHECK; +} + +/***************************************************************************//** + The MRV32_cpu_soft_reset() function is used to cause a soft cpu reset on + the MIV_RV32 soft processor core. + @param + This function does not take any parameters. + + @return + This function does not return any value. + */ +static inline void MRV32_cpu_soft_reset(void) +{ + SUBSYS->soft_reg |= SUBSYS_SOFT_RESET; +} +#endif /* MIV_RV32_SUBSYS_H */ \ No newline at end of file diff --git a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_syscall.c b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_syscall.c index 98e0036..c767ab4 100644 --- a/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_syscall.c +++ b/bootloaders/miv-rv32-bootloader/src/platform/miv_rv32_hal/miv_rv32_syscall.c @@ -18,7 +18,7 @@ #include #ifndef LEGACY_DIR_STRUCTURE -#include "drivers/fabric_ip/CoreUARTapb/core_uart_apb.h" +#include "drivers/fpga_ip/CoreUARTapb/core_uart_apb.h" #else #include "core_uart_apb.h" #endif