diff --git a/cmsis/device/rtos/mbed_lib.json b/cmsis/device/rtos/mbed_lib.json index 6ef6c49..46bc00c 100644 --- a/cmsis/device/rtos/mbed_lib.json +++ b/cmsis/device/rtos/mbed_lib.json @@ -84,6 +84,12 @@ }, "MCU_PSOC6_M4": { "target.macros_add": ["CY_RTOS_AWARE"] + }, + "ARM_MUSCA_S1": { + "mutex-num": 4, + "semaphore-num": 4, + "thread-num": 9, + "thread-user-stack-size": 8096 } } } diff --git a/platform/mbed_lib.json b/platform/mbed_lib.json index 8c1b1c9..c08a433 100644 --- a/platform/mbed_lib.json +++ b/platform/mbed_lib.json @@ -230,6 +230,10 @@ "NUCLEO_L452RE-P": { "crash-capture-enabled": true, "fatal-error-auto-reboot-enabled": true + }, + "ARM_MUSCA_S1": { + "stdio-convert-newlines": true, + "stdio-baud-rate": 115200 } } } diff --git a/storage/kvstore/kv_config/global/mbed_lib.json b/storage/kvstore/kv_config/global/mbed_lib.json index 173a742..b15e4bf 100644 --- a/storage/kvstore/kv_config/global/mbed_lib.json +++ b/storage/kvstore/kv_config/global/mbed_lib.json @@ -43,6 +43,9 @@ }, "ARM_MUSCA_B1_S": { "storage_type": "TDB_INTERNAL" + }, + "ARM_MUSCA_S1_S": { + "storage_type": "TDB_INTERNAL" } } } diff --git a/storage/kvstore/kv_config/tdb_internal/mbed_lib.json b/storage/kvstore/kv_config/tdb_internal/mbed_lib.json index ec7ee1b..42518aa 100644 --- a/storage/kvstore/kv_config/tdb_internal/mbed_lib.json +++ b/storage/kvstore/kv_config/tdb_internal/mbed_lib.json @@ -31,6 +31,10 @@ "internal_size": "0x8000", "internal_base_address": "0x10000000" }, + "ARM_MUSCA_S1_S": { + "internal_size": "0x8000", + "internal_base_address": "0x1A1CA000" + }, "FVP_MPS2": { "internal_size": "0x200000", "internal_base_address": "0x00200000" diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/LICENSE b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/LICENSE new file mode 100644 index 0000000..d859683 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/LICENSE @@ -0,0 +1,2 @@ +Unless specifically indicated otherwise in a file, MUSCA_S1 files in this directory are licensed under the BSD-3-Clause license, +as can be found in: LICENSE-bsd-3-clause.txt diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/LICENSE-BSD-3-Clause b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/LICENSE-BSD-3-Clause new file mode 100644 index 0000000..2c212cc --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/LICENSE-BSD-3-Clause @@ -0,0 +1,26 @@ +Copyright 2019-2020 Arm Limited and affiliates. +SPDX-License-Identifier: BSD-3-Clause + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/LICENSE-permissive-binary-license-1.0.txt b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/LICENSE-permissive-binary-license-1.0.txt new file mode 100644 index 0000000..92d2328 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/LICENSE-permissive-binary-license-1.0.txt @@ -0,0 +1,49 @@ +Permissive Binary License + +Version 1.0, December 2020 + +Redistribution. Redistribution and use in binary form, without +modification, are permitted provided that the following conditions are +met: + +1) Redistributions must reproduce the above copyright notice and the + following disclaimer in the documentation and/or other materials + provided with the distribution. + +2) Unless to the extent explicitly permitted by law, no reverse + engineering, decompilation, or disassembly of this software is + permitted. + +3) Redistribution as part of a software development kit must include the + accompanying file named DEPENDENCIES and any dependencies listed in + that file. + +4) Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +Limited patent license. The copyright holders (and contributors) grant a +worldwide, non-exclusive, no-charge, royalty-free patent license to +make, have made, use, offer to sell, sell, import, and otherwise +transfer this software, where such license applies only to those patent +claims licensable by the copyright holders (and contributors) that are +necessarily infringed by this software. This patent license shall not +apply to any combinations that include this software. No hardware is +licensed hereunder. + +If you institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the software +itself infringes your patent(s), then your rights granted under this +license shall terminate as of the date such litigation is filed. + +DISCLAIMER. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND +CONTRIBUTORS "AS IS." ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT +NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/Libraries/mt25ql_flash_lib.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/Libraries/mt25ql_flash_lib.c new file mode 100644 index 0000000..3b57c6c --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/Libraries/mt25ql_flash_lib.c @@ -0,0 +1,903 @@ +/* + * Copyright (c) 2018-2019 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +/* Use memcpy function */ +#include + +#include "mt25ql_flash_lib.h" +#include "qspi_ip6514e_drv.h" + +/** Setter bit manipulation macro */ +#define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX))) +/** Clearing bit manipulation macro */ +#define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX))) +/** Getter bit manipulation macro */ +#define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX)))) + +#define BITS_PER_WORD 32U +#define BYTES_PER_WORD 4U + +#define ARG_NOT_USED 0 +#define ARG_PTR_NOT_USED NULL + +/** MT25QL used command */ +#define WRITE_ENABLE_CMD 0x06U +#define READ_ENHANCED_VOLATILE_CFG_REG_CMD 0x65U +#define WRITE_ENHANCED_VOLATILE_CFG_REG_CMD 0x61U +#define READ_VOLATILE_CFG_REG_CMD 0x85U +#define WRITE_VOLATILE_CFG_REG_CMD 0x81U +#define READ_FLAG_STATUS_REG_CMD 0x70U +#define SUBSECTOR_ERASE_32KB_CMD 0x52U +#define SUBSECTOR_ERASE_4KB_CMD 0x20U +#define SECTOR_ERASE_CMD 0xD8U +#define BULK_ERASE_CMD 0xC7U +/* + * The baud rate divisor in \ref mt25ql_dev_t needs to be configured adequately + * to handle those commands. + */ +#define QUAD_OUTPUT_FAST_READ_CMD 0x6BU +#define FAST_READ_CMD 0x0BU +#define READ_CMD 0x03U +#define QUAD_INPUT_FAST_PROGRAM_CMD 0x32U +#define PAGE_PROGRAM_CMD 0x02U + +/** MT25QL Enhanced Volatile Configuration Register access */ +#define ENHANCED_VOLATILE_CFG_REG_LEN 1U +#define ENHANCED_VOLATILE_CFG_REG_QSPI_POS 7U +#define ENHANCED_VOLATILE_CFG_REG_DSPI_POS 6U + +/** MT25QL Volatile Configuration Register access */ +#define VOLATILE_CFG_REG_LEN 1U +#define VOLATILE_CFG_REG_DUMMY_CYCLES_POS 4U +#define VOLATILE_CFG_REG_DUMMY_CYCLES_BITS 4U + +/** MT25QL Flag Status Register access */ +#define FLAG_STATUS_REG_LEN 1U +#define FLAG_STATUS_REG_READY_POS 7U + +/* + * 10 is the minimal number of dummy clock cycles needed to reach the maximal + * frequency of the Quad Output Fast Read Command. + */ +#define QUAD_OUTPUT_FAST_READ_DUMMY_CYCLES 10U +#define FAST_READ_DUMMY_CYCLES 8U +#define RESET_STATE_DUMMY_CYCLES 8U +#define DEFAULT_READ_DUMMY_CYCLES 0U +#define QUAD_INPUT_FAST_PROGRAM_DUMMY_CYCLES 0U +#define PAGE_PROGRAM_DUMMY_CYCLES 0U + +/* Only up to 8 bytes can be read or written using the Flash commands. */ +#define CMD_DATA_MAX_SIZE 8U + +/** + * \brief Change specific bits in a 32 bits word. + * + * \param[in,out] word Pointer of the word to change + * \param[in] bits bits_length bits to put at bits_pos in the word + * pointed + * \param[in] bits_length Number of bits to change + * \param[in] bits_pos Position of the bits to change + * + * \note This function will do nothing if the parameters given are incorrect: + * * word is NULL + * * bits_length + bits_pos > 32 + * * bits_length is 0 + */ +static void change_bits_in_word(volatile uint32_t *word, + uint32_t bits, + uint32_t bits_length, + uint32_t bits_pos) +{ + uint32_t mask; + + if ((word == NULL) || + ((bits_length + bits_pos) > BITS_PER_WORD) || + (bits_length == 0U)) { + /* Silently fail */ + return; + } + + /* Change all the bits */ + if (bits_length == BITS_PER_WORD) { + *word = bits; + return; + } + + mask = ((1U << bits_length) - 1); + /* + * We change the bits in three steps: + * - clear bits_length bits with zeroes at bits_pos in the word + * - mask bits in case it contains more than bits_length bits + * - set the new bits in the cleared word + * Because the data pointed by word is only read once, the data will still + * be coherent after an interruption that changes it. + */ + *word = ((*word & ~(mask << bits_pos)) | ((bits & mask) << bits_pos)); +} + +/** + * \brief Send the Write Enable command, needed before any write. + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + */ +static void send_write_enable(struct mt25ql_dev_t* dev) +{ + qspi_ip6514e_send_simple_cmd(dev->controller, WRITE_ENABLE_CMD); +} + +/** + * \brief Set SPI mode on the flash device and on the controller. + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * \param[in] spi_mode SPI mode to be set on flash device and controller + * \ref qspi_ip6514e_spi_mode_t + * + * \return Return error code as specified in \ref mt25ql_error_t + */ +static enum mt25ql_error_t set_spi_mode(struct mt25ql_dev_t* dev, + enum qspi_ip6514e_spi_mode_t spi_mode) +{ + uint8_t enhanced_volatile_cfg_reg = 0; + enum qspi_ip6514e_error_t controller_error; + + /* Read the Enhanced Volatile Configuration Register, modify it according + * to the requested SPI mode then write back the modified value to the + * register. This will activate the SPI mode on the flash side. + */ + controller_error = qspi_ip6514e_send_read_cmd( + dev->controller, + READ_ENHANCED_VOLATILE_CFG_REG_CMD, + &enhanced_volatile_cfg_reg, + ENHANCED_VOLATILE_CFG_REG_LEN, + ARG_NOT_USED, + ARG_NOT_USED, + 0); /* No dummy cycles needed for + this command. */ + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + switch(spi_mode) { + case QSPI_IP6514E_SPI_MODE: + /* Disable the Dual- and Quad-SPI modes. + * Clearing the bit enables the mode, setting it disables it. + */ + SET_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_DSPI_POS); + SET_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_QSPI_POS); + break; + case QSPI_IP6514E_DSPI_MODE: + /* Disable the Quad-SPI mode and activate DSPI mode. + * Clearing the bit enables the mode, setting it disables it. + */ + CLR_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_DSPI_POS); + SET_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_QSPI_POS); + break; + case QSPI_IP6514E_QSPI_MODE: + /* Disable the Dual-SPI mode and activate QSPI mode. + * Clearing the bit enables the mode, setting it disables it. + */ + SET_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_DSPI_POS); + CLR_BIT(enhanced_volatile_cfg_reg, ENHANCED_VOLATILE_CFG_REG_QSPI_POS); + break; + default: + return MT25QL_ERR_WRONG_ARGUMENT; + } + + send_write_enable(dev); + + controller_error = qspi_ip6514e_send_write_cmd( + dev->controller, + WRITE_ENHANCED_VOLATILE_CFG_REG_CMD, + &enhanced_volatile_cfg_reg, + ENHANCED_VOLATILE_CFG_REG_LEN, + ARG_NOT_USED, + ARG_NOT_USED, + 0); /* No dummy cycles needed for + this command. */ + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + /* Activate the requested SPI mode on the controller side as well. */ + controller_error = qspi_ip6514e_set_spi_mode(dev->controller, + spi_mode, + spi_mode, + spi_mode); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + return MT25QL_ERR_NONE; +} + +/** + * \brief Change the number of dummy clock cycles subsequent to all FAST READ + * commands. + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * \param[in] dummy_cycles Dummy clock cycles to set + * + * \return Return error code as specified in \ref mt25ql_error_t + */ +static enum mt25ql_error_t change_dummy_cycles(struct mt25ql_dev_t* dev, + uint32_t dummy_cycles) +{ + uint32_t volatile_cfg_reg = 0; + enum qspi_ip6514e_error_t controller_error; + + /* + * Changes the number of dummy cycles in the Volatile Configuration + * Register. + */ + controller_error = qspi_ip6514e_send_read_cmd(dev->controller, + READ_VOLATILE_CFG_REG_CMD, + &volatile_cfg_reg, + VOLATILE_CFG_REG_LEN, + ARG_NOT_USED, + ARG_NOT_USED, + 0); /* No dummy cycles needed + for this command. */ + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + change_bits_in_word(&volatile_cfg_reg, + dummy_cycles, + VOLATILE_CFG_REG_DUMMY_CYCLES_BITS, + VOLATILE_CFG_REG_DUMMY_CYCLES_POS); + + send_write_enable(dev); + + controller_error = qspi_ip6514e_send_write_cmd(dev->controller, + WRITE_VOLATILE_CFG_REG_CMD, + &volatile_cfg_reg, + VOLATILE_CFG_REG_LEN, + ARG_NOT_USED, + ARG_NOT_USED, + 0); /* No dummy cycles needed + for this command. */ + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + return MT25QL_ERR_NONE; +} + +/** + * \brief Wait until the current program/erase is finished. + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * + * \return Return error code as specified in \ref mt25ql_error_t + */ +static enum mt25ql_error_t wait_program_or_erase_complete( + struct mt25ql_dev_t* dev) +{ + enum qspi_ip6514e_error_t controller_error; + uint8_t flag_status_reg = 0; + + /* Wait until the ready bit of the Flag Status Register is set */ + while (!GET_BIT(flag_status_reg, FLAG_STATUS_REG_READY_POS)) { + controller_error = qspi_ip6514e_send_read_cmd(dev->controller, + READ_FLAG_STATUS_REG_CMD, + &flag_status_reg, + FLAG_STATUS_REG_LEN, + ARG_NOT_USED, + ARG_NOT_USED, + 0); /* No dummy cycles + needed for this + command. */ + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + } + + return MT25QL_ERR_NONE; +} + +/** + * \brief Execute a program command that crosses the page size boundary. + * + * \param[in] dev Pointer to MT25QL device structure + * \ref mt25ql_dev_t + * \param[in] opcode Opcode for the command. + * \param[in] write_data Pointer to a memory zone where the write_len + * number of bytes are located to write for this + * command. + * \param[in] write_len Number of bytes to write for the command. + * Between 1 and 8 bytes (both included) can be + * written. + * \param[in] addr Address used for the command + * \param[in] addr_bytes_number Number of address bytes for this command. + * If an address is not needed for the command, + * use 0 for argument, otherwise between 1 and + * 4 bytes (both included) can be used. + * \param[in] dummy_cycles Number of dummy cycles required for the + * command, between 0 and 31 (both included). + * + * \return Return error code as specified in \ref mt25ql_error_t + * + * \note This function will execute two commands: one to program the bytes up to + * the page boundary and another one to program the rest. It will wait + * that bytes are programmed from first command before triggering the + * second one. + * \note This function does not send a write enable command before the first + * command and does not check that bytes were programmed after the second + * command. + */ +static enum mt25ql_error_t send_boundary_cross_write_cmd( + struct mt25ql_dev_t* dev, + uint8_t opcode, + const void *write_data, + uint32_t write_len, + uint32_t addr, + uint32_t addr_bytes_number, + uint32_t dummy_cycles) +{ + enum qspi_ip6514e_error_t controller_error; + enum mt25ql_error_t library_error; + /* + * Remaining bytes between the current address and the end of the current + * page. + */ + uint32_t page_remainder = FLASH_PAGE_SIZE - (addr % FLASH_PAGE_SIZE); + + /* First write up to the end of the current page. */ + controller_error = qspi_ip6514e_send_write_cmd(dev->controller, opcode, + write_data, page_remainder, + addr, addr_bytes_number, + dummy_cycles); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + write_data = (void *)((uint32_t)write_data + page_remainder); + addr += page_remainder; + + /* Wait for the page to be written before sending new commands. */ + library_error = wait_program_or_erase_complete(dev); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + + /* Then write the remaining data of the write_len bytes. */ + send_write_enable(dev); + controller_error = qspi_ip6514e_send_write_cmd(dev->controller, opcode, + write_data, + write_len - page_remainder, + addr, addr_bytes_number, + dummy_cycles); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + return MT25QL_ERR_NONE; +} + +enum mt25ql_error_t mt25ql_config_mode(struct mt25ql_dev_t* dev, + enum mt25ql_functional_state_t f_state) +{ + enum qspi_ip6514e_error_t controller_error; + enum mt25ql_error_t library_error; + + switch(f_state) { + case MT25QL_FUNC_STATE_DEFAULT: + dev->config_state.spi_mode = QSPI_IP6514E_SPI_MODE; + dev->config_state.opcode_read = READ_CMD; + dev->config_state.dummy_cycles_read = DEFAULT_READ_DUMMY_CYCLES; + dev->config_state.opcode_write = PAGE_PROGRAM_CMD; + dev->config_state.dummy_cycles_write = PAGE_PROGRAM_DUMMY_CYCLES; + break; + case MT25QL_FUNC_STATE_FAST: + dev->config_state.spi_mode = QSPI_IP6514E_SPI_MODE; + dev->config_state.opcode_read = FAST_READ_CMD; + dev->config_state.dummy_cycles_read = FAST_READ_DUMMY_CYCLES; + dev->config_state.opcode_write = PAGE_PROGRAM_CMD; + dev->config_state.dummy_cycles_write = PAGE_PROGRAM_DUMMY_CYCLES; + break; + case MT25QL_FUNC_STATE_QUAD_FAST: + dev->config_state.spi_mode = QSPI_IP6514E_QSPI_MODE; + dev->config_state.opcode_read = QUAD_OUTPUT_FAST_READ_CMD; + dev->config_state.dummy_cycles_read = + QUAD_OUTPUT_FAST_READ_DUMMY_CYCLES; + dev->config_state.opcode_write = QUAD_INPUT_FAST_PROGRAM_CMD; + dev->config_state.dummy_cycles_write = + QUAD_INPUT_FAST_PROGRAM_DUMMY_CYCLES; + break; + default: + return MT25QL_ERR_WRONG_ARGUMENT; + } + + dev->config_state.func_state = f_state; + + /* This function will first set the Flash memory SPI mode and then set + * the controller's SPI mode. It will fail if the two sides do not have + * the same mode when this function is called. + */ + library_error = set_spi_mode(dev, dev->config_state.spi_mode); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + + /* Set the number of dummy cycles for read commands. */ + library_error = change_dummy_cycles( + dev, dev->config_state.dummy_cycles_read); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + + /* The rest of the configuration needs the controller to be disabled */ + while(!qspi_ip6514e_is_idle(dev->controller)); + qspi_ip6514e_disable(dev->controller); + + /* Set the baud rate divisor as configured in the device structure. */ + controller_error = qspi_ip6514e_set_baud_rate_div(dev->controller, + dev->baud_rate_div); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + /* Set opcode and dummy cycles needed for read commands. */ + controller_error = qspi_ip6514e_cfg_reads( + dev->controller, dev->config_state.opcode_read, + dev->config_state.dummy_cycles_read); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + /* Set opcode and dummy cycles needed for write commands. */ + controller_error = qspi_ip6514e_cfg_writes( + dev->controller, dev->config_state.opcode_write, + dev->config_state.dummy_cycles_write); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + /* Set Flash memory constants: bytes per page and address bytes. */ + controller_error = qspi_ip6514e_cfg_page_size(dev->controller, + FLASH_PAGE_SIZE); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + controller_error = qspi_ip6514e_cfg_addr_bytes(dev->controller, + ADDR_BYTES); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + qspi_ip6514e_enable(dev->controller); + + return MT25QL_ERR_NONE; +} + +enum mt25ql_error_t mt25ql_restore_reset_state(struct mt25ql_dev_t* dev) +{ + enum mt25ql_error_t library_error; + + /* + * This function will first change the Flash memory mode to single SPI and + * then change the controller to single SPI. It will fail if the two sides + * do not have the same mode when this function is called. + */ + library_error = set_spi_mode(dev, QSPI_IP6514E_SPI_MODE); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + + /* Set the default number of dummy cycles for direct read commands. */ + library_error = change_dummy_cycles(dev, RESET_STATE_DUMMY_CYCLES); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + + /* The rest of the configuration needs the controller to be disabled */ + while(!qspi_ip6514e_is_idle(dev->controller)); + qspi_ip6514e_disable(dev->controller); + + /* Restore the default value of the QSPI controller registers. */ + qspi_ip6514e_reset_regs(dev->controller); + + qspi_ip6514e_enable(dev->controller); + + dev->config_state = (struct mt25ql_config_state_t){ 0 }; + dev->config_state.func_state = MT25QL_FUNC_STATE_NOT_INITED; + + return MT25QL_ERR_NONE; +} + +enum mt25ql_error_t mt25ql_direct_read(struct mt25ql_dev_t* dev, + uint32_t addr, + void *data, + uint32_t len) +{ + /* + * The direct access window size is the size of the memory that can be + * accessed with a direct access. + */ + uint32_t direct_access_window_size = dev->controller->cfg->addr_mask + 1; + /* + * The window number is the number of times it will be needed to remap the + * address with the remap register. We move this Direct Access window first + * window_number times starting at the beginning address to read full + * windows of direct_access_window_size bytes. Then we read the remainder + * bytes. + */ + uint32_t window_number = len / direct_access_window_size; + + if (data == NULL || len == 0) { + return MT25QL_ERR_WRONG_ARGUMENT; + } + + if ((addr + len) >= dev->size) { + return MT25QL_ERR_ADDR_TOO_BIG; + } + + /* + * There is no limitation reading through a Flash page boundary hence we + * do not add the same logic here than in the write function. + */ + + /* Transfer the bytes for the window_number windows first. */ + for (uint32_t window = 0; window < window_number; window++) { + qspi_ip6514e_remap_addr(dev->controller, addr); + + /* + * The AHB address to access the Flash memory does not change but it + * will be translated differently thanks to the remap function. + */ + memcpy(data, + (void *)dev->direct_access_start_addr, + direct_access_window_size); + + len -= direct_access_window_size; + data = (void *)((uint32_t)data + direct_access_window_size); + addr += direct_access_window_size; + } + + if (len) { + /* Transfer the reminder bytes */ + qspi_ip6514e_remap_addr(dev->controller, addr); + + memcpy(data, (void *)dev->direct_access_start_addr, len); + } + + /* Disable remapping for direct accesses outside of this function. */ + qspi_ip6514e_disable_remap(dev->controller); + + return MT25QL_ERR_NONE; +} + +enum mt25ql_error_t mt25ql_direct_write(struct mt25ql_dev_t* dev, + uint32_t addr, + const void *data, + uint32_t len) +{ + enum mt25ql_error_t library_error; + /* + * The direct access window size is the size of the memory that can be + * accessed with a direct access. + */ + uint32_t direct_access_window_size = dev->controller->cfg->addr_mask + 1; + uint32_t window_number; + /* Offset between address and the previous 32 bits aligned word */ + uint32_t word_offset; + + if (data == NULL || len == 0) { + return MT25QL_ERR_WRONG_ARGUMENT; + } + + if ((addr + len) >= dev->size) { + return MT25QL_ERR_ADDR_TOO_BIG; + } + + /* + * If the remapping address is not aligned on a 32 bits boundary, a direct + * access of one word could cross a Flash page boundary. If that happens, + * the bytes of that word that are over the page boundary will instead be + * written at the beginning of the same page. + * To counter this problem, we align the remapping address and add the word + * offset to the address of the direct access for the first window only. + */ + word_offset = addr % BYTES_PER_WORD; + /* Make address aligned on a 32 bits alignment. */ + addr -= word_offset; + /* + * Only direct_access_window_size address locations are available by direct + * access. We calculate the number of windows that we will need to transfer + * len bytes. We have to add in the window the offset that we add in the + * beginning. + */ + window_number = (len + word_offset) / direct_access_window_size; + + /* + * This function assumes that the flash has already been erased. + * Transfer the bytes for the window_number windows first. + */ + for (uint32_t window = 0; window < window_number; window++) { + /* The controller needs to be disabled while remapping is done. */ + qspi_ip6514e_remap_addr(dev->controller, addr); + + /* + * The AHB address to access the Flash memory does not change but it + * will be translated differently thanks to the remap function. + */ + memcpy((void *)(dev->direct_access_start_addr + word_offset), + data, + direct_access_window_size - word_offset); + + len -= (direct_access_window_size - word_offset); + data = (void *)((uint32_t)data + + (direct_access_window_size - word_offset)); + addr += direct_access_window_size; + + /* + * The address is now aligned, there is no need to add an offset for the + * remaining windows. + */ + word_offset = 0; + + /* + * Wait until the last program operation is complete before changing + * the remap address. + */ + library_error = wait_program_or_erase_complete(dev); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + } + + if (len) { + /* Transfer the reminder bytes */ + qspi_ip6514e_remap_addr(dev->controller, addr); + + memcpy((void *)(dev->direct_access_start_addr + word_offset), + data, + len); + + /* Wait until the last program operation is complete */ + library_error = wait_program_or_erase_complete(dev); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + } + + /* + * Disable the default remap address for direct accesses outside of this + * function. + */ + qspi_ip6514e_disable_remap(dev->controller); + + return MT25QL_ERR_NONE; +} + +enum mt25ql_error_t mt25ql_command_read(struct mt25ql_dev_t* dev, + uint32_t addr, + void *data, + uint32_t len) +{ + /* With one single command only 8 bytes can be read. */ + uint32_t cmd_number = len / CMD_DATA_MAX_SIZE; + enum qspi_ip6514e_error_t controller_error; + + if (dev->config_state.func_state == MT25QL_FUNC_STATE_NOT_INITED) { + return MT25QL_ERR_NOT_INITED; + } + + for (uint32_t cmd_index = 0; cmd_index < cmd_number; cmd_index++) { + controller_error = qspi_ip6514e_send_read_cmd( + dev->controller, + dev->config_state.opcode_read, + data, CMD_DATA_MAX_SIZE, addr, + ADDR_BYTES, + dev->config_state.dummy_cycles_read); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + data = (void *)((uint32_t)data + CMD_DATA_MAX_SIZE); + addr += CMD_DATA_MAX_SIZE; + len -= CMD_DATA_MAX_SIZE; + } + + if (len) { + /* Read the remainder. */ + controller_error = qspi_ip6514e_send_read_cmd( + dev->controller, + dev->config_state.opcode_read, + data, len, addr, ADDR_BYTES, + dev->config_state.dummy_cycles_read); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + } + + return MT25QL_ERR_NONE; + +} + +enum mt25ql_error_t mt25ql_command_write(struct mt25ql_dev_t* dev, + uint32_t addr, + const void *data, + uint32_t len) +{ + /* With one single command only 8 bytes can be written. */ + uint32_t cmd_number = len / CMD_DATA_MAX_SIZE; + enum qspi_ip6514e_error_t controller_error; + enum mt25ql_error_t library_error; + + if (dev->config_state.func_state == MT25QL_FUNC_STATE_NOT_INITED) { + return MT25QL_ERR_NOT_INITED; + } + + for (uint32_t cmd_index = 0; cmd_index < cmd_number; cmd_index++) { + send_write_enable(dev); + + /* + * Check if this command is not writing over a page boundary: first and + * last bytes are in the same page. + */ + if ((addr / FLASH_PAGE_SIZE) != + ((addr + CMD_DATA_MAX_SIZE - 1) / FLASH_PAGE_SIZE)) { + /* The CMD_DATA_MAX_SIZE bytes written are crossing the boundary. */ + library_error = send_boundary_cross_write_cmd( + dev, dev->config_state.opcode_write, + data, CMD_DATA_MAX_SIZE, addr, + ADDR_BYTES, + dev->config_state.dummy_cycles_write); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + } else { + /* Normal case: not crossing the boundary. */ + controller_error = qspi_ip6514e_send_write_cmd( + dev->controller, + dev->config_state.opcode_write, + data, CMD_DATA_MAX_SIZE, addr, + ADDR_BYTES, + dev->config_state.dummy_cycles_write); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + } + + /* Wait until the write operation is complete. */ + library_error = wait_program_or_erase_complete(dev); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + + data = (void *)((uint32_t)data + CMD_DATA_MAX_SIZE); + addr += CMD_DATA_MAX_SIZE; + len -= CMD_DATA_MAX_SIZE; + } + + if (len) { + /* Write the remainder. */ + send_write_enable(dev); + /* + * Check if this command is not writing over a page boundary: first and + * last bytes are in the same page. + */ + if ((addr / FLASH_PAGE_SIZE) != ((addr + len - 1) / FLASH_PAGE_SIZE)) { + /* The CMD_DATA_MAX_SIZE bytes written are crossing the boundary. */ + library_error = send_boundary_cross_write_cmd( + dev, dev->config_state.opcode_write, + data, len, addr, ADDR_BYTES, + dev->config_state.dummy_cycles_write); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + } else { + /* Normal case: not crossing the boundary. */ + controller_error = qspi_ip6514e_send_write_cmd( + dev->controller, + dev->config_state.opcode_write, + data, len, addr, ADDR_BYTES, + dev->config_state.dummy_cycles_write); + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + } + + /* Wait until the write operation is complete. */ + library_error = wait_program_or_erase_complete(dev); + if (library_error != MT25QL_ERR_NONE) { + return library_error; + } + } + + return MT25QL_ERR_NONE; + +} + +enum mt25ql_error_t mt25ql_erase(struct mt25ql_dev_t* dev, + uint32_t addr, + enum mt25ql_erase_t erase_type) +{ + enum qspi_ip6514e_error_t controller_error; + enum mt25ql_error_t library_error; + uint8_t erase_cmd; + uint32_t addr_bytes; + + if (dev->config_state.func_state == MT25QL_FUNC_STATE_NOT_INITED) { + return MT25QL_ERR_NOT_INITED; + } + + send_write_enable(dev); + + switch (erase_type) { + case MT25QL_ERASE_ALL_FLASH: + if (addr != 0) { + return MT25QL_ERR_ADDR_NOT_ALIGNED; + } + erase_cmd = BULK_ERASE_CMD; + addr_bytes = ARG_NOT_USED; + break; + case MT25QL_ERASE_SECTOR_64K: + erase_cmd = SECTOR_ERASE_CMD; + addr_bytes = ADDR_BYTES; + if ((addr % SECTOR_64KB) != 0) { + return MT25QL_ERR_ADDR_NOT_ALIGNED; + } + break; + case MT25QL_ERASE_SUBSECTOR_32K: + erase_cmd = SUBSECTOR_ERASE_32KB_CMD; + addr_bytes = ADDR_BYTES; + if ((addr % SUBSECTOR_32KB) != 0) { + return MT25QL_ERR_ADDR_NOT_ALIGNED; + } + break; + case MT25QL_ERASE_SUBSECTOR_4K: + erase_cmd = SUBSECTOR_ERASE_4KB_CMD; + addr_bytes = ADDR_BYTES; + if ((addr % SUBSECTOR_4KB) != 0) { + return MT25QL_ERR_ADDR_NOT_ALIGNED; + } + break; + default: + return MT25QL_ERR_WRONG_ARGUMENT; + } + + if (addr >= dev->size) { + return MT25QL_ERR_ADDR_TOO_BIG; + } + + controller_error = qspi_ip6514e_send_cmd(dev->controller, + erase_cmd, + ARG_PTR_NOT_USED, + ARG_NOT_USED, + ARG_PTR_NOT_USED, + ARG_NOT_USED, + addr, + addr_bytes, + 0); /* No dummy cycles needed for + any erase command. */ + if (controller_error != QSPI_IP6514E_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + /* Wait until the erase operation is complete */ + library_error = wait_program_or_erase_complete(dev); + if (library_error != MT25QL_ERR_NONE) { + return (enum mt25ql_error_t)controller_error; + } + + return MT25QL_ERR_NONE; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/Libraries/mt25ql_flash_lib.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/Libraries/mt25ql_flash_lib.h new file mode 100644 index 0000000..d0c5dc9 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/Libraries/mt25ql_flash_lib.h @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2018-2019 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This library provides functions to control the MT25QL256ABA-1EW7-OSIT flash + * memory from Micron and should work for similar devices from the same vendor. + */ + +#ifndef __MT25QL_H__ +#define __MT25QL_H__ + +#include "qspi_ip6514e_drv.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MT25QL Flash Memory documentation defined values. + */ +#define FLASH_PAGE_SIZE (256U) /* 256B */ +#define SUBSECTOR_4KB (0x00001000U) /* 4KB */ +#define SUBSECTOR_32KB (0x00008000U) /* 32KB */ +#define SECTOR_64KB (0x00010000U) /* 64KB */ +#define ADDR_BYTES (3U) + +enum mt25ql_error_t { + MT25QL_ERR_NONE = QSPI_IP6514E_ERR_NONE, + MT25QL_ERR_WRONG_ARGUMENT = QSPI_IP6514E_ERR_WRONG_ARGUMENT, + MT25QL_ERR_CTRL_NOT_DISABLED = QSPI_IP6514E_ERR_CONTROLLER_NOT_DISABLED, + MT25QL_ERR_READ_IN_PROGRESS = QSPI_IP6514E_ERR_READ_IN_PROGRESS, + MT25QL_ERR_WRITE_IN_PROGRESS = QSPI_IP6514E_ERR_WRITE_IN_PROGRESS, + MT25QL_ERR_ADDR_NOT_ALIGNED, + MT25QL_ERR_NOT_INITED, + MT25QL_ERR_ADDR_TOO_BIG, +}; + +enum mt25ql_erase_t { + MT25QL_ERASE_ALL_FLASH = 0U, /*!< Erase all flash */ + MT25QL_ERASE_SUBSECTOR_4K = SUBSECTOR_4KB, /*!< Erase a 4 KB subsector */ + MT25QL_ERASE_SUBSECTOR_32K = SUBSECTOR_32KB, /*!< Erase a 32 KB subsector */ + MT25QL_ERASE_SECTOR_64K = SECTOR_64KB, /*!< Erase a sector (64 KB) */ +}; + +enum mt25ql_functional_state_t { + MT25QL_FUNC_STATE_NOT_INITED = 0U, + /*!< QSPI Flash controller is not initialized, only direct read + * is guaranteed to be working + */ + MT25QL_FUNC_STATE_DEFAULT = 1U, + /*!< The QSPI Flash controller and memory is in default state, + * using basic read/write commands + */ + MT25QL_FUNC_STATE_FAST = 2U, + /*!< The QSPI Flash controller and memory is configured to operate in + * single SPI mode and fast Flash commands could be used for read and + * program operations. + */ + MT25QL_FUNC_STATE_QUAD_FAST = 3U, + /*!< The QSPI Flash controller and memory is configured to operate in + * Quad SPI mode and fast Flash commands could be used for read and + * program operations. + */ +}; + +struct mt25ql_config_state_t { + enum mt25ql_functional_state_t func_state; + /*!< Functional state id */ + enum qspi_ip6514e_spi_mode_t spi_mode; + /*!< SPI mode for the current functional state */ + uint8_t opcode_read; + /*!< Read opcode for the current functional state */ + uint8_t opcode_write; + /*!< Write opcode for the current functional state */ + uint32_t dummy_cycles_read; + /*!< Dummy cycles for the read command for the current functional state */ + uint32_t dummy_cycles_write; + /*!< Dummy cycles for the write command for the current functional state */ +}; + +struct mt25ql_dev_t { + struct qspi_ip6514e_dev_t *controller; + /*!< QSPI Flash controller. */ + uint32_t direct_access_start_addr; + /*!< AHB address to directly access the contents of the Flash memory + * through the QSPI Controller. + */ + uint32_t baud_rate_div; + /*!< Clock divisor that will be used to configure the QSPI Flash + * Controller to access the Flash memory. The clock which frequency is + * divived is the one linked to the QSPI Flash controller. It can only + * be an even number between 2 and 32 (both included). It needs to be + * high enough to support the Quad Output Fast Read command with 8 + * dummy cycles and the Quad Input Fast Program with 0 dummy cycles. + */ + uint32_t size; /*!< Total size of the MT25QL Flash memory */ + struct mt25ql_config_state_t config_state; + /*!< Configured functional state (with parameter settings) of the + * QSPI Flash controller and memory. + */ + +}; + +/** + * \brief Change configuration of the QSPI Flash controller and MT25QL memory + * + * Changes the configuration of the QSPI Flash controller and MT25QL + * Flash memory to operate in the specified SPI mode and to use the + * appropriate Flash commands for read and program operations. + * It also sets: + * + The number of dummy cycles for each operation + * + The bytes per page constant to 256 (MT25QL Flash specific) + * + The number of address bytes to 3 + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * \param[in] f_state Functional state to be set on flash controller + * and device \ref mt25ql_functional_state_t + * + * \return Return error code as specified in \ref mt25ql_error_t + * + * \note This function assumes that the Flash memory device and the QSPI Flash + * controller operates with the same SPI protocol. This function will fail + * if the Flash device is in a different configuration. + */ +enum mt25ql_error_t mt25ql_config_mode(struct mt25ql_dev_t* dev, + enum mt25ql_functional_state_t f_state); + +/** + * \brief Restore the QSPI Flash controller and MT25QL to reset state. + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * + * \return Return error code as specified in \ref mt25ql_error_t + * + * \note This function assumes that the Flash memory device and the QSPI Flash + * controller operates with the same SPI protocol. This function will fail + * if the Flash device is in a different configuration. + */ +enum mt25ql_error_t mt25ql_restore_reset_state(struct mt25ql_dev_t* dev); + +/** + * \brief Read bytes from the flash memory (direct access) + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * \param[in] addr Flash memory address for the read operation + * \param[out] data Pointer where len bytes read from the flash memory will be + * written to + * \param[in] len Number of bytes to read + * + * \return Return error code as specified in \ref mt25ql_error_t + * + * \note This function will use direct access to read from the Flash memory. It + * can be used to access above the direct accessible memory zone if + * not all the AHB address wires are connected. + * \note The address given should be the address of the data inside the flash + * memory. To read the first byte inside the memory, use 0x00000000. + */ +enum mt25ql_error_t mt25ql_direct_read(struct mt25ql_dev_t* dev, + uint32_t addr, + void *data, + uint32_t len); + +/** + * \brief Write bytes in the flash memory, at a location where data has already + * been erased (direct access) + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * \param[in] addr Flash memory address for the write operation + * \param[in] data Pointer to the len bytes that will be written to the flash + * memory + * \param[in] len Number of bytes to write + * + * \return Return error code as specified in \ref mt25ql_error_t + * + * \note This function will use direct access to write to the Flash memory. It + * can be used to access outside of the direct accessible memory zone if + * not all the AHB address wires are connected. + * \note The address given should be the address of the data inside the flash + * memory. To write the first byte inside the memory, use 0x00000000. + * \note Writing bytes in the flash memory clear them from 1 to 0, for that + * matter the location where data is written needs to be erased + * beforehand. + */ +enum mt25ql_error_t mt25ql_direct_write(struct mt25ql_dev_t* dev, + uint32_t addr, + const void *data, + uint32_t len); + +/** + * \brief Read bytes from the flash memory (using Flash commands) + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * \param[in] addr Flash memory address for the read operation + * \param[out] data Pointer where len bytes read from the flash memory will be + * written to + * \param[in] len Number of bytes to read + * + * \return Return error code as specified in \ref mt25ql_error_t + * + * \note This function will use the Software Triggered Instruction Generator to + * read from the Flash memory using Flash commands. + * \note The address given should be the address of the data inside the flash + * memory. To read the first byte inside the memory, use 0x00000000. + */ +enum mt25ql_error_t mt25ql_command_read(struct mt25ql_dev_t* dev, + uint32_t addr, + void *data, + uint32_t len); + +/** + * \brief Write bytes in the flash memory, at a location where data has already + * been erased (using Flash commands) + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * \param[in] addr Flash memory address for the write operation + * \param[in] data Pointer to the len bytes that will be written to the flash + * memory + * \param[in] len Number of bytes to write + * + * \return Return error code as specified in \ref mt25ql_error_t + * + * \note This function will use the Software Triggered Instruction Generator to + * write to the Flash memory using Flash commands. + * \note The address given should be the address of the data inside the flash + * memory. To write the first byte inside the memory, use 0x00000000. + * \note Writing bytes in the flash memory clear them from 1 to 0, for that + * matter the location where data is written needs to be erased + * beforehand. + */ +enum mt25ql_error_t mt25ql_command_write(struct mt25ql_dev_t* dev, + uint32_t addr, + const void *data, + uint32_t len); + +/** + * \brief Erase all flash memory, a sector (64 KiB) or a subsector + * (32 KiB or 4 KiB) + * + * \param[in] dev Pointer to MT25QL device structure \ref mt25ql_dev_t + * \param[in] addr Address where to erase in the flash memory + * \param[in] erase_type Type of what to erase at the specified address: + * * whole flash memory + * * a subsector (4 KiB or 32 KiB) + * * a sector (64 KiB) + * \return Return error code as specified in \ref mt25ql_error_t + * + * \note The address need to be aligned with the size of what is erased or 0 if + * all flash memory is to be erased. + */ +enum mt25ql_error_t mt25ql_erase(struct mt25ql_dev_t* dev, + uint32_t addr, + enum mt25ql_erase_t erase_type); + +#ifdef __cplusplus +} +#endif + +#endif /* __MT25QL_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/PeripheralNames.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/PeripheralNames.h new file mode 100644 index 0000000..158beff --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/PeripheralNames.h @@ -0,0 +1,49 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_PERIPHERALNAMES_H +#define MBED_PERIPHERALNAMES_H + +#include "cmsis.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + UART_0 = 0, + UART_1 +} UARTName; + +typedef enum { + I2C_0 = 0, + I2C_1 +} I2CName; + +#define STDIO_UART_TX UART1_TX +#define STDIO_UART_RX UART1_RX +#define STDIO_UART UART_1 + +#define USBTX STDIO_UART_TX +#define USBRX STDIO_UART_RX + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/PinNames.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/PinNames.h new file mode 100644 index 0000000..9223c0a --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/PinNames.h @@ -0,0 +1,117 @@ +/* mbed Microcontroller Library + * Copyright (c) 2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_PINNAMES_H +#define MBED_PINNAMES_H + +#include "cmsis.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + PIN_INPUT, + PIN_OUTPUT +} PinDirection; + +typedef enum { + PA0 = 0, + PA1 = 1, + PA2 = 2, + PA3 = 3, + PA4 = 4, + PA5 = 5, + PA6 = 6, + PA7 = 7, + PA8 = 8, + PA9 = 9, + PA10 = 10, + PA11 = 11, + PA12 = 12, + PA13 = 13, + PA14 = 14, + PA15 = 15, + PA16 = 16, + PA17 = 17, + PA18 = 18, + PA19 = 19, + PA20 = 20, + PA21 = 21, + PA22 = 22, + PA23 = 23, + PA24 = 24, + PA25 = 25, + + /* Arduino Connector Namings */ + D0 = PA0, + D1 = PA1, + D2 = PA2, + D3 = PA3, + D4 = PA4, + D5 = PA5, + D6 = PA6, + D7 = PA7, + D8 = PA8, + D9 = PA9, + D10 = PA10, + D11 = PA11, + D12 = PA12, + D13 = PA13, + D14 = PA14, + D15 = PA15, + + /* UART pins */ + UART0_RX = PA0, /* Alternate Function - 1 */ + UART0_TX = PA1, /* Alternate Function - 1 */ + UART1_RX = PA16, + UART1_TX = PA17, + + LED1 = PA2, + LED2 = PA3, + LED3 = PA4, + + /* I2C pins */ + I2C0_SDA = PA14, /* Alternate Function - 1 */ + I2C0_SCL = PA15, /* Alternate Function - 1 */ + I2C1_SDA = PA18, + I2C1_SCL = PA19, + + /* Not connected */ + NC = (int)0xFFFFFFFF +} PinName; + +typedef enum { + PRIMARY_FUNC = 0, + ALTERNATE_FUNC_1 = 1, + ALTERNATE_FUNC_2 = 2 +} PinFunction; + +typedef enum { + PullNone = 0, + PullUp, + PullDown, + PullDefault = PullNone +} PinMode; + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device.h new file mode 100644 index 0000000..6059d39 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device.h @@ -0,0 +1,24 @@ +/* mbed Microcontroller Library + * Copyright (c) 2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_DEVICE_H +#define MBED_DEVICE_H + +#include "objects.h" + +#endif diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_ARMC6/musca_ns.sct b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_ARMC6/musca_ns.sct new file mode 100644 index 0000000..77554e2 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_ARMC6/musca_ns.sct @@ -0,0 +1,68 @@ +#! armclang --target=arm-arm-none-eabi -march=armv8-m.main -E -xc + +/* + * Copyright (c) 2019-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../../partition/region_defs.h" +#include "../cmsis_nvic.h" + +#if !defined(MBED_ROM_START) + #define MBED_ROM_START NS_CODE_START // 0x0A080400 +#endif + +#if !defined(MBED_ROM_SIZE) + #define MBED_ROM_SIZE NS_CODE_SIZE // 0x7f400 +#endif + +#if !defined(MBED_RAM_START) + #define MBED_RAM_START NS_DATA_START // 0x20040000 +#endif + +#if !defined(MBED_RAM_SIZE) + #define MBED_RAM_SIZE NS_DATA_SIZE // 0x40000 +#endif + +#define VECTOR_SIZE NVIC_RAM_VECTOR_SIZE + +#if !defined(MBED_CONF_TARGET_BOOT_STACK_SIZE) +# if defined(MBED_BOOT_STACK_SIZE) +# define MBED_CONF_TARGET_BOOT_STACK_SIZE MBED_BOOT_STACK_SIZE +# else +# define MBED_CONF_TARGET_BOOT_STACK_SIZE 0x400 +# endif +#endif + +#define RAM_FIXED_SIZE (MBED_CONF_TARGET_BOOT_STACK_SIZE+VECTOR_SIZE) + +LR_CODE MBED_ROM_START MBED_ROM_SIZE { + ER_CODE MBED_ROM_START MBED_ROM_SIZE { + *.o (VECTOR +First) + .ANY (+RO) + } + + RW_IRAM1 (MBED_RAM_START+VECTOR_SIZE) (MBED_RAM_SIZE-VECTOR_SIZE) { + * (+RW) ; RW data that gets copied from Flash to SRAM + * (+ZI) ; ZI data that gets initialised to zero in SRAM + } + + ARM_LIB_HEAP AlignExpr(+0, 16) EMPTY (MBED_RAM_SIZE-RAM_FIXED_SIZE+MBED_RAM_START-AlignExpr(ImageLimit(RW_IRAM1), 16)) { + } + + ARM_LIB_STACK (MBED_RAM_START+MBED_RAM_SIZE) EMPTY -MBED_CONF_TARGET_BOOT_STACK_SIZE { ; stack + } +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_ARMC6/startup_cmsdk_musca_ns.S b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_ARMC6/startup_cmsdk_musca_ns.S new file mode 100644 index 0000000..368c289 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_ARMC6/startup_cmsdk_musca_ns.S @@ -0,0 +1,242 @@ +;/* +; * Copyright (c) 2019-2020 Arm Limited +; * +; * SPDX-License-Identifier: Apache-2.0 +; * +; * Licensed under the Apache License, Version 2.0 (the "License"); +; * you may not use this file except in compliance with the License. +; * You may obtain a copy of the License at +; * +; * http://www.apache.org/licenses/LICENSE-2.0 +; * +; * Unless required by applicable law or agreed to in writing, software +; * distributed under the License is distributed on an "AS IS" BASIS, +; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; * See the License for the specific language governing permissions and +; * limitations under the License. +; */ +; +; This file is derivative of CMSIS V5.01 startup_ARMv8MML.s +; Git SHA: 8a1d9d6ee18b143ae5befefa14d89fb5b3f99c75 + +;/* +;//-------- <<< Use Configuration Wizard in Context Menu >>> ------------------ +;*/ + +; Vector Table Mapped to Address 0 at Reset + + AREA VECTOR, DATA, READONLY + EXPORT __Vectors + EXPORT __Vectors_End + EXPORT __Vectors_Size + + IMPORT |Image$$ARM_LIB_STACK$$ZI$$Limit| + +__Vectors ;Core Interrupts + DCD |Image$$ARM_LIB_STACK$$ZI$$Limit|; Top of Stack + DCD Reset_Handler ; Reset Handler + DCD NMI_Handler ; NMI Handler + DCD HardFault_Handler ; Hard Fault Handler + DCD MemManage_Handler ; MPU Fault Handler + DCD BusFault_Handler ; Bus Fault Handler + DCD UsageFault_Handler ; Usage Fault Handler + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD 0 ; Reserved + DCD SVC_Handler ; SVCall Handler + DCD DebugMon_Handler ; Debug Monitor Handler + DCD 0 ; Reserved + DCD PendSV_Handler ; PendSV Handler + DCD SysTick_Handler ; SysTick Handler + ;SSE-200 Interrupts + DCD NS_WATCHDOG_RESET_IRQHandler ; 0: Non-Secure Watchdog Reset Request Interrupt + DCD NS_WATCHDOG_IRQHandler ; 1: Non-Secure Watchdog Interrupt + DCD S32K_TIMER_IRQHandler ; 2: S32K Timer Interrupt + DCD TIMER0_IRQHandler ; 3: CMSDK Timer 0 Interrupt + DCD TIMER1_IRQHandler ; 4: CMSDK Timer 1 Interrupt + DCD DUALTIMER_IRQHandler ; 5: CMSDK Dual Timer Interrupt + DCD MHU0_IRQHandler ; 6: Message Handling Unit 0 Interrupt + DCD MHU1_IRQHandler ; 7: Message Handling Unit 1 Interrupt + DCD CRYPTOCELL_IRQHandler ; 8: CryptoCell-312 Interrupt + DCD 0 ; 9: Reserved + DCD 0 ; 10: Reserved + DCD 0 ; 11: Reserved + DCD 0 ; 12: Reserved + DCD I_CACHE_INV_ERR_IRQHandler ; 13: Intsruction Cache Invalidation Interrupt + DCD 0 ; 14: Reserved + DCD SYS_PPU_IRQHandler ; 15: System PPU Interrupt + DCD CPU0_PPU_IRQHandler ; 16: CPU0 PPU Interrupt + DCD CPU1_PPU_IRQHandler ; 17: CPU1 PPU Interrupt + DCD CPU0_DGB_PPU_IRQHandler ; 18: CPU0 Debug PPU Interrupt + DCD CPU1_DGB_PPU_IRQHandler ; 19: CPU1 Debug PPU Interrupt + DCD CRYPTOCELL_PPU_IRQHandler ; 20: CryptoCell PPU Interrupt + DCD 0 ; 21: Reserved + DCD RAM0_PPU_IRQHandler ; 22: RAM 0 PPU Interrupt + DCD RAM1_PPU_IRQHandler ; 23: RAM 1 PPU Interrupt + DCD RAM2_PPU_IRQHandler ; 24: RAM 2 PPU Interrupt + DCD RAM3_PPU_IRQHandler ; 25: RAM 3 PPU Interrupt + DCD DEBUG_PPU_IRQHandler ; 26: Debug PPU Interrupt + DCD 0 ; 27: Reserved + DCD CPU0_CTI_IRQHandler ; 28: CPU0 CTI Interrupt + DCD CPU1_CTI_IRQHandler ; 29: CPU1 CTI Interrupt + DCD 0 ; 30: Reserved + DCD 0 ; 31: Reserved + ;Expansion Interrupts + DCD 0 ; 32: Reserved + DCD GpTimer_IRQHandler ; 33: General Purpose Timer + DCD I2C0_IRQHandler ; 34: I2C0 + DCD I2C1_IRQHandler ; 35: I2C1 + DCD I2S_IRQHandler ; 36: I2S + DCD SPI_IRQHandler ; 37: SPI + DCD QSPI_IRQHandler ; 38: QSPI + DCD UART0_Rx_IRQHandler ; 39: UART0 receive FIFO interrupt + DCD UART0_Tx_IRQHandler ; 40: UART0 transmit FIFO interrupt + DCD UART0_RxTimeout_IRQHandler ; 41: UART0 receive timeout interrupt + DCD UART0_ModemStatus_IRQHandler ; 42: UART0 modem status interrupt + DCD UART0_Error_IRQHandler ; 43: UART0 error interrupt + DCD UART0_IRQHandler ; 44: UART0 interrupt + DCD UART1_Rx_IRQHandler ; 45: UART0 receive FIFO interrupt + DCD UART1_Tx_IRQHandler ; 46: UART0 transmit FIFO interrupt + DCD UART1_RxTimeout_IRQHandler ; 47: UART0 receive timeout interrupt + DCD UART1_ModemStatus_IRQHandler ; 48: UART0 modem status interrupt + DCD UART1_Error_IRQHandler ; 49: UART0 error interrupt + DCD UART1_IRQHandler ; 50: UART0 interrupt + DCD GPIO_0_IRQHandler ; 51: GPIO 0 interrupt + DCD GPIO_1_IRQHandler ; 52: GPIO 1 interrupt + DCD GPIO_2_IRQHandler ; 53: GPIO 2 interrupt + DCD GPIO_3_IRQHandler ; 54: GPIO 3 interrupt + DCD GPIO_4_IRQHandler ; 55: GPIO 4 interrupt + DCD GPIO_5_IRQHandler ; 56: GPIO 5 interrupt + DCD GPIO_6_IRQHandler ; 57: GPIO 6 interrupt + DCD GPIO_7_IRQHandler ; 58: GPIO 7 interrupt + DCD GPIO_8_IRQHandler ; 59: GPIO 8 interrupt + DCD GPIO_9_IRQHandler ; 60: GPIO 9 interrupt + DCD GPIO_10_IRQHandler ; 61: GPIO 10 interrupt + DCD GPIO_11_IRQHandler ; 62: GPIO 11 interrupt + DCD GPIO_12_IRQHandler ; 63: GPIO 12 interrupt + DCD GPIO_13_IRQHandler ; 64: GPIO 13 interrupt + DCD GPIO_14_IRQHandler ; 65: GPIO 14 interrupt + DCD GPIO_15_IRQHandler ; 66: GPIO 15 interrupt + DCD GPIO_Combined_IRQHandler ; 67: GPIO Combined interrupt + DCD PVT_IRQHandler ; 68: PVT sensor interrupt + DCD 0 ; 69: Reserved + DCD PWM_0_IRQHandler ; 70: PWM0 interrupt + DCD RTC_IRQHandler ; 71: RTC interrupt + DCD GpTimer1_IRQHandler ; 72: General Purpose Timer1 + DCD GpTimer0_IRQHandler ; 73: General Purpose Timer0 + DCD PWM_1_IRQHandler ; 74: PWM1 interrupt + DCD PWM_2_IRQHandler ; 75: PWM2 interrupt + DCD IOMUX_IRQHandler ; 76: IOMUX interrupt + + +__Vectors_End + +__Vectors_Size EQU __Vectors_End - __Vectors + +; Reset Handler + AREA RESET, CODE, READONLY +Reset_Handler PROC + EXPORT Reset_Handler [WEAK] + IMPORT SystemInit + IMPORT __main + LDR R0, =SystemInit + BLX R0 + LDR R0, =__main + BX R0 + ENDP +End_Of_Main + B . + + ALIGN 4 + +; Dummy Exception Handlers (infinite loops which can be modified) + MACRO + Default_Handler $handler_name +$handler_name PROC + EXPORT $handler_name [WEAK] + B . + ENDP + MEND + + Default_Handler NMI_Handler + Default_Handler HardFault_Handler + Default_Handler MemManage_Handler + Default_Handler BusFault_Handler + Default_Handler UsageFault_Handler + Default_Handler SVC_Handler + Default_Handler DebugMon_Handler + Default_Handler PendSV_Handler + Default_Handler SysTick_Handler + + Default_Handler NS_WATCHDOG_RESET_IRQHandler + Default_Handler NS_WATCHDOG_IRQHandler + Default_Handler S32K_TIMER_IRQHandler + Default_Handler TIMER0_IRQHandler + Default_Handler TIMER1_IRQHandler + Default_Handler DUALTIMER_IRQHandler + Default_Handler MHU0_IRQHandler + Default_Handler MHU1_IRQHandler + Default_Handler CRYPTOCELL_IRQHandler + Default_Handler I_CACHE_INV_ERR_IRQHandler + Default_Handler SYS_PPU_IRQHandler + Default_Handler CPU0_PPU_IRQHandler + Default_Handler CPU1_PPU_IRQHandler + Default_Handler CPU0_DGB_PPU_IRQHandler + Default_Handler CPU1_DGB_PPU_IRQHandler + Default_Handler CRYPTOCELL_PPU_IRQHandler + Default_Handler RAM0_PPU_IRQHandler + Default_Handler RAM1_PPU_IRQHandler + Default_Handler RAM2_PPU_IRQHandler + Default_Handler RAM3_PPU_IRQHandler + Default_Handler DEBUG_PPU_IRQHandler + Default_Handler CPU0_CTI_IRQHandler + Default_Handler CPU1_CTI_IRQHandler + + Default_Handler GpTimer_IRQHandler + Default_Handler I2C0_IRQHandler + Default_Handler I2C1_IRQHandler + Default_Handler I2S_IRQHandler + Default_Handler SPI_IRQHandler + Default_Handler QSPI_IRQHandler + Default_Handler UART0_Rx_IRQHandler + Default_Handler UART0_Tx_IRQHandler + Default_Handler UART0_RxTimeout_IRQHandler + Default_Handler UART0_ModemStatus_IRQHandler + Default_Handler UART0_Error_IRQHandler + Default_Handler UART0_IRQHandler + Default_Handler UART1_Rx_IRQHandler + Default_Handler UART1_Tx_IRQHandler + Default_Handler UART1_RxTimeout_IRQHandler + Default_Handler UART1_ModemStatus_IRQHandler + Default_Handler UART1_Error_IRQHandler + Default_Handler UART1_IRQHandler + Default_Handler GPIO_0_IRQHandler + Default_Handler GPIO_1_IRQHandler + Default_Handler GPIO_2_IRQHandler + Default_Handler GPIO_3_IRQHandler + Default_Handler GPIO_4_IRQHandler + Default_Handler GPIO_5_IRQHandler + Default_Handler GPIO_6_IRQHandler + Default_Handler GPIO_7_IRQHandler + Default_Handler GPIO_8_IRQHandler + Default_Handler GPIO_9_IRQHandler + Default_Handler GPIO_10_IRQHandler + Default_Handler GPIO_11_IRQHandler + Default_Handler GPIO_12_IRQHandler + Default_Handler GPIO_13_IRQHandler + Default_Handler GPIO_14_IRQHandler + Default_Handler GPIO_15_IRQHandler + Default_Handler GPIO_Combined_IRQHandler + Default_Handler PVT_IRQHandler + Default_Handler PWM_0_IRQHandler + Default_Handler RTC_IRQHandler + Default_Handler GpTimer1_IRQHandler + Default_Handler GpTimer0_IRQHandler + Default_Handler PWM_1_IRQHandler + Default_Handler PWM_2_IRQHandler + Default_Handler IOMUX_IRQHandler + + ALIGN + + END diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_GCC_ARM/musca_ns.ld b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_GCC_ARM/musca_ns.ld new file mode 100644 index 0000000..4d43c72 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_GCC_ARM/musca_ns.ld @@ -0,0 +1,197 @@ +;/* +; * Copyright (c) 2019 ARM Limited +; * +; * SPDX-License-Identifier: Apache-2.0 +; * +; * Licensed under the Apache License, Version 2.0 (the "License"); +; * you may not use this file except in compliance with the License. +; * You may obtain a copy of the License at +; * +; * http://www.apache.org/licenses/LICENSE-2.0 +; * +; * Unless required by applicable law or agreed to in writing, software +; * distributed under the License is distributed on an "AS IS" BASIS, +; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; * See the License for the specific language governing permissions and +; * limitations under the License. +; * +; * +; * This file is derivative of CMSIS V5.00 gcc_arm.ld +; */ + +/* Linker script to configure memory regions. */ +/* This file will be run trough the pre-processor. */ + +#include "../../partition/region_defs.h" +#include "../cmsis_nvic.h" + +/* Stack size is 1K for Mbed-OS */ +#if !defined(MBED_CONF_TARGET_BOOT_STACK_SIZE) + #define MBED_CONF_TARGET_BOOT_STACK_SIZE 0x400 +#endif + +MEMORY +{ + FLASH (rx) : ORIGIN = NS_CODE_START, LENGTH = NS_CODE_SIZE + /* Vector table is copied to RAM, so RAM address needs to be adjusted */ + RAM (rwx) : ORIGIN = NVIC_RAM_VECTOR_LIMIT, LENGTH = (NS_DATA_SIZE - NVIC_RAM_VECTOR_SIZE) +} + +__stack_size__ = MBED_CONF_TARGET_BOOT_STACK_SIZE; + +/* Library configurations */ +GROUP(libgcc.a libc.a libm.a libnosys.a) + +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.vectors)) + __Vectors_End = .; + __Vectors_Size = __Vectors_End - __Vectors; + __end__ = .; + + *(.text*) + KEEP(*(.init)) + KEEP(*(.fini)) + + + + + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + KEEP(*(.eh_frame*)) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * define etext2/data2_start/data2_end and + * define __STARTUP_COPY_MULTIPLE in startup_cmsdk_musca_ns.S */ + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (DEFINED(__etext2) ? __etext2 : 0) + LONG (DEFINED(__data2_start__) ? __data2_start__ : 0) + LONG (DEFINED(__data2_start__) ? __data2_end__ - __data2_start__ : 0) + __copy_table_end__ = .; + } > FLASH + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_cmsdk_musca_ns.S */ + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (DEFINED(__bss2_start__) ? __bss2_start__ : 0) + LONG (DEFINED(__bss2_start__) ? __bss2_end__ - __bss2_start__ : 0) + __zero_table_end__ = .; + } > FLASH + + __etext = .; + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + KEEP(*(.jcr*)) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + bss_size = __bss_end__ - __bss_start__; + + .stack : + { + . = ALIGN(8); + __StackLimit = .; + KEEP(*(.stack*)) + . += __stack_size__; + __StackTop = .; + } > RAM + PROVIDE(__stack = __StackTop); + + .heap (COPY): + { + . = ALIGN(8); + __HeapBase = .; + __end__ = .; + end = __end__; + KEEP(*(.heap*)) + . += (ORIGIN(RAM) + LENGTH(RAM) - .); + __HeapLimit = .; + __heap_limit = .; /* Add for _sbrk */ + } > RAM + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackTop <= (NS_DATA_START + NS_DATA_SIZE), "RAM region overflowed") +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_GCC_ARM/startup_cmsdk_musca_ns.S b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_GCC_ARM/startup_cmsdk_musca_ns.S new file mode 100644 index 0000000..91bac46 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/TOOLCHAIN_GCC_ARM/startup_cmsdk_musca_ns.S @@ -0,0 +1,357 @@ +;/* +; * Copyright (c) 2019-2020 Arm Limited +; * +; * SPDX-License-Identifier: Apache-2.0 +; * +; * Licensed under the Apache License, Version 2.0 (the "License"); +; * you may not use this file except in compliance with the License. +; * You may obtain a copy of the License at +; * +; * http://www.apache.org/licenses/LICENSE-2.0 +; * +; * Unless required by applicable law or agreed to in writing, software +; * distributed under the License is distributed on an "AS IS" BASIS, +; * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +; * See the License for the specific language governing permissions and +; * limitations under the License. +; * +; * +; * This file is derivative of CMSIS V5.00 startup_ARMCM33.S +; */ + + .syntax unified + .arch armv8-m.main + + .section .vectors + .align 2 + .globl __Vectors +__Vectors: + .long __StackTop /* Top of Stack */ + .long Reset_Handler /* Reset Handler */ + .long NMI_Handler /* NMI Handler */ + .long HardFault_Handler /* Hard Fault Handler */ + .long MemManage_Handler /* MPU Fault Handler */ + .long BusFault_Handler /* Bus Fault Handler */ + .long UsageFault_Handler /* Usage Fault Handler */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long SVC_Handler /* SVCall Handler */ + .long DebugMon_Handler /* Debug Monitor Handler */ + .long 0 /* Reserved */ + .long PendSV_Handler /* PendSV Handler */ + .long SysTick_Handler /* SysTick Handler */ + + /* Core interrupts */ + .long NS_WATCHDOG_RESET_IRQHandler /* 0: Non-Secure Watchdog Reset Request Interrupt */ + .long NS_WATCHDOG_IRQHandler /* 1: Non-Secure Watchdog Interrupt */ + .long S32K_TIMER_IRQHandler /* 2: S32K Timer Interrupt */ + .long TIMER0_IRQHandler /* 3: CMSDK Timer 0 Interrupt */ + .long TIMER1_IRQHandler /* 4: CMSDK Timer 1 Interrupt */ + .long DUALTIMER_IRQHandler /* 5: CMSDK Dual Timer Interrupt */ + .long MHU0_IRQHandler /* 6: Message Handling Unit 0 Interrupt */ + .long MHU1_IRQHandler /* 7: Message Handling Unit 1 Interrupt */ + .long CRYPTOCELL_IRQHandler /* 8: CryptoCell-312 Interrupt */ + .long 0 /* 9: Reserved */ + .long 0 /* 10: Reserved */ + .long 0 /* 11: Reserved */ + .long 0 /* 12: Reserved */ + .long I_CACHE_INV_ERR_IRQHandler /* 13: Intsruction Cache Invalidation Interrupt */ + .long 0 /* 14: Reserved */ + .long SYS_PPU_IRQHandler /* 15: System PPU Interrupt */ + .long CPU0_PPU_IRQHandler /* 16: CPU0 PPU Interrupt */ + .long CPU1_PPU_IRQHandler /* 17: CPU1 PPU Interrupt */ + .long CPU0_DGB_PPU_IRQHandler /* 18: CPU0 Debug PPU Interrupt */ + .long CPU1_DGB_PPU_IRQHandler /* 19: CPU1 Debug PPU Interrupt */ + .long CRYPTOCELL_PPU_IRQHandler /* 20: CryptoCell PPU Interrupt */ + .long 0 /* 21: Reserved */ + .long RAM0_PPU_IRQHandler /* 22: RAM 0 PPU Interrupt */ + .long RAM1_PPU_IRQHandler /* 23: RAM 1 PPU Interrupt */ + .long RAM2_PPU_IRQHandler /* 24: RAM 2 PPU Interrupt */ + .long RAM3_PPU_IRQHandler /* 25: RAM 3 PPU Interrupt */ + .long DEBUG_PPU_IRQHandler /* 26: Debug PPU Interrupt */ + .long 0 /* 27: Reserved */ + .long CPU0_CTI_IRQHandler /* 28: CPU0 CTI Interrupt */ + .long CPU1_CTI_IRQHandler /* 29: CPU1 CTI Interrupt */ + .long 0 /* 30: Reserved */ + .long 0 /* 31: Reserved */ + + /* External interrupts */ + .long 0 /* 32: Reserved */ + .long GpTimer_IRQHandler /* 33: General Purpose Timer */ + .long I2C0_IRQHandler /* 34: I2C0 */ + .long I2C1_IRQHandler /* 35: I2C1 */ + .long I2S_IRQHandler /* 36: I2S */ + .long SPI_IRQHandler /* 37: SPI */ + .long QSPI_IRQHandler /* 38: QSPI */ + .long UART0_Rx_IRQHandler /* 39: UART0 receive FIFO interrupt */ + .long UART0_Tx_IRQHandler /* 40: UART0 transmit FIFO interrupt */ + .long UART0_RxTimeout_IRQHandler /* 41: UART0 receive timeout interrupt */ + .long UART0_ModemStatus_IRQHandler /* 42: UART0 modem status interrupt */ + .long UART0_Error_IRQHandler /* 43: UART0 error interrupt */ + .long UART0_IRQHandler /* 44: UART0 interrupt */ + .long UART1_Rx_IRQHandler /* 45: UART1 receive FIFO interrupt */ + .long UART1_Tx_IRQHandler /* 46: UART1 transmit FIFO interrupt */ + .long UART1_RxTimeout_IRQHandler /* 47: UART1 receive timeout interrupt */ + .long UART1_ModemStatus_IRQHandler /* 48: UART1 modem status interrupt */ + .long UART1_Error_IRQHandler /* 49: UART1 error interrupt */ + .long UART1_IRQHandler /* 50: UART1 interrupt */ + .long GPIO_0_IRQHandler /* 51: GPIO 0 interrupt */ + .long GPIO_1_IRQHandler /* 52: GPIO 1 interrupt */ + .long GPIO_2_IRQHandler /* 53: GPIO 2 interrupt */ + .long GPIO_3_IRQHandler /* 54: GPIO 3 interrupt */ + .long GPIO_4_IRQHandler /* 55: GPIO 4 interrupt */ + .long GPIO_5_IRQHandler /* 56: GPIO 5 interrupt */ + .long GPIO_6_IRQHandler /* 57: GPIO 6 interrupt */ + .long GPIO_7_IRQHandler /* 58: GPIO 7 interrupt */ + .long GPIO_8_IRQHandler /* 59: GPIO 8 interrupt */ + .long GPIO_9_IRQHandler /* 60: GPIO 9 interrupt */ + .long GPIO_10_IRQHandler /* 61: GPIO 10 interrupt */ + .long GPIO_11_IRQHandler /* 62: GPIO 11 interrupt */ + .long GPIO_12_IRQHandler /* 63: GPIO 12 interrupt */ + .long GPIO_13_IRQHandler /* 64: GPIO 13 interrupt */ + .long GPIO_14_IRQHandler /* 65: GPIO 14 interrupt */ + .long GPIO_15_IRQHandler /* 66: GPIO 15 interrupt */ + .long GPIO_Combined_IRQHandler /* 67: GPIO Combined interrupt */ + .long PVT_IRQHandler /* 68: PVT sensor interrupt */ + .long 0 /* 69: Reserved */ + .long PWM_0_IRQHandler /* 70: PWM0 interrupt */ + .long RTC_IRQHandler /* 71: RTC interrupt */ + .long GpTimer1_IRQHandler /* 72: General Purpose Timer0 */ + .long GpTimer0_IRQHandler /* 73: General Purpose Timer1 */ + .long PWM_1_IRQHandler /* 74: PWM1 interrupt */ + .long PWM_2_IRQHandler /* 75: PWM2 interrupt */ + .long IOMUX_IRQHandler /* 76: IOMUX interrupt */ + + + .size __Vectors, . - __Vectors + + .text + .thumb + .thumb_func + .align 2 + .globl Reset_Handler + .type Reset_Handler, %function +Reset_Handler: +/* Firstly it copies data from read only memory to RAM. There are two schemes + * to copy. One can copy more than one sections. Another can only copy + * one section. The former scheme needs more instructions and read-only + * data to implement than the latter. + * Macro __STARTUP_COPY_MULTIPLE is used to choose between two schemes. */ + +#ifdef __STARTUP_COPY_MULTIPLE +/* Multiple sections scheme. + * + * Between symbol address __copy_table_start__ and __copy_table_end__, + * there are array of triplets, each of which specify: + * offset 0: LMA of start of a section to copy from + * offset 4: VMA of start of a section to copy to + * offset 8: size of the section to copy. Must be multiply of 4 + * + * All addresses must be aligned to 4 bytes boundary. + */ + ldr r4, =__copy_table_start__ + ldr r5, =__copy_table_end__ + +.L_loop0: + cmp r4, r5 + bge .L_loop0_done + ldr r1, [r4] + ldr r2, [r4, #4] + ldr r3, [r4, #8] + +.L_loop0_0: + subs r3, #4 + ittt ge + ldrge r0, [r1, r3] + strge r0, [r2, r3] + bge .L_loop0_0 + + adds r4, #12 + b .L_loop0 + +.L_loop0_done: +#else +/* Single section scheme. + * + * The ranges of copy from/to are specified by following symbols + * __etext: LMA of start of the section to copy from. Usually end of text + * __data_start__: VMA of start of the section to copy to + * __data_end__: VMA of end of the section to copy to + * + * All addresses must be aligned to 4 bytes boundary. + */ + ldr r1, =__etext + ldr r2, =__data_start__ + ldr r3, =__data_end__ + +.L_loop1: + cmp r2, r3 + ittt lt + ldrlt r0, [r1], #4 + strlt r0, [r2], #4 + blt .L_loop1 +#endif /*__STARTUP_COPY_MULTIPLE */ + +/* This part of work usually is done in C library startup code. Otherwise, + * define this macro to enable it in this startup. + * + * There are two schemes too. One can clear multiple BSS sections. Another + * can only clear one section. The former is more size expensive than the + * latter. + * + * Define macro __STARTUP_CLEAR_BSS_MULTIPLE to choose the former. + * Otherwise efine macro __STARTUP_CLEAR_BSS to choose the later. + */ +#ifdef __STARTUP_CLEAR_BSS_MULTIPLE +/* Multiple sections scheme. + * + * Between symbol address __copy_table_start__ and __copy_table_end__, + * there are array of tuples specifying: + * offset 0: Start of a BSS section + * offset 4: Size of this BSS section. Must be multiply of 4 + */ + ldr r3, =__zero_table_start__ + ldr r4, =__zero_table_end__ + +.L_loop2: + cmp r3, r4 + bge .L_loop2_done + ldr r1, [r3] + ldr r2, [r3, #4] + movs r0, 0 + +.L_loop2_0: + subs r2, #4 + itt ge + strge r0, [r1, r2] + bge .L_loop2_0 + + adds r3, #8 + b .L_loop2 +.L_loop2_done: +#elif defined (__STARTUP_CLEAR_BSS) +/* Single BSS section scheme. + * + * The BSS section is specified by following symbols + * __bss_start__: start of the BSS section. + * __bss_end__: end of the BSS section. + * + * Both addresses must be aligned to 4 bytes boundary. + */ + ldr r1, =__bss_start__ + ldr r2, =__bss_end__ + + movs r0, 0 +.L_loop3: + cmp r1, r2 + itt lt + strlt r0, [r1], #4 + blt .L_loop3 +#endif /* __STARTUP_CLEAR_BSS_MULTIPLE || __STARTUP_CLEAR_BSS */ + +#ifndef __NO_SYSTEM_INIT + bl SystemInit +#endif + +#ifndef __START +#define __START _start +#endif + bl __START + + .pool + .size Reset_Handler, . - Reset_Handler + + +/* Macro to define default handlers. */ + .macro def_irq_handler handler_name + .align 1 + .thumb_func + .weak \handler_name + \handler_name: + b \handler_name + .endm + + def_irq_handler NMI_Handler + def_irq_handler HardFault_Handler + def_irq_handler MemManage_Handler + def_irq_handler BusFault_Handler + def_irq_handler UsageFault_Handler + def_irq_handler SVC_Handler + def_irq_handler DebugMon_Handler + def_irq_handler PendSV_Handler + def_irq_handler SysTick_Handler + + /* Core interrupts */ + def_irq_handler NS_WATCHDOG_RESET_IRQHandler /* 0: Non-Secure Watchdog Reset Request Interrupt */ + def_irq_handler NS_WATCHDOG_IRQHandler /* 1: Non-Secure Watchdog Interrupt */ + def_irq_handler S32K_TIMER_IRQHandler /* 2: S32K Timer Interrupt */ + def_irq_handler TIMER0_IRQHandler /* 3: CMSDK Timer 0 Interrupt */ + def_irq_handler TIMER1_IRQHandler /* 4: CMSDK Timer 1 Interrupt */ + def_irq_handler DUALTIMER_IRQHandler /* 5: CMSDK Dual Timer Interrupt */ + def_irq_handler MHU0_IRQHandler /* 6: Message Handling Unit 0 Interrupt */ + def_irq_handler MHU1_IRQHandler /* 7: Message Handling Unit 1 Interrupt */ + def_irq_handler CRYPTOCELL_IRQHandler /* 8: CryptoCell-312 Interrupt */ + def_irq_handler I_CACHE_INV_ERR_IRQHandler /* 13: Intsruction Cache Invalidation Interrupt */ + def_irq_handler SYS_PPU_IRQHandler /* 15: System PPU Interrupt */ + def_irq_handler CPU0_PPU_IRQHandler /* 16: CPU0 PPU Interrupt */ + def_irq_handler CPU1_PPU_IRQHandler /* 17: CPU1 PPU Interrupt */ + def_irq_handler CPU0_DGB_PPU_IRQHandler /* 18: CPU0 Debug PPU Interrupt */ + def_irq_handler CPU1_DGB_PPU_IRQHandler /* 19: CPU1 Debug PPU Interrupt */ + def_irq_handler CRYPTOCELL_PPU_IRQHandler /* 20: CryptoCell PPU Interrupt */ + def_irq_handler RAM0_PPU_IRQHandler /* 22: RAM 0 PPU Interrupt */ + def_irq_handler RAM1_PPU_IRQHandler /* 23: RAM 1 PPU Interrupt */ + def_irq_handler RAM2_PPU_IRQHandler /* 24: RAM 2 PPU Interrupt */ + def_irq_handler RAM3_PPU_IRQHandler /* 25: RAM 3 PPU Interrupt */ + def_irq_handler DEBUG_PPU_IRQHandler /* 26: Debug PPU Interrupt */ + def_irq_handler CPU0_CTI_IRQHandler /* 28: CPU0 CTI Interrupt */ + def_irq_handler CPU1_CTI_IRQHandler /* 29: CPU1 CTI Interrupt */ + + /* External interrupts */ + def_irq_handler GpTimer_IRQHandler /* 33: General Purpose Timer */ + def_irq_handler I2C0_IRQHandler /* 34: I2C0 */ + def_irq_handler I2C1_IRQHandler /* 35: I2C1 */ + def_irq_handler I2S_IRQHandler /* 36: I2S */ + def_irq_handler SPI_IRQHandler /* 37: SPI */ + def_irq_handler QSPI_IRQHandler /* 38: QSPI */ + def_irq_handler UART0_Rx_IRQHandler /* 39: UART0 receive FIFO interrupt */ + def_irq_handler UART0_Tx_IRQHandler /* 40: UART0 transmit FIFO interrupt */ + def_irq_handler UART0_RxTimeout_IRQHandler /* 41: UART0 receive timeout interrupt */ + def_irq_handler UART0_ModemStatus_IRQHandler /* 42: UART0 modem status interrupt */ + def_irq_handler UART0_Error_IRQHandler /* 43: UART0 error interrupt */ + def_irq_handler UART0_IRQHandler /* 44: UART0 interrupt */ + def_irq_handler UART1_Rx_IRQHandler /* 45: UART1 receive FIFO interrupt */ + def_irq_handler UART1_Tx_IRQHandler /* 46: UART1 transmit FIFO interrupt */ + def_irq_handler UART1_RxTimeout_IRQHandler /* 47: UART1 receive timeout interrupt */ + def_irq_handler UART1_ModemStatus_IRQHandler /* 48: UART1 modem status interrupt */ + def_irq_handler UART1_Error_IRQHandler /* 49: UART1 error interrupt */ + def_irq_handler UART1_IRQHandler /* 50: UART1 interrupt */ + def_irq_handler GPIO_0_IRQHandler /* 51: GPIO 0 interrupt */ + def_irq_handler GPIO_1_IRQHandler /* 52: GPIO 1 interrupt */ + def_irq_handler GPIO_2_IRQHandler /* 53: GPIO 2 interrupt */ + def_irq_handler GPIO_3_IRQHandler /* 54: GPIO 3 interrupt */ + def_irq_handler GPIO_4_IRQHandler /* 55: GPIO 4 interrupt */ + def_irq_handler GPIO_5_IRQHandler /* 56: GPIO 5 interrupt */ + def_irq_handler GPIO_6_IRQHandler /* 57: GPIO 6 interrupt */ + def_irq_handler GPIO_7_IRQHandler /* 58: GPIO 7 interrupt */ + def_irq_handler GPIO_8_IRQHandler /* 59: GPIO 8 interrupt */ + def_irq_handler GPIO_9_IRQHandler /* 60: GPIO 9 interrupt */ + def_irq_handler GPIO_10_IRQHandler /* 61: GPIO 10 interrupt */ + def_irq_handler GPIO_11_IRQHandler /* 62: GPIO 11 interrupt */ + def_irq_handler GPIO_12_IRQHandler /* 63: GPIO 12 interrupt */ + def_irq_handler GPIO_13_IRQHandler /* 64: GPIO 13 interrupt */ + def_irq_handler GPIO_14_IRQHandler /* 65: GPIO 14 interrupt */ + def_irq_handler GPIO_15_IRQHandler /* 66: GPIO 15 interrupt */ + def_irq_handler GPIO_Combined_IRQHandler /* 67: GPIO Combined interrupt */ + def_irq_handler PVT_IRQHandler /* 68: PVT sensor interrupt */ + def_irq_handler PWM_0_IRQHandler /* 70: PWM0 interrupt */ + def_irq_handler RTC_IRQHandler /* 71: RTC interrupt */ + def_irq_handler GpTimer1_IRQHandler /* 72: General Purpose Timer0 */ + def_irq_handler GpTimer0_IRQHandler /* 73: General Purpose Timer1 */ + def_irq_handler PWM_1_IRQHandler /* 74: PWM1 interrupt */ + def_irq_handler PWM_2_IRQHandler /* 75: PWM2 interrupt */ + def_irq_handler IOMUX_IRQHandler /* 76: IOMUX interrupt */ + + + .end diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/cmsis.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/cmsis.h new file mode 100644 index 0000000..22a3aad --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/cmsis.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2017-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MUSCA_S1_CMSIS_H__ +#define __MUSCA_S1_CMSIS_H__ + +/* Processor and Core Peripherals and configurations */ + +/* ========================================================================== */ +/* ============= Processor and Core Peripheral Section ============= */ +/* ========================================================================== */ + +/* ----- Start of section using anonymous unions and disabling warnings ----- */ +#if defined (__CC_ARM) + #pragma push + #pragma anon_unions +#elif defined (__ICCARM__) + #pragma language=extended +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wc11-extensions" + #pragma clang diagnostic ignored "-Wreserved-id-macro" +#elif defined (__GNUC__) + /* anonymous unions are enabled by default */ +#elif defined (__TMS470__) + /* anonymous unions are enabled by default */ +#elif defined (__TASKING__) + #pragma warning 586 +#elif defined (__CSMC__) + /* anonymous unions are enabled by default */ +#else + #warning Not supported compiler type +#endif + + +/* -- Configuration of the Cortex-M33 Processor and Core Peripherals -- */ +#define __CM33_REV 0x0002U /* Core revision r0p2 */ +#define __SAUREGION_PRESENT 1U /* SAU regions present */ +#define __MPU_PRESENT 1U /* MPU present */ +#define __VTOR_PRESENT 1U /* VTOR present */ +#define __NVIC_PRIO_BITS 4U /* Number of Bits used for the + * Priority Levels */ +#define __Vendor_SysTickConfig 0U /* Set to 1 if different SysTick + * Config is used */ +#define __FPU_PRESENT 1U /* FPU present */ +#define __DSP_PRESENT 1U /* DSP extension present */ + +#include "system_core_init.h" +#include "platform_irq.h" +#include /*!< Arm Cortex-M33 processor and core peripherals */ + +/* ------ End of section using anonymous unions and disabling warnings ------ */ +#if defined (__CC_ARM) + #pragma pop +#elif defined (__ICCARM__) + /* leave anonymous unions enabled */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang diagnostic pop +#elif defined (__GNUC__) + /* anonymous unions are enabled by default */ +#elif defined (__TMS470__) + /* anonymous unions are enabled by default */ +#elif defined (__TASKING__) + #pragma warning restore +#elif defined (__CSMC__) + /* anonymous unions are enabled by default */ +#else + #warning Not supported compiler type +#endif + +#endif /*__MUSCA_S1_CMSIS_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/cmsis_nvic.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/cmsis_nvic.h new file mode 100644 index 0000000..b83a445 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/cmsis_nvic.h @@ -0,0 +1,35 @@ +/* mbed Microcontroller Library + * Copyright (c) 2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file is included from the linker script, + * limited set of C constructs can be used here + */ + +#ifndef MBED_CMSIS_NVIC_H +#define MBED_CMSIS_NVIC_H + +#include "../partition/region_defs.h" + +#define NVIC_NUM_VECTORS (16 + 77) +/** Location of vectors to move in RAM */ +#define NVIC_RAM_VECTOR_ADDRESS NS_DATA_START +#define NVIC_RAM_VECTOR_SIZE (NVIC_NUM_VECTORS * 4) +#define NVIC_RAM_VECTOR_LIMIT (NVIC_RAM_VECTOR_ADDRESS + NVIC_RAM_VECTOR_SIZE) + +#endif diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/cmsis_nvic_virtual.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/cmsis_nvic_virtual.h new file mode 100644 index 0000000..5e6c6f3 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/cmsis_nvic_virtual.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cmsis.h" + +#ifndef NVIC_VIRTUAL_H +#define NVIC_VIRTUAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* NVIC functions */ +#define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping +#define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping +#define NVIC_EnableIRQ __NVIC_EnableIRQ +#define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ +#define NVIC_DisableIRQ __NVIC_DisableIRQ +#define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ +#define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ +#define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ +#define NVIC_GetActive __NVIC_GetActive +#define NVIC_SetPriority __NVIC_SetPriority +#define NVIC_GetPriority __NVIC_GetPriority + +/** + * \brief Overriding the default CMSIS system reset implementation by calling + * secure TFM service. + * + */ +void NVIC_SystemReset(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/device_cfg.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/device_cfg.h new file mode 100644 index 0000000..cc4301f --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/device_cfg.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing software + * distributed under the License is distributed on an "AS IS" BASIS + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MUSCA_S1_DEVICE_CFG_H__ +#define __MUSCA_S1_DEVICE_CFG_H__ + +/** + * \file device_cfg.h + * \brief Configuration file native driver re-targeting + * + * \details This file can be used to add native driver specific macro + * definitions to select which peripherals are available in the build. + * + * This is a default device configuration file with all peripherals enabled. + */ + +/*ARM UART Controller PL011*/ + +#define UART0_PL011_NS +#define UART0_PL011_DEV UART0_PL011_DEV_NS +#define uart0_tx_irq_handler UART0_Tx_IRQHandler +#define uart0_rx_irq_handler UART0_Rx_IRQHandler +#define uart0_rx_timeout_irq_handler UART0_RxTimeout_IRQHandler + +#define UART1_PL011_NS +#define UART1_PL011_DEV UART1_PL011_DEV_NS +#define uart1_tx_irq_handler UART1_Tx_IRQHandler +#define uart1_rx_irq_handler UART1_Rx_IRQHandler +#define uart1_rx_timeout_irq_handler UART1_RxTimeout_IRQHandler + +/* CMSDK Timers */ +#define CMSDK_TIMER0_NS +#define CMSDK_TIMER0_DEV CMSDK_TIMER0_DEV_NS +#define CMSDK_TIMER1_NS +#define CMSDK_TIMER1_DEV CMSDK_TIMER1_DEV_NS + +/* GPIO */ +#define GPIO0_CMSDK_NS +#define GPIO0_CMSDK_DEV GPIO0_CMSDK_DEV_NS; + +/* GP Timer */ +#define GP_TIMER_NS +#define GP_TIMER_DEV GP_TIMER_DEV_NS + +#define GP_TIMER_ALARM0_IRQ GpTimer0_IRQn +#define GP_TIMER_IRQ0_HANDLER GpTimer0_IRQHandler +#define GP_TIMER_ALARM_NR TIMER_GP_READ_ALARM_0 +#define GP_TIMER_FREQ_HZ 32768UL /* System Ref Clock */ +#define GP_TIMER_BIT_WIDTH 32U + +/* I2C IP6510 */ +#define I2C0_IP6510_NS +#define I2C0_IP6510_DEV I2C0_IP6510_DEV_NS +#define I2C1_IP6510_NS +#define I2C1_IP6510_DEV I2C1_IP6510_DEV_NS + +/** + * mbed usec high-resolution ticker configuration + */ +#define USEC_TIMER_DEV CMSDK_TIMER0_DEV_NS +#define usec_interval_irq_handler TIMER0_IRQHandler +#define USEC_INTERVAL_IRQ TIMER0_IRQn +/** Timer frequency is equal to SYSTEM_CLOCK, defined in system_core_clk.c */ +#define TIMER_FREQ_HZ 50000000U +/** The us Ticker uses CMSDK Timer, that does not have HW prescaler. + * The reported shift define is necessary for the software emulated + * prescaler behavior, so the ticker works as if it was ticking on a + * virtually slower frequency. The value 6 sets up the ticker to work + * properly in the specified frequency interval. + */ +#define USEC_REPORTED_SHIFT 6 +#define USEC_REPORTED_FREQ_HZ (TIMER_FREQ_HZ >> USEC_REPORTED_SHIFT) +#define USEC_REPORTED_BITS (32 - USEC_REPORTED_SHIFT) + +#define UART_DEFAULT_BAUD_RATE 115200U + +/* Cadence QSPI Flash Controller */ +#define QSPI_IP6514E_NS + +/* MT25QL Flash memory library */ +#define MT25QL_NS +#define FLASH_DEV MT25QL_DEV_NS + +#endif /* __ARM_LTD_DEVICE_CFG_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/device_definition.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/device_definition.c new file mode 100644 index 0000000..4b18415 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/device_definition.c @@ -0,0 +1,573 @@ +/* + * Copyright (c) 2017-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file device_definition.c + * \brief This file defines exports the structures based on the peripheral + * definitions from device_cfg.h. + * This file is meant to be used as a helper for baremetal + * applications and/or as an example of how to configure the generic + * driver structures. + */ + +#include "device_cfg.h" +#include "device_definition.h" +#include "platform_base_address.h" + +/* ======= Peripheral configuration structure definitions ======= */ +/* MUSCA S1 SCC driver structures */ +#ifdef MUSCA_S1_SCC_S +static const struct musca_s1_scc_dev_cfg_t MUSCA_S1_SCC_DEV_CFG_S = { + .base = MUSCA_S1_SCC_S_BASE}; +struct musca_s1_scc_dev_t MUSCA_S1_SCC_DEV_S = {&(MUSCA_S1_SCC_DEV_CFG_S)}; +#endif +#ifdef MUSCA_S1_SCC_NS +static const struct musca_s1_scc_dev_cfg_t MUSCA_S1_SCC_DEV_CFG_NS = { + .base = MUSCA_S1_SCC_NS_BASE}; +struct musca_s1_scc_dev_t MUSCA_S1_SCC_DEV_NS = {&(MUSCA_S1_SCC_DEV_CFG_NS)}; +#endif + +/* CMSDK GPIO driver structures */ +#ifdef GPIO0_CMSDK_S +static const struct gpio_cmsdk_dev_cfg_t GPIO0_CMSDK_DEV_CFG_S = { + .base = MUSCA_S1_GPIO_S_BASE}; +struct gpio_cmsdk_dev_t GPIO0_CMSDK_DEV_S = {&(GPIO0_CMSDK_DEV_CFG_S)}; +#endif +#ifdef GPIO0_CMSDK_NS +static const struct gpio_cmsdk_dev_cfg_t GPIO0_CMSDK_DEV_CFG_NS = { + .base = MUSCA_S1_GPIO_NS_BASE}; +struct gpio_cmsdk_dev_t GPIO0_CMSDK_DEV_NS = {&(GPIO0_CMSDK_DEV_CFG_NS)}; +#endif + +/* ARM PPC SSE 200 driver structures */ +#ifdef AHB_PPC0_S +static struct ppc_sse200_dev_cfg_t AHB_PPC0_DEV_CFG_S = { + .spctrl_base = MUSCA_S1_SPCTRL_S_BASE, + .nspctrl_base = MUSCA_S1_NSPCTRL_NS_BASE }; +static struct ppc_sse200_dev_data_t AHB_PPC0_DEV_DATA_S = { + .p_ns_ppc = 0, + .p_sp_ppc = 0, + .p_nsp_ppc = 0, + .int_bit_mask = 0, + .state = 0 }; +struct ppc_sse200_dev_t AHB_PPC0_DEV_S = { + &AHB_PPC0_DEV_CFG_S, &AHB_PPC0_DEV_DATA_S }; +#endif + +#ifdef AHB_PPCEXP0_S +static struct ppc_sse200_dev_cfg_t AHB_PPCEXP0_DEV_CFG_S = { + .spctrl_base = MUSCA_S1_SPCTRL_S_BASE, + .nspctrl_base = MUSCA_S1_NSPCTRL_NS_BASE }; +static struct ppc_sse200_dev_data_t AHB_PPCEXP0_DEV_DATA_S = { + .p_ns_ppc = 0, + .p_sp_ppc = 0, + .p_nsp_ppc = 0, + .int_bit_mask = 0, + .state = 0 }; +struct ppc_sse200_dev_t AHB_PPCEXP0_DEV_S = { + &AHB_PPCEXP0_DEV_CFG_S, &AHB_PPCEXP0_DEV_DATA_S }; +#endif + +#ifdef APB_PPC0_S +static struct ppc_sse200_dev_cfg_t APB_PPC0_DEV_CFG_S = { + .spctrl_base = MUSCA_S1_SPCTRL_S_BASE, + .nspctrl_base = MUSCA_S1_NSPCTRL_NS_BASE }; +static struct ppc_sse200_dev_data_t APB_PPC0_DEV_DATA_S = { + .p_ns_ppc = 0, + .p_sp_ppc = 0, + .p_nsp_ppc = 0, + .int_bit_mask = 0, + .state = 0 }; +struct ppc_sse200_dev_t APB_PPC0_DEV_S = { + &APB_PPC0_DEV_CFG_S, &APB_PPC0_DEV_DATA_S }; +#endif + +#ifdef APB_PPC1_S +static struct ppc_sse200_dev_cfg_t APB_PPC1_DEV_CFG_S = { + .spctrl_base = MUSCA_S1_SPCTRL_S_BASE, + .nspctrl_base = MUSCA_S1_NSPCTRL_NS_BASE }; +static struct ppc_sse200_dev_data_t APB_PPC1_DEV_DATA_S = { + .p_ns_ppc = 0, + .p_sp_ppc = 0, + .p_nsp_ppc = 0, + .int_bit_mask = 0, + .state = 0 }; +struct ppc_sse200_dev_t APB_PPC1_DEV_S = { + &APB_PPC1_DEV_CFG_S, &APB_PPC1_DEV_DATA_S}; +#endif + +#ifdef APB_PPCEXP0_S +static struct ppc_sse200_dev_cfg_t APB_PPCEXP0_DEV_CFG_S = { + .spctrl_base = MUSCA_S1_SPCTRL_S_BASE, + .nspctrl_base = MUSCA_S1_NSPCTRL_NS_BASE }; +static struct ppc_sse200_dev_data_t APB_PPCEXP0_DEV_DATA_S = { + .p_ns_ppc = 0, + .p_sp_ppc = 0, + .p_nsp_ppc = 0, + .int_bit_mask = 0, + .state = 0 }; +struct ppc_sse200_dev_t APB_PPCEXP0_DEV_S = { + &APB_PPCEXP0_DEV_CFG_S, &APB_PPCEXP0_DEV_DATA_S }; +#endif + +#ifdef APB_PPCEXP1_S +static struct ppc_sse200_dev_cfg_t APB_PPCEXP1_DEV_CFG = { + .spctrl_base = MUSCA_S1_SPCTRL_S_BASE, + .nspctrl_base = MUSCA_S1_NSPCTRL_NS_BASE }; +static struct ppc_sse200_dev_data_t APB_PPCEXP1_DEV_DATA_S = { + .p_ns_ppc = 0, + .p_sp_ppc = 0, + .p_nsp_ppc = 0, + .int_bit_mask = 0, + .state = 0 }; +struct ppc_sse200_dev_t APB_PPCEXP1_DEV_S = { + &APB_PPCEXP1_DEV_CFG, &APB_PPCEXP1_DEV_DATA_S }; +#endif + +/* ARM MPC SIE 200 driver structures */ +#ifdef MPC_ISRAM0_S +static const struct mpc_sie_dev_cfg_t MPC_ISRAM0_DEV_CFG_S = { + .base = MUSCA_S1_MPC_SRAM0_S_BASE}; +static struct mpc_sie_dev_data_t MPC_ISRAM0_DEV_DATA_S = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_ISRAM0_DEV_S = { + &(MPC_ISRAM0_DEV_CFG_S), + &(MPC_ISRAM0_DEV_DATA_S)}; +#endif + +#ifdef MPC_ISRAM1_S +static const struct mpc_sie_dev_cfg_t MPC_ISRAM1_DEV_CFG_S = { + .base = MUSCA_S1_MPC_SRAM1_S_BASE}; +static struct mpc_sie_dev_data_t MPC_ISRAM1_DEV_DATA_S = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_ISRAM1_DEV_S = { + &(MPC_ISRAM1_DEV_CFG_S), + &(MPC_ISRAM1_DEV_DATA_S)}; +#endif + +#ifdef MPC_ISRAM2_S +static const struct mpc_sie_dev_cfg_t MPC_ISRAM2_DEV_CFG_S = { + .base = MUSCA_S1_MPC_SRAM2_S_BASE}; +static struct mpc_sie_dev_data_t MPC_ISRAM2_DEV_DATA_S = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_ISRAM2_DEV_S = { + &(MPC_ISRAM2_DEV_CFG_S), + &(MPC_ISRAM2_DEV_DATA_S)}; +#endif + +#ifdef MPC_ISRAM3_S +static const struct mpc_sie_dev_cfg_t MPC_ISRAM3_DEV_CFG_S = { + .base = MUSCA_S1_MPC_SRAM3_S_BASE}; +static struct mpc_sie_dev_data_t MPC_ISRAM3_DEV_DATA_S = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_ISRAM3_DEV_S = { + &(MPC_ISRAM3_DEV_CFG_S), + &(MPC_ISRAM3_DEV_DATA_S)}; +#endif + +#ifdef MPC_CODE_SRAM_NS +static const struct mpc_sie_dev_cfg_t MPC_CODE_SRAM_DEV_CFG_NS = { + .base = MUSCA_S1_CODE_SRAM_MPC_NS_BASE}; +static struct mpc_sie_dev_data_t MPC_CODE_SRAM_DEV_DATA_NS = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_CODE_SRAM_DEV_NS = { + &(MPC_CODE_SRAM_DEV_CFG_NS), + &(MPC_CODE_SRAM_DEV_DATA_NS)}; +#endif + +#ifdef MPC_CODE_SRAM_S +static const struct mpc_sie_dev_cfg_t MPC_CODE_SRAM_DEV_CFG_S = { + .base = MUSCA_S1_CODE_SRAM_MPC_S_BASE}; +static struct mpc_sie_dev_data_t MPC_CODE_SRAM_DEV_DATA_S = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_CODE_SRAM_DEV_S = { + &(MPC_CODE_SRAM_DEV_CFG_S), + &(MPC_CODE_SRAM_DEV_DATA_S)}; +#endif + +#ifdef MPC_QSPI_S +static const struct mpc_sie_dev_cfg_t MPC_QSPI_DEV_CFG_S = { + .base = MUSCA_S1_QSPI_MPC_S_BASE}; +static struct mpc_sie_dev_data_t MPC_QSPI_DEV_DATA_S = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_QSPI_DEV_S = { + &(MPC_QSPI_DEV_CFG_S), + &(MPC_QSPI_DEV_DATA_S)}; +#endif + +#ifdef MPC_QSPI_NS +static const struct mpc_sie_dev_cfg_t MPC_QSPI_DEV_CFG_NS = { + .base = MUSCA_S1_QSPI_MPC_NS_BASE}; +static struct mpc_sie_dev_data_t MPC_QSPI_DEV_DATA_NS = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_QSPI_DEV_NS = { + &(MPC_QSPI_DEV_CFG_NS), + &(MPC_QSPI_DEV_DATA_NS)}; +#endif + +#ifdef MPC_MRAM_S +static const struct mpc_sie_dev_cfg_t MPC_MRAM_DEV_CFG_S = { + .base = MUSCA_S1_MRAM_MPC_S_BASE}; +static struct mpc_sie_dev_data_t MPC_MRAM_DEV_DATA_S = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_MRAM_DEV_S = { + &(MPC_MRAM_DEV_CFG_S), + &(MPC_MRAM_DEV_DATA_S)}; +#endif + +#ifdef MPC_MRAM_NS +static const struct mpc_sie_dev_cfg_t MPC_MRAM_DEV_CFG_NS = { + .base = MUSCA_S1_MRAM_MPC_NS_BASE}; +static struct mpc_sie_dev_data_t MPC_MRAM_DEV_DATA_NS = { + .range_list = 0, + .nbr_of_ranges = 0, + .is_initialized = false}; +struct mpc_sie_dev_t MPC_MRAM_DEV_NS = { + &(MPC_MRAM_DEV_CFG_NS), + &(MPC_MRAM_DEV_DATA_NS)}; +#endif + +/* ARM MHU driver structures */ +#ifdef ARM_MHU0_S +static const struct arm_mhu_sse_200_dev_cfg_t ARM_MHU0_DEV_CFG_S = { + .base = MUSCA_S1_MHU0_S_BASE}; +struct arm_mhu_sse_200_dev_t ARM_MHU0_DEV_S = {&(ARM_MHU0_DEV_CFG_S)}; +#endif +#ifdef ARM_MHU0_NS +static const struct arm_mhu_sse_200_dev_cfg_t ARM_MHU0_DEV_CFG_NS = { + .base = MUSCA_S1_MHU0_NS_BASE}; +struct arm_mhu_sse_200_dev_t ARM_MHU0_DEV_NS = {&(ARM_MHU0_DEV_CFG_NS)}; +#endif + +#ifdef ARM_MHU1_S +static const struct arm_mhu_sse_200_dev_cfg_t ARM_MHU1_DEV_CFG_S = { + .base = MUSCA_S1_MHU1_S_BASE}; +struct arm_mhu_sse_200_dev_t ARM_MHU1_DEV_S = {&(ARM_MHU1_DEV_CFG_S)}; +#endif +#ifdef ARM_MHU1_NS +static const struct arm_mhu_sse_200_dev_cfg_t ARM_MHU1_DEV_CFG_NS = { + .base = MUSCA_S1_MHU1_NS_BASE}; +struct arm_mhu_sse_200_dev_t ARM_MHU1_DEV_NS = {&(ARM_MHU1_DEV_CFG_NS)}; +#endif + +/* SSE-200 Cache driver structure */ +#ifdef SSE_200_CACHE_S +static const struct arm_cache_dev_cfg_t SSE_200_CACHE_CFG_S = { + .base = MUSCA_S1_CPU_ELEMENT_S_BASE}; +struct arm_cache_dev_t SSE_200_CACHE_DEV_S = {&(SSE_200_CACHE_CFG_S)}; +#endif + +#ifdef SSE_200_CACHE_NS +static const struct arm_cache_dev_cfg_t SSE_200_CACHE_CFG_NS = { + .base = MUSCA_S1_CPU_ELEMENT_NS_BASE}; +struct arm_cache_dev_t SSE_200_CACHE_DEV_NS = {&(SSE_200_CACHE_CFG_NS)}; +#endif + +/* I2C IP6510 driver structures */ +#ifdef I2C0_IP6510_S +static const struct i2c_ip6510_dev_cfg_t I2C0_IP6510_DEV_CFG_S = { + .base = MUSCA_S1_I2C0_S_BASE, + .default_mode = I2C_IP6510_MASTER_MODE, + .default_bus_speed = I2C_IP6510_SPEED_100KHZ}; +static struct i2c_ip6510_dev_data_t I2C0_IP6510_DEV_DATA_S = { + .state = 0, + .mode = 0, + .bus_speed = 0}; +struct i2c_ip6510_dev_t I2C0_IP6510_DEV_S = { + &(I2C0_IP6510_DEV_CFG_S), + &(I2C0_IP6510_DEV_DATA_S)}; +#endif + +#ifdef I2C0_IP6510_NS +static const struct i2c_ip6510_dev_cfg_t I2C0_IP6510_DEV_CFG_NS = { + .base = MUSCA_S1_I2C0_NS_BASE, + .default_mode = I2C_IP6510_MASTER_MODE, + .default_bus_speed = I2C_IP6510_SPEED_100KHZ}; +static struct i2c_ip6510_dev_data_t I2C0_IP6510_DEV_DATA_NS = { + .state = 0, + .mode = 0, + .bus_speed = 0}; +struct i2c_ip6510_dev_t I2C0_IP6510_DEV_NS = { + &(I2C0_IP6510_DEV_CFG_NS), + &(I2C0_IP6510_DEV_DATA_NS)}; +#endif + +#ifdef I2C1_IP6510_S +static const struct i2c_ip6510_dev_cfg_t I2C1_IP6510_DEV_CFG_S = { + .base = MUSCA_S1_I2C1_S_BASE, + .default_mode = I2C_IP6510_MASTER_MODE, + .default_bus_speed = I2C_IP6510_SPEED_100KHZ}; +static struct i2c_ip6510_dev_data_t I2C1_IP6510_DEV_DATA_S = { + .state = 0, + .mode = 0, + .bus_speed = 0}; +struct i2c_ip6510_dev_t I2C1_IP6510_DEV_S = { + &(I2C1_IP6510_DEV_CFG_S), + &(I2C1_IP6510_DEV_DATA_S)}; +#endif + +#ifdef I2C1_IP6510_NS +static const struct i2c_ip6510_dev_cfg_t I2C1_IP6510_DEV_CFG_NS = { + .base = MUSCA_S1_I2C1_NS_BASE, + .default_mode = I2C_IP6510_MASTER_MODE, + .default_bus_speed = I2C_IP6510_SPEED_100KHZ}; +static struct i2c_ip6510_dev_data_t I2C1_IP6510_DEV_DATA_NS = { + .state = 0, + .mode = 0, + .bus_speed = 0}; +struct i2c_ip6510_dev_t I2C1_IP6510_DEV_NS = { + &(I2C1_IP6510_DEV_CFG_NS), + &(I2C1_IP6510_DEV_DATA_NS)}; +#endif + +/* CMSDK Timers driver structures */ +#ifdef CMSDK_TIMER0_S +static const struct timer_cmsdk_dev_cfg_t CMSDK_TIMER0_DEV_CFG_S = { + .base = MUSCA_S1_CMSDK_TIMER0_S_BASE}; +static struct timer_cmsdk_dev_data_t CMSDK_TIMER0_DEV_DATA_S = { + .is_initialized = 0}; +struct timer_cmsdk_dev_t CMSDK_TIMER0_DEV_S = {&(CMSDK_TIMER0_DEV_CFG_S), + &(CMSDK_TIMER0_DEV_DATA_S)}; +#endif +#ifdef CMSDK_TIMER0_NS +static const struct timer_cmsdk_dev_cfg_t CMSDK_TIMER0_DEV_CFG_NS = { + .base = MUSCA_S1_CMSDK_TIMER0_NS_BASE}; +static struct timer_cmsdk_dev_data_t CMSDK_TIMER0_DEV_DATA_NS = { + .is_initialized = 0}; +struct timer_cmsdk_dev_t CMSDK_TIMER0_DEV_NS = {&(CMSDK_TIMER0_DEV_CFG_NS), + &(CMSDK_TIMER0_DEV_DATA_NS)}; +#endif + +#ifdef CMSDK_TIMER1_S +static const struct timer_cmsdk_dev_cfg_t CMSDK_TIMER1_DEV_CFG_S = { + .base = MUSCA_S1_CMSDK_TIMER1_S_BASE}; +static struct timer_cmsdk_dev_data_t CMSDK_TIMER1_DEV_DATA_S = { + .is_initialized = 0}; +struct timer_cmsdk_dev_t CMSDK_TIMER1_DEV_S = {&(CMSDK_TIMER1_DEV_CFG_S), + &(CMSDK_TIMER1_DEV_DATA_S)}; +#endif +#ifdef CMSDK_TIMER1_NS +static const struct timer_cmsdk_dev_cfg_t CMSDK_TIMER1_DEV_CFG_NS = { + .base = MUSCA_S1_CMSDK_TIMER1_NS_BASE}; +static struct timer_cmsdk_dev_data_t CMSDK_TIMER1_DEV_DATA_NS = { + .is_initialized = 0}; +struct timer_cmsdk_dev_t CMSDK_TIMER1_DEV_NS = {&(CMSDK_TIMER1_DEV_CFG_NS), + &(CMSDK_TIMER1_DEV_DATA_NS)}; +#endif + +/* CMSDK Dualtimer driver structures */ +#ifdef CMSDK_DUALTIMER_S +static const struct dualtimer_cmsdk_dev_cfg_t CMSDK_DUALTIMER_DEV_CFG_S = { + .base = MUSCA_S1_CMSDK_DUALTIMER_S_BASE}; +static struct dualtimer_cmsdk_dev_data_t CMSDK_DUALTIMER_DEV_DATA_S = { + .is_initialized = 0}; + +struct dualtimer_cmsdk_dev_t CMSDK_DUALTIMER_DEV_S = { + &(CMSDK_DUALTIMER_DEV_CFG_S), + &(CMSDK_DUALTIMER_DEV_DATA_S)}; +#endif + +#ifdef CMSDK_DUALTIMER_NS +static const struct dualtimer_cmsdk_dev_cfg_t CMSDK_DUALTIMER_DEV_CFG_NS = { + .base = MUSCA_S1_CMSDK_DUALTIMER_NS_BASE}; +static struct dualtimer_cmsdk_dev_data_t CMSDK_DUALTIMER_DEV_DATA_NS = { + .is_initialized = 0}; + +struct dualtimer_cmsdk_dev_t CMSDK_DUALTIMER_DEV_NS = { + &(CMSDK_DUALTIMER_DEV_CFG_NS), + &(CMSDK_DUALTIMER_DEV_DATA_NS)}; +#endif + +/* General-Purpose Timer driver structures */ +#ifdef GP_TIMER_S +static const struct timer_gp_dev_cfg_t GP_TIMER_DEV_CFG_S = { + .base = MUSCA_S1_TIMER_S_BASE}; +static struct timer_gp_dev_data_t GP_TIMER_DEV_DATA_S = { + .is_initialized = false, + .alarm0_init = 0, + .alarm1_init = 0}; +struct timer_gp_dev_t GP_TIMER_DEV_S = { + &(GP_TIMER_DEV_CFG_S), + &(GP_TIMER_DEV_DATA_S)}; +#endif + +#ifdef GP_TIMER_NS +static const struct timer_gp_dev_cfg_t GP_TIMER_DEV_CFG_NS = { + .base = MUSCA_S1_TIMER_NS_BASE}; +static struct timer_gp_dev_data_t GP_TIMER_DEV_DATA_NS = { + .is_initialized = false, + .alarm0_init = 0, + .alarm1_init = 0}; +struct timer_gp_dev_t GP_TIMER_DEV_NS = { + &(GP_TIMER_DEV_CFG_NS), + &(GP_TIMER_DEV_DATA_NS)}; +#endif + +/* PL031 Real-Time Clock structure */ +#ifdef RTC_PL031_S +static const struct rtc_pl031_dev_cfg_t RTC_PL031_DEV_CFG_S = { + .base = MUSCA_S1_RTC_S_BASE}; +struct rtc_pl031_dev_t RTC_PL031_DEV_S = {&(RTC_PL031_DEV_CFG_S)}; +#endif + +#ifdef RTC_PL031_NS +static const struct rtc_pl031_dev_cfg_t RTC_PL031_DEV_CFG_NS = { + .base = MUSCA_S1_RTC_NS_BASE}; +struct rtc_pl031_dev_t RTC_PL031_DEV_NS = {&(RTC_PL031_DEV_CFG_NS)}; +#endif + +#ifdef UART0_PL011_S +static const struct uart_pl011_dev_cfg_t UART0_PL011_DEV_CFG_S = { + .base = MUSCA_S1_UART0_S_BASE, + .def_baudrate = UART_DEFAULT_BAUD_RATE, + .def_wlen = UART_PL011_WLEN_8, + .def_parity = UART_PL011_PARITY_DISABLED, + .def_stopbit = UART_PL011_STOPBIT_1}; +static struct uart_pl011_dev_data_t UART0_PL011_DEV_DATA_S = { + .state = 0, + .uart_clk = 0, + .baudrate = 0}; +struct uart_pl011_dev_t UART0_PL011_DEV_S = {&(UART0_PL011_DEV_CFG_S), + &(UART0_PL011_DEV_DATA_S)}; +#endif + +#ifdef UART0_PL011_NS +static const struct uart_pl011_dev_cfg_t UART0_PL011_DEV_CFG_NS = { + .base = MUSCA_S1_UART0_NS_BASE, + .def_baudrate = UART_DEFAULT_BAUD_RATE, + .def_wlen = UART_PL011_WLEN_8, + .def_parity = UART_PL011_PARITY_DISABLED, + .def_stopbit = UART_PL011_STOPBIT_1}; +static struct uart_pl011_dev_data_t UART0_PL011_DEV_DATA_NS = { + .state = 0, + .uart_clk = 0, + .baudrate = 0}; +struct uart_pl011_dev_t UART0_PL011_DEV_NS = {&(UART0_PL011_DEV_CFG_NS), + &(UART0_PL011_DEV_DATA_NS)}; +#endif + +#ifdef UART1_PL011_S +static const struct uart_pl011_dev_cfg_t UART1_PL011_DEV_CFG_S = { + .base = MUSCA_S1_UART1_S_BASE, + .def_baudrate = UART_DEFAULT_BAUD_RATE, + .def_wlen = UART_PL011_WLEN_8, + .def_parity = UART_PL011_PARITY_DISABLED, + .def_stopbit = UART_PL011_STOPBIT_1}; +static struct uart_pl011_dev_data_t UART1_PL011_DEV_DATA_S = { + .state = 0, + .uart_clk = 0, + .baudrate = 0}; +struct uart_pl011_dev_t UART1_PL011_DEV_S = {&(UART1_PL011_DEV_CFG_S), + &(UART1_PL011_DEV_DATA_S)}; +#endif + +#ifdef UART1_PL011_NS +static const struct uart_pl011_dev_cfg_t UART1_PL011_DEV_CFG_NS = { + .base = MUSCA_S1_UART1_NS_BASE, + .def_baudrate = UART_DEFAULT_BAUD_RATE, + .def_wlen = UART_PL011_WLEN_8, + .def_parity = UART_PL011_PARITY_DISABLED, + .def_stopbit = UART_PL011_STOPBIT_1}; +static struct uart_pl011_dev_data_t UART1_PL011_DEV_DATA_NS = { + .state = 0, + .uart_clk = 0, + .baudrate = 0}; +struct uart_pl011_dev_t UART1_PL011_DEV_NS = {&(UART1_PL011_DEV_CFG_NS), + &(UART1_PL011_DEV_DATA_NS)}; +#endif + +/* SPI IP6524 driver structures */ +#ifdef SPI0_IP6524_S +static const struct spi_ip6524_dev_cfg_t SPI0_DEV_CFG_S = { + .base = MUSCA_S1_SPI0_S_BASE}; +static struct spi_ip6524_dev_data_t SPI0_DEV_DATA_S = { + .state = 0}; +struct spi_ip6524_dev_t SPI0_DEV_S = {&(SPI0_DEV_CFG_S), + &(SPI0_DEV_DATA_S)}; +#endif + +#ifdef SPI0_IP6524_NS +static const struct spi_ip6524_dev_cfg_t SPI0_DEV_CFG_NS = { + .base = MUSCA_S1_SPI0_NS_BASE}; +static struct spi_ip6524_dev_data_t SPI0_DEV_DATA_NS = { + .state = 0}; +struct spi_ip6524_dev_t SPI0_DEV_NS = {&(SPI0_DEV_CFG_NS), + &(SPI0_DEV_DATA_NS)}; +#endif + +/* QSPI IP6514E driver structures */ +#ifdef QSPI_IP6514E_S +static const struct qspi_ip6514e_dev_cfg_t QSPI_DEV_CFG_S = { + .base = MUSCA_S1_QSPI_REG_S_BASE, + .addr_mask = (1U << 25) - 1, /* 32 MiB minus 1 byte */ +}; +struct qspi_ip6514e_dev_t QSPI_DEV_S = { + &QSPI_DEV_CFG_S +}; +#endif + +#ifdef QSPI_IP6514E_NS +static const struct qspi_ip6514e_dev_cfg_t QSPI_DEV_CFG_NS = { + .base = MUSCA_S1_QSPI_REG_NS_BASE, + .addr_mask = (1U << 25) - 1, /* 32 MiB minus 1 byte */ +}; +struct qspi_ip6514e_dev_t QSPI_DEV_NS = { + &QSPI_DEV_CFG_NS +}; +#endif + +/* ======= External peripheral configuration structure definitions ======= */ + +/* MT25QL Flash memory library structures */ +#if (defined(MT25QL_S) && defined(QSPI_IP6514E_S)) +struct mt25ql_dev_t MT25QL_DEV_S = { + .controller = &QSPI_DEV_S, + .direct_access_start_addr = MUSCA_S1_QSPI_FLASH_S_BASE, + .baud_rate_div = 4U, + .size = 0x01000000U, /* 16 MiB */ + .config_state = { 0 }, +}; +#endif + +#if (defined(MT25QL_NS) && defined(QSPI_IP6514E_NS)) +struct mt25ql_dev_t MT25QL_DEV_NS = { + .controller = &QSPI_DEV_NS, + .direct_access_start_addr = MUSCA_S1_QSPI_FLASH_NS_BASE, + .baud_rate_div = 4U, + .size = 0x01000000U, /* 16 MiB */ + .config_state = { 0 }, +}; +#endif diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/device_definition.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/device_definition.h new file mode 100644 index 0000000..723664f --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/device_definition.h @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2017-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file device_definition.h + * \brief The structure definitions in this file are exported based + * on the peripheral definitions from device_cfg.h. + * This file is meant to be used as a helper for baremetal + * applications and/or as an example of how to configure the generic + * driver structures. + */ + +#ifndef __DEVICE_DEFINITION_H__ +#define __DEVICE_DEFINITION_H__ + +#include "device_cfg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ======= Peripheral configuration structure declarations ======= */ + +/* ARM SCC driver structures */ +#ifdef MUSCA_S1_SCC_S +#include "musca_s1_scc_drv.h" +extern struct musca_s1_scc_dev_t MUSCA_S1_SCC_DEV_S; +#endif +#ifdef MUSCA_S1_SCC_NS +#include "musca_s1_scc_drv.h" +extern struct musca_s1_scc_dev_t MUSCA_S1_SCC_DEV_NS; +#endif + +/* ARM GPIO driver structures */ +#ifdef GPIO0_CMSDK_S +#include "gpio_cmsdk_drv.h" +extern struct gpio_cmsdk_dev_t GPIO0_CMSDK_DEV_S; +#endif +#ifdef GPIO0_CMSDK_NS +#include "gpio_cmsdk_drv.h" +extern struct gpio_cmsdk_dev_t GPIO0_CMSDK_DEV_NS; +#endif + +/* ARM MPC SIE 200 driver structures */ +#ifdef MPC_ISRAM0_S +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_ISRAM0_DEV_S; +#endif +#ifdef MPC_ISRAM1_S +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_ISRAM1_DEV_S; +#endif +#ifdef MPC_ISRAM2_S +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_ISRAM2_DEV_S; +#endif +#ifdef MPC_ISRAM3_S +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_ISRAM3_DEV_S; +#endif +#ifdef MPC_CODE_SRAM_S +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_CODE_SRAM_DEV_S; +#endif +#ifdef MPC_CODE_SRAM_NS +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_CODE_SRAM_DEV_NS; +#endif +#ifdef MPC_QSPI_S +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_QSPI_DEV_S; +#endif +#ifdef MPC_QSPI_NS +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_QSPI_DEV_NS; +#endif +#ifdef MPC_MRAM_S +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_MRAM_DEV_S; +#endif +#ifdef MPC_MRAM_NS +#include "mpc_sie_drv.h" +extern struct mpc_sie_dev_t MPC_MRAM_DEV_NS; +#endif + +/* ARM MHU driver structures */ +#ifdef ARM_MHU0_S +#include "mhu_sse_200_drv.h" +extern struct arm_mhu_sse_200_dev_t ARM_MHU0_DEV_S; +#endif +#ifdef ARM_MHU0_NS +#include "mhu_sse_200_drv.h" +extern struct arm_mhu_sse_200_dev_t ARM_MHU0_DEV_NS; +#endif +#ifdef ARM_MHU1_S +#include "mhu_sse_200_drv.h" +extern struct arm_mhu_sse_200_dev_t ARM_MHU1_DEV_S; +#endif +#ifdef ARM_MHU1_NS +#include "mhu_sse_200_drv.h" +extern struct arm_mhu_sse_200_dev_t ARM_MHU1_DEV_NS; +#endif + +/* ARM UART PL011 driver structures */ +#ifdef UART0_PL011_S +#include "uart_pl011_drv.h" +extern struct uart_pl011_dev_t UART0_PL011_DEV_S; +#endif +#ifdef UART0_PL011_NS +#include "uart_pl011_drv.h" +extern struct uart_pl011_dev_t UART0_PL011_DEV_NS; +#endif +#ifdef UART1_PL011_S +#include "uart_pl011_drv.h" +extern struct uart_pl011_dev_t UART1_PL011_DEV_S; +#endif +#ifdef UART1_PL011_NS +#include "uart_pl011_drv.h" +extern struct uart_pl011_dev_t UART1_PL011_DEV_NS; +#endif + +/* SSE-200 Cache driver structure */ +#ifdef SSE_200_CACHE_S +#include "cache_drv.h" +extern struct arm_cache_dev_t SSE_200_CACHE_DEV_S; +#endif +#ifdef SSE_200_CACHE_NS +#include "cache_drv.h" +extern struct arm_cache_dev_t SSE_200_CACHE_DEV_NS; +#endif + +/* I2C IP6510 driver structures */ +#ifdef I2C0_IP6510_S +#include "i2c_ip6510_drv.h" +extern struct i2c_ip6510_dev_t I2C0_IP6510_DEV_S; +#endif +#ifdef I2C0_IP6510_NS +#include "i2c_ip6510_drv.h" +extern struct i2c_ip6510_dev_t I2C0_IP6510_DEV_NS; +#endif +#ifdef I2C1_IP6510_S +#include "i2c_ip6510_drv.h" +extern struct i2c_ip6510_dev_t I2C1_IP6510_DEV_S; +#endif +#ifdef I2C1_IP6510_NS +#include "i2c_ip6510_drv.h" +extern struct i2c_ip6510_dev_t I2C1_IP6510_DEV_NS; +#endif + +/* CMSDK Dualtimer driver structures */ +#ifdef CMSDK_DUALTIMER_S +#include "dualtimer_cmsdk_drv.h" +extern struct dualtimer_cmsdk_dev_t CMSDK_DUALTIMER_DEV_S; +#endif +#ifdef CMSDK_DUALTIMER_NS +#include "dualtimer_cmsdk_drv.h" +extern struct dualtimer_cmsdk_dev_t CMSDK_DUALTIMER_DEV_NS; +#endif + +/* CMSDK Timer driver structures */ +#ifdef CMSDK_TIMER0_S +#include "timer_cmsdk_drv.h" +extern struct timer_cmsdk_dev_t CMSDK_TIMER0_DEV_S; +#endif +#ifdef CMSDK_TIMER0_NS +#include "timer_cmsdk_drv.h" +extern struct timer_cmsdk_dev_t CMSDK_TIMER0_DEV_NS; +#endif + +#ifdef CMSDK_TIMER1_S +#include "timer_cmsdk_drv.h" +extern struct timer_cmsdk_dev_t CMSDK_TIMER1_DEV_S; +#endif +#ifdef CMSDK_TIMER1_NS +#include "timer_cmsdk_drv.h" +extern struct timer_cmsdk_dev_t CMSDK_TIMER1_DEV_NS; +#endif + +/* General-Purpose Timer driver structures */ +#ifdef GP_TIMER_S +#include "timer_gp_drv.h" +extern struct timer_gp_dev_t GP_TIMER_DEV_S; +#endif +#ifdef GP_TIMER_NS +#include "timer_gp_drv.h" +extern struct timer_gp_dev_t GP_TIMER_DEV_NS; +#endif + +/* RTC PL031 */ +#ifdef RTC_PL031_S +#include "rtc_pl031_drv.h" +extern struct rtc_pl031_dev_t RTC_PL031_DEV_S; +#endif + +#ifdef RTC_PL031_NS +#include "rtc_pl031_drv.h" +extern struct rtc_pl031_dev_t RTC_PL031_DEV_NS; +#endif + +/* Cadence SPI IP6524 driver structures */ +#ifdef SPI0_IP6524_S +#include "spi_ip6524_drv.h" +extern struct spi_ip6524_dev_t SPI0_DEV_S; +#endif +#ifdef SPI0_IP6524_NS +#include "spi_ip6524_drv.h" +extern struct spi_ip6524_dev_t SPI0_DEV_NS; +#endif + +/* QSPI Flash Controller driver structures */ +#ifdef QSPI_IP6514E_S +#include "qspi_ip6514e_drv.h" +extern struct qspi_ip6514e_dev_t QSPI_DEV_S; +#endif + +#ifdef QSPI_IP6514E_NS +#include "qspi_ip6514e_drv.h" +extern struct qspi_ip6514e_dev_t QSPI_DEV_NS; +#endif + +/* ARM PPC driver structures */ +#ifdef AHB_PPC0_S +#include "ppc_sse200_drv.h" +extern struct ppc_sse200_dev_t AHB_PPC0_DEV_S; +#endif + +#ifdef AHB_PPCEXP0_S +#include "ppc_sse200_drv.h" +extern struct ppc_sse200_dev_t AHB_PPCEXP0_DEV_S; +#endif + +#ifdef APB_PPC0_S +#include "ppc_sse200_drv.h" +extern struct ppc_sse200_dev_t APB_PPC0_DEV_S; +#endif + +#ifdef APB_PPC1_S +#include "ppc_sse200_drv.h" +extern struct ppc_sse200_dev_t APB_PPC1_DEV_S; +#endif + +#ifdef APB_PPCEXP0_S +#include "ppc_sse200_drv.h" +extern struct ppc_sse200_dev_t APB_PPCEXP0_DEV_S; +#endif + +#ifdef APB_PPCEXP1_S +#include "ppc_sse200_drv.h" +extern struct ppc_sse200_dev_t APB_PPCEXP1_DEV_S; +#endif + +/* ======= External peripheral configuration structure declarations ======= */ + +/* MT25QL Flash memory library structures */ +#if (defined(MT25QL_S) && defined(QSPI_IP6514E_S)) +#include "mt25ql_flash_lib.h" +extern struct mt25ql_dev_t MT25QL_DEV_S; +#endif +#if (defined(MT25QL_NS) && defined(QSPI_IP6514E_NS)) +#include "mt25ql_flash_lib.h" +extern struct mt25ql_dev_t MT25QL_DEV_NS; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __DEVICE_DEFINITION_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/cache_drv.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/cache_drv.c new file mode 100644 index 0000000..638fc8f --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/cache_drv.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2017-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file cache_drv.c + * \brief Driver for L1 instruction cache based on SSE-200 version r1p0 + */ + +#include "cache_drv.h" + +/** + * \brief L1 cache register map structure + */ +struct _arm_cache_reg_map_t { + volatile uint32_t cacheichwparams; + /*!< Offset: 0x000 (R/ ) HW Parameters Register */ + volatile uint32_t cacheicctrl; + /*!< Offset: 0x004 (R/W) Control Register */ + volatile uint32_t reserved_0[62]; + /*!< Offset: 0x00C-0x0FC Reserved */ + volatile uint32_t cacheicirqstat; + /*!< Offset: 0x100 (R/ ) Interrupt Request Status Register */ + volatile uint32_t cacheicirqsclr; + /*!< Offset: 0x104 ( /W) Interrupt Status Clear Register */ + volatile uint32_t cacheicirqen; + /*!< Offset: 0x108 (R/W) Interrupt Enable Register */ + volatile uint32_t cacheicdbgfillerr; + /*!< Offset: 0x10C (R/ ) Fill Error Address Register */ + volatile uint32_t reserved_1[124]; + /*!< Offset: 0x110-0x2FC Reserved */ + volatile uint32_t cacheicsh; + /*!< Offset: 0x300 (R/ ) Cache Statistic Hit Register */ + volatile uint32_t cacheicsm; + /*!< Offset: 0x304 (R/ ) Cache Statistic Miss Register */ + volatile uint32_t cacheicsuc; + /*!< Offset: 0x308 (R/ ) Cache Statistic Uncached Register */ + volatile uint32_t reserved_2[331]; + /*!< Offset: 0x30C-0xFCC Reserved */ + volatile uint32_t cachepidr4; + /*!< Offset: 0xFD0 (R/ ) Product ID Register 4 */ + volatile uint32_t cachepidr5; + /*!< Offset: 0xFD4 (R/ ) Product ID Register 5 */ + volatile uint32_t cachepidr6; + /*!< Offset: 0xFD8 (R/ ) Product ID Register 6 */ + volatile uint32_t cachepidr7; + /*!< Offset: 0xFDC (R/ ) Product ID Register 7 */ + volatile uint32_t cachepidr0; + /*!< Offset: 0xFE0 (R/ ) Product ID Register 0 */ + volatile uint32_t cachepidr1; + /*!< Offset: 0xFE4 (R/ ) Product ID Register 1 */ + volatile uint32_t cachepidr2; + /*!< Offset: 0xFE8 (R/ ) Product ID Register 2 */ + volatile uint32_t cachepidr3; + /*!< Offset: 0xFEC (R/ ) Product ID Register 3 */ + volatile uint32_t cachecidr0; + /*!< Offset: 0xFF0 (R/ ) Component ID Register 0 */ + volatile uint32_t cachecidr1; + /*!< Offset: 0xFF4 (R/ ) Component ID Register 1 */ + volatile uint32_t cachecidr2; + /*!< Offset: 0xFF8 (R/ ) Component ID Register 2 */ + volatile uint32_t cachecidr3; + /*!< Offset: 0xFFC (R/ ) Component ID Register 3 */ +}; + +#define ARM_CACHEICHWPARAMS_CSIZE_MASK (0xFu<cfg->base; + + enum arm_cache_size_t val = (enum arm_cache_size_t) + (p_cache->cacheichwparams & ARM_CACHEICHWPARAMS_CSIZE_MASK); + /** + * 9: 512 byte + * 10: 1 KB + * 11: 2 KB + * 12: 4 KB + * 13: 8 KB + * 14: 16 KB + * Other values are reserved, returning error + */ + if(val < arm_cache_size_512B || val > arm_cache_size_16KB) { + return arm_cache_size_err; + } else { + return val; + } +} + +bool arm_cache_is_stat_func_available(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + return (bool)(p_cache->cacheichwparams & ARM_CACHEICHWPARAMS_STATS_MASK); +} + +bool arm_cache_is_invalidate_cache_line_enabled(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + return (bool)(p_cache->cacheichwparams & ARM_CACHEICHWPARAMS_INVMAT_MASK); +} + +void arm_cache_enable(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl |= ARM_CACHEICCTRL_CACHEEN_MASK; + + return; +} + +void arm_cache_enable_blocking(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl |= ARM_CACHEICCTRL_CACHEEN_MASK; + + while(!(arm_cache_get_raw_intr_status(dev) & arm_cache_cec_intr_mask)); + + arm_cache_clear_intr(dev, arm_cache_cec_intr_mask); + + return; +} + +void arm_cache_disable(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl &= ~ARM_CACHEICCTRL_CACHEEN_MASK; + + return; +} + +void arm_cache_disable_blocking(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl &= ~ARM_CACHEICCTRL_CACHEEN_MASK; + + while(!(arm_cache_get_raw_intr_status(dev) & arm_cache_cdc_intr_mask)); + + arm_cache_clear_intr(dev, arm_cache_cdc_intr_mask); + + return; +} + +bool arm_cache_is_enabled(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + return (bool)(p_cache->cacheicctrl & ARM_CACHEICCTRL_CACHEEN_MASK); +} + +void arm_cache_full_invalidate(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl |= ARM_CACHEICCTRL_FINV_MASK; + + return; +} + +void arm_cache_full_invalidate_blocking(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl |= ARM_CACHEICCTRL_FINV_MASK; + + while(!(arm_cache_get_raw_intr_status(dev) & arm_cache_ic_intr_mask)); + + arm_cache_clear_intr(dev, arm_cache_ic_intr_mask); + + return; +} + +void arm_cache_statistic_enable(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl |= ARM_CACHEICCTRL_STATEN_MASK; + + return; +} + +void arm_cache_statistic_disable(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl &= ~ARM_CACHEICCTRL_STATEN_MASK; + + return; +} + +void arm_cache_clear_statistic_value(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl |= ARM_CACHEICCTRL_STATC_MASK; + + return; +} + +void arm_cache_handler_alloc_enable(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl |= ARM_CACHEICCTRL_HALLOC_MASK; + + return; +} + +void arm_cache_handler_alloc_disable(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicctrl &= ~ARM_CACHEICCTRL_HALLOC_MASK; + + return; +} + +void arm_cache_enable_intr(struct arm_cache_dev_t* dev, + enum arm_cache_intr_t mask) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicirqen |= (uint32_t)(mask); + + return; +} + +void arm_cache_disable_intr(struct arm_cache_dev_t* dev, + enum arm_cache_intr_t mask) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicirqen &= ~(uint32_t)(mask); + + return; +} +void arm_cache_clear_intr(struct arm_cache_dev_t* dev, + enum arm_cache_intr_t mask) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + p_cache->cacheicirqsclr = (uint32_t)mask; + + return; +} + +enum arm_cache_intr_t arm_cache_get_masked_intr_status( + struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + return (enum arm_cache_intr_t) + (p_cache->cacheicirqstat & p_cache->cacheicirqen); +} + +enum arm_cache_intr_t arm_cache_get_raw_intr_status( + struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + return (enum arm_cache_intr_t)(p_cache->cacheicirqstat); +} + +uint32_t arm_cache_get_debug_fill_address(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + return p_cache->cacheicdbgfillerr; +} + +uint32_t arm_cache_get_hit_count(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + return p_cache->cacheicsh; +} + +uint32_t arm_cache_get_miss_count(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + return p_cache->cacheicsm; +} + +uint32_t arm_cache_get_uncached_count(struct arm_cache_dev_t* dev) +{ + struct _arm_cache_reg_map_t* p_cache = + (struct _arm_cache_reg_map_t*)dev->cfg->base; + + return p_cache->cacheicsuc; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/cache_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/cache_drv.h new file mode 100644 index 0000000..f213cc2 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/cache_drv.h @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2017-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file cache_drv.h + * \brief Driver for L1 instruction cache based on SSE-200 version r1p0 + */ + +#ifndef __ARM_CACHE_DRV_H__ +#define __ARM_CACHE_DRV_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief L1 cache configuration structure + */ +struct arm_cache_dev_cfg_t { + const uint32_t base; /*!< L1 cache base address */ +}; + +/** + * \brief L1 cache device structure + */ +struct arm_cache_dev_t { + const struct arm_cache_dev_cfg_t* const cfg; /*!< L1 cache configuration */ +}; + +#define ARM_CACHEICHWPARAMS_CSIZE_OFF 0x0u + /*!< Instruction cache size bit field offset */ +#define ARM_CACHEICHWPARAMS_STATS_OFF 0x4u + /*!< Statistic functionality bit field offset */ +#define ARM_CACHEICHWPARAMS_DMA_OFF 0x5u + /*!< DMA engine bit field offset */ +#define ARM_CACHEICHWPARAMS_INVMAT_OFF 0x6u + /*!< Bit field offset to indicates whether + * invalidate cache line on write match is + * enabled */ +#define ARM_CACHEICHWPARAMS_COFFSIZE_OFF 0xCu + /*!< Cacheable Block Size bit field offset */ +#define ARM_CACHEICHWPARAMS_COFFSET_OFF 0x10u + /*!< Cacheable Offset Addr bit field offset */ + +#define ARM_CACHEICCTRL_CACHEEN_OFF 0x0u + /*!< Cache enable bit field offset */ +#define ARM_CACHEICCTRL_FINV_OFF 0x2u + /*!< Full invalidate bit field offset */ +#define ARM_CACHEICCTRL_STATEN_OFF 0x3u + /*!< Enable Statistic bit field offset */ +#define ARM_CACHEICCTRL_STATC_OFF 0x4u + /*!< Clear Statistic bit field offset */ +#define ARM_CACHEICCTRL_HALLOC_OFF 0x5u + /*!< Enable handler alloc bit field offset */ + +#define ARM_CACHE_INTR_IC_OFF 0x0u /*!< Invalidate Complete IRQ offset */ +#define ARM_CACHE_INTR_CDC_OFF 0x1u /*!< Cache Disable Complete IRQ offset */ +#define ARM_CACHE_INTR_CEC_OFF 0x2u /*!< Cache Enable Complete IRQ offset */ +#define ARM_CACHE_INTR_CFE_OFF 0x3u /*!< Cache Fill Error IRQ offset */ +#define ARM_CACHE_INTR_SV_OFF 0x4u /*!< Security violation IRQ offset */ +#define ARM_CACHE_INTR_SS_OFF 0x5u /*!< Statistics Saturated IRQ offset */ + +/** + * \brief L1 Cache Interrupt data structure + */ +enum arm_cache_intr_t { + arm_cache_ic_intr_mask = (0x1u< +#include +#include "gpio_cmsdk_drv.h" + +/* GPIO register map structure */ +struct gpio_cmsdk_reg_map_t { + volatile uint32_t data; /* Offset: 0x000 (R/W) Data register */ + volatile uint32_t dataout; /* Offset: 0x004 (R/W) Data output + * latch register */ + volatile uint32_t reserved0[2]; + volatile uint32_t outenableset; /* Offset: 0x010 (R/W) Output enable + * set register */ + volatile uint32_t outenableclr; /* Offset: 0x014 (R/W) Output enable + * clear register */ + volatile uint32_t altfuncset; /* Offset: 0x018 (R/W) Alternate function + * set register */ + volatile uint32_t altfuncclr; /* Offset: 0x01C (R/W) Alternate function + * clear register */ + volatile uint32_t intenset; /* Offset: 0x020 (R/W) Interrupt enable + * set register */ + volatile uint32_t intenclr; /* Offset: 0x024 (R/W) Interrupt enable + * clear register */ + volatile uint32_t inttypeset; /* Offset: 0x028 (R/W) Interrupt type + * set register */ + volatile uint32_t inttypeclr; /* Offset: 0x02C (R/W) Interrupt type + * clear register */ + volatile uint32_t intpolset; /* Offset: 0x030 (R/W) Interrupt polarity + * set register */ + volatile uint32_t intpolclr; /* Offset: 0x034 (R/W) Interrupt polarity + * clear register */ + union { + volatile uint32_t intstatus; /* Offset: 0x038 (R/ ) Interrupt status + * register */ + volatile uint32_t intclear; /* Offset: 0x038 ( /W) Interrupt clear + * register */ + }intreg; + volatile uint32_t reserved1[997]; + volatile uint32_t pid4; /* Peripheral ID Register 4 */ + volatile uint32_t pid0; /* Peripheral ID Register 0 */ + volatile uint32_t pid1; /* Peripheral ID Register 1 */ + volatile uint32_t pid2; /* Peripheral ID Register 2 */ + volatile uint32_t pid3; /* Peripheral ID Register 3 */ + volatile uint32_t cid0; /* Component ID Register 0 */ + volatile uint32_t cid1; /* Component ID Register 1 */ + volatile uint32_t cid2; /* Component ID Register 2 */ + volatile uint32_t cid4; /* Component ID Register 3 */ +}; + +void gpio_cmsdk_init(struct gpio_cmsdk_dev_t* dev) +{ + /* Nothing to init on the GPIO device */ +} + +/** + * \brief Configures port. + * + * \param[in] dev GPIO device to initalize \ref gpio_cmsdk_dev_t + * \param[in] pin_mask Pin mask for port access + * \param[in] direction Input or output \ref gpio_cmsdk_direction_t + * \param[in] altfunc_flags Alternate function \ref gpio_cmsdk_altfunc_t + * + */ +static void set_port_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask, + enum gpio_cmsdk_direction_t direction, + enum gpio_cmsdk_altfunc_t altfunc_flags) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + if(direction == GPIO_CMSDK_INPUT) { + p_gpio_port->outenableclr = pin_mask; + } else { + p_gpio_port->outenableset = pin_mask; + } + + if (altfunc_flags == GPIO_CMSDK_MAIN_FUNC) { + p_gpio_port->altfuncclr = pin_mask; + } else { + p_gpio_port->altfuncset = pin_mask; + } + + return; +} + +enum gpio_cmsdk_error_t +gpio_cmsdk_pin_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num, + enum gpio_cmsdk_direction_t direction, + enum gpio_cmsdk_altfunc_t altfunc_flags) +{ + uint32_t pin_mask = (1UL << pin_num); + + if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + set_port_config(dev, pin_mask, direction, altfunc_flags); + + return GPIO_CMSDK_ERR_NONE; +} + +enum gpio_cmsdk_error_t +gpio_cmsdk_port_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask, + enum gpio_cmsdk_direction_t direction, + enum gpio_cmsdk_altfunc_t altfunc_flags) +{ + if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + set_port_config(dev, pin_mask, direction, altfunc_flags); + + return GPIO_CMSDK_ERR_NONE; +} + +void gpio_cmsdk_config_irq(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask, + enum gpio_cmsdk_irq_type_t irq_type, + enum gpio_cmsdk_irq_polarity_t irq_pol) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + /* Interrupt type: EDGE = 1 - LEVEL = 0 */ + if(irq_type == GPIO_CMSDK_IRQ_EDGE) { + p_gpio_port->inttypeset = pin_mask; + } else if(irq_type == GPIO_CMSDK_IRQ_LEVEL) { + p_gpio_port->inttypeclr = pin_mask; + } + + /* Interrupt polarity */ + if(irq_pol == GPIO_CMSDK_IRQ_LOW_OR_FALLING_EDGE) { + p_gpio_port->intpolclr = pin_mask; + } else if(irq_pol == GPIO_CMSDK_IRQ_HIGH_OR_RISING_EDGE) { + p_gpio_port->intpolset = pin_mask; + } +} + +enum gpio_cmsdk_error_t gpio_cmsdk_pin_write(struct gpio_cmsdk_dev_t* dev, + uint32_t pin_num, + uint32_t value) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + /* GPIO data output register is a read-modify-write register, + * so before writing a value on a GPIO pin it is required to disable + * the interrupts to prevent concurrency problems. + */ + if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + if(value) { + /* Sets the pin */ + p_gpio_port->dataout |= (1UL << pin_num); + } else { + /* Clears the pin */ + p_gpio_port->dataout &= ~(1UL << pin_num); + } + + return GPIO_CMSDK_ERR_NONE; +} + +enum gpio_cmsdk_error_t gpio_cmsdk_port_write(struct gpio_cmsdk_dev_t* dev, + uint32_t pin_mask, + uint32_t value) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + /* GPIO data output register is a read-modify-write register, + * so before writing a value on a GPIO pin it is required to disable + * the interrupts to prevent concurrency problems. + */ + if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + /* Clear all bits defined in the mask, + * and set selected bits from value parameter. + */ + p_gpio_port->dataout = + ((~pin_mask & p_gpio_port->dataout) | (pin_mask & value)); + + return GPIO_CMSDK_ERR_NONE; +} + +enum gpio_cmsdk_error_t +gpio_cmsdk_pin_read(struct gpio_cmsdk_dev_t* dev, + uint32_t pin_num, + uint32_t *data) +{ + uint32_t value; + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + value = p_gpio_port->data; + + *data = (value >> pin_num) & 1UL; + + return GPIO_CMSDK_ERR_NONE; +} + +enum gpio_cmsdk_error_t +gpio_cmsdk_port_read(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask, + uint32_t *data) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + *data = p_gpio_port->data & pin_mask; + + return GPIO_CMSDK_ERR_NONE; +} + +enum gpio_cmsdk_error_t +gpio_cmsdk_set_pin_irq_cfg(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num, + enum gpio_cmsdk_irq_status_t status) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + if(status == GPIO_CMSDK_IRQ_ENABLE) { + p_gpio_port->intenset = (1UL << pin_num); + } else { + p_gpio_port->intenclr = (1UL << pin_num); + } + + return GPIO_CMSDK_ERR_NONE; +} + +enum gpio_cmsdk_error_t +gpio_cmsdk_set_port_irq_cfg(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask, + enum gpio_cmsdk_irq_status_t status) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + if(status == GPIO_CMSDK_IRQ_ENABLE) { + p_gpio_port->intenset = pin_mask; + } else { + p_gpio_port->intenclr = pin_mask; + } + + return GPIO_CMSDK_ERR_NONE; +} + +enum gpio_cmsdk_error_t +gpio_cmsdk_get_pin_irq_status(struct gpio_cmsdk_dev_t* dev, + uint32_t pin_num, uint32_t* status) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + *status = ((p_gpio_port->intreg.intstatus >> pin_num) & 1UL); + + return GPIO_CMSDK_ERR_NONE; +} + +enum gpio_cmsdk_error_t +gpio_cmsdk_get_port_irq_status(struct gpio_cmsdk_dev_t* dev, + uint32_t pin_mask, uint32_t* status) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + if(pin_mask > GPIO_CMSDK_MAX_PORT_MASK) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + *status = (p_gpio_port->intreg.intstatus & pin_mask); + + return GPIO_CMSDK_ERR_NONE; +} + + +enum gpio_cmsdk_error_t gpio_cmsdk_clear_irq(struct gpio_cmsdk_dev_t* dev, + uint8_t pin_num) +{ + struct gpio_cmsdk_reg_map_t* p_gpio_port = + (struct gpio_cmsdk_reg_map_t*)dev->cfg->base; + + if(pin_num >= GPIO_CMSDK_MAX_PIN_NUM) { + return GPIO_CMSDK_ERR_INVALID_ARG; + } + + p_gpio_port->intreg.intclear = (1UL << pin_num); + + return GPIO_CMSDK_ERR_NONE; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/gpio_cmsdk_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/gpio_cmsdk_drv.h new file mode 100644 index 0000000..7374ed9 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/gpio_cmsdk_drv.h @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2016-2018 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file gpio_cmsdk_drv.h + * \brief Generic driver for ARM GPIO. + */ + +#ifndef __GPIO_CMSDK_DRV_H__ +#define __GPIO_CMSDK_DRV_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define GPIO_CMSDK_MAX_PIN_NUM 16U +#define GPIO_CMSDK_MAX_PORT_MASK ((1U << GPIO_CMSDK_MAX_PIN_NUM) - 1U) + +/* GPIO enumeration types */ +enum gpio_cmsdk_direction_t { + GPIO_CMSDK_INPUT = 0, /*!< GPIO is input */ + GPIO_CMSDK_OUTPUT /*!< GPIO is output */ +}; + +enum gpio_cmsdk_altfunc_t { + GPIO_CMSDK_MAIN_FUNC = 0, /*!< Alternate function is not enabled */ + GPIO_CMSDK_ALT_FUNC /*!< Alternate function is enabled */ +}; + +enum gpio_cmsdk_irq_status_t { + GPIO_CMSDK_IRQ_DISABLE = 0, /*!< Disable interruptions */ + GPIO_CMSDK_IRQ_ENABLE /*!< Enable interruptions */ +}; + +enum gpio_cmsdk_irq_type_t { + GPIO_CMSDK_IRQ_LEVEL = 0, /*!< Level Interrupt */ + GPIO_CMSDK_IRQ_EDGE /*!< Edge Interrupt */ +}; + +enum gpio_cmsdk_irq_polarity_t { + GPIO_CMSDK_IRQ_LOW_OR_FALLING_EDGE = 0, /*!< Interrupt active low or + falling edge */ + GPIO_CMSDK_IRQ_HIGH_OR_RISING_EDGE /*!< Interrupt active high or + rising edge */ +}; + +enum gpio_cmsdk_error_t { + GPIO_CMSDK_ERR_NONE = 0, /*!< No error */ + GPIO_CMSDK_ERR_INVALID_ARG, /*!< Error invalid input argument */ + GPIO_CMSDK_ALTFUNC_EERROR, /*!< Alternate function returned error */ +}; + +/* CMSDK GPIO device configuration structure */ +struct gpio_cmsdk_dev_cfg_t { + const uint32_t base; /*!< GPIO base address */ +}; + +/* CMSDK GPIO device structure */ +struct gpio_cmsdk_dev_t { + const struct gpio_cmsdk_dev_cfg_t* const cfg; /*!< GPIO configuration */ +}; + +/** + * \brief Initializes GPIO port. + * + * \param[in] dev GPIO device to initalize \ref gpio_cmsdk_dev_t + * + * \note This function doesn't check if dev is NULL. + */ +void gpio_cmsdk_init(struct gpio_cmsdk_dev_t* dev); + +/** + * \brief Configures pin. + * + * \param[in] dev GPIO device to configure \ref gpio_cmsdk_dev_t + * \param[in] pin_num Pin number for pin access + * \param[in] direction Input or output \ref gpio_cmsdk_direction_t + * \param[in] altfunc_flags Alternate function \ref gpio_cmsdk_altfunc_t + * + * \return Returns error code as specified in \ref gpio_cmsdk_flags_t + * + * \note This function doesn't check if dev is NULL. + */ +enum gpio_cmsdk_error_t +gpio_cmsdk_pin_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num, + enum gpio_cmsdk_direction_t direction, + enum gpio_cmsdk_altfunc_t altfunc_flags); + +/** + * \brief Configures port. + * + * \param[in] dev GPIO device to configure \ref gpio_cmsdk_dev_t + * \param[in] pin_mask Bitmask of the selected pins + * \param[in] direction Input or output \ref gpio_cmsdk_direction_t + * \param[in] altfunc_flags Alternate function \ref gpio_cmsdk_altfunc_t + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + */ +enum gpio_cmsdk_error_t +gpio_cmsdk_port_config(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask, + enum gpio_cmsdk_direction_t direction, + enum gpio_cmsdk_altfunc_t altfunc_flags); + + +/** + * \brief Configures interrupt type + * + * \param[in] dev GPIO device to initalize \ref gpio_cmsdk_dev_t + * \param[in] pin_mask Bitmask of the selected pins + * \param[in] irq_type Interrupt type \ref gpio_cmsdk_irq_type_t + * \param[in] irq_pol Interrupt polarity \ref gpio_cmsdk_irq_polarity_t + * + * \note This function doesn't check if dev is NULL. + */ +void gpio_cmsdk_config_irq(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask, + enum gpio_cmsdk_irq_type_t irq_type, + enum gpio_cmsdk_irq_polarity_t irq_pol); + +/** + * \brief Sets state of the output pin. + * + * \param[in] dev GPIO device to use for the pin \ref gpio_cmsdk_dev_t + * \param[in] pin_num Pin number for pin access + * \param[in] value Value(s) to set. + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + * \note GPIO data output register is a read-modify-write register, + * so before writing a value on a GPIO pin it is required to disable + * the interrupts to prevent concurrency problems. + */ +enum gpio_cmsdk_error_t gpio_cmsdk_pin_write(struct gpio_cmsdk_dev_t* dev, + uint32_t pin_num, + uint32_t value); + +/** + * \brief Sets state of the output port. + * + * \param[in] dev GPIO device to use for the pins \ref gpio_cmsdk_dev_t + * \param[in] pin_mask Bitmask of the selected pins + * \param[in] value Bitmask of pins states to set + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + * \note GPIO data output register is a read-modify-write register, + * so before writing a value on a GPIO pin it is required to disable + * the interrupts to prevent concurrency problems. + */ +enum gpio_cmsdk_error_t gpio_cmsdk_port_write(struct gpio_cmsdk_dev_t* dev, + uint32_t pin_mask, + uint32_t value); + +/** + * \brief Reads the pin status. + * + * \param[in] dev GPIO device to use for the pin \ref gpio_cmsdk_dev_t + * \param[in] pin_num Pin number for pin access + * \param[out] data Bit value read from the IO pin + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + */ +enum gpio_cmsdk_error_t +gpio_cmsdk_pin_read(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num, uint32_t *data); + +/** + * \brief Reads the port status. + * + * \param[in] dev GPIO device to use for the pins \ref gpio_cmsdk_dev_t + * \param[in] pin_mask Bitmask of the selected pins + * \param[out] data Bit values for the mask read from the IO pin + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + */ +enum gpio_cmsdk_error_t +gpio_cmsdk_port_read(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask, + uint32_t *data); + +/** + * \brief Enables/disables interrupt for the given pin. + * + * \param[in] dev GPIO device to initalize \ref gpio_cmsdk_dev_t + * \param[in] pin_num Pin number to configure + * \param[in] status Interrupt status \ref gpio_cmsdk_irq_status + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + */ +enum gpio_cmsdk_error_t +gpio_cmsdk_set_pin_irq_cfg(struct gpio_cmsdk_dev_t* dev, uint32_t pin_num, + enum gpio_cmsdk_irq_status_t status); + +/** + * \brief Enables/disables interrupt for the given pins. + * + * \param[in] dev GPIO device to use for the pins \ref gpio_cmsdk_dev_t + * \param[in] pin_mask Bitmask of the pins to configure + * \param[in] status Interrupt status \ref gpio_cmsdk_irq_status + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + */ +enum gpio_cmsdk_error_t +gpio_cmsdk_set_port_irq_cfg(struct gpio_cmsdk_dev_t* dev, uint32_t pin_mask, + enum gpio_cmsdk_irq_status_t status); + +/** + * \brief Get interrupt status for the given pin. + * + * \param[in] dev GPIO device to use for the pin \ref gpio_cmsdk_dev_t + * \param[in] pin_num Pin number for the access + * \param[out] status Interrupt status values. If the access is by pin, then + * the status will be 0 or 1. + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + */ +enum gpio_cmsdk_error_t +gpio_cmsdk_get_pin_irq_status(struct gpio_cmsdk_dev_t* dev, + uint32_t pin_num, uint32_t* status); + +/** + * \brief Get interrupt status for the given port. + * + * \param[in] dev GPIO device to use for the pins \ref gpio_cmsdk_dev_t + * \param[in] pin_mask Bitmask of the pins to configure + * \param[out] status Interrupt status values. If the access is by pin, + * then the status will be 0 or 1. + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + */ +enum gpio_cmsdk_error_t +gpio_cmsdk_get_port_irq_status(struct gpio_cmsdk_dev_t* dev, + uint32_t pin_mask, uint32_t* status); + +/** + * \brief Clears gpio interrupt. + * + * \param[in] dev GPIO device to initalize \ref gpio_cmsdk_dev_t + * \param[in] pin_num Pin number. + * + * \return Returns error code as specified in \ref gpio_cmsdk_error_t + * + * \note This function doesn't check if dev is NULL. + */ +enum gpio_cmsdk_error_t gpio_cmsdk_clear_irq(struct gpio_cmsdk_dev_t* dev, + uint8_t pin_num); + +#ifdef __cplusplus +} +#endif +#endif /* __GPIO_CMSDK_DRV_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/i2c_ip6510_drv.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/i2c_ip6510_drv.c new file mode 100644 index 0000000..74d6030 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/i2c_ip6510_drv.c @@ -0,0 +1,1364 @@ +/* + * Copyright (c) 2018-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file i2c_ip6510_drv.c + * \brief Driver for IP6510 I2C controller. + */ + +#include "i2c_ip6510_drv.h" + +#include +#include +#include "cmsis_compiler.h" + +/******************************************************************************* + * Cadence IP6510 I2C device specific definitions based on: + * I2C Controller IP User Guide + * Part Number: IP6510 + * IP Version Number: r115_f01 + * User Guide Revision: 1.20 + * + ******************************************************************************/ + +/** Setter bit manipulation macro */ +#define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX))) +/** Clearing bit manipulation macro */ +#define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX))) +/** Getter bit manipulation macro */ +#define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX)))) +/** Clear-and-Set bit manipulation macro */ +#define ASSIGN_BIT(WORD, BIT_INDEX, VALUE) \ + (WORD = ((WORD & ~(1U << (BIT_INDEX))) | (VALUE << (BIT_INDEX)))) + +/** Getter bit-field manipulation macro */ +#define GET_BIT_FIELD(WORD, BIT_MASK, BIT_OFFSET) \ + ((WORD & BIT_MASK) >> BIT_OFFSET) + +/** Clear-and-Set bit-field manipulation macro */ +#define ASSIGN_BIT_FIELD(WORD, BIT_MASK, BIT_OFFSET, VALUE) \ + (WORD = ((WORD & ~(BIT_MASK)) | ((VALUE << BIT_OFFSET) & BIT_MASK))) + +#define BITMASK(width) ((1u<<(width))-1) + +/** + * \brief I2C (IP6510) register map structure + */ +struct i2c_ip6510_reg_map_t { + volatile uint32_t control_reg; + /*!< Offset: 0x00 (R/W) Control Register */ + volatile uint32_t status_reg; + /*!< Offset: 0x04 (R/ ) Status Register */ + volatile uint32_t address_reg; + /*!< Offset: 0x08 (R/W) I2C Address Register */ + volatile uint32_t data_reg; + /*!< Offset: 0x0C (R/W) I2C Data Register */ + volatile uint32_t irq_status_reg; + /*!< Offset: 0x10 (R/ ) Interrupt Status Register */ + volatile uint32_t transfer_size_reg; + /*!< Offset: 0x14 (R/W) Transfer Size Register */ + volatile uint32_t slave_monitor_pause_reg; + /*!< Offset: 0x18 (R/W) Slave Monitor Pause Register */ + volatile uint32_t time_out_reg; + /*!< Offset: 0x1C (R/W) Time Out Register */ + volatile uint32_t irq_mask_reg; + /*!< Offset: 0x20 (R/ ) Interrupt Mask Register */ + volatile uint32_t irq_enable_reg; + /*!< Offset: 0x24 ( /W) Interrupt Enable Register */ + volatile uint32_t irq_disable_reg; + /*!< Offset: 0x28 ( /W) Interrupt Disable Register */ + volatile uint32_t glitch_filter_control_reg; + /*!< Offset: 0x2C (R/W) Glitch Filter Control Register */ +}; + +#define I2C_IP6510_I2CCR_RW_OFF (0u) + /*!< Control Register Read/Write bit field offset */ +#define I2C_IP6510_I2CCR_MS_OFF (1u) + /*!< Control Register Master/Slave bit field offset */ +#define I2C_IP6510_I2CCR_NEA_OFF (2u) + /*!< Control Register Normal/Extended address bit field offset */ +#define I2C_IP6510_I2CCR_ACKEN_OFF (3u) + /*!< Control Register Acknowledge Enable bit field offset */ +#define I2C_IP6510_I2CCR_HOLD_OFF (4u) + /*!< Control Register Hold mode bit field offset */ +#define I2C_IP6510_I2CCR_SLVMON_OFF (5u) + /*!< Control Register Slave Monitor mode bit field offset */ +#define I2C_IP6510_I2CCR_CLRFIFO_OFF (6u) + /*!< Control Register Clear FIFO bit field offset */ +#define I2C_IP6510_I2CCR_DIV_B_OFF (8u) + /*!< Control Register Divisor B bit field offset */ +#define I2C_IP6510_I2CCR_DIV_A_OFF (14u) + /*!< Control Register Divisor A bit field offset */ + +#define I2C_IP6510_I2CSR_RXRW_OFF (3u) + /*!< Status Register RX read/write flag bit field offset*/ +#define I2C_IP6510_I2CSR_RXDV_OFF (5u) + /*!< Status Register Receiver Data Valid bit field offset */ +#define I2C_IP6510_I2CSR_TXDV_OFF (6u) + /*!< Status Register Transmitter Data Valid bit field offset */ +#define I2C_IP6510_I2CSR_BA_OFF (8u) + /*!< Status Register Bus Active bit field offset */ + + +/* Bit mask to determine the I2C address mode, if at least one of the upper + * 3bits (from 10bits) is used (set to 1) than it is a 10bit I2C address */ +#define I2C_10BIT_ADDR_MASK (0x0380u) + +/* Valid range of I2C addresses based on specification */ +#define I2C_7BIT_ADDR_LOWEST (0x8u) +#define I2C_10BIT_ADDR_HIGHEST (0x3FFu) + +/* The default value is based on the Cadence I2C IP User Guide */ +#define I2C_TIMEOUT_REG_DEFAULT_VALUE (0x001Fu) + +/* The frequency of the inner clock_enable signal is 22 times faster than the + * required SCL output frequency */ +#define I2C_SPEED_100KHZ_CLOCK_EN_FREQ (2200000u) +#define I2C_SPEED_400KHZ_CLOCK_EN_FREQ (8800000u) + +/* In case of slave mode with FIFO implemented, to support the minimum + * SCL period specification for fast-mode (400kHz), the device must be + * programmed to run at higher frequency. The value is based on the + * Cadence I2C IP User Guide and the clock divisor calculation method */ +#define I2C_SPEED_MAX_SUPP_CLOCK_EN_FREQ (13200000u) + +/* Mask for Divisor A field in the Control Register */ +#define I2C_IP6510_I2CCR_DIV_A_WIDTH (2u) +#define I2C_IP6510_I2CCR_DIV_A_MASK (BITMASK(I2C_IP6510_I2CCR_DIV_A_WIDTH) \ + << I2C_IP6510_I2CCR_DIV_A_OFF) + +/* Mask for Divisor B field in the Control Register */ +#define I2C_IP6510_I2CCR_DIV_B_WIDTH (6u) +#define I2C_IP6510_I2CCR_DIV_B_MASK (BITMASK(I2C_IP6510_I2CCR_DIV_B_WIDTH) \ + << I2C_IP6510_I2CCR_DIV_B_OFF) + +/* The maximum value of stage A clock divider is 3.*/ +#define I2C_IP6510_DIVISOR_A_MAX_VALUE (3u) + +/* The maximum value of stage B clock divider is 63.*/ +#define I2C_IP6510_DIVISOR_B_MAX_VALUE (63u) + +/* The maximum number of received bytes in one (not combined) transfer + * is 0xF (due to Transfer Size Register constraints). */ +#define I2C_RECEIVED_BYTE_MAX_NUMBER (15u) + + +/** + * \brief Sets the direction of the I2C transfer. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * \param[in] transf_dir Required direction of the I2C transfer. + * \ref i2c_ip6510_transf_dir_t + */ + static void set_transfer_dir(struct i2c_ip6510_reg_map_t *p_i2c, + enum i2c_ip6510_transf_dir_t transf_dir) +{ + if(transf_dir == I2C_IP6510_TRANSMITTER) { + CLR_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_RW_OFF); + + } else { + /* I2C_IP6510_RECEIVER */ + SET_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_RW_OFF); + } +} + +/** + * \brief Determines and sets the I2C addressing mode based on the address. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * \param[in] addr I2C device address (7bits or 10bits). + * + * \return Returns with the determined addressing mode. + * \ref i2c_ip6510_addr_mode_t + */ +static enum i2c_ip6510_addr_mode_t set_address_mode( + struct i2c_ip6510_reg_map_t *p_i2c, + uint16_t addr) +{ + /* If at least one of the upper 3bits (from 10bits) is used (set to 1) + * than it is a 10bit I2C address */ + if(addr & I2C_10BIT_ADDR_MASK) { + /* Using I2C Extended Address mode */ + CLR_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_NEA_OFF); + return I2C_IP6510_EXT_ADDR_MODE; + + } else { + /* Using I2C Normal Address mode */ + SET_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_NEA_OFF); + return I2C_IP6510_NOR_ADDR_MODE; + } +} + +/** + * \brief Enables Slave Monitor mode (in master mode only). + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static void enable_slave_monitor(struct i2c_ip6510_reg_map_t *p_i2c) +{ + SET_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_SLVMON_OFF); +} + +/** + * \brief Disables Slave Monitor mode (in master mode only). + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static void disable_slave_monitor(struct i2c_ip6510_reg_map_t *p_i2c) +{ + CLR_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_SLVMON_OFF); +} + +/** + * \brief Check if Slave Monitor mode is enabled. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * + * \return Returns bool, true if Slave Monitor is enabled, false otherwise + */ +static bool is_slave_monitor_enabled(const struct i2c_ip6510_reg_map_t *p_i2c) +{ + return GET_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_SLVMON_OFF); +} + +/** + * \brief Configures the clock dividers (A and B) with the given values. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * \param[in] div_a Value of divisor stage A. + * \param[in] div_b Value of divisor stage B. + */ +static void set_divisor(struct i2c_ip6510_reg_map_t *p_i2c, + uint32_t div_a, uint32_t div_b) +{ + ASSIGN_BIT_FIELD(p_i2c->control_reg, + I2C_IP6510_I2CCR_DIV_A_MASK, + I2C_IP6510_I2CCR_DIV_A_OFF, + div_a); + + ASSIGN_BIT_FIELD(p_i2c->control_reg, + I2C_IP6510_I2CCR_DIV_B_MASK, + I2C_IP6510_I2CCR_DIV_B_OFF, + div_b); +} + +/** + * \brief Enables transmission of ACK. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static void ack_enable(struct i2c_ip6510_reg_map_t *p_i2c) +{ + SET_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_ACKEN_OFF); +} + +/** + * \brief Disables transmission of ACK. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static void ack_disable(struct i2c_ip6510_reg_map_t *p_i2c) +{ + CLR_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_ACKEN_OFF); +} + +/** + * \brief Enables Hold mode. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static void hold_enable(struct i2c_ip6510_reg_map_t *p_i2c) +{ + SET_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_HOLD_OFF); +} + +/** + * \brief Disables Hold mode. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static void hold_disable(struct i2c_ip6510_reg_map_t *p_i2c) +{ + CLR_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_HOLD_OFF); +} + +/** + * \brief Clears FIFO (and clears the Transfer Size register). + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static void clr_fifo(struct i2c_ip6510_reg_map_t *p_i2c) +{ + __DMB(); + SET_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_CLRFIFO_OFF); + __DSB(); +} + +/** + * \brief Clears the specified I2C interrupts. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * \param[in] mask Bit mask for clearing interrupts. Values from + * \ref i2c_ip6510_intr_t could be used to create the mask. + */ +static void clr_irq(struct i2c_ip6510_reg_map_t *p_i2c, uint32_t mask) +{ + p_i2c->irq_status_reg = mask; +} + +/** + * \brief Configures the address register with the given address. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * \param[in] addr I2C device address (7bits or 10bits). + */ +static void set_address(struct i2c_ip6510_reg_map_t *p_i2c, uint16_t addr) +{ + __DMB(); + p_i2c->address_reg = (uint32_t)addr; + __DSB(); +} + +/** + * \brief Checks if new and valid data is available to be read. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * + * \return Returns bool, true if received data is available, false otherwise. + */ +static bool is_rx_data_ready(const struct i2c_ip6510_reg_map_t *p_i2c) +{ + return GET_BIT(p_i2c->status_reg, I2C_IP6510_I2CSR_RXDV_OFF); +} + +/** + * \brief Checks if there is still data to be transmitted. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * + * \return Returns bool, true if there is still data to be transmitted, + * false otherwise. + */ +static bool is_tx_data_waiting(const struct i2c_ip6510_reg_map_t *p_i2c) +{ + return GET_BIT(p_i2c->status_reg, I2C_IP6510_I2CSR_TXDV_OFF); +} + +/** + * \brief Reads a data byte from the FIFO. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * + * \return Returns the received data byte. + */ +static uint8_t rx_byte(const struct i2c_ip6510_reg_map_t *p_i2c) +{ + return (uint8_t)(p_i2c->data_reg); +} + +/** + * \brief Writes a data byte into the FIFO to be transmitted. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * \param[in] data Data byte to be transmitted. + */ +static void tx_byte(struct i2c_ip6510_reg_map_t *p_i2c, uint8_t data) +{ + __DMB(); + p_i2c->data_reg = (uint32_t)data; + __DSB(); +} + +/** + * \brief Checks if I2C transfer is successful. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * + * \return Returns bool, true if transfer is successful, false otherwise. + */ +static bool is_transfer_complete(const struct i2c_ip6510_reg_map_t *p_i2c) +{ + return GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_COMP_OFF); +} + +/** + * \brief Clears the complete interrupt status register. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static void clear_irq_status_reg(struct i2c_ip6510_reg_map_t *p_i2c) +{ + p_i2c->irq_status_reg = I2C_IP6510_ALL_INTR_MASK; +} + +/** + * \brief Sets the Transfer Size register with the given value. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * \param[in] byte_num New Transfer Size register value. + */ +static void set_transfer_size(struct i2c_ip6510_reg_map_t *p_i2c, + uint32_t byte_num) +{ + p_i2c->transfer_size_reg = byte_num; +} + +/** + * \brief Returns the value of the Transfer Size register. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static uint32_t get_transfer_size(struct i2c_ip6510_reg_map_t *p_i2c) +{ + return p_i2c->transfer_size_reg; +} + +/** + * \brief Writes the default values into the registers where it is applicable. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + */ +static void reset_regs(struct i2c_ip6510_reg_map_t *p_i2c) +{ + p_i2c->control_reg = 0U; + p_i2c->address_reg = 0U; + p_i2c->transfer_size_reg = 0U; + p_i2c->slave_monitor_pause_reg = 0U; + p_i2c->time_out_reg = I2C_TIMEOUT_REG_DEFAULT_VALUE; + p_i2c->glitch_filter_control_reg = 0U; +} + +/** + * \brief Sets the I2C interface mode. + * + * \param[in] dev I2C (IP6510) device structure \ref i2c_ip6510_dev_t + * \param[in] mode I2C interface mode \ref i2c_ip6510_device_mode_t + * + * \note This function doesn't check if dev is NULL. + */ +static void set_device_mode(struct i2c_ip6510_dev_t *dev, + enum i2c_ip6510_device_mode_t mode) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + ASSIGN_BIT(p_i2c->control_reg, I2C_IP6510_I2CCR_MS_OFF, mode); + + dev->data->mode = mode; +} + +enum i2c_ip6510_error_t i2c_ip6510_init(struct i2c_ip6510_dev_t *dev, + uint32_t sys_clk) +{ + enum i2c_ip6510_error_t err = I2C_IP6510_ERR_NONE; + + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if(dev->data->state != I2C_IP6510_UNINITIALIZED) { + return I2C_IP6510_ERR_ALREADY_INIT; + } + + if(sys_clk == 0U) { + return I2C_IP6510_ERR_INVALID_ARG; + } + + i2c_ip6510_disable_irq(dev, I2C_IP6510_ALL_INTR_MASK); + + clear_irq_status_reg(p_i2c); + clr_fifo(p_i2c); + + /* Updating the system clock frequency */ + dev->data->sys_clk = sys_clk; + + set_device_mode(dev, dev->cfg->default_mode); + err = i2c_ip6510_set_speed(dev, dev->cfg->default_bus_speed); + + if(err != I2C_IP6510_ERR_NONE) { + return err; + } + + dev->data->state = I2C_IP6510_INITIALIZED; + + return I2C_IP6510_ERR_NONE; +} + +void i2c_ip6510_uninit(struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + i2c_ip6510_disable_irq(dev, I2C_IP6510_ALL_INTR_MASK); + + clear_irq_status_reg(p_i2c); + + reset_regs(p_i2c); + + clr_fifo(p_i2c); + + dev->data->state = I2C_IP6510_UNINITIALIZED; +} + +void i2c_ip6510_hold_enable(const struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + hold_enable(p_i2c); +} + +void i2c_ip6510_hold_disable(const struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + hold_disable(p_i2c); +} + +enum i2c_ip6510_state_t i2c_ip6510_get_state(const struct i2c_ip6510_dev_t *dev) +{ + return dev->data->state; +} + +enum i2c_ip6510_device_mode_t i2c_ip6510_get_device_mode( + const struct i2c_ip6510_dev_t *dev) +{ + return dev->data->mode; +} + +enum i2c_ip6510_error_t i2c_ip6510_set_speed(struct i2c_ip6510_dev_t *dev, + enum i2c_ip6510_speed_t speed) +{ + uint32_t div_a = 0U; + uint32_t div_b = 0U; + uint32_t clock_enable_freq = 0U; + + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if(dev->data->sys_clk == 0U) { + /* Invalid system clock frequency */ + return I2C_IP6510_ERR; + } + + /* The required frequency of SCL output is 22 times slower than the + * frequency of the inner clock_enable signal. */ + switch(speed) { + + case I2C_IP6510_SPEED_100KHZ: + clock_enable_freq = I2C_SPEED_100KHZ_CLOCK_EN_FREQ; + dev->data->bus_speed = I2C_IP6510_SPEED_100KHZ; + break; + + case I2C_IP6510_SPEED_400KHZ: + clock_enable_freq = I2C_SPEED_400KHZ_CLOCK_EN_FREQ; + dev->data->bus_speed = I2C_IP6510_SPEED_400KHZ; + break; + + case I2C_IP6510_SPEED_MAX_SUPPORTED: + /* In case of slave mode with FIFO implemented, to support the minimum + * SCL period specification for fast-mode (400kHz), the device must be + * programmed to run at higher frequency. */ + clock_enable_freq = I2C_SPEED_MAX_SUPP_CLOCK_EN_FREQ; + dev->data->bus_speed = I2C_IP6510_SPEED_MAX_SUPPORTED; + break; + + default: + return I2C_IP6510_ERR_INVALID_ARG; + } + + /* Calculating the value of stage A and B clock dividers */ + div_a = 0U; + div_b = (uint32_t)(dev->data->sys_clk / clock_enable_freq); + + if(div_b > I2C_IP6510_DIVISOR_B_MAX_VALUE) { + + /* (div_a+1)x(div_b+1) must be equal to former div_b value */ + div_a = I2C_IP6510_DIVISOR_A_MAX_VALUE; + div_b = (uint32_t)(div_b+1U) >> I2C_IP6510_I2CCR_DIV_A_WIDTH; + } + + set_divisor(p_i2c, div_a, div_b); + + return I2C_IP6510_ERR_NONE; +} + +enum i2c_ip6510_speed_t i2c_ip6510_get_speed(const struct i2c_ip6510_dev_t *dev) +{ + return dev->data->bus_speed; +} + +enum i2c_ip6510_bus_state_t i2c_ip6510_get_bus_status( + const struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + return (GET_BIT(p_i2c->status_reg, I2C_IP6510_I2CSR_BA_OFF)) ? + I2C_IP6510_BUS_ACTIVE : I2C_IP6510_BUS_INACTIVE; +} + +int i2c_ip6510_get_transfer_size(const struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + return p_i2c->transfer_size_reg; +} + +uint32_t i2c_ip6510_get_irq_status(const struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + return p_i2c->irq_status_reg; +} + +uint32_t i2c_ip6510_get_irq_mask(const struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + return p_i2c->irq_mask_reg; +} + +void i2c_ip6510_clear_irq(struct i2c_ip6510_dev_t *dev, uint32_t mask) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + clr_irq(p_i2c, mask); +} + +void i2c_ip6510_enable_irq(struct i2c_ip6510_dev_t *dev, uint32_t mask) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + p_i2c->irq_enable_reg = mask; +} + +void i2c_ip6510_disable_irq(struct i2c_ip6510_dev_t *dev, uint32_t mask) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + p_i2c->irq_disable_reg = mask; +} + +void i2c_ip6510_set_timeout(struct i2c_ip6510_dev_t *dev, + uint8_t interval) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + p_i2c->time_out_reg = (uint32_t)interval; +} + +void i2c_ip6510_set_slave_monitor_pause_interval(struct i2c_ip6510_dev_t *dev, + uint8_t interval) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + p_i2c->slave_monitor_pause_reg = (uint32_t)interval; +} + +uint8_t i2c_ip6510_get_slave_monitor_pause_interval( + struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + return (uint8_t)(p_i2c->slave_monitor_pause_reg); +} + +void i2c_ip6510_set_glitch_filter_length(struct i2c_ip6510_dev_t *dev, + uint32_t length) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + p_i2c->glitch_filter_control_reg = length; +} + +uint8_t i2c_ip6510_get_glitch_filter_length(const struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + return (uint8_t)(p_i2c->glitch_filter_control_reg); +} + +enum i2c_ip6510_error_t i2c_ip6510_monitor_slave(struct i2c_ip6510_dev_t *dev, + uint16_t addr) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if(i2c_ip6510_get_state(dev) != I2C_IP6510_INITIALIZED) { + return I2C_IP6510_ERR_NOT_INIT; + } + + clear_irq_status_reg(p_i2c); + set_address_mode(p_i2c, addr); + set_transfer_dir(p_i2c, I2C_IP6510_TRANSMITTER); + enable_slave_monitor(p_i2c); + + /* Initiates slave addressing */ + set_address(p_i2c, addr); + + /* Slave Monitor Mode gets disabled if given slave is present */ + while(is_slave_monitor_enabled(p_i2c) || + !(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_SLVRDY_OFF))) { + + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF)) { + disable_slave_monitor(p_i2c); + return I2C_IP6510_ERR_NACK; + } + } + return I2C_IP6510_ERR_NONE; +} + +/** + * \brief Initiates transfer and writes the given number of data bytes to send. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * \param[in] addr I2C device address (7 bits or 10 bits). + * \param[in] tx_data Data buffer pointer to write. + * \param[in] tx_length Data buffer length (number of bytes to write). + * \param[out] write_cntr Number of bytes written. + * + * \return Returns error code as specified in \ref i2c_ip6510_error_t + */ +static enum i2c_ip6510_error_t tx_transfer( + struct i2c_ip6510_reg_map_t *p_i2c, + uint16_t addr, + const uint8_t *tx_data, + uint32_t *tx_length) +{ + uint32_t write_cntr = *tx_length; + + ack_enable(p_i2c); + clear_irq_status_reg(p_i2c); + set_address_mode(p_i2c, addr); + set_transfer_dir(p_i2c, I2C_IP6510_TRANSMITTER); + + /* Initiates I2C transfer */ + set_address(p_i2c, addr); + + while(write_cntr) { + + tx_byte(p_i2c, *tx_data); + + /* If the sent data byte or slave addressing is not acknowledged */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF)) { + *tx_length -= write_cntr; + return I2C_IP6510_ERR_NACK; + + } else if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_TXOVF_OFF)) { + /* In case of FIFO overflow the last written byte is ignored and + * the Data Register access must be repeated. */ + clr_irq(p_i2c, I2C_IP6510_INTR_TXOVF_MASK); + continue; + } + + tx_data++; + write_cntr--; + } + *tx_length -= write_cntr; + + return I2C_IP6510_ERR_NONE; +} + +enum i2c_ip6510_error_t i2c_ip6510_master_write(struct i2c_ip6510_dev_t *dev, + uint16_t addr, + const uint8_t *tx_data, + bool stop, + uint32_t *tx_length) +{ + enum i2c_ip6510_error_t err = I2C_IP6510_ERR_NONE; + + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if(*tx_length == 0U) { + return I2C_IP6510_ERR_INVALID_ARG; + } + + if(i2c_ip6510_get_state(dev) != I2C_IP6510_INITIALIZED) { + return I2C_IP6510_ERR_NOT_INIT; + } + + clr_fifo(p_i2c); + + /* Prevents the I2C interface from generating a STOP condition */ + hold_enable(p_i2c); + + /* Initiates transfer and transmits the given number of data bytes */ + err = tx_transfer(p_i2c, addr, tx_data, tx_length); + + if(err != I2C_IP6510_ERR_NONE) { + hold_disable(p_i2c); + + return err; + } + + while(!is_transfer_complete(p_i2c)) { + + /* If the last transmitted byte did not get an ACK */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF)) { + return I2C_IP6510_ERR_NACK; + } + } + + /* If enabled, the host can terminate the transfer with disabled hold mode + */ + if (stop) { + hold_disable(p_i2c); + } + + return I2C_IP6510_ERR_NONE; +} + +/** + * \brief Initiates transfer and reads the received data bytes. + * + * \param[in] p_i2c I2C (IP6510) register map structure. + * \ref i2c_ip6510_reg_map_t + * \param[in] addr I2C device address (7 bits or 10 bits). + * \param[in] rx_data Buffer pointer to store the read data. + * \param[in] rx_length Buffer length (number of bytes to read). + * \param[out] read_cntr Number of bytes read. + * + * \return Returns error code as specified in \ref i2c_ip6510_error_t + */ +static enum i2c_ip6510_error_t rx_transfer_combined( + struct i2c_ip6510_reg_map_t *p_i2c, + uint16_t addr, + uint8_t *rx_data, + uint32_t *rx_length) +{ + uint32_t read_cntr = *rx_length; + uint32_t part_rx_length = (read_cntr > I2C_RECEIVED_BYTE_MAX_NUMBER) ? + I2C_RECEIVED_BYTE_MAX_NUMBER : read_cntr; + + /* The I2C controller handles the Acknowledge generation. And Acknowledge + * has to be enabled. */ + ack_enable(p_i2c); + clear_irq_status_reg(p_i2c); + set_address_mode(p_i2c, addr); + set_transfer_dir(p_i2c, I2C_IP6510_RECEIVER); + + /* Initiates I2C transfer */ + set_address(p_i2c, addr); + set_transfer_size(p_i2c, part_rx_length); + + while(read_cntr) { + + /* The maximum number of received bytes in one transfer is limited. If + * the read length is more than the maximum number of bytes that can be + * received in one transfer, the transfer size register has to be + * adjusted before reaching 0. If the transfer size register reaches + * zero, the I2C controller terminates the transfer before completion. + */ + if (get_transfer_size(p_i2c) == 1U) { + part_rx_length = (read_cntr > I2C_RECEIVED_BYTE_MAX_NUMBER) ? + I2C_RECEIVED_BYTE_MAX_NUMBER : read_cntr; + + set_transfer_size(p_i2c, part_rx_length); + } + + /* Waiting for new valid data to read */ + while(!is_rx_data_ready(p_i2c)) { + + /* If the previous slave addressing is not acknowledged */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF)) { + *rx_length -= read_cntr; + return I2C_IP6510_ERR_NACK; + + } else if(GET_BIT(p_i2c->irq_status_reg, + I2C_IP6510_INTR_RXOVF_OFF)) { + + *rx_length -= read_cntr; + /* In case of Receive Overflow return with error code */ + return I2C_IP6510_ERR_RXOVF; + } + } + + *rx_data = rx_byte(p_i2c); + + rx_data++; + read_cntr--; + } + *rx_length -= read_cntr; + + return I2C_IP6510_ERR_NONE; +} + +enum i2c_ip6510_error_t i2c_ip6510_master_read(struct i2c_ip6510_dev_t *dev, + uint16_t addr, + uint8_t *rx_data, + bool stop, + uint32_t *rx_length) +{ + enum i2c_ip6510_error_t err = I2C_IP6510_ERR_NONE; + + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if(*rx_length == 0U) { + return I2C_IP6510_ERR_INVALID_ARG; + } + + if(i2c_ip6510_get_state(dev) != I2C_IP6510_INITIALIZED) { + return I2C_IP6510_ERR_NOT_INIT; + } + + clr_fifo(p_i2c); + + /* Receive overflow can be avoided and combined read transfer can be + * realized if Hold Mode is enabled */ + hold_enable(p_i2c); + + /* It reads the given number of received bytes from the FIFO + * (in a combined transfer if necessary) */ + err = rx_transfer_combined(p_i2c, addr, rx_data, rx_length); + + if(err != I2C_IP6510_ERR_NONE) { + hold_disable(p_i2c); + + return err; + } + + /* If enabled, the host can terminate the transfer with disabled hold mode + */ + if (stop) { + hold_disable(p_i2c); + } + + /* Waiting for the whole transfer to be complete */ + while(!is_transfer_complete(p_i2c)) { + /* If there is more, unexpected data byte received due to + * any kind of error. */ + if(is_rx_data_ready(p_i2c)) { + return I2C_IP6510_ERR; + } + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_RXOVF_OFF)) { + return I2C_IP6510_ERR_RXOVF; + } + } + + return I2C_IP6510_ERR_NONE; +} + +enum i2c_ip6510_error_t i2c_ip6510_master_write_read( + struct i2c_ip6510_dev_t *dev, + uint16_t addr, + const uint8_t *tx_data, + uint8_t *rx_data, + uint32_t *tx_length, + uint32_t *rx_length) +{ + enum i2c_ip6510_error_t err = I2C_IP6510_ERR_NONE; + + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if((*tx_length == 0U) || (*rx_length == 0U)) { + return I2C_IP6510_ERR_INVALID_ARG; + } + + if(i2c_ip6510_get_state(dev) != I2C_IP6510_INITIALIZED) { + return I2C_IP6510_ERR_NOT_INIT; + } + + /* Prevents the I2C interface from generating a STOP condition */ + hold_enable(p_i2c); + + /* Initiates transfer and transmits the given number of data bytes */ + err = tx_transfer(p_i2c, addr, tx_data, tx_length); + + if(err != I2C_IP6510_ERR_NONE) { + hold_disable(p_i2c); + return err; + } + + while(!is_transfer_complete(p_i2c)) { + + /* If the last transmitted byte did not get an ACK */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF)) { + hold_disable(p_i2c); + return I2C_IP6510_ERR_NACK; + } + } + + clr_irq(p_i2c, I2C_IP6510_INTR_COMP_MASK); + + /* Write transaction is complete, continue with read transaction */ + + /* The host does not need to ACK only 1 byte, + * it generates a STOP condition after reception */ + if(*rx_length == 1U) { + ack_disable(p_i2c); + } + + /* It reads the given number of received bytes from the FIFO + * (in a combined transfer if necessary) */ + err = rx_transfer_combined(p_i2c, addr, rx_data, rx_length); + + if(err != I2C_IP6510_ERR_NONE) { + hold_disable(p_i2c); + return err; + } + + /* The host can terminate the transfer with disabled hold mode */ + hold_disable(p_i2c); + + /* Waiting for the whole combined transfer to be complete */ + while(!is_transfer_complete(p_i2c)) { + + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_RXOVF_OFF)) { + return I2C_IP6510_ERR_RXOVF; + } + } + + return I2C_IP6510_ERR_NONE; +} + +enum i2c_ip6510_error_t i2c_ip6510_master_byte_write( + const struct i2c_ip6510_dev_t *dev, + uint16_t addr, + const uint8_t *tx_data, + bool set_addr) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if(i2c_ip6510_get_state(dev) != I2C_IP6510_INITIALIZED) { + return I2C_IP6510_ERR_NOT_INIT; + } + + clear_irq_status_reg(p_i2c); + + if(set_addr == true) { + clr_fifo(p_i2c); + set_address_mode(p_i2c, addr); + set_transfer_dir(p_i2c, I2C_IP6510_TRANSMITTER); + } + ack_enable(p_i2c); + + /* Write the data byte to the FIFO */ + tx_byte(p_i2c, *tx_data); + + /* If the first data byte was written, only then set the address */ + if(set_addr == true) { + /* Initiates I2C transfer */ + set_address(p_i2c, addr); + } + + /* If the sent data byte or slave addressing is not acknowledged */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF)) { + return I2C_IP6510_ERR_NACK; + } else if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_TXOVF_OFF)) { + /* In case of FIFO overflow the last written byte is ignored */ + clr_irq(p_i2c, I2C_IP6510_INTR_TXOVF_MASK); + return I2C_IP6510_ERR_TXOVF; + } + + /* Waiting for the written byte to be transmitted */ + while(!is_transfer_complete(p_i2c)) { + /* If the last transmitted byte did not get an ACK */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF)) { + return I2C_IP6510_ERR_NACK; + } + } + + return I2C_IP6510_ERR_NONE; +} + +enum i2c_ip6510_error_t i2c_ip6510_master_byte_read( + const struct i2c_ip6510_dev_t *dev, + uint16_t addr, + bool last_byte, + bool set_addr, + uint8_t *rx_data) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if(i2c_ip6510_get_state(dev) != I2C_IP6510_INITIALIZED) { + return I2C_IP6510_ERR_NOT_INIT; + } + + clear_irq_status_reg(p_i2c); + + if(last_byte) { + /* This is the last byte to receive */ + ack_disable(p_i2c); + set_transfer_size(p_i2c, 1U); + } else { + /* There will be more then one data bytes */ + ack_enable(p_i2c); + set_transfer_size(p_i2c, I2C_RECEIVED_BYTE_MAX_NUMBER); + } + + /* If its the first read, the I2C controller has to be configured */ + if (set_addr){ + clr_fifo(p_i2c); + set_address_mode(p_i2c, addr); + set_transfer_dir(p_i2c, I2C_IP6510_RECEIVER); + set_address(p_i2c, addr); + } + + /* Waiting for new valid data to read */ + while(!is_rx_data_ready(p_i2c)) { + + /* If the previous slave addressing is not acknowledged */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF)) { + return I2C_IP6510_ERR_NACK; + + } else if(GET_BIT(p_i2c->irq_status_reg, + I2C_IP6510_INTR_RXOVF_OFF)) { + /* In case of Receive Overflow return with error code */ + return I2C_IP6510_ERR_RXOVF; + } + } + + /* Read the data byte from the FIFO */ + *rx_data = rx_byte(p_i2c); + + return I2C_IP6510_ERR_NONE; +} + +enum i2c_ip6510_error_t i2c_ip6510_set_slave_mode( + struct i2c_ip6510_dev_t *dev, + uint16_t addr) +{ + enum i2c_ip6510_error_t err = I2C_IP6510_ERR_NONE; + + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + /* Checking whether the address is a valid 7/10bit I2C slave address */ + if((addr < I2C_7BIT_ADDR_LOWEST) || (addr > I2C_10BIT_ADDR_HIGHEST)) { + return I2C_IP6510_ERR_INVALID_ARG; + } + + if(i2c_ip6510_get_state(dev) != I2C_IP6510_INITIALIZED) { + return I2C_IP6510_ERR_NOT_INIT; + } + + /* I2C speed must be set to the fastest SCL frequency supported */ + err = i2c_ip6510_set_speed(dev, I2C_IP6510_SPEED_MAX_SUPPORTED); + + if(err != I2C_IP6510_ERR_NONE) { + return err; + } + + set_device_mode(dev, I2C_IP6510_SLAVE_MODE); + clear_irq_status_reg(p_i2c); + ack_enable(p_i2c); + hold_enable(p_i2c); + set_address_mode(p_i2c, addr); + set_address(p_i2c, addr); + + return I2C_IP6510_ERR_NONE; +} + +void i2c_ip6510_set_master_mode(struct i2c_ip6510_dev_t *dev) +{ + set_device_mode(dev, I2C_IP6510_MASTER_MODE); +} + +enum i2c_ip6510_transf_dir_t i2c_ip6510_get_slave_tranf_dir( + struct i2c_ip6510_dev_t *dev) +{ + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + return (GET_BIT(p_i2c->status_reg, I2C_IP6510_I2CSR_RXRW_OFF)) ? + I2C_IP6510_TRANSMITTER : I2C_IP6510_RECEIVER; +} + +enum i2c_ip6510_error_t i2c_ip6510_slave_write(struct i2c_ip6510_dev_t *dev, + const uint8_t *tx_data, + uint32_t *tx_length) +{ + uint32_t write_cntr = *tx_length; + + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if(write_cntr == 0U) { + return I2C_IP6510_ERR_INVALID_ARG; + } + + if(i2c_ip6510_get_state(dev) != I2C_IP6510_INITIALIZED) { + return I2C_IP6510_ERR_NOT_INIT; + } + + clr_fifo(p_i2c); + ack_enable(p_i2c); + hold_enable(p_i2c); + + /* The amount of data to be transferred is a system known parameter */ + while(write_cntr) { + + /* If the previously sent data byte is not acknowledged */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF)) { + + hold_disable(p_i2c); + clr_fifo(p_i2c); + *tx_length -= write_cntr; + return I2C_IP6510_ERR_NACK; + } + + tx_byte(p_i2c, *tx_data); + + /* In case of FIFO overflow the last written byte is ignored and + * the Data Register access must be repeated. */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_TXOVF_OFF)) { + + clr_irq(p_i2c, I2C_IP6510_INTR_TXOVF_MASK); + continue; + } + + tx_data++; + write_cntr--; + } + *tx_length -= write_cntr; + + hold_disable(p_i2c); + + /* Waiting for the last byte to be transmitted from the FIFO */ + while(is_tx_data_waiting(p_i2c)) { + + /* If the transfer is terminated by the Master before completion */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_NACK_OFF) && + is_tx_data_waiting(p_i2c)) { + + clr_fifo(p_i2c); + return I2C_IP6510_ERR_NACK; + } + + /* DATA interrupt flag is set when there are only 2 bytes left in + * the FIFO, so at this point there is still data in the FIFO to be + * transmitted and DATA flag should be cleared for further + * examination. */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_DATA_OFF)) { + + clr_irq(p_i2c, I2C_IP6510_INTR_DATA_MASK); + } + } + + clr_fifo(p_i2c); + + while(!is_transfer_complete(p_i2c)) { + + /* If DATA interrupt flag is set while the TXDV flag in the Status + * Register is cleared the Master wants to continue the transfer. */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_DATA_OFF) && + !is_tx_data_waiting(p_i2c)) { + + return I2C_IP6510_ERR; + } + } + + return I2C_IP6510_ERR_NONE; +} + +enum i2c_ip6510_error_t i2c_ip6510_slave_read(struct i2c_ip6510_dev_t *dev, + uint8_t *rx_data, + uint32_t *rx_length) +{ + uint32_t read_cntr = *rx_length; + + struct i2c_ip6510_reg_map_t *p_i2c = + (struct i2c_ip6510_reg_map_t*)dev->cfg->base; + + if(read_cntr == 0U) { + return I2C_IP6510_ERR_INVALID_ARG; + } + + if(i2c_ip6510_get_state(dev) != I2C_IP6510_INITIALIZED) { + return I2C_IP6510_ERR_NOT_INIT; + } + + ack_enable(p_i2c); + + /* Receive overflow can be avoided if Hold Mode is enabled */ + hold_enable(p_i2c); + + while(read_cntr) { + + while(!is_rx_data_ready(p_i2c)) { + + /* With HOLD enabled the overflow conditions are avoided */ + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_RXOVF_OFF)) { + hold_disable(p_i2c); + *rx_length -= read_cntr; + return I2C_IP6510_ERR_RXOVF; + } + } + + *rx_data = rx_byte(p_i2c); + + rx_data++; + read_cntr--; + } + *rx_length -= read_cntr; + + hold_disable(p_i2c); + + /* Waiting for the master to terminate the transfer */ + while(!is_transfer_complete(p_i2c)) { + + if(GET_BIT(p_i2c->irq_status_reg, I2C_IP6510_INTR_RXOVF_OFF)) { + return I2C_IP6510_ERR_RXOVF; + + } else if(is_rx_data_ready(p_i2c)) { + /* If there are more, unexpected data bytes received from the Master + */ + return I2C_IP6510_ERR; + } + } + + return I2C_IP6510_ERR_NONE; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/i2c_ip6510_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/i2c_ip6510_drv.h new file mode 100644 index 0000000..f57233d --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/i2c_ip6510_drv.h @@ -0,0 +1,649 @@ +/* + * Copyright (c) 2018-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file i2c_ip6510_drv.h + * \brief Driver for IP6510 I2C controller. + */ + +#ifndef __I2C_IP6510_DRV_H__ +#define __I2C_IP6510_DRV_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief I2C (IP6510) device state types. + */ +enum i2c_ip6510_state_t { + I2C_IP6510_UNINITIALIZED = 0u, + I2C_IP6510_INITIALIZED = 1u, +}; + +/** + * \brief I2C (IP6510) bus state types. + */ +enum i2c_ip6510_bus_state_t { + I2C_IP6510_BUS_INACTIVE = 0u, + I2C_IP6510_BUS_ACTIVE = 1u, +}; + +/** + * \brief Allowed transfer direction options. + */ +enum i2c_ip6510_transf_dir_t { + I2C_IP6510_TRANSMITTER = 0u, + I2C_IP6510_RECEIVER = 1u, +}; + +/** + * \brief Supported I2C (IP6510) device mode options. + */ +enum i2c_ip6510_device_mode_t { + I2C_IP6510_SLAVE_MODE = 0u, + I2C_IP6510_MASTER_MODE = 1u, +}; + +/** + * \brief Supported I2C (IP6510) addressing options. + */ +enum i2c_ip6510_addr_mode_t { + I2C_IP6510_EXT_ADDR_MODE = 0u, + I2C_IP6510_NOR_ADDR_MODE = 1u, +}; + +/** + * \brief Supported I2C (IP6510) bus data rate options. + */ +enum i2c_ip6510_speed_t { + I2C_IP6510_SPEED_100KHZ = 0u, + I2C_IP6510_SPEED_400KHZ = 1u, + I2C_IP6510_SPEED_MAX_SUPPORTED = 2u, +}; + +#define I2C_IP6510_INTR_COMP_OFF (0u) + /*!< Transfer complete interrupt bit field offset */ +#define I2C_IP6510_INTR_DATA_OFF (1u) + /*!< More data interrupt bit field offset */ +#define I2C_IP6510_INTR_NACK_OFF (2u) + /*!< Transfer not ACKed interrupt bit field offset */ +#define I2C_IP6510_INTR_TO_OFF (3u) + /*!< Transfer time out interrupt bit field offset */ +#define I2C_IP6510_INTR_SLVRDY_OFF (4u) + /*!< Monitored slave ready interrupt bit field offset */ +#define I2C_IP6510_INTR_RXOVF_OFF (5u) + /*!< Receive overflow interrupt bit field offset */ +#define I2C_IP6510_INTR_TXOVF_OFF (6u) + /*!< FIFO transmit overflow interrupt bit field offset */ +#define I2C_IP6510_INTR_RXUNF_OFF (7u) + /*!< FIFO receive underflow interrupt bit field offset */ +#define I2C_IP6510_INTR_ARBLOST_OFF (9u) + /*!< Arbitration lost interrupt bit field offset */ + +#define I2C_IP6510_ALL_INTR_MASK (0x2FFu) + +/** + * \brief I2C (IP6510) interrupt data structure + */ +enum i2c_ip6510_intr_t { + I2C_IP6510_INTR_COMP_MASK = (0x1u<iomux_main_insel &= ~pin_mask; + scc_regs->iomux_main_outsel &= ~pin_mask; + scc_regs->iomux_main_oensel &= ~pin_mask; + } + if (func_mask & GPIO_ALTFUNC_1_MASK) { + scc_regs->iomux_altf1_insel &= ~pin_mask; + scc_regs->iomux_altf1_outsel &= ~pin_mask; + scc_regs->iomux_altf1_oensel &= ~pin_mask; + } + if (func_mask & GPIO_ALTFUNC_2_MASK) { + scc_regs->iomux_altf2_insel &= ~pin_mask; + scc_regs->iomux_altf2_outsel &= ~pin_mask; + scc_regs->iomux_altf2_oensel &= ~pin_mask; + } +} + +void musca_s1_scc_set_alt_func(struct musca_s1_scc_dev_t* dev, + enum gpio_altfunc_t altfunc, uint32_t pin_mask) +{ + struct musca_s1_scc_reg_map_t* scc_regs = + (struct musca_s1_scc_reg_map_t*) dev->cfg->base; + enum gpio_altfunc_mask_t altfunc_to_clear = GPIO_ALTFUNC_NONE; + volatile uint32_t *insel = NULL; + volatile uint32_t *outsel = NULL; + volatile uint32_t *oensel = NULL; + + if (altfunc >= GPIO_ALTFUNC_MAX) { + /* If no altfunction is selected, then nothing to do. + * This is possible during init and we do not + * want to change the reset values set by the HW + */ + return; + } + + switch (altfunc) { + case GPIO_MAIN_FUNC: + insel = &scc_regs->iomux_main_insel; + outsel = &scc_regs->iomux_main_outsel; + oensel = &scc_regs->iomux_main_oensel; + altfunc_to_clear = GPIO_MAIN_FUNC_NEG_MASK; + break; + + case GPIO_ALTFUNC_1: + insel = &scc_regs->iomux_altf1_insel; + outsel = &scc_regs->iomux_altf1_outsel; + oensel = &scc_regs->iomux_altf1_oensel; + altfunc_to_clear = GPIO_ALTFUNC_1_NEG_MASK; + break; + + case GPIO_ALTFUNC_2: + insel = &scc_regs->iomux_altf2_insel; + outsel = &scc_regs->iomux_altf2_outsel; + oensel = &scc_regs->iomux_altf2_oensel; + altfunc_to_clear = GPIO_ALTFUNC_2_NEG_MASK; + break; + default: + break; + } + + /* Select the wanted function's output enable bit first. + * This way the output won't be disabled which is desired + * if we switch from output to output function + */ + *oensel |= pin_mask; + + /* Clear all alternate function registers which are not selected */ + scc_clear_alt_func(scc_regs, altfunc_to_clear, pin_mask); + + /* Enable input and output data line */ + *insel |= pin_mask; + *outsel |= pin_mask; +} + +void musca_s1_scc_set_pinmode(struct musca_s1_scc_dev_t* dev, uint32_t pin_mask, + enum pinmode_select_t mode) +{ + struct musca_s1_scc_reg_map_t* scc_regs = + (struct musca_s1_scc_reg_map_t*) dev->cfg->base; + + switch (mode) { + case PINMODE_NONE: + scc_regs->iopad_pe &= ~pin_mask; + break; + case PINMODE_PULL_DOWN: + /* If the pull select bit is set to 0 it means pull down */ + scc_regs->iopad_ps &= ~pin_mask; + scc_regs->iopad_pe |= pin_mask; + break; + case PINMODE_PULL_UP: + /* If the pull select bit is set to 1 it means pull up */ + scc_regs->iopad_ps |= pin_mask; + scc_regs->iopad_pe |= pin_mask; + break; + default: + break; + } +} + +void musca_s1_scc_set_default_in(struct musca_s1_scc_dev_t* dev, + enum gpio_altfunc_t altfunc, + uint32_t default_in_mask, + uint32_t default_in_value) +{ + struct musca_s1_scc_reg_map_t* scc_regs = + (struct musca_s1_scc_reg_map_t*) dev->cfg->base; + uint32_t iomux_value = 0; + + if (altfunc >= GPIO_ALTFUNC_MAX) { + /* If no altfunction is selected, then nothing to do */ + return; + } + + switch (altfunc) { + case GPIO_MAIN_FUNC: + iomux_value = scc_regs->iomux_main_default_in & ~default_in_mask; + iomux_value |= (default_in_value & default_in_mask); + scc_regs->iomux_main_default_in = iomux_value; + scc_regs->iomux_main_insel = + (scc_regs->iomux_main_insel & ~default_in_mask); + break; + + case GPIO_ALTFUNC_1: + iomux_value = scc_regs->iomux_altf1_default_in & ~default_in_mask; + iomux_value |= (default_in_value & default_in_mask); + scc_regs->iomux_altf1_default_in = iomux_value; + scc_regs->iomux_altf1_insel = + (scc_regs->iomux_altf1_insel & ~default_in_mask); + break; + + case GPIO_ALTFUNC_2: + iomux_value = scc_regs->iomux_altf2_default_in & ~default_in_mask; + iomux_value |= (default_in_value & default_in_mask); + scc_regs->iomux_altf2_default_in = iomux_value; + scc_regs->iomux_altf2_insel = + (scc_regs->iomux_altf2_insel & ~default_in_mask); + break; + default: + break; + } +} + +void musca_s1_scc_mram_fast_read_enable(struct musca_s1_scc_dev_t* dev) +{ + struct musca_s1_scc_reg_map_t* scc_regs = + (struct musca_s1_scc_reg_map_t*) dev->cfg->base; + __DSB(); + SET_BIT(scc_regs->scc_mram_ctrl0, SCC_MRAM_CTRL0_FAST_READ_EN); + __DSB(); + __ISB(); +} + +void musca_s1_scc_mram_fast_read_disable(struct musca_s1_scc_dev_t* dev) +{ + struct musca_s1_scc_reg_map_t* scc_regs = + (struct musca_s1_scc_reg_map_t*) dev->cfg->base; + __DSB(); + CLR_BIT(scc_regs->scc_mram_ctrl0, SCC_MRAM_CTRL0_FAST_READ_EN); + __DSB(); + __ISB(); +} + +bool musca_s1_scc_mram_is_fast_read_enabled(struct musca_s1_scc_dev_t* dev) +{ + struct musca_s1_scc_reg_map_t* scc_regs = + (struct musca_s1_scc_reg_map_t*) dev->cfg->base; + return (bool)(scc_regs->scc_mram_ctrl0 & + (1u << SCC_MRAM_CTRL0_FAST_READ_EN)); +} \ No newline at end of file diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/musca_s1_scc_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/musca_s1_scc_drv.h new file mode 100644 index 0000000..63694e6 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/musca_s1_scc_drv.h @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2017-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __MUSCA_S1_SCC_DRV_H__ +#define __MUSCA_S1_SCC_DRV_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Enum to store alternate function values. + * They are used as shift operand, must be unsigned. + */ +enum gpio_altfunc_t { + GPIO_MAIN_FUNC = 0UL, + GPIO_ALTFUNC_1, + GPIO_ALTFUNC_2, + GPIO_ALTFUNC_MAX +}; + +#define GPIO_ALTFUNC_ALL_MASK ((1U << GPIO_ALTFUNC_MAX) - 1) + +/** +* \brief Enum to store alternate function mask values. +*/ +enum gpio_altfunc_mask_t { + GPIO_ALTFUNC_NONE = 0, + GPIO_MAIN_FUNC_MASK = (1UL << GPIO_MAIN_FUNC), + GPIO_ALTFUNC_1_MASK = (1UL << GPIO_ALTFUNC_1), + GPIO_ALTFUNC_2_MASK = (1UL << GPIO_ALTFUNC_2), + GPIO_MAIN_FUNC_NEG_MASK = (~GPIO_MAIN_FUNC_MASK & GPIO_ALTFUNC_ALL_MASK), + GPIO_ALTFUNC_1_NEG_MASK = (~GPIO_ALTFUNC_1_MASK & GPIO_ALTFUNC_ALL_MASK), + GPIO_ALTFUNC_2_NEG_MASK = (~GPIO_ALTFUNC_2_MASK & GPIO_ALTFUNC_ALL_MASK) +}; + +enum pinmode_select_t { + PINMODE_NONE, + PINMODE_PULL_DOWN, + PINMODE_PULL_UP +}; + +/* MUSCA SCC device configuration structure */ +struct musca_s1_scc_dev_cfg_t { + const uint32_t base; /*!< SCC base address */ +}; + +/* MUSCA SCC device structure */ +struct musca_s1_scc_dev_t { + const struct musca_s1_scc_dev_cfg_t* const cfg; /*!< SCC configuration */ +}; + +/** + * \brief Sets selected alternate functions for selected pins + * + * \param[in] dev SCC device pointer \ref musca_s1_scc_dev_t + * \param[in] altfunc Alternate function to set \ref gpio_altfunc_t + * \param[in] pin_mask Pin mask for the alternate functions + * + * \note This function doesn't check if scc dev is NULL. + * \note If no alternate function is selected, the function won't do anything + */ +void musca_s1_scc_set_alt_func(struct musca_s1_scc_dev_t* dev, + enum gpio_altfunc_t altfunc, uint32_t pin_mask); + +/** + * \brief Sets pinmode for the given pins + * + * \param[in] dev SCC device pointer \ref musca_s1_scc_dev_t + * \param[in] pin_mask Pin mask for the alternate functions + * \param[in] mode Pin mode to set \ref pinmode_select_t + * + * \note This function doesn't check if scc dev is NULL. + */ +void musca_s1_scc_set_pinmode(struct musca_s1_scc_dev_t* dev, uint32_t pin_mask, + enum pinmode_select_t mode); + +/** + * \brief Sets default input values for the selected pins + * + * \param[in] dev SCC device pointer \ref musca_s1_scc_dev_t + * \param[in] altfunc The selected alternate function that is set the + * specified default in value \ref gpio_altfunc_t + * \param[in] default_in_mask Pin mask for selecting pins + * \param[in] default_in_value Pin values for the selected pins + * + * \note This function doesn't check if scc_base is NULL. + * \note If no alternate function is selected, the function won't do anything + */ +void musca_s1_scc_set_default_in(struct musca_s1_scc_dev_t* dev, + enum gpio_altfunc_t altfunc, + uint32_t default_in_mask, + uint32_t default_in_value); + +/** + * \brief Enables eMRAM fast read + * + */ +void musca_s1_scc_mram_fast_read_enable(struct musca_s1_scc_dev_t* dev); + +/** + * \brief Disables eMRAM fast read + * + */ +void musca_s1_scc_mram_fast_read_disable(struct musca_s1_scc_dev_t* dev); + +/** + * \brief Check if eMRAM fast read is enabled + * + * \return Returns bool, true if fast read is enabled, false otherwise + */ +bool musca_s1_scc_mram_is_fast_read_enabled(struct musca_s1_scc_dev_t* dev); + +#ifdef __cplusplus +} +#endif + +#endif /* __MUSCA_S1_SCC_DRV_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/qspi_ip6514e_drv.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/qspi_ip6514e_drv.c new file mode 100644 index 0000000..2c1b427 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/qspi_ip6514e_drv.c @@ -0,0 +1,757 @@ +/* + * Copyright (c) 2018-2019 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +/* Use memcpy */ +#include + +#include "qspi_ip6514e_drv.h" + +/** Setter bit manipulation macro */ +#define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX))) +/** Clearing bit manipulation macro */ +#define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX))) +/** Getter bit manipulation macro */ +#define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX)))) + +#define WORD_ALIGN_4B_MASK 0x3U /* Mask the first 2 bits */ +#define IS_ADDR_ALIGNED(ADDR) (((uint32_t)(ADDR) & (WORD_ALIGN_4B_MASK)) == 0U) + +#define BITS_PER_BYTE 8U +#define BITS_PER_WORD 32U + +#define CFG_READS true +#define CFG_WRITES false + +#define ARG_NOT_USED 0 +#define ARG_PTR_NOT_USED NULL + +#define DATA_REG_NUMBER 2U +#define DATA_REG_LOWER 0U +#define DATA_REG_UPPER 1U + +#define ERROR_VALUE 0xFFFFFFFFU + +/** + * \brief QSPI IP6514E register map structure + */ +struct _qspi_ip6514e_reg_map_t { + volatile uint32_t qspi_cfg; /*!< 0x00 (R/W) */ + volatile uint32_t device_read_inst; /*!< 0x04 (R/W) */ + volatile uint32_t device_write_inst; /*!< 0x08 (R/W) */ + volatile uint32_t hidden1[2]; + volatile uint32_t device_size; /*!< 0x14 (R/W) */ + volatile uint32_t hidden2[3]; + volatile uint32_t remap_addr; /*!< 0x24 (R/W) */ + volatile uint32_t hidden3[26]; + volatile uint32_t flash_cmd_ctrl; /*!< 0x90 (R/W) */ + volatile uint32_t flash_cmd_addr; /*!< 0x94 (R/W) */ + volatile uint32_t hidden4[2]; + volatile uint32_t flash_cmd_read_data_lower; /*!< 0xA0 (R/ ) */ + volatile uint32_t flash_cmd_read_data_upper; /*!< 0xA4 (R/ ) */ + volatile uint32_t flash_cmd_write_data_lower; /*!< 0xA8 (R/W) */ + volatile uint32_t flash_cmd_write_data_upper; /*!< 0xAC (R/W) */ + volatile uint32_t hidden5[2]; +}; + +/** QSPI Configuration register description (offset 0x00) */ +#define QSPI_CFG_ENABLE_POS 0U +#define QSPI_CFG_ENABLE_ADDR_REMAP_POS 16U +#define QSPI_CFG_BAUD_DIV_POS 19U + #define QSPI_CFG_BAUD_DIV_MIN 2U + #define QSPI_CFG_BAUD_DIV_MAX 32U + #define QSPI_CFG_BAUD_DIV_BITS 4U +#define QSPI_CFG_IDLE_POS 31U + +/** + * Device Read/Write Instruction registers description (offset 0x04 and 0x08). + * These values are the same for the Device Read Instruction register at offset + * 0x04 and the Device Write Instruction register at offset 0x08. + */ +#define DEVICE_READ_WRITE_INST_OPCODE_POS 0U +#define DEVICE_READ_INST_INST_TYPE_POS 8U /* Only applies to the Read + * register. */ +#define DEVICE_READ_WRITE_INST_ADDR_TYPE_POS 12U +#define DEVICE_READ_WRITE_INST_DATA_TYPE_POS 16U + #define DEVICE_READ_WRITE_INST_MODE_QSPI 2U + #define DEVICE_READ_WRITE_INST_MODE_DSPI 1U + #define DEVICE_READ_WRITE_INST_MODE_SPI 0U + #define DEVICE_READ_WRITE_INST_MODE_BITS 2U +#define DEVICE_READ_WRITE_INST_DUMMY_CYCLES_POS 24U + #define DEVICE_READ_WRITE_INST_DUMMY_CYCLES_BITS 5U + #define DEVICE_READ_WRITE_INST_DUMMY_CYCLES_MAX 31U + +/** Device Size Configuration register description (offset 0x14) */ +#define DEVICE_SIZE_ADDR_BYTES_POS 0U + #define DEVICE_SIZE_ADDR_BYTES_MIN 1U + #define DEVICE_SIZE_ADDR_BYTES_MAX 16U + #define DEVICE_SIZE_ADDR_BYTES_BITS 4U +#define DEVICE_SIZE_PAGE_BYTES_POS 4U + #define DEVICE_SIZE_PAGE_BYTES_MAX 4095U + #define DEVICE_SIZE_PAGE_BYTES_BITS 12U + +/** Flash Command Control register description (offset 0x90) */ +#define FLASH_CMD_CTRL_EXECUTE_POS 0U +#define FLASH_CMD_CTRL_BUSY_POS 1U +#define FLASH_CMD_CTRL_DUMMY_CYCLES_POS 7U + #define FLASH_CMD_CTRL_DUMMY_CYCLES_MAX 31U + #define FLASH_CMD_CTRL_DUMMY_CYCLES_BITS 5U +#define FLASH_CMD_CTRL_WRITE_BYTES_POS 12U + #define FLASH_CMD_CTRL_WRITE_BYTES_MAX 8U + #define FLASH_CMD_CTRL_WRITE_BYTES_BITS 3U +#define FLASH_CMD_CTRL_WRITE_ENABLE_POS 15U +#define FLASH_CMD_CTRL_ADDR_BYTES_POS 16U + #define FLASH_CMD_CTRL_ADDR_BYTES_MAX 4U + #define FLASH_CMD_CTRL_ADDR_BYTES_BITS 2U +#define FLASH_CMD_CTRL_ADDR_ENABLE_POS 19U +#define FLASH_CMD_CTRL_READ_BYTES_POS 20U + #define FLASH_CMD_CTRL_READ_BYTES_MAX 8U + #define FLASH_CMD_CTRL_READ_BYTES_BITS 3U +#define FLASH_CMD_CTRL_READ_ENABLE_POS 23U +#define FLASH_CMD_CTRL_OPCODE_POS 24U + +/** Default register values of the QSPI Flash controller */ +#define QSPI_CFG_REG_RESET_VALUE (0x80080080U) +#define DEVICE_READ_INSTR_REG_RESET_VALUE (0x080220EBU) +#define DEVICE_WRITE_INSTR_REG_RESET_VALUE (0x00000002U) +#define DEVICE_SIZE_CFG_REG_RESET_VALUE (0x00101002U) +#define REMAP_ADDR_REG_RESET_VALUE (0x00000000U) +#define FLASH_CMD_CONTROL_REG_RESET_VALUE (0x00000000U) +#define FLASH_CMD_ADDRESS_REG_RESET_VALUE (0x00000000U) +#define FLASH_CMD_WRITE_DATA_REG_RESET_VALUE (0x00000000U) + +/** + * \brief Change specific bits in a 32 bits word. + * + * \param[in,out] word Pointer of the word to change + * \param[in] bits bits_length bits to put at bits_pos in the word + * pointed + * \param[in] bits_length Number of bits to change + * \param[in] bits_pos Position of the bits to change + * + * \note This function will do nothing if the parameters given are incorret: + * * word is NULL + * * bits_length + bits_pos > 32 + * * bits_length is 0 + */ +static void change_bits_in_word(volatile uint32_t *word, + uint32_t bits, + uint32_t bits_length, + uint32_t bits_pos) +{ + uint32_t mask; + + if ((word == NULL) || + ((bits_length + bits_pos) > BITS_PER_WORD) || + (bits_length == 0U)) { + /* Silently fail */ + return; + } + + /* Change all the bits */ + if (bits_length == BITS_PER_WORD) { + *word = bits; + return; + } + + mask = ((1U << bits_length) - 1); + /* + * We change the bits in three steps: + * - clear bits_length bits with zeroes at bits_pos in the word + * - mask bits in case it contains more than bits_length bits + * - set the new bits in the cleared word + * Because the data pointed by word is only read once, the data will still + * be coherent after an interruption that changes it. + */ + *word = ((*word & ~(mask << bits_pos)) | ((bits & mask) << bits_pos)); +} + +/** + * \brief Configure reads or writes commands for direct operations. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * \param[in] opcode Read/write opcode that will be used for every + * direct read/write + * \param[in] dummy_cycles Number of dummy cycles to wait before triggering + * the command, this value must be between 0 and 31 + * (both included) + * \param[in] is_reads_cfg true to configure direct reads, false to configure + * direct writes + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note The QSPI controller should be idle before calling this function. + */ +static enum qspi_ip6514e_error_t qspi_ip6514e_cfg_reads_writes( + struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + uint32_t dummy_cycles, + bool is_reads_cfg) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + /* + * Select the good register address if we want to configure reads or writes. + */ + volatile uint32_t *device_read_write_inst_reg = is_reads_cfg ? + &(reg_map->device_read_inst) : + &(reg_map->device_write_inst); + uint32_t device_read_write_inst_reg_copy = *device_read_write_inst_reg; + + /* + * Wait for the Serial Interface and QSPI pipeline to be IDLE when + * all low level synchronization has been done. + */ + while(!qspi_ip6514e_is_idle(dev)); + + if (dummy_cycles > DEVICE_READ_WRITE_INST_DUMMY_CYCLES_MAX) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + change_bits_in_word(&device_read_write_inst_reg_copy, + (uint32_t)opcode, + BITS_PER_BYTE, + DEVICE_READ_WRITE_INST_OPCODE_POS); + change_bits_in_word(&device_read_write_inst_reg_copy, + dummy_cycles, + DEVICE_READ_WRITE_INST_DUMMY_CYCLES_BITS, + DEVICE_READ_WRITE_INST_DUMMY_CYCLES_POS); + + *device_read_write_inst_reg = device_read_write_inst_reg_copy; + + return QSPI_IP6514E_ERR_NONE; +} + +/** + * \brief Given the public SPI mode enumeration, returns the private value it + * maps to in the register field. + * + * \param[in] spi_mode Read/write opcode that will be used for every direct + * read/write + * + * \return Return the correct DEVICE_READ_WRITE_INST_MODE value. + */ +static uint32_t spi_mode_field_value(enum qspi_ip6514e_spi_mode_t spi_mode) +{ + switch (spi_mode) { + case QSPI_IP6514E_SPI_MODE: + return DEVICE_READ_WRITE_INST_MODE_SPI; + case QSPI_IP6514E_DSPI_MODE: + return DEVICE_READ_WRITE_INST_MODE_DSPI; + case QSPI_IP6514E_QSPI_MODE: + return DEVICE_READ_WRITE_INST_MODE_QSPI; + default: + return ERROR_VALUE; + } +} + +bool qspi_ip6514e_is_idle(struct qspi_ip6514e_dev_t* dev) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + + return GET_BIT(reg_map->qspi_cfg, QSPI_CFG_IDLE_POS); +} + +bool qspi_ip6514e_is_enabled(struct qspi_ip6514e_dev_t* dev) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + + return GET_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_POS); +} + +void qspi_ip6514e_disable(struct qspi_ip6514e_dev_t* dev) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + + CLR_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_POS); +} + +void qspi_ip6514e_enable(struct qspi_ip6514e_dev_t* dev) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + + SET_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_POS); +} + +enum qspi_ip6514e_error_t qspi_ip6514e_set_baud_rate_div( + struct qspi_ip6514e_dev_t* dev, + uint32_t div) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + + /* + * Wait for the Serial Interface and QSPI pipeline to be IDLE when + * all low level synchronization has been done. + */ + while(!qspi_ip6514e_is_idle(dev)); + + /* div should be an even number. */ + if (((div & 1U) == 1) || + (div < QSPI_CFG_BAUD_DIV_MIN) || + (div > QSPI_CFG_BAUD_DIV_MAX)) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + /* + * The div value (between 2 and 32) needs to be stored in the register on a + * 4 bits field. + */ + change_bits_in_word(&(reg_map->qspi_cfg), + (div / 2) - 1, + QSPI_CFG_BAUD_DIV_BITS, + QSPI_CFG_BAUD_DIV_POS); + + return QSPI_IP6514E_ERR_NONE; +} + +enum qspi_ip6514e_error_t qspi_ip6514e_set_spi_mode( + struct qspi_ip6514e_dev_t* dev, + enum qspi_ip6514e_spi_mode_t inst_type, + enum qspi_ip6514e_spi_mode_t addr_type, + enum qspi_ip6514e_spi_mode_t data_type) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + uint32_t inst_spi_mode, addr_spi_mode, data_spi_mode; + /* + * A local copy of the Device Read Instruction and Device Write Instruction + * registers is used to limit APB accesses. + */ + uint32_t device_read_inst_cpy = reg_map->device_read_inst; + uint32_t device_write_inst_cpy = reg_map->device_write_inst; + + /* + * Wait for the Serial Interface and QSPI pipeline to be IDLE when + * all low level synchronization has been done. + */ + while(!qspi_ip6514e_is_idle(dev)); + + /* + * First check that the instruction mode is not SPI. If that is the case, + * the address and data mode register fields become DO NOT CARE. + */ + inst_spi_mode = spi_mode_field_value(inst_type); + if (inst_spi_mode == ERROR_VALUE) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + if (inst_type != QSPI_IP6514E_SPI_MODE) { + change_bits_in_word(&(reg_map->device_read_inst), + inst_spi_mode, + DEVICE_READ_WRITE_INST_MODE_BITS, + DEVICE_READ_INST_INST_TYPE_POS); + return QSPI_IP6514E_ERR_NONE; + } + + /* Now check and set address and data modes. */ + addr_spi_mode = spi_mode_field_value(addr_type); + data_spi_mode = spi_mode_field_value(data_type); + if ((addr_spi_mode == ERROR_VALUE) || (data_spi_mode == ERROR_VALUE)) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + /* Change the Device Read Instruction register. */ + change_bits_in_word(&device_read_inst_cpy, + inst_spi_mode, + DEVICE_READ_WRITE_INST_MODE_BITS, + DEVICE_READ_INST_INST_TYPE_POS); + change_bits_in_word(&device_read_inst_cpy, + addr_spi_mode, + DEVICE_READ_WRITE_INST_MODE_BITS, + DEVICE_READ_WRITE_INST_ADDR_TYPE_POS); + change_bits_in_word(&device_read_inst_cpy, + data_spi_mode, + DEVICE_READ_WRITE_INST_MODE_BITS, + DEVICE_READ_WRITE_INST_DATA_TYPE_POS); + + /* Change the Device Write Instruction register. */ + change_bits_in_word(&device_write_inst_cpy, + addr_spi_mode, + DEVICE_READ_WRITE_INST_MODE_BITS, + DEVICE_READ_WRITE_INST_ADDR_TYPE_POS); + change_bits_in_word(&device_write_inst_cpy, + data_spi_mode, + DEVICE_READ_WRITE_INST_MODE_BITS, + DEVICE_READ_WRITE_INST_DATA_TYPE_POS); + + /* Save the changes. */ + reg_map->device_read_inst = device_read_inst_cpy; + reg_map->device_write_inst = device_write_inst_cpy; + + return QSPI_IP6514E_ERR_NONE; +} + +enum qspi_ip6514e_error_t qspi_ip6514e_cfg_reads(struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + uint32_t dummy_cycles) +{ + return qspi_ip6514e_cfg_reads_writes(dev, opcode, dummy_cycles, CFG_READS); +} + +enum qspi_ip6514e_error_t qspi_ip6514e_cfg_writes( + struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + uint32_t dummy_cycles) +{ + return qspi_ip6514e_cfg_reads_writes(dev, opcode, dummy_cycles, CFG_WRITES); +} + +enum qspi_ip6514e_error_t qspi_ip6514e_cfg_page_size( + struct qspi_ip6514e_dev_t* dev, + uint32_t page_size) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + + /* + * Wait for the Serial Interface and QSPI pipeline to be IDLE when + * all low level synchronization has been done. + */ + while(!qspi_ip6514e_is_idle(dev)); + + if (page_size > DEVICE_SIZE_PAGE_BYTES_MAX) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + change_bits_in_word(&(reg_map->device_size), + page_size, + DEVICE_SIZE_PAGE_BYTES_BITS, + DEVICE_SIZE_PAGE_BYTES_POS); + + return QSPI_IP6514E_ERR_NONE; +} + +enum qspi_ip6514e_error_t qspi_ip6514e_cfg_addr_bytes( + struct qspi_ip6514e_dev_t* dev, + uint32_t bytes_number) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + + /* + * Wait for the Serial Interface and QSPI pipeline to be IDLE when + * all low level synchronization has been done. + */ + while(!qspi_ip6514e_is_idle(dev)); + + if (bytes_number < DEVICE_SIZE_ADDR_BYTES_MIN || + bytes_number > DEVICE_SIZE_ADDR_BYTES_MAX) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + change_bits_in_word(&(reg_map->device_size), + bytes_number - 1, + DEVICE_SIZE_ADDR_BYTES_BITS, + DEVICE_SIZE_ADDR_BYTES_POS); + + + return QSPI_IP6514E_ERR_NONE; +} + +void qspi_ip6514e_remap_addr(struct qspi_ip6514e_dev_t* dev, uint32_t offset) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + /* Save the enable state to restore it after. */ + bool is_enabled = qspi_ip6514e_is_enabled(dev); + + if (is_enabled) { + qspi_ip6514e_disable(dev); + } + + reg_map->remap_addr = offset; + SET_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_ADDR_REMAP_POS); + + if (is_enabled) { + qspi_ip6514e_enable(dev); + } +} + +void qspi_ip6514e_disable_remap(struct qspi_ip6514e_dev_t* dev) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + /* Save the enable state to restore it after. */ + bool is_enabled = qspi_ip6514e_is_enabled(dev); + + if (is_enabled) { + qspi_ip6514e_disable(dev); + } + + CLR_BIT(reg_map->qspi_cfg, QSPI_CFG_ENABLE_ADDR_REMAP_POS); + + if (is_enabled) { + qspi_ip6514e_enable(dev); + } +} + +void qspi_ip6514e_reset_regs(struct qspi_ip6514e_dev_t* dev) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + + /* Restore the default value of the QSPI Configuration register. */ + reg_map->qspi_cfg = QSPI_CFG_REG_RESET_VALUE; + + /* Restore the default value of the Device R/W Instruction registers. */ + reg_map->device_read_inst = DEVICE_READ_INSTR_REG_RESET_VALUE; + reg_map->device_write_inst = DEVICE_WRITE_INSTR_REG_RESET_VALUE; + + /* Restore the default value of the Device Size Configuration register. */ + reg_map->device_size = DEVICE_SIZE_CFG_REG_RESET_VALUE; + + /* Restore the default value of the Remap Address register. */ + reg_map->remap_addr = REMAP_ADDR_REG_RESET_VALUE; + + /* Restore the default value of the Flash Command Control register. */ + reg_map->flash_cmd_ctrl = FLASH_CMD_CONTROL_REG_RESET_VALUE; + /* Restore the default value of the Flash Command Address register. */ + reg_map->flash_cmd_addr = FLASH_CMD_ADDRESS_REG_RESET_VALUE; + + /* Restore the default value of the Flash Command Write Data registers. */ + reg_map->flash_cmd_write_data_lower = FLASH_CMD_WRITE_DATA_REG_RESET_VALUE; + reg_map->flash_cmd_write_data_upper = FLASH_CMD_WRITE_DATA_REG_RESET_VALUE; + + /* + * This function does not affect the Flash Command Read Data registers + * which are completely Read-Only. + */ +} + +enum qspi_ip6514e_error_t qspi_ip6514e_send_cmd(struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + void *read_data, + uint32_t read_len, + const void *write_data, + uint32_t write_len, + uint32_t addr, + uint32_t addr_bytes_number, + uint32_t dummy_cycles) +{ + struct _qspi_ip6514e_reg_map_t *reg_map = + (struct _qspi_ip6514e_reg_map_t *)dev->cfg->base; + /* To limit APB accesses, we set this reg up locally before */ + uint32_t flash_cmd_ctrl = 0U; + bool read_requested = ((read_data != NULL) && (read_len != 0)); + bool write_requested = ((write_data != NULL) && (write_len != 0)); + bool addr_requested = (addr_bytes_number != 0); + /* + * To prevent unaligned and byte or halfbyte accesses to the APB registers, + * a word aligned buffer is used to temporary transfer the data before doing + * word accesses on these registers from that buffer. + */ + uint32_t data_regs[DATA_REG_NUMBER] = {0}; + + if (read_len > FLASH_CMD_CTRL_READ_BYTES_MAX) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + if (write_len > FLASH_CMD_CTRL_WRITE_BYTES_MAX) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + if (addr_bytes_number > FLASH_CMD_CTRL_ADDR_BYTES_MAX) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + if (dummy_cycles > FLASH_CMD_CTRL_DUMMY_CYCLES_MAX) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + if (read_requested && write_requested) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + change_bits_in_word(&flash_cmd_ctrl, + (uint32_t)opcode, + BITS_PER_BYTE, + FLASH_CMD_CTRL_OPCODE_POS); + + /* Enable read if requested */ + if (read_requested) { + SET_BIT(flash_cmd_ctrl, FLASH_CMD_CTRL_READ_ENABLE_POS); + change_bits_in_word(&flash_cmd_ctrl, + read_len - 1, + FLASH_CMD_CTRL_READ_BYTES_BITS, + FLASH_CMD_CTRL_READ_BYTES_POS); + } + + /* Enable write if requested */ + if (write_requested) { + SET_BIT(flash_cmd_ctrl, FLASH_CMD_CTRL_WRITE_ENABLE_POS); + change_bits_in_word(&flash_cmd_ctrl, + write_len - 1, + FLASH_CMD_CTRL_WRITE_BYTES_BITS, + FLASH_CMD_CTRL_WRITE_BYTES_POS); + + if (IS_ADDR_ALIGNED(write_data) && IS_ADDR_ALIGNED(write_len)) { + /* + * Optimised case when write_data is word aligned and write_len is + * 4 or 8. + */ + reg_map->flash_cmd_write_data_lower = *(uint32_t *)write_data; + if (write_len == FLASH_CMD_CTRL_WRITE_BYTES_MAX) { + reg_map->flash_cmd_write_data_upper = + *((uint32_t *)write_data + 1); + } + } else { + /* + * data_regs is used as a buffer to only do unaligned access on the + * AHB bus and word aligned accesses to the APB registers. + */ + memcpy((void *)data_regs, write_data, write_len); + /* + * Only write_len bytes will be written even if both data registers + * are written. + */ + reg_map->flash_cmd_write_data_lower = data_regs[DATA_REG_LOWER]; + reg_map->flash_cmd_write_data_upper = data_regs[DATA_REG_UPPER]; + } + } + + /* Enable the address if requested */ + if (addr_requested) { + SET_BIT(flash_cmd_ctrl, FLASH_CMD_CTRL_ADDR_ENABLE_POS); + reg_map->flash_cmd_addr = addr; + change_bits_in_word(&flash_cmd_ctrl, + addr_bytes_number - 1, + FLASH_CMD_CTRL_ADDR_BYTES_BITS, + FLASH_CMD_CTRL_ADDR_BYTES_POS); + } + + /* Put dummy cycles number */ + change_bits_in_word(&flash_cmd_ctrl, + dummy_cycles, + FLASH_CMD_CTRL_DUMMY_CYCLES_BITS, + FLASH_CMD_CTRL_DUMMY_CYCLES_POS); + + /* Copy the Flash Command Control register and execute the command */ + reg_map->flash_cmd_ctrl = flash_cmd_ctrl; + SET_BIT(reg_map->flash_cmd_ctrl, FLASH_CMD_CTRL_EXECUTE_POS); + + /* Wait for termination */ + while (GET_BIT(reg_map->flash_cmd_ctrl, FLASH_CMD_CTRL_BUSY_POS)); + + /* + * Recolt the read data if it was requested. read_len validity has already + * been verified at this point. + */ + if (read_requested) { + if (IS_ADDR_ALIGNED(read_data) && IS_ADDR_ALIGNED(read_len)) { + /* + * Optimised case when read_data is word aligned and read_len is + * 4 or 8. + */ + *(uint32_t *)read_data = reg_map->flash_cmd_read_data_lower; + if (read_len == FLASH_CMD_CTRL_READ_BYTES_MAX) { + *((uint32_t *)read_data + 1) = + reg_map->flash_cmd_read_data_upper; + } + } else { + /* + * Only read_len bytes have been written even if both data registers + * are written. + */ + data_regs[DATA_REG_LOWER] = reg_map->flash_cmd_read_data_lower; + data_regs[DATA_REG_UPPER] = reg_map->flash_cmd_read_data_upper; + /* + * data_regs is used as a buffer to only do unaligned access on the + * AHB bus and word aligned accesses to the APB registers. + */ + memcpy(read_data, (void *)data_regs, read_len); + } + } + + return QSPI_IP6514E_ERR_NONE; +} + +void qspi_ip6514e_send_simple_cmd(struct qspi_ip6514e_dev_t* dev, + uint8_t opcode) +{ + /* + * No read/write data, no address, no dummy cycles. + * Given the arguments, this function can not fail. + */ + (void)qspi_ip6514e_send_cmd(dev, + opcode, + ARG_PTR_NOT_USED, + ARG_NOT_USED, + ARG_PTR_NOT_USED, + ARG_NOT_USED, + ARG_NOT_USED, + ARG_NOT_USED, + 0); +} + +enum qspi_ip6514e_error_t qspi_ip6514e_send_read_cmd( + struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + void *read_data, + uint32_t read_len, + uint32_t addr, + uint32_t addr_bytes_number, + uint32_t dummy_cycles) +{ + /* Read arguments are expected */ + if (read_data == ARG_PTR_NOT_USED || read_len == ARG_NOT_USED) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + /* No write data */ + return qspi_ip6514e_send_cmd(dev, + opcode, + read_data, + read_len, + ARG_PTR_NOT_USED, + ARG_NOT_USED, + addr, + addr_bytes_number, + dummy_cycles); +} + +enum qspi_ip6514e_error_t qspi_ip6514e_send_write_cmd( + struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + const void *write_data, + uint32_t write_len, + uint32_t addr, + uint32_t addr_bytes_number, + uint32_t dummy_cycles) +{ + /* Write arguments are expected */ + if (write_data == ARG_PTR_NOT_USED || write_len == ARG_NOT_USED) { + return QSPI_IP6514E_ERR_WRONG_ARGUMENT; + } + + /* No read data, no dummy cycles */ + return qspi_ip6514e_send_cmd(dev, + opcode, + ARG_PTR_NOT_USED, + ARG_NOT_USED, + write_data, + write_len, + addr, + addr_bytes_number, + dummy_cycles); +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/qspi_ip6514e_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/qspi_ip6514e_drv.h new file mode 100644 index 0000000..9dabbb9 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/qspi_ip6514e_drv.h @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2018 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file qspi_ip6514e_drv.h + * \brief Driver for Cadence QSPI Flash Controller IP. + * There are two ways to communicate with the flash memory device: + * - issue AHB requests for direct read and writes in the Flash memory + * mapped address zone. The commands used for those can be configured + * by the driver + * - send a command to the device to access his internal registers and + * do other operations like erasing a sector + * At reset, the QSPI controller will work in a default mode which will + * allow to do basic commands. It should be configured with the + * flash memory device specifications for optimal use for commands and + * direct reads/writes. Here is an example of configuration: + * - send command to activate QSPI mode on the flash memory device + * - send command to change dummy cycles on the flash memory device + * - check if any operation is ungoing + * - disable the QSPI controller + * - change the baud rate divisor + * - activate the QSPI mode on the controller + * - change the dummy cycles number and opcode for reads/writes + * - change the number of bytes per page + * - change the number of address bytes + * - activate the QSPI controller + * + * Warning: none of the functions declared here check if the dev + * argument points to NULL. + */ + +#ifndef __QSPI_IP6514E_DRV_H__ +#define __QSPI_IP6514E_DRV_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Cadence QSPI IP6514E error enumeration types + */ +enum qspi_ip6514e_error_t { + QSPI_IP6514E_ERR_NONE, + QSPI_IP6514E_ERR_WRONG_ARGUMENT, + QSPI_IP6514E_ERR_CONTROLLER_NOT_DISABLED, + QSPI_IP6514E_ERR_READ_IN_PROGRESS, + QSPI_IP6514E_ERR_WRITE_IN_PROGRESS, + /* Any new error should be added to the enumeration type error of + * the corresponding Flash device library as well. + */ +}; + +/** + * \brief Cadence QSPI IP6514E SPI modes + */ +enum qspi_ip6514e_spi_mode_t { + QSPI_IP6514E_SPI_MODE, + /*!< Use 1 line for Instruction, Address and Data */ + QSPI_IP6514E_DSPI_MODE, + /*!< Use 2 lines for Instruction, Address and Data */ + QSPI_IP6514E_QSPI_MODE, + /*!< Use 4 lines for Instruction, Address and Data */ +}; + +/** + * \brief Cadence QSPI IP6514E device configuration structure + */ +struct qspi_ip6514e_dev_cfg_t { + const uint32_t base; /*!< QSPI IP6514E base address */ + /* + * If not all the AHB wires are connected to the QSPI Flash Controller the + * driver can still access all of the Flash memory. The bits of this value + * should be put to 1 for every wire that is connected. Set it to + * 0xFFFFFFFFU if all AHB address wires are connected to the + * QSPI Flash Controller. + */ + uint32_t addr_mask; +}; + +/** + * \brief Cadence QSPI IP6514E device structure + */ +struct qspi_ip6514e_dev_t { + const struct qspi_ip6514e_dev_cfg_t* const cfg; + /*!< QSPI IP6514E configuration */ +}; + +/** + * \brief Check if the controller is idle. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * + * \return true if the controller is idle, false otherwise. + */ +bool qspi_ip6514e_is_idle(struct qspi_ip6514e_dev_t* dev); + +/** + * \brief Check if the controller is enabled. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * + * \return true if the controller is enabled, false otherwise. + */ +bool qspi_ip6514e_is_enabled(struct qspi_ip6514e_dev_t* dev); + +/** + * \brief Disable the QSPI controller. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + */ +void qspi_ip6514e_disable(struct qspi_ip6514e_dev_t* dev); + +/** + * \brief Enable the QSPI controller. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + */ +void qspi_ip6514e_enable(struct qspi_ip6514e_dev_t* dev); + +/** + * \brief Change the baud rate divisor. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * \param[in] div Baud rate divisor value. It can only be an even number + * between 2 and 32 (both included). + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note The QSPI frequency is calculated dividing the QSPI controller clock by + * this divisor. Please check Flash memory device specifications to know + * the maximal frequency that can be used. + * \note The QSPI controller should be disabled before calling this function. + */ +enum qspi_ip6514e_error_t qspi_ip6514e_set_baud_rate_div( + struct qspi_ip6514e_dev_t* dev, + uint32_t div); + +/** + * \brief Set SPI mode for instruction, address and data. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * \param[in] inst_type SPI mode to use for the instruction part of the command + * \param[in] addr_type SPI mode to use for the address part of the command + * \param[in] data_type SPI mode to use for the data part of the command + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note The QSPI controller should be idle before calling this function. + * \note Changing this setting will affect commands and direct operations. + */ +enum qspi_ip6514e_error_t qspi_ip6514e_set_spi_mode( + struct qspi_ip6514e_dev_t* dev, + enum qspi_ip6514e_spi_mode_t inst_type, + enum qspi_ip6514e_spi_mode_t addr_type, + enum qspi_ip6514e_spi_mode_t data_type); + +/** + * \brief Configure read commands for direct reads. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * \param[in] opcode Read opcode that will be used for every direct read + * \param[in] dummy_cycles Number of dummy cycles to wait before triggering the + * command, this value must be between 0 and 31 + * (both included) + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note The QSPI controller should be idle before calling this function. + */ +enum qspi_ip6514e_error_t qspi_ip6514e_cfg_reads(struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + uint32_t dummy_cycles); + +/** + * \brief Configure write commands for direct writes. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * \param[in] opcode Write opcode that will be used for every direct write + * \param[in] dummy_cycles Number of dummy cycles to wait before triggering the + * command, this value must be between 0 and 31 + * (both included) + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note The QSPI controller should be idle before calling this function. + */ +enum qspi_ip6514e_error_t qspi_ip6514e_cfg_writes( + struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + uint32_t dummy_cycles); + +/** + * \brief Change the number of bytes per device page. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * \param[in] page_size Number of bytes per device page, must be between 0 + * and 4095 (both included) + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note The QSPI controller should be idle before calling this function. + * \note This function will affect direct reads/writes. + */ +enum qspi_ip6514e_error_t qspi_ip6514e_cfg_page_size( + struct qspi_ip6514e_dev_t* dev, + uint32_t page_size); + +/** + * \brief Change the number of device address bytes. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * \param[in] bytes_number Number of device address bytes, must be between 1 + * and 16 (both included) + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note The QSPI controller should be idle before calling this function. + * \note This function will affect direct reads/writes. + */ +enum qspi_ip6514e_error_t qspi_ip6514e_cfg_addr_bytes( + struct qspi_ip6514e_dev_t* dev, + uint32_t bytes_number); + +/** + * \brief Remap the incoming AHB address with an offset for direct accesses. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * \param[in] offset Offset that will be added to the incoming AHB address to + * access the Flash memory + * + * \note This function will only affect direct reads/writes. + * \note This function does not check if the resulting address is out of memory + * bounds. + */ +void qspi_ip6514e_remap_addr(struct qspi_ip6514e_dev_t* dev, uint32_t offset); + +/** + * \brief Disable AHB address remapping for direct accesses. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * + * \note This function will disable the controller if it is not already + * disabled and enable it again (if it was). + * \note This function will only affect direct reads/writes. + */ +void qspi_ip6514e_disable_remap(struct qspi_ip6514e_dev_t* dev); + +/** + * \brief Restore the default value of the QSPI controller registers. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * + * \note The QSPI controller should be disabled before calling this function. + */ +void qspi_ip6514e_reset_regs(struct qspi_ip6514e_dev_t* dev); + +/** + * \brief Send a command to the flash memory device using the Software Triggered + * Instruction Generator (STIG). + * + * \param[in] dev QSPI IP6514E device struct + * \ref qspi_ip6514e_dev_t + * \param[in] opcode Opcode for the command. + * \param[out] read_data Pointer to a memory zone where the read_len + * bytes read will be written to. If no data is to + * be read for the command, + * this argument should be NULL. + * \param[in] read_len Number of bytes to read for the command. If + * no bytes are to be read, use 0 for argument + * otherwise between 1 and 8 bytes (both + * included) can be read. + * \param[in] write_data Pointer to a memory zone where are + * located the write_len bytes to write for + * this command. If no bytes are to be written, + * use NULL as argument. + * \param[in] write_len Number of bytes to write for the command. If + * no bytes are to be written, use 0 for + * argument otherwise between 1 and 8 bytes + * (both included) can be written. + * \param[in] addr Address used for the command + * \param[in] addr_bytes_number Number of address bytes for this command. + * If an address is not needed for the command, + * use 0 for argument, otherwise between 1 and + * 4 bytes (both included) can be used. + * \param[in] dummy_cycles Number of dummy cycles required for the + * command, between 0 and 31 (both included). + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note Check the flash memory device specifications for the possible opcodes + * that can be used and the other informations needed for this function. + * \note The SPI mode used for this command is the one set with the + * \ref qspi_ip6514e_activate_qspi_mode function or the default one. + */ +enum qspi_ip6514e_error_t qspi_ip6514e_send_cmd(struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + void *read_data, + uint32_t read_len, + const void *write_data, + uint32_t write_len, + uint32_t addr, + uint32_t addr_bytes_number, + uint32_t dummy_cycles); + +/** + * \brief Send a simple command to the flash memory device using the Software + * Triggered Instruction Generator (STIG) with no data arguments. + * This command can be used for example to send the WRITE ENABLE command. + * + * \param[in] dev QSPI IP6514E device struct \ref qspi_ip6514e_dev_t + * \param[in] opcode Opcode for the command. + * + * \note Check the flash memory device specifications for the possible opcodes + * that can be used and the other informations needed for this function. + * \note The SPI mode used for this command is the one set with the + * \ref qspi_ip6514e_activate_qspi_mode function or the default one. + */ +void qspi_ip6514e_send_simple_cmd(struct qspi_ip6514e_dev_t* dev, + uint8_t opcode); + +/** + * \brief Send a read command to the flash memory device using the Software + * Triggered Instruction Generator (STIG). This command can be used to + * read Flash memory data or registers. + * + * \param[in] dev QSPI IP6514E device struct + * \ref qspi_ip6514e_dev_t + * \param[in] opcode Opcode for the command. + * \param[out] read_data Pointer to a memory zone where the + * read_len bytes read will be written to. + * \param[in] read_len Number of bytes to read for the command. + * Between 1 and 8 bytes (both included) can be + * read. + * \param[in] addr Address used for the command + * \param[in] addr_bytes_number Number of address bytes for this command. + * If an address is not needed for the command, + * use 0 for argument, otherwise between 1 and + * 4 bytes (both included) can be used. + * \param[in] dummy_cycles Number of dummy cycles required for the + * command, between 0 and 31 (both included). + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note Check the flash memory device specifications for the possible opcodes + * that can be used and the other informations needed for this function. + * \note The SPI mode used for this command is the one set with the + * \ref qspi_ip6514e_activate_qspi_mode function or the default one. + */ +enum qspi_ip6514e_error_t qspi_ip6514e_send_read_cmd( + struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + void *read_data, + uint32_t read_len, + uint32_t addr, + uint32_t addr_bytes_number, + uint32_t dummy_cycles); + +/** + * \brief Send a write command to the flash memory device using the Software + * Triggered Instruction Generator (STIG). This command can be used to + * write Flash memory or registers. + * + * \param[in] dev QSPI IP6514E device struct + * \ref qspi_ip6514e_dev_t + * \param[in] opcode Opcode for the command. + * \param[in] write_data Pointer to a memory zone where are + * located the write_len bytes to write for + * this command. + * \param[in] write_len Number of bytes to write for the command. + * Between 1 and 8 bytes (both included) can be + * written. + * \param[in] addr Address used for the command + * \param[in] addr_bytes_number Number of address bytes for this command. + * If an address is not needed for the command, + * use 0 for argument, otherwise between 1 and + * 4 bytes (both included) can be used. + * \param[in] dummy_cycles Number of dummy cycles required for the + * command, between 0 and 31 (both included). + * + * \return Returns error code as specified in \ref qspi_ip6514e_error_t + * + * \note Check the flash memory device specifications for the possible opcodes + * that can be used and the other informations needed for this function. + * \note The SPI mode used for this command is the one set with the + * \ref qspi_ip6514e_activate_qspi_mode function or the default one. + */ +enum qspi_ip6514e_error_t qspi_ip6514e_send_write_cmd( + struct qspi_ip6514e_dev_t* dev, + uint8_t opcode, + const void *write_data, + uint32_t write_len, + uint32_t addr, + uint32_t addr_bytes_number, + uint32_t dummy_cycles); + +#ifdef __cplusplus +} +#endif + +#endif /* __QSPI_IP6514E_DRV_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_cmsdk_drv.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_cmsdk_drv.c new file mode 100644 index 0000000..547d83c --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_cmsdk_drv.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2016-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file timer_cmsdk_drv.c + * \brief Generic driver for CMSDK APB Timers. + * The timer is a 32-bit down-counter with the following features: + * - optional programmable external clock source + * - programmable interrupt source, triggered if counter reaches 0 + * - automatic reload if counter reaches 0 + */ + +#include "timer_cmsdk_drv.h" + +/** Setter bit manipulation macro */ +#define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX))) +/** Clearing bit manipulation macro */ +#define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX))) +/** Getter bit manipulation macro */ +#define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX)))) + +/** + * \brief Timer register map structure + * + */ +struct timer_cmsdk_reg_map_t { + volatile uint32_t ctrl; /* Offset: 0x000 (R/W) control register */ + volatile uint32_t value; /* Offset: 0x004 (R/W) current value register */ + volatile uint32_t reload; /* Offset: 0x008 (R/W) reload value register */ + union { + volatile uint32_t intstatus; /* Offset: 0x00C (R/ ) interrupt + * status register + */ + volatile uint32_t intclear; /* Offset: 0x00C ( /W) interrupt + * clear register + */ + }intreg; +}; + +/** + * \brief CTRL register bit definitions + * + */ +enum ctrl_reg_bits_t { + CTRL_REG_ENUM_ENABLE_INDEX = 0, + CTRL_REG_ENUM_EXTERNAL_INPUT_ENABLE_INDEX = 1, + CTRL_REG_ENUM_EXTERNAL_INPUT_CLOCK_INDEX = 2, + CTRL_REG_ENUM_IRQ_ENABLE_INDEX = 3 +}; + +/** + * \brief INTSTATUS/INTCLEAR register bit definitions + * + */ +enum interrupt_reg_bits_t { + INTERRUPT_REG_ENUM_STATUS_AND_CLEAR_INDEX = 0 +}; + +void timer_cmsdk_init(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + + if (dev->data->is_initialized == 0) { + register_map->ctrl = 0; + register_map->reload = TIMER_CMSDK_DEFAULT_RELOAD; + dev->data->is_initialized = 1; + } +} + +bool timer_cmsdk_is_initialized(const struct timer_cmsdk_dev_t* dev) +{ + return dev->data->is_initialized; +} + +void timer_cmsdk_enable_external_input(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + SET_BIT(register_map->ctrl, CTRL_REG_ENUM_EXTERNAL_INPUT_ENABLE_INDEX); +} + +void timer_cmsdk_disable_external_input(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + CLR_BIT(register_map->ctrl, CTRL_REG_ENUM_EXTERNAL_INPUT_ENABLE_INDEX); +} + +bool timer_cmsdk_is_external_input_enabled(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + return GET_BIT(register_map->ctrl, + CTRL_REG_ENUM_EXTERNAL_INPUT_ENABLE_INDEX); +} + +void timer_cmsdk_set_clock_to_internal(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + CLR_BIT(register_map->ctrl, CTRL_REG_ENUM_EXTERNAL_INPUT_CLOCK_INDEX); +} + +void timer_cmsdk_set_clock_to_external(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + SET_BIT(register_map->ctrl, CTRL_REG_ENUM_EXTERNAL_INPUT_CLOCK_INDEX); +} + +bool timer_cmsdk_is_clock_external(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + return GET_BIT(register_map->ctrl, + CTRL_REG_ENUM_EXTERNAL_INPUT_CLOCK_INDEX); +} + +void timer_cmsdk_enable(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + SET_BIT(register_map->ctrl, CTRL_REG_ENUM_ENABLE_INDEX); +} + +void timer_cmsdk_disable(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + CLR_BIT(register_map->ctrl, CTRL_REG_ENUM_ENABLE_INDEX); +} + +bool timer_cmsdk_is_enabled(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + return GET_BIT(register_map->ctrl, CTRL_REG_ENUM_ENABLE_INDEX); +} + +void timer_cmsdk_enable_interrupt(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + SET_BIT(register_map->ctrl, CTRL_REG_ENUM_IRQ_ENABLE_INDEX); +} + +void timer_cmsdk_disable_interrupt(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + CLR_BIT(register_map->ctrl, CTRL_REG_ENUM_IRQ_ENABLE_INDEX); +} + +bool timer_cmsdk_is_interrupt_enabled(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + return GET_BIT(register_map->ctrl, CTRL_REG_ENUM_IRQ_ENABLE_INDEX); +} + +bool timer_cmsdk_is_interrupt_active(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + return GET_BIT(register_map->intreg.intstatus, + INTERRUPT_REG_ENUM_STATUS_AND_CLEAR_INDEX); +} + +void timer_cmsdk_clear_interrupt(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + SET_BIT(register_map->intreg.intclear, + INTERRUPT_REG_ENUM_STATUS_AND_CLEAR_INDEX); +} + +uint32_t timer_cmsdk_get_current_value(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + return register_map->value; +} + +void timer_cmsdk_set_reload_value(const struct timer_cmsdk_dev_t* dev, + uint32_t reload) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + register_map->reload = reload; +} + +void timer_cmsdk_reset(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + register_map->value = register_map->reload; +} + +uint32_t timer_cmsdk_get_reload_value(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + return register_map->reload; +} + +uint32_t timer_cmsdk_get_elapsed_value(const struct timer_cmsdk_dev_t* dev) +{ + struct timer_cmsdk_reg_map_t* register_map = + (struct timer_cmsdk_reg_map_t*)dev->cfg->base; + return register_map->reload - register_map->value; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_cmsdk_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_cmsdk_drv.h new file mode 100644 index 0000000..42e810b --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_cmsdk_drv.h @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2016-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file timer_cmsdk_drv.h + * \brief Generic driver for CMSDK APB Timers. + * The timer is a 32-bit down-counter with the following features: + * - optional programmable external clock source + * - programmable interrupt source, triggered if counter reaches 0 + * - automatic reload if counter reaches 0 + */ + +#ifndef __TIMER_CMSDK_DRV_H__ +#define __TIMER_CMSDK_DRV_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Maximum reload value */ +#define TIMER_CMSDK_MAX_RELOAD UINT32_MAX /* max of 32-bit */ +#define TIMER_CMSDK_DEFAULT_RELOAD TIMER_CMSDK_MAX_RELOAD + +/** CMSDK timer device configuration structure */ +struct timer_cmsdk_dev_cfg_t { + const uintptr_t base; /*!< Timer base address */ +}; + +/** CMSDK timer device data structure */ +struct timer_cmsdk_dev_data_t { + bool is_initialized; /*!< Indicates if the timer is initialized */ +}; + +/* CMSDK timer device structure */ +struct timer_cmsdk_dev_t { + const struct timer_cmsdk_dev_cfg_t* const cfg; /*!< Timer configuration */ + struct timer_cmsdk_dev_data_t* const data; /*!< Timer data */ +}; + +/** + * \brief Initializes timer to a known default state, which is: + * - timer disabled + * - timer interrupt disabled + * - clock source set to internal + * - external input disabled + * - reload value maxed out + * Init should be called prior to any other process and + * it's the caller's responsibility to follow proper call order. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_init(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Checks if a timer is initialized. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * + * \return true if initialized, false otherwise + */ +bool timer_cmsdk_is_initialized(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Enables external input, which could be used as clock source + * by calling \ref timer_cmsdk_set_clock_to_external. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_enable_external_input(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Disables external input. + * Make sure if the timer is explicitly wanted to be stopped or set + * the clock source to internal by \ref timer_cmsdk_set_clock_to_internal + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_disable_external_input(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Checks if external input is enabled. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * + * \return true if enabled, false otherwise + */ +bool timer_cmsdk_is_external_input_enabled(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Sets the clock source to internal. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_set_clock_to_internal(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Sets the clock source to external. + * Make sure external input is enabled correspondingly + * by \ref timer_cmsdk_enable_external_input. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_set_clock_to_external(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Checks if clock source is external input. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * + * \return true if external, false if internal + */ +bool timer_cmsdk_is_clock_external(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Enables timer operation. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_enable(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Disables the given hardware timer. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_disable(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Checks if a timer is enabled. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * + * \return true if enabled, false otherwise + */ +bool timer_cmsdk_is_enabled(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Enables timer interrupt. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_enable_interrupt(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Disables timer interrupt. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_disable_interrupt(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Checks if a timer interrupt is enabled. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * + * \return true if enabled, false otherwise + */ +bool timer_cmsdk_is_interrupt_enabled(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Gets timer interrupt status + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * + * * \return true if active, false otherwise + */ +bool timer_cmsdk_is_interrupt_active(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Clears timer interrupt + * The interrupt request is held until it is cleared. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_clear_interrupt(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Reads timer current value. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * + * \return Timer value + */ +uint32_t timer_cmsdk_get_current_value(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Sets the reload value of the selected timer. + * + * New reload value takes effect when: + * - timer is restarted + * - on timer underflow + * - when timer_cmsdk_reset is called + * + * \note In r1p0 technical reference manual it's incorrectly stated + * writing the reload value automatically sets the current value also. + * r1p1 technical reference manual includes the fix. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * \param[in] reload Timer reload value to set. + * This is the start value of the 32-bit down counter, + * which automatically reloaded if 0 is reached. + */ +void timer_cmsdk_set_reload_value(const struct timer_cmsdk_dev_t* dev, + uint32_t reload); + +/** + * \brief Resets the timer counter to the reload value instantly + * (i.e. without waiting for underflow). + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + */ +void timer_cmsdk_reset(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Gets the reload value of the selected timer. + * This is the start value of the 32-bit down counter, + * which is automatically reloaded if 0 is reached by the counter. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * + * \return Reload value of the selected timer. + */ +uint32_t timer_cmsdk_get_reload_value(const struct timer_cmsdk_dev_t* dev); + +/** + * \brief Reads the number of ticks elapsed in the current cycle. + * + * \param[in] dev Timer configuration \ref timer_cmsdk_dev_t + * + * \return Get elapsed number of ticks since last reload was set. + * Elapsed = (Reload value - Current value) + */ +uint32_t timer_cmsdk_get_elapsed_value(const struct timer_cmsdk_dev_t* dev); + +#ifdef __cplusplus +} +#endif +#endif /* __TIMER_CMSDK_DRV_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_gp_drv.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_gp_drv.c new file mode 100644 index 0000000..d686828 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_gp_drv.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2018 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file timer_gp_drv.c + * + * \brief Generic driver for general purpose timer. + */ + +#include "timer_gp_drv.h" + +/** Setter bit manipulation macro */ +#define SET_BIT(WORD, BIT_INDEX) ((WORD) |= (1U << (BIT_INDEX))) +/** Clearing bit manipulation macro */ +#define CLR_BIT(WORD, BIT_INDEX) ((WORD) &= ~(1U << (BIT_INDEX))) +/** Getter bit manipulation macro */ +#define GET_BIT(WORD, BIT_INDEX) (bool)(((WORD) & (1U << (BIT_INDEX)))) + +/** + * \brief Timer register map structure + * + */ +struct timer_gp_reg_map_t { + volatile uint32_t reset; /*!< Offset: 0x000 (R/W) Control Reset */ + volatile uint32_t irq_mask; /*!< Offset: 0x004 (R/W) Masked Interrupt */ + volatile uint32_t irq_clear; /*!< Offset: 0x008 (R/W) Interrupt Clear */ + volatile uint32_t reserved; /*!< Offset: 0x00C Reserved */ + volatile uint32_t alarm0; /*!< Offset: 0x010 (R/W) Alarm0 data value */ + volatile uint32_t alarm1; /*!< Offset: 0x014 (R/W) Alarm1 data value */ + volatile uint32_t irq_status; /*!< Offset: 0x018 (R) Raw Interrupt status */ + volatile uint32_t counter; /*!< Offset: 0x01C (R) Counter data value */ +}; + +/** + * \brief Reset control register bit identifiers + * + */ +enum reset_reg_bits_t{ + RESET_REG_INDEX = 0 + /* 1-31: Reserved. Read as zero. Do No Modify (DNM). */ +}; + +void timer_gp_init(const struct timer_gp_dev_t* dev) +{ + if (dev->data->is_initialized == false) { + timer_gp_interrupt_disable(dev, TIMER_GP_ALARM_0); + timer_gp_interrupt_clear(dev, TIMER_GP_ALARM_0); + timer_gp_interrupt_disable(dev, TIMER_GP_ALARM_1); + timer_gp_interrupt_clear(dev, TIMER_GP_ALARM_1); + timer_gp_set_alarm_value(dev, TIMER_GP_ALARM_0, dev->data->alarm0_init); + timer_gp_set_alarm_value(dev, TIMER_GP_ALARM_1, dev->data->alarm1_init); + timer_gp_counter_reset(dev); + dev->data->is_initialized = true; + } +} + +void timer_gp_counter_reset(const struct timer_gp_dev_t* dev) +{ + struct timer_gp_reg_map_t* const register_map = + (struct timer_gp_reg_map_t*)dev->cfg->base; + + SET_BIT(register_map->reset, RESET_REG_INDEX); + /* Reset bit is not self-clearing and some pulse width is required + * for successful reset, so we have to check whether the + * timer counter is set to reset value. Until this bit is asserted + * the timer won't be started. + * The timer is running only if the reset bit is cleared.*/ + while (timer_gp_get_counter(dev) != TIMER_GP_DEFAULT_RESET) + ; + CLR_BIT(register_map->reset, RESET_REG_INDEX); +} + +uint32_t timer_gp_get_counter(const struct timer_gp_dev_t* dev) +{ + struct timer_gp_reg_map_t* const register_map = + (struct timer_gp_reg_map_t*)dev->cfg->base; + return register_map->counter; +} + +void timer_gp_interrupt_enable(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm) +{ + struct timer_gp_reg_map_t* const register_map = + (struct timer_gp_reg_map_t*)dev->cfg->base; + SET_BIT(register_map->irq_mask, alarm); +} + +void timer_gp_interrupt_disable(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm) +{ + struct timer_gp_reg_map_t* const register_map = + (struct timer_gp_reg_map_t*)dev->cfg->base; + CLR_BIT(register_map->irq_mask, alarm); +} + +bool timer_gp_interrupt_is_enabled(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm) +{ + struct timer_gp_reg_map_t* const register_map = + (struct timer_gp_reg_map_t*)dev->cfg->base; + return GET_BIT(register_map->irq_mask, alarm); +} + +bool timer_gp_interrupt_is_active(const struct timer_gp_dev_t* dev, + const enum timer_gp_read_alarm_identifier_t alarm) +{ + struct timer_gp_reg_map_t* const register_map = + (struct timer_gp_reg_map_t*)dev->cfg->base; + return GET_BIT(register_map->irq_status, alarm); +} + +void timer_gp_interrupt_clear(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm) +{ + struct timer_gp_reg_map_t* const register_map = + (struct timer_gp_reg_map_t*)dev->cfg->base; + enum timer_gp_read_alarm_identifier_t read_alarm = + ((alarm == TIMER_GP_ALARM_0) ? + (TIMER_GP_READ_ALARM_0) : + (TIMER_GP_READ_ALARM_1)); + + SET_BIT(register_map->irq_clear, alarm); + + /* Clear bit is not self-clearing and some pulse width is required + * for successful interrupt clear, so we have to check whether the + * interrupt is cleared. */ + while(timer_gp_interrupt_is_active(dev, read_alarm)) + ; + CLR_BIT(register_map->irq_clear, alarm); +} + +void timer_gp_set_alarm_value(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm, + const uint32_t value) +{ + struct timer_gp_reg_map_t* const register_map = + (struct timer_gp_reg_map_t*)dev->cfg->base; + if (alarm == TIMER_GP_ALARM_0) { + register_map->alarm0 = value; + } else { + register_map->alarm1 = value; + } +} + +uint32_t timer_gp_get_alarm_value(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm) +{ + struct timer_gp_reg_map_t* const register_map = + (struct timer_gp_reg_map_t*)dev->cfg->base; + if (alarm == TIMER_GP_ALARM_0) { + return register_map->alarm0; + } else { + return register_map->alarm1; + } +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_gp_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_gp_drv.h new file mode 100644 index 0000000..73fa559 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/timer_gp_drv.h @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2018 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file timer_gp_drv.h + * + * \brief Generic driver for general purpose timer. + * + * \details + * The free running counter is a 32 bit size counter that counts + * up to 0xFFFFFFFF. + * At this maximum value it wraps around to 0x00000000 and continues + * incrementing. + * Software can reset the counter to default 1 by calling + * \ref timer_gp_counter_reset. + * The counter implements two compare interrupts. When the counter + * reaches compare value "alarm0" or "alarm1" value it can trigger a + * corresponding interrupt. + */ + +#ifndef __TIMER_GP_DRV_H__ +#define __TIMER_GP_DRV_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define TIMER_GP_MAX_VALUE UINT32_MAX /*!< max of 32-bit */ +#define TIMER_GP_DEFAULT_RESET 1U +/*!< Counter's reset value will be set at HW level if reset bit is asserted */ + +/** GP timer device structure */ +struct timer_gp_dev_cfg_t { + const uintptr_t base; /*!< Timer base address */ +}; + +/** GP timer device data structure */ +struct timer_gp_dev_data_t { + bool is_initialized; + uint32_t alarm0_init; /*!< Alarm0 value will be set by init */ + uint32_t alarm1_init; /*!< Alarm1 value will be set by init */ +}; + +/** GP timer device structure */ +struct timer_gp_dev_t { + const struct timer_gp_dev_cfg_t* const cfg; /*!< Timer configuration */ + struct timer_gp_dev_data_t* const data; /*!< Timer data */ +}; + +/** + * \brief GP Timer alarm number identifiers + * + */ +enum timer_gp_alarm_identifier_t{ + TIMER_GP_ALARM_0 = 0, + TIMER_GP_ALARM_1 = 1 +}; + +/** + * \brief GP Timer read alarm number identifiers + * + */ +enum timer_gp_read_alarm_identifier_t{ + TIMER_GP_READ_ALARM_0 = 0, + TIMER_GP_READ_ALARM_1 = 1, + TIMER_GP_READ_ALARM_COMBINED = 2 + /*!< Combined is asserted if Alarm1 OR Alarm2 is asserted */ +}; + +/** + * \brief Initializes timer to a known default state, which is: + * - interrupts disabled + * - alarm0 and alarm1 set to init value in \ref timer_gp_dev_data_t + * - timer reset to default reset value \ref TIMER_GP_DEFAULT_RESET + * Init should be called prior to any other process and + * it's the caller's responsibility to follow proper call order. + * More than one call results fall through. + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + */ +void timer_gp_init(const struct timer_gp_dev_t* dev); + +/** + * \brief Resets the timer counter to 1. + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + */ +void timer_gp_counter_reset(const struct timer_gp_dev_t* dev); + +/** + * \brief Read the 32bit free runnning counter's current value + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + * + * \return 32bit counter current value + */ +uint32_t timer_gp_get_counter(const struct timer_gp_dev_t* dev); + +/** + * \brief Enable alarm interrupt of the given source + * Note: This function is not interrupt safe. + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + * \param[in] alarm Alarm source of the interrupt + * \ref timer_gp_alarm_identifier_t + * + */ +void timer_gp_interrupt_enable(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm); + +/** + * \brief Disable alarm interrupt of the given source + * Note: This function is not interrupt safe. + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + * \param[in] alarm Alarm source of the interrupt + * \ref timer_gp_alarm_identifier_t + * + */ +void timer_gp_interrupt_disable(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm); + +/** + * \brief Get alarm interrupt enabled status of the given source + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + * \param[in] alarm Alarm source of the interrupt + * \ref timer_gp_alarm_identifier_t + * + * \return true if enabled, false if not + */ +bool timer_gp_interrupt_is_enabled(const struct timer_gp_dev_t* dev, + const enum + timer_gp_alarm_identifier_t alarm); + +/** + * \brief Get alarm interrupt pending status of the given source + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + * \param[in] alarm Alarm source of the interrupt + * \ref timer_gp_read_alarm_identifier_t + * + * \return true if active, false if not + */ +bool timer_gp_interrupt_is_active(const struct timer_gp_dev_t* dev, + const enum timer_gp_read_alarm_identifier_t alarm); + +/** + * \brief Clear alarm interrupt of the given source + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + * \param[in] alarm Alarm source of the interrupt + * \ref timer_gp_alarm_identifier_t + * + */ +void timer_gp_interrupt_clear(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm); + +/** + * \brief Set alarm value of the given source + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + * \param[in] alarm Alarm source \ref timer_gp_alarm_identifier_t + * \param[in] value When the counter reaches this tick value + * corresponding interrupt status will be asserted. + */ +void timer_gp_set_alarm_value(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm, + const uint32_t value); + +/** + * \brief Get alarm value of the given source + * + * \param[in] dev Timer device struct \ref timer_gp_dev_t + * \param[in] alarm Alarm source \ref timer_gp_alarm_identifier_t + * + * \return value Counter value when the alarm is asserted. + */ +uint32_t timer_gp_get_alarm_value(const struct timer_gp_dev_t* dev, + const enum timer_gp_alarm_identifier_t alarm); + +#ifdef __cplusplus +} +#endif +#endif /* __TIMER_GP_DRV_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.c new file mode 100644 index 0000000..557f256 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2016-2019 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "uart_pl011_drv.h" + +#include +#include "cmsis_compiler.h" + +#define FREQ_IRLPBAUD16_MIN (1420000u) /* 1.42 MHz */ +#define FREQ_IRLPBAUD16_MAX (2120000u) /* 2.12 MHz */ +#define SAMPLING_FACTOR (16u) +#define UART_PL011_FBRD_WIDTH (6u) + +/** + * \brief UART PL011 register map structure + */ +struct _uart_pl011_reg_map_t { + volatile uint32_t uartdr; /*!< Offset: 0x000 (R/W) Data register */ + union { + volatile uint32_t uartrsr; + /*!< Offset: 0x004 (R/ ) Receive status register */ + volatile uint32_t uartecr; + /*!< Offset: 0x004 ( /W) Error clear register */ + }; + volatile uint32_t reserved_0[4]; /*!< Offset: 0x008-0x014 Reserved */ + volatile uint32_t uartfr; /*!< Offset: 0x018 (R/ ) Flag register */ + volatile uint32_t reserved_1; /*!< Offset: 0x01C Reserved */ + volatile uint32_t uartilpr; + /*!< Offset: 0x020 (R/W) IrDA low-power counter register */ + volatile uint32_t uartibrd; + /*!< Offset: 0x024 (R/W) Integer baud rate register */ + volatile uint32_t uartfbrd; + /*!< Offset: 0x028 (R/W) Fractional baud rate register */ + volatile uint32_t uartlcr_h; + /*!< Offset: 0x02C (R/W) Line control register */ + volatile uint32_t uartcr; + /*!< Offset: 0x030 (R/W) Control register */ + volatile uint32_t uartifls; + /*!< Offset: 0x034 (R/W) Interrupt FIFO level select register */ + volatile uint32_t uartimsc; + /*!< Offset: 0x038 (R/W) Interrupt mask set/clear register */ + volatile uint32_t uartris; + /*!< Offset: 0x03C (R/ ) Raw interrupt status register */ + volatile uint32_t uartmis; + /*!< Offset: 0x040 (R/ ) Masked interrupt status register */ + volatile uint32_t uarticr; + /*!< Offset: 0x044 ( /W) Interrupt clear register */ + volatile uint32_t uartdmacr; + /*!< Offset: 0x048 (R/W) DMA control register */ + volatile uint32_t reserved_2[13]; /*!< Offset: 0x04C-0x07C Reserved */ + volatile uint32_t reserved_3[4]; + /*!< Offset: 0x080-0x08C Reserved for test purposes */ + volatile uint32_t reserved_4[976]; /*!< Offset: 0x090-0xFCC Reserved */ + volatile uint32_t reserved_5[4]; + /*!< Offset: 0xFD0-0xFDC Reserved for future ID expansion */ + volatile uint32_t uartperiphid0; + /*!< Offset: 0xFE0 (R/ ) UARTPeriphID0 register */ + volatile uint32_t uartperiphid1; + /*!< Offset: 0xFE4 (R/ ) UARTPeriphID1 register */ + volatile uint32_t uartperiphid2; + /*!< Offset: 0xFE8 (R/ ) UARTPeriphID2 register */ + volatile uint32_t uartperiphid3; + /*!< Offset: 0xFEC (R/ ) UARTPeriphID3 register */ + volatile uint32_t uartpcellid0; + /*!< Offset: 0xFF0 (R/ ) UARTPCellID0 register */ + volatile uint32_t uartpcellid1; + /*!< Offset: 0xFF4 (R/ ) UARTPCellID1 register */ + volatile uint32_t uartpcellid2; + /*!< Offset: 0xFF8 (R/ ) UARTPCellID2 register */ + volatile uint32_t uartpcellid3; + /*!< Offset: 0xFFC (R/ ) UARTPCellID3 register */ +}; + +#define UART_PL011_UARTFR_CTS_MASK ( \ + 0x1u<uartcr |= UART_PL011_UARTCR_EN_MASK; +} + +static void _uart_pl011_disable(struct _uart_pl011_reg_map_t* p_uart) +{ + p_uart->uartcr &= ~UART_PL011_UARTCR_EN_MASK; +} + +static bool _uart_pl011_is_enabled(struct _uart_pl011_reg_map_t* p_uart) +{ + return (bool)(p_uart->uartcr & UART_PL011_UARTCR_EN_MASK); +} + +static void _uart_pl011_enable_fifo(struct _uart_pl011_reg_map_t* p_uart) +{ + p_uart->uartlcr_h |= UART_PL011_UARTLCR_H_FEN_MASK; +} + +static void _uart_pl011_disable_fifo(struct _uart_pl011_reg_map_t* p_uart) +{ + p_uart->uartlcr_h &= ~UART_PL011_UARTLCR_H_FEN_MASK; +} + +static bool _uart_pl011_is_fifo_enabled(struct _uart_pl011_reg_map_t* p_uart) +{ + return (bool)(p_uart->uartlcr_h & UART_PL011_UARTLCR_H_FEN_MASK); +} + +static bool _uart_pl011_is_busy(struct _uart_pl011_reg_map_t* p_uart) +{ + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_BUSYBIT); +} + +static enum uart_pl011_error_t _uart_pl011_set_baudrate( + struct _uart_pl011_reg_map_t* p_uart, + uint32_t clk, uint32_t baudrate) +{ + /* Avoiding float calculations, bauddiv is left shifted by 6 */ + uint64_t bauddiv = (((uint64_t)clk)<= 16 x baud_rate (max) + * uart_clk (max) <= 16 x 65535 x baud_rate (min) + */ + if((bauddiv < (1u< (65535u<uartibrd = (uint32_t)(bauddiv >> UART_PL011_FBRD_WIDTH); + p_uart->uartfbrd = (uint32_t)(bauddiv & + ((1u << UART_PL011_FBRD_WIDTH) - 1u)); + + __DMB(); + + /* In order to internally update the contents of uartibrd or uartfbrd, a + * uartlcr_h write must always be performed at the end + * ARM DDI 0183F, Pg 3-13 + */ + p_uart->uartlcr_h = p_uart->uartlcr_h; + + return UART_PL011_ERR_NONE; +} + +static void _uart_pl011_set_format(struct _uart_pl011_reg_map_t* p_uart, + enum uart_pl011_wlen_t word_len, + enum uart_pl011_parity_t parity, + enum uart_pl011_stopbit_t stop_bits) +{ + uint32_t ctrl_reg = p_uart->uartlcr_h & ~(UART_PL011_FORMAT_MASK); + + /* Making sure other bit are not changed */ + word_len &= UART_PL011_UARTLCR_H_WLEN_MASK; + parity &= UART_PL011_UARTLCR_H_PARITY_MASK; + stop_bits &= UART_PL011_UARTLCR_H_STOPBIT_MASK; + + p_uart->uartlcr_h = ctrl_reg | word_len | parity | stop_bits; + +} + +static void _uart_pl011_set_cr_bit(struct _uart_pl011_reg_map_t* p_uart, + uint32_t mask) +{ + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + bool fifo_enabled = _uart_pl011_is_fifo_enabled(p_uart); + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + /* Flush the transmit FIFO by disabling bit 4 (FEN) in + * the line control register (UARTCLR_H) */ + _uart_pl011_disable_fifo(p_uart); + + p_uart->uartcr |= (mask); + + /* Enabling the FIFOs if previously enabled */ + if(fifo_enabled) { + _uart_pl011_enable_fifo(p_uart); + } + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } +} + +static void _uart_pl011_clear_cr_bit(struct _uart_pl011_reg_map_t* p_uart, + uint32_t mask) +{ + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + bool fifo_enabled = _uart_pl011_is_fifo_enabled(p_uart); + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + /* Flush the transmit FIFO by disabling bit 4 (FEN) in + * the line control register (UARTCLR_H) */ + _uart_pl011_disable_fifo(p_uart); + + p_uart->uartcr &= ~(mask); + + /* Enabling the FIFOs if previously enabled */ + if(fifo_enabled) { + _uart_pl011_enable_fifo(p_uart); + } + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } +} + +static void _uart_pl011_set_lcr_h_bit(struct _uart_pl011_reg_map_t* p_uart, + uint32_t mask) +{ + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + p_uart->uartlcr_h |= (mask); + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } +} + +static void _uart_pl011_clear_lcr_h_bit(struct _uart_pl011_reg_map_t* p_uart, + uint32_t mask) +{ + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + p_uart->uartlcr_h &= ~(mask); + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } +} + +static void _uart_pl011_reset_regs(struct _uart_pl011_reg_map_t* p_uart) +{ + /* Restore the default value of UART registers, the registers which + * are not listed below are Read-Only */ + + /* Will disable the UART */ + p_uart->uartcr = UART_PL011_CR_REG_RESET_VALUE; + p_uart->uartdr = UART_PL011_DATA_REG_RESET_VALUE; + /* Clear all the errors */ + p_uart->uartecr = UART_PL011_ECR_REG_CLEAR_VALUE; + p_uart->uartilpr = UART_PL011_ILPR_REG_RESET_VALUE; + p_uart->uartibrd = UART_PL011_IBRD_REG_RESET_VALUE; + p_uart->uartfbrd = UART_PL011_FBRD_REG_RESET_VALUE; + p_uart->uartlcr_h = UART_PL011_LCR_H_REG_RESET_VALUE; + p_uart->uartifls = UART_PL011_IFLS_REG_RESET_VALUE; + p_uart->uartimsc = UART_PL011_IMSC_REG_RESET_VALUE; + /* Clear all the interrupts */ + p_uart->uarticr = UART_PL011_ICR_REG_CLEAR_VALUE; + p_uart->uartdmacr = UART_PL011_DMACR_REG_RESET_VALUE; +} + +enum uart_pl011_error_t uart_pl011_init(struct uart_pl011_dev_t* dev, + uint32_t uart_clk) +{ + enum uart_pl011_error_t err; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + uint32_t def_baud = dev->cfg->def_baudrate; + + if(uart_clk == 0) { + return UART_PL011_ERR_INVALID_ARG; + } + + if(def_baud == 0) { + return UART_PL011_ERR_INVALID_BAUD; + } + + /* Updating the system clock */ + dev->data->uart_clk = uart_clk; + + /* Setting the default baudrate */ + err = _uart_pl011_set_baudrate(p_uart, uart_clk, def_baud); + + if(err != UART_PL011_ERR_NONE) { + return err; + } + + /* Setting the default character format */ + _uart_pl011_set_format(p_uart, dev->cfg->def_wlen, + dev->cfg->def_parity, + dev->cfg->def_stopbit); + + /* Enabling the FIFOs */ + _uart_pl011_enable_fifo(p_uart); + + dev->data->state = UART_PL011_INITIALIZED; + + return UART_PL011_ERR_NONE; +} + +void uart_pl011_uninit(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + while(_uart_pl011_is_busy(p_uart)); + + /* Disable and restore the default configuration of the peripheral */ + _uart_pl011_reset_regs(p_uart); + + dev->data->state = UART_PL011_UNINITIALIZED; + + return; +} + +enum uart_pl011_state_t uart_pl011_get_state(struct uart_pl011_dev_t* dev) +{ + return dev->data->state; +} + +enum uart_pl011_error_t uart_pl011_set_baudrate( + struct uart_pl011_dev_t* dev, uint32_t baudrate) +{ + enum uart_pl011_error_t err = UART_PL011_ERR_NONE; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + + if(uart_pl011_get_state(dev) != UART_PL011_INITIALIZED) { + return UART_PL011_ERR_NOT_INIT; + } + + if(baudrate == 0) { + return UART_PL011_ERR_INVALID_BAUD; + } + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + /* If baudrate is not valid ie UART_PL011_ERR_NONE is not returned then + * the UART will continue to function at the old baudrate */ + err = _uart_pl011_set_baudrate(p_uart, dev->data->uart_clk, baudrate); + + if(err == UART_PL011_ERR_NONE) { + dev->data->baudrate = baudrate; + } + + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } + + return err; +} + +uint32_t uart_pl011_get_baudrate(struct uart_pl011_dev_t* dev) +{ + return dev->data->baudrate; +} + +void uart_pl011_enable_intr(struct uart_pl011_dev_t* dev, + enum uart_pl011_intr_t mask) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + p_uart->uartimsc |= (uint32_t)(mask); + + return; +} + +void uart_pl011_disable_intr(struct uart_pl011_dev_t* dev, + enum uart_pl011_intr_t mask) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + p_uart->uartimsc &= (uint32_t)(~mask); + + return; +} + +void uart_pl011_clear_intr(struct uart_pl011_dev_t* dev, + enum uart_pl011_intr_t mask) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + p_uart->uarticr = (uint32_t)mask; + + return; +} + + +enum uart_pl011_intr_t uart_pl011_get_masked_intr_status( + struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + return (enum uart_pl011_intr_t)(p_uart->uartmis); + +} + +enum uart_pl011_intr_t uart_pl011_get_raw_intr_status( + struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + return (enum uart_pl011_intr_t)(p_uart->uartris); +} + +void uart_pl011_set_rx_fifo_lvl(struct uart_pl011_dev_t* dev, + enum uart_pl011_rx_fifo_lvl_t rx_lvl) +{ + uint32_t fifo_lvl; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + /* Check if rx_lvl have valid values */ + rx_lvl &= UART_PL011_UARTIFLS_RX_FIFO_LVL_MASK; + + fifo_lvl = p_uart->uartifls + & ~(UART_PL011_UARTIFLS_RX_FIFO_LVL_MASK); + p_uart->uartifls = fifo_lvl | rx_lvl; + + return; +} + +void uart_pl011_set_tx_fifo_lvl(struct uart_pl011_dev_t* dev, + enum uart_pl011_tx_fifo_lvl_t tx_lvl) +{ + uint32_t fifo_lvl; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + /* Check if tx_lvl have valid values */ + tx_lvl &= UART_PL011_UARTIFLS_TX_FIFO_LVL_MASK; + + fifo_lvl = p_uart->uartifls + & ~(UART_PL011_UARTIFLS_TX_FIFO_LVL_MASK); + p_uart->uartifls = fifo_lvl | tx_lvl; + + return; +} + +void uart_pl011_set_tx_dma(struct uart_pl011_dev_t* dev, + enum uart_pl011_tx_dma_t enable) +{ + uint32_t dma_cr; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + enable &= UART_PL011_UARTDMACR_TX_MASK; + + dma_cr = p_uart->uartdmacr + & ~(UART_PL011_UARTDMACR_TX_MASK); + + p_uart->uartdmacr = dma_cr | enable; + + return; +} + +void uart_pl011_set_rx_dma(struct uart_pl011_dev_t* dev, + enum uart_pl011_rx_dma_t enable) +{ + uint32_t dma_cr; + + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + enable &= UART_PL011_UARTDMACR_RX_MASK; + + dma_cr = p_uart->uartdmacr + & ~(UART_PL011_UARTDMACR_RX_MASK); + + p_uart->uartdmacr = dma_cr | enable; + + return; +} + +bool uart_pl011_is_readable(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + if( (uart_pl011_get_state(dev) == UART_PL011_INITIALIZED) && + /* UART is initialized */ + (p_uart->uartcr & UART_PL011_UARTCR_EN_MASK) && + /* UART is enabled */ + (p_uart->uartcr & UART_PL011_UARTCR_RX_EN_MASK) && + /* Receive is enabled */ + ((p_uart->uartfr & UART_PL011_UARTFR_RX_FIFO_EMPTY) == 0)) { + /* Receive Fifo is not empty */ + return true; + } + + return false; + +} + +enum uart_pl011_error_t uart_pl011_read( + struct uart_pl011_dev_t* dev, uint8_t* byte) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + *byte = p_uart->uartdr; + + return (enum uart_pl011_error_t)(p_uart->uartrsr + & UART_PL011_RX_ERR_MASK); +} + +bool uart_pl011_is_writable(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + if( (uart_pl011_get_state(dev) == UART_PL011_INITIALIZED) && + /* UART is initialized */ + (p_uart->uartcr & UART_PL011_UARTCR_EN_MASK) && + /* UART is enabled */ + (p_uart->uartcr & UART_PL011_UARTCR_TX_EN_MASK) && + /* Transmit is enabled */ + ((p_uart->uartfr & UART_PL011_UARTFR_TX_FIFO_FULL) == 0)) { + /* Transmit Fifo is not full */ + return true; + } + return false; + +} + +void uart_pl011_write(struct uart_pl011_dev_t* dev, uint8_t byte) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + p_uart->uartdr = byte; + + return; +} + +enum uart_pl011_error_t uart_pl011_set_format(struct uart_pl011_dev_t* dev, + enum uart_pl011_wlen_t word_len, + enum uart_pl011_parity_t parity, + enum uart_pl011_stopbit_t stop_bits) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + bool uart_enabled = _uart_pl011_is_enabled(p_uart); + + if(uart_pl011_get_state(dev) != UART_PL011_INITIALIZED) { + return UART_PL011_ERR_NOT_INIT; + } + + /* UART must be disabled before any Control Register or + * Line Control Register are reprogrammed */ + _uart_pl011_disable(p_uart); + + _uart_pl011_set_format(p_uart, word_len, parity, stop_bits); + + /* Enabling the UART if previously enabled */ + if(uart_enabled) { + _uart_pl011_enable(p_uart); + } + + return UART_PL011_ERR_NONE; +} + +void uart_pl011_enable_fifo(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_FEN_MASK); + + return; +} + +void uart_pl011_disable_fifo(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_FEN_MASK); + + return; +} + +void uart_pl011_enable_break(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_BRK_MASK); + + return; +} + +void uart_pl011_disable_break(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_lcr_h_bit(p_uart, UART_PL011_UARTLCR_H_BRK_MASK); + + return; +} + +void uart_pl011_enable_cts_flowcontrol(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_CTSE_MASK); + + return; +} + +void uart_pl011_disable_cts_flowcontrol(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_CTSE_MASK); + + return; +} + +void uart_pl011_enable_rts_flowcontrol(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_RTSE_MASK); + + return; +} + +void uart_pl011_disable_rts_flowcontrol(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_RTSE_MASK); + + return; +} + +void uart_pl011_enable_ri(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_OUT2_MASK); + + return; +} + +void uart_pl011_disable_ri(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_OUT2_MASK); + + return; +} + +void uart_pl011_enable_dcd(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_OUT1_MASK); + + return; +} + +void uart_pl011_disable_dcd(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_OUT1_MASK); + + return; +} + +void uart_pl011_set_rts(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_RTS_MASK); + + return; +} + +void uart_pl011_clear_rts(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_RTS_MASK); + + return; +} + +void uart_pl011_set_dtr(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_DTR_MASK); + + return; +} + +void uart_pl011_clear_dtr(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_DTR_MASK); + + return; +} + +void uart_pl011_enable_receive(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_RX_EN_MASK); + + return; +} + +void uart_pl011_disable_receive(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_RX_EN_MASK); + + return; +} + +void uart_pl011_enable_transmit(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_TX_EN_MASK); + + return; +} + +void uart_pl011_disable_transmit(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_TX_EN_MASK); + + return; +} + +void uart_pl011_set_loopback(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_LBE_MASK); + + return; +} + +void uart_pl011_clear_loopback(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_LBE_MASK); + + return; +} + +void uart_pl011_enable_sirlp(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, + UART_PL011_UARTCR_SIREN_MASK | UART_PL011_UARTCR_SIRLP_MASK); + + return; +} + +void uart_pl011_disable_sirlp(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, + UART_PL011_UARTCR_SIREN_MASK | UART_PL011_UARTCR_SIRLP_MASK); + + return; +} + +void uart_pl011_enable_sir(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_set_cr_bit(p_uart, UART_PL011_UARTCR_SIREN_MASK); + + return; +} + +void uart_pl011_disable_sir(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_clear_cr_bit(p_uart, UART_PL011_UARTCR_SIREN_MASK); + + return; +} + +void uart_pl011_enable(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_enable(p_uart); + + return; +} + +void uart_pl011_disable(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + _uart_pl011_disable(p_uart); + + return; +} + +bool uart_pl011_get_cts_status(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_CTS_MASK); + +} + +bool uart_pl011_get_dsr_status(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_DSR_MASK); + +} + +bool uart_pl011_get_dcd_status(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_DCD_MASK); + +} + +bool uart_pl011_get_ri_status(struct uart_pl011_dev_t* dev) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + return (bool)(p_uart->uartfr & UART_PL011_UARTFR_RI_MASK); + +} + +enum uart_pl011_error_t uart_pl011_set_sirlp_divisor( + struct uart_pl011_dev_t* dev, uint32_t value) +{ + struct _uart_pl011_reg_map_t* p_uart = + (struct _uart_pl011_reg_map_t*)dev->cfg->base; + + uint32_t irlp_baud16_clk; + + if(uart_pl011_get_state(dev) != UART_PL011_INITIALIZED) { + return UART_PL011_ERR_NOT_INIT; + } + + if(value == 0) { + return UART_PL011_ERR_INVALID_ARG; + } + + irlp_baud16_clk = dev->data->uart_clk/value; + + /* Chose the divisor so that 1.42MHz < FIrLPBaud16 < 2.12MHz, that + * results in a low-power pulse duration of 1.41–2.11μs (three times + * the period of IrLPBaud16). ARM DDI0183F Pg 3-9 */ + if(irlp_baud16_clk < FREQ_IRLPBAUD16_MIN || + irlp_baud16_clk > FREQ_IRLPBAUD16_MAX) { + return UART_PL011_ERR_INVALID_ARG; + } + + p_uart->uartilpr = value; + + return UART_PL011_ERR_NONE; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.h new file mode 100644 index 0000000..1cf5b62 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.h @@ -0,0 +1,854 @@ +/* + * Copyright (c) 2016-2018 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * \file uart_pl011_drv.h + * \brief Driver for ARM UART PL011. + */ + +#ifndef __UART_PL011_DRV_H__ +#define __UART_PL011_DRV_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief ARM UART PL011 state types + */ +enum uart_pl011_state_t { + UART_PL011_UNINITIALIZED = 0x0u, + UART_PL011_INITIALIZED = 0x1u, +}; + +#define UART_PL011_UARTRSR_FE_ERR_OFF 0x0u + /*!< Receive Status Register Frame Error bit field offset */ +#define UART_PL011_UARTRSR_PE_ERR_OFF 0x1u + /*!< Receive Status Register Parity Error bit field offset */ +#define UART_PL011_UARTRSR_BE_ERR_OFF 0x2u + /*!< Receive Status Register Break Error bit field offset */ +#define UART_PL011_UARTRSR_OE_ERR_OFF 0x3u + /*!< Receive Status Register Overrun Error bit field offset */ + +#define UART_PL011_RX_ERR_MASK ( \ + 0x1u< +#include "platform_base_address.h" + +/* sysinfo memory mapped register access structure */ +struct sysinfo_t { + volatile uint32_t sysversion; /* (R/ ) 0x000 System version */ + volatile uint32_t sysconfig; /* (R/ ) 0x004 System configuration */ + volatile uint32_t reserved0[1010]; /* 0x010-0xFCC Reserved */ + volatile uint32_t pidr4; /* (R/ ) 0xFD0 Peripheral ID 4 */ + volatile uint32_t reserved1[3]; /* 0xFD4-0xFDC Reserved */ + volatile uint32_t pidr0; /* (R/ ) 0xFE0 Peripheral ID 0 */ + volatile uint32_t pidr1; /* (R/ ) 0xFE4 Peripheral ID 1 */ + volatile uint32_t pidr2; /* (R/ ) 0xFE8 Peripheral ID 2 */ + volatile uint32_t pidr3; /* (R/ ) 0xFEC Peripheral ID 3 */ + volatile uint32_t cidr0; /* (R/ ) 0xFF0 Component ID 0 */ + volatile uint32_t cidr1; /* (R/ ) 0xFF4 Component ID 1 */ + volatile uint32_t cidr2; /* (R/ ) 0xFF8 Component ID 2 */ + volatile uint32_t cidr3; /* (R/ ) 0xFFC Component ID 3 */ +}; + +/* Secure System Control (SYSCTRL) Alias */ +#define CMSDK_SYSCTRL_BASE_S MUSCA_S1_SYSTEM_CTRL_S_BASE + +/* sysctrl memory mapped register access structure */ +struct sysctrl_t { + /* (R/ ) 0x000 Secure Debug Configuration Status Register*/ + volatile uint32_t secdbgstat; + /* ( /W) 0x004 Secure Debug Configuration Set Register */ + volatile uint32_t secdbgset; + /* ( /W) 0x008 Secure Debug Configuration Clear Register */ + volatile uint32_t secdbgclr; + /* (R/W) 0x00C System Control Security Control Register */ + volatile uint32_t scsecctrl; + /* (R/W) 0x010 Fast Clock Divider Configuration Register */ + volatile uint32_t fclk_div; + /* (R/W) 0x014 System Clock Divider Configuration Register */ + volatile uint32_t sysclk_div; + /* (R/W) 0x018 Clock Forces */ + volatile uint32_t clockforce; + /* 0x01C-0x0FC Reserved */ + volatile uint32_t reserved0[57]; + /* (R/W) 0x100 Reset syndrome */ + volatile uint32_t resetsyndrome; + /* (R/W) 0x104 Reset MASK */ + volatile uint32_t resetmask; + /* ( /W) 0x108 Software Reset */ + volatile uint32_t swreset; + /* (R/W) 0x10C General Purpose Retention Register */ + volatile uint32_t gretreg; + /* (R/W) 0x110 Initial Secure Reset Vector Register For CPU 0 */ + volatile uint32_t initsvtor0; + /* (R/W) 0x114 Initial Secure Reset Vector Register For CPU 1*/ + volatile uint32_t initsvtor1; + /* (R/W) 0x118 CPU Boot wait control after reset */ + volatile uint32_t cpuwait; + /* (R/W) 0x11C NMI Enable */ + volatile uint32_t nmi_enable; + /* (R/W) 0x120 CPU WIC Request and Acknowledgement */ + volatile uint32_t wicctrl; + /* (R/W) 0x124 External Wakeup Control */ + volatile uint32_t ewctrl; + /* 0x128-0x1FC Reserved */ + volatile uint32_t reserved2[54]; + /* (R/W) 0x200 Power Control Dependency Matrix + * PD_SYS Power Domain Sensitivity.*/ + volatile uint32_t pdcm_pd_sys_sense; + /* 0x204-0x208 Reserved */ + volatile uint32_t reserved3[2]; + /* (R/W) 0x20C Power Control Dependency Matrix + * PD_SRAM0 Power Domain Sensitivity.*/ + volatile uint32_t pdcm_pd_sram0_sense; + /* (R/W) 0x210 Power Control Dependency Matrix + * PD_SRAM1 Power Domain Sensitivity.*/ + volatile uint32_t pdcm_pd_sram1_sense; + /* 0x214(R/W) Power Control Dependency Matrix + * PD_SRAM2 Power Domain Sensitivity.*/ + volatile uint32_t pdcm_pd_sram2_sense; + /* (R/W) 0x218 Power Control Dependency Matrix + * PD_SRAM3 Power Domain Sensitivity.*/ + volatile uint32_t pdcm_pd_sram3_sense; + /* 0x21C-0xFCC Reserved */ + volatile uint32_t reserved4[877]; + /* (R/ ) 0xFD0 Peripheral ID 4 */ + volatile uint32_t pidr4; + /* 0xFD4-0xFDC Reserved */ + volatile uint32_t reserved5[3]; + /* (R/ ) 0xFE0 Peripheral ID 0 */ + volatile uint32_t pidr0; + /* (R/ ) 0xFE4 Peripheral ID 1 */ + volatile uint32_t pidr1; + /* (R/ ) 0xFE8 Peripheral ID 2 */ + volatile uint32_t pidr2; + /* (R/ ) 0xFEC Peripheral ID 3 */ + volatile uint32_t pidr3; + /* (R/ ) 0xFF0 Component ID 0 */ + volatile uint32_t cidr0; + /* (R/ ) 0xFF4 Component ID 1 */ + volatile uint32_t cidr1; + /* (R/ ) 0xFF8 Component ID 2 */ + volatile uint32_t cidr2; + /* (R/ ) 0xFFC Component ID 3 */ + volatile uint32_t cidr3; +}; + +/* Secure Privilege Control */ +#define CMSDK_SPCTRL ((struct spctrl_def*)MUSCA_S1_SPCTRL_S_BASE) + +/* SPCTRL memory mapped register access structure */ +struct spctrl_def { + /* (R/W) 0x000 Secure Configuration Control Register */ + volatile uint32_t spcsecctrl; + /* (R/W) 0x004 Bus Access wait control after reset.*/ + volatile uint32_t buswait; + /* 0x008-0x00C Reserved */ + volatile uint32_t reserved1[2]; + /* (R/W) 0x010Security Violation Response Configuration register.*/ + volatile uint32_t secrespcfg; + /* (R/W) 0x014 Non Secure Callable Configuration for IDAU. */ + volatile uint32_t nsccfg; + /* 0x018 Reserved */ + volatile uint32_t reserved2; + /* (R/W) 0x01C Secure MPC Interrupt Status. */ + volatile uint32_t secmpcintstat; + /* (R/W) 0x020 Secure PPC Interrupt Status. */ + volatile uint32_t secppcintstat; + /* (R/W) 0x024 Secure PPC Interrupt Clear. */ + volatile uint32_t secppcintclr; + /* (R/W) 0x28 Secure PPC Interrupt Enable. */ + volatile uint32_t secppcinten; + /* 0x02C-0x03C Reserved */ + volatile uint32_t reserved3[5]; + /* (R/W) 0x040 Bridge Buffer Error Interrupt Status. */ + volatile uint32_t brgintstat; + /* (R/W) 0x044 Bridge Buffer Error Interrupt Clear. */ + volatile uint32_t brgintclr; + /* (R/W) 0x048 Bridge Buffer Error Interrupt Enable. */ + volatile uint32_t brginten; + /* 0x04C-0x05C Reserved */ + volatile uint32_t reserved4[5]; + /* (R/W) 0x060 Expansion 0 Non_Secure Access + * AHB slave Peripheral Protection Control */ + volatile uint32_t ahbnsppcexp0; + /* 0x064-0x06C Reserved */ + volatile uint32_t reserved5[3]; + /* (R/W) 0x070 Non-Secure Access + * APB slave Peripheral Protection Control #0 */ + volatile uint32_t apbnsppc0; + /* (R/W) 0x074 Non-Secure Access + * APB slave Peripheral Protection Control #1 */ + volatile uint32_t apbnsppc1; + /* 0x078-0x07C Reserved */ + volatile uint32_t reserved6[2]; + /* (R/W) 0x080 Expansion 0 Non_Secure Access + * APB slave Peripheral Protection Control */ + volatile uint32_t apbnsppcexp0; + /* (R/W) 0x084 Expansion 1 Non_Secure Access + * APB slave Peripheral Protection Control */ + volatile uint32_t apbnsppcexp1; + /* 0x088-0x08C Reserved */ + volatile uint32_t reserved7[2]; + /* (R/W) 0x090 Secure Unprivileged Access + * AHB slave Peripheral Protection Control #0. */ + volatile uint32_t ahbspppc0; + /* 0x094-0x09C Reserved */ + volatile uint32_t reserved8[3]; + /* (R/W) 0x0A0 Expansion 0 Secure Unprivileged Access + * AHB slave Peripheral Protection Control. */ + volatile uint32_t ahbspppcexp0; + /* 0x0A4-0x0AC Reserved */ + volatile uint32_t reserved9[3]; + /* (R/W) 0x0B0 Secure Unprivileged Access + * APB slave Peripheral Protection Control #0 */ + volatile uint32_t apbspppc0; + /* (R/W) 0x0B4 Secure Unprivileged Access + * APB slave Peripheral Protection Control #1 */ + volatile uint32_t apbspppc1; + /* 0x0B8-0x0BC Reserved */ + volatile uint32_t reserved10[2]; + /* (R/W) 0x0C0 Expansion 0 Secure Unprivileged Access + * APB slave Peripheral Protection Control */ + volatile uint32_t apbspppcexp0; + /* (R/W) 0x0C4 Expansion 1 Secure Unprivileged Access + * APB slave Peripheral Protection Control */ + volatile uint32_t apbspppcexp1; + /* 0x0C8-0xFCC Reserved */ + volatile uint32_t reserved11[962]; + /* (R/W) 0xFD0 Peripheral ID 4 */ + volatile uint32_t pid4; + /* 0xFD4-0xFDC Reserved */ + volatile uint32_t reserved12[3]; + /* (R/W) 0xFE0 Peripheral ID 0 */ + volatile uint32_t pid0; + /* (R/W) 0xFE4 Peripheral ID 1 */ + volatile uint32_t pid1; + /* (R/W) 0xFE8 Peripheral ID 2 */ + volatile uint32_t pid2; + /* (R/W) 0xFEC Peripheral ID 3 */ + volatile uint32_t pid3; + /* (R/W) 0xFF0 Component ID 0 */ + volatile uint32_t cid0; + /* (R/W) 0xFF4 Component ID 1 */ + volatile uint32_t cid1; + /* (R/W) 0xFF8 Component ID 2 */ + volatile uint32_t cid2; + /* (R/W) 0xFFC Component ID 3 */ + volatile uint32_t cid3; +}; + +/* Secure PPC interrupt position mask */ +#define CMSDK_APB_PPC0_INT_POS_MASK (1UL << 0) +#define CMSDK_APB_PPC1_INT_POS_MASK (1UL << 1) +#define CMSDK_APB_PPCEXP0_INT_POS_MASK (1UL << 4) +#define CMSDK_APB_PPCEXP1_INT_POS_MASK (1UL << 5) +#define CMSDK_APB_PPCEXP2_INT_POS_MASK (1UL << 6) +#define CMSDK_APB_PPCEXP3_INT_POS_MASK (1UL << 7) +#define CMSDK_AHB_PPCEXP0_INT_POS_MASK (1UL << 20) +#define CMSDK_AHB_PPCEXP1_INT_POS_MASK (1UL << 21) +#define CMSDK_AHB_PPCEXP2_INT_POS_MASK (1UL << 22) +#define CMSDK_AHB_PPCEXP3_INT_POS_MASK (1UL << 23) + +/* Non-Secure Privilege Control */ +#define CMSDK_NSPCTRL ((struct nspctrl_def*)MUSCA_S1_NSPCTRL_NS_BASE) + +/* NSPCTRL memory mapped register access structure */ +struct nspctrl_def { + /* 0x000-0x09C Reserved */ + volatile uint32_t reserved1[40]; + /* (R/W) 0x0A0 Expansion 0 Non-Secure Unprivileged Access + * AHB slave Peripheral Protection Control */ + volatile uint32_t ahbnspppcexp0; + /* 0x0A4-0x0AC Reserved */ + volatile uint32_t reserved2[3]; + /* (R/W) 0x0B0 Non-Secure Unprivileged Access + * APB slave Peripheral Protection Control #0 */ + volatile uint32_t apbnspppc0; + /* (R/W) 0x0B4 Non-Secure Unprivileged Access + * APB slave Peripheral Protection Control #1 */ + volatile uint32_t apbnspppc1; + /* 0x0B8-0x0BC Reserved */ + volatile uint32_t reserved3[2]; + /* (R/W) 0x0C0 Expansion 0 Non-Secure Unprivileged Access + * APB slave Peripheral Protection Control */ + volatile uint32_t apbnspppcexp0; + /* (R/W) 0x0C4 Expansion 1 Non-Secure Unprivileged Access + * APB slave Peripheral Protection Control */ + volatile uint32_t apbnspppcexp1; + /* 0x0C8-0xFCC Reserved */ + volatile uint32_t reserved4[962]; + /* (R/W) 0xFD0 Peripheral ID 4 */ + volatile uint32_t pidr4; + /* 0xFD4-0xFDC Reserved */ + volatile uint32_t reserved5[3]; + /* (R/W) 0xFE0 Peripheral ID 0 */ + volatile uint32_t pidr0; + /* (R/W) 0xFE4 Peripheral ID 1 */ + volatile uint32_t pidr1; + /* (R/W) 0xFE8 Peripheral ID 2 */ + volatile uint32_t pidr2; + /* (R/W) 0xFEC Peripheral ID 3 */ + volatile uint32_t pidr3; + /* (R/W) 0xFF0 Component ID 0 */ + volatile uint32_t cidr0; + /* (R/W) 0xFF4 Component ID 1 */ + volatile uint32_t cidr1; + /* (R/W) 0xFF8 Component ID 2 */ + volatile uint32_t cidr2; + /* (R/W) 0xFFC Component ID 3 */ + volatile uint32_t cidr3; +}; + +/* ARM APB PPC0 peripherals definition */ +#define CMSDK_TIMER0_APB_PPC_POS 0U +#define CMSDK_TIMER1_APB_PPC_POS 1U +#define CMSDK_DTIMER_APB_PPC_POS 2U +#define CMSDK_MHU0_APB_PPC_POS 3U +#define CMSDK_MHU1_APB_PPC_POS 4U +/* The bits 31:5 are reserved */ + +/* ARM APB PPC1 peripherals definition */ +#define CMSDK_S32K_TIMER_PPC_POS 0U +/* The bits 31:1 are reserved */ + +/* ARM AHB PPC0 peripherals definition */ +/* The bits 31:0 are reserved */ + +/* ARM AHB PPCEXP0 peripherals definition */ +#define MUSCA_S1_GPIO_AHB_PPC_POS 1U +/* The bits 31:1 are reserved */ + +/* ARM AHB PPCEXP1 peripherals definition */ +/* The bits 31:0 are reserved */ + +/* ARM AHB PPCEXP2 peripherals definition */ +/* The bits 31:0 are reserved */ + +/* ARM AHB PPCEXP3 peripherals definition */ +/* The bits 31:0 are reserved */ + +/* ARM APB PPCEXP0 peripherals definition */ +#define MUSCA_S1_QSPI_MPC_APB_PPC_POS 0U +#define MUSCA_S1_SRAM_MPC_APB_PPC_POS 1U +#define MUSCA_S1_MRAM_MPC_APB_PPC_POS 2U + +/* ARM APB PPCEXP1 peripherals definition */ +#define MUSCA_S1_UART0_APB_PPC_POS 0U +#define MUSCA_S1_UART1_APB_PPC_POS 1U +#define MUSCA_S1_SPI_APB_PPC_POS 2U +#define MUSCA_S1_I2C0_APB_PPC_POS 3U +#define MUSCA_S1_I2C1_APB_PPC_POS 4U +#define MUSCA_S1_I2S_APB_PPC_POS 5U +#define MUSCA_S1_PWM0_APB_PPC_POS 6U +#define MUSCA_S1_RTC_APB_PPC_POS 7U +#define MUSCA_S1_PVT_APB_PPC_POS 8U +#define MUSCA_S1_QSPI_APB_PPC_POS 9U +#define MUSCA_S1_GPTIMER_APB_PPC_POS 10U +#define MUSCA_S1_SCC_APB_PPC_POS 11U +#define MUSCA_S1_PWM1_APB_PPC_POS 12U +#define MUSCA_S1_PWM2_APB_PPC_POS 13U + +#endif /* __MUSCA_S1_PLATFORM_REGS__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/system_core_init.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/system_core_init.c new file mode 100644 index 0000000..f0bd971 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/system_core_init.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is derivative of CMSIS V5.01 \Device\ARM\ARMCM33\Source\system_ARMCM33.c + * https://github.com/ARM-software/CMSIS_5/tree/5.0.1 + * Git SHA: 8a1d9d6ee18b143ae5befefa14d89fb5b3f99c75 + */ + +#include +#include "system_core_init.h" +#include "platform_description.h" + +/*---------------------------------------------------------------------------- + Define clocks + *----------------------------------------------------------------------------*/ +#define XTAL (50000000UL) +#define SYSTEM_CLOCK (XTAL) +#define SYSTEM_REFCLK (32768UL) + +/*---------------------------------------------------------------------------- + Externals + *----------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------- + System Core Clock Variable + *----------------------------------------------------------------------------*/ +uint32_t SystemCoreClock = SYSTEM_CLOCK; +uint32_t PeripheralClock = SYSTEM_CLOCK; +uint32_t RefClock = SYSTEM_REFCLK; + +/*---------------------------------------------------------------------------- + System Core Clock update function + *----------------------------------------------------------------------------*/ +void SystemCoreClockUpdate (void) +{ + SystemCoreClock = SYSTEM_CLOCK; + PeripheralClock = SYSTEM_CLOCK; + RefClock = SYSTEM_REFCLK; +} + +/*---------------------------------------------------------------------------- + System initialization function + *----------------------------------------------------------------------------*/ +void SystemInit (void) +{ +#if defined (__VTOR_PRESENT) && (__VTOR_PRESENT == 1U) + extern uint32_t __Vectors; + SCB->VTOR = (uint32_t) &__Vectors; +#endif + +#if defined (__FPU_USED) && (__FPU_USED == 1U) + SCB->CPACR |= ((3U << 10U*2U) | /* set CP10 Full Access */ + (3U << 11U*2U) ); /* set CP11 Full Access */ +#endif + +#ifdef UNALIGNED_SUPPORT_DISABLE + SCB->CCR |= SCB_CCR_UNALIGN_TRP_Msk; +#endif + + SystemCoreClock = SYSTEM_CLOCK; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/system_core_init.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/system_core_init.h new file mode 100644 index 0000000..7778024 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/system_core_init.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017-2019 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is derivative of CMSIS V5.01 \Device\ARM\ARMCM33\Include\system_ARMCM33.h + * Git SHA: 8a1d9d6ee18b143ae5befefa14d89fb5b3f99c75 + * + */ + +#ifndef __SYSTEM_CORE_INIT_H__ +#define __SYSTEM_CORE_INIT_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ +extern uint32_t PeripheralClock; /*!< Peripheral Clock Frequency */ +extern uint32_t RefClock; /*!< External Reference Clock Frequency */ + +/** + \brief Setup the microcontroller system. + + Initialize the System and update the SystemCoreClock variable. + It should be called from Reset Handler within the first few steps. + The minimal feature set should be initialised for successful exit + from Reset Handler to main entry point. + */ +extern void SystemInit (void); + + +/** + \brief Update SystemCoreClock variable. + + Updates the SystemCoreClock with current core Clock retrieved from cpu registers. + */ +extern void SystemCoreClockUpdate (void); + +#ifdef __cplusplus +} +#endif + +#endif /* __SYSTEM_CORE_INIT_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/flash_api_qspi.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/flash_api_qspi.c new file mode 100644 index 0000000..1ce1ccb --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/flash_api_qspi.c @@ -0,0 +1,136 @@ +/* mbed Microcontroller Library + * Copyright (c) 2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "device.h" +#include "flash_layout.h" +#include "flash_api.h" + +#if DEVICE_FLASH + +int32_t flash_init(flash_t *obj) +{ + (void)(obj); + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + qspi_ip6514e_enable(FLASH_DEV.controller); + + /* Configure QSPI Flash controller to operate in single SPI mode and + * to use fast Flash commands */ + err = mt25ql_config_mode(&FLASH_DEV, MT25QL_FUNC_STATE_FAST); + if (err != MT25QL_ERR_NONE) { + return -1; + } + + return 0; +} + +int32_t flash_free(flash_t *obj) +{ + (void)(obj); + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + /* Restores the QSPI Flash controller and MT25QL to reset state */ + err = mt25ql_restore_reset_state(&FLASH_DEV); + if (err != MT25QL_ERR_NONE) { + return -1; + } + + return 0; +} + +int32_t flash_erase_sector(flash_t *obj, uint32_t address) +{ + (void)(obj); + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + address -= FLASH_DEV.direct_access_start_addr; + + err = mt25ql_erase(&FLASH_DEV, address, MT25QL_ERASE_SUBSECTOR_4K); + if (err != MT25QL_ERR_NONE) { + return -1; + } + + return 0; +} + +int32_t flash_read(flash_t *obj, uint32_t address, + uint8_t *data, uint32_t size) +{ + (void)obj; + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + address -= FLASH_DEV.direct_access_start_addr; + + err = mt25ql_command_read(&FLASH_DEV, address, data, size); + if (err != MT25QL_ERR_NONE) { + return -1; + } + + return 0; +} + +int32_t flash_program_page(flash_t *obj, uint32_t address, const uint8_t *data, uint32_t size) +{ + (void)(obj); + enum mt25ql_error_t err = MT25QL_ERR_NONE; + + address -= FLASH_DEV.direct_access_start_addr; + + err = mt25ql_command_write(&FLASH_DEV, address, data, size); + if (err != MT25QL_ERR_NONE) { + return -1; + } + + return 0; +} + +uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address) +{ + (void)(obj); + if ((address >= NS_QSPI_ALIAS_BASE) && (address < NS_QSPI_ALIAS_BASE + QSPI_FLASH_TOTAL_SIZE)) { + return SUBSECTOR_4KB; + } + + return MBED_FLASH_INVALID_SIZE; +} + +uint32_t flash_get_page_size(const flash_t *obj) +{ + (void)(obj); + return FLASH_PAGE_SIZE; +} + +uint32_t flash_get_start_address(const flash_t *obj) +{ + (void)(obj); + return NS_QSPI_ALIAS_BASE; +} + +uint32_t flash_get_size(const flash_t *obj) +{ + (void)(obj); + return QSPI_FLASH_TOTAL_SIZE; +} + +uint8_t flash_get_erase_value(const flash_t *obj) +{ + (void)obj; + return 0xFF; +} + +#endif // DEVICE_FLASH diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/gpio_api_ns.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/gpio_api_ns.c new file mode 100644 index 0000000..aa09bc1 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/gpio_api_ns.c @@ -0,0 +1,141 @@ +/* mbed Microcontroller Library + * Copyright (c) 2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file implements APIS defined in hal/gpio_api.h + * Note: Due to a HW limitation, GPIO in Musca-S1 is Secure only, so secure + * service should be used for GPIO in NS domain. + */ + +#include +#include "gpio_api.h" +#include "pinmap.h" +#include "objects.h" +#include "mbed_error.h" +#include "mbed_assert.h" +#include "rtx_lib.h" +#include "tfm_platform_api.h" +#include "tfm_ioctl_api.h" + +#define RETURN_VOID_true return; +#define RETURN_VOID_false return 0; + +#define IRQ_MODE_CHECK(is_func_void) \ + /* Secure service can't be called in interrupt context. */ \ + if (IsIrqMode()) { \ + MBED_WARNING(MBED_MAKE_ERROR(MBED_MODULE_HAL, \ + MBED_ERROR_INVALID_OPERATION), \ + "GPIO secure service can't be called in interrupt context\n"); \ + RETURN_VOID_ ## is_func_void \ + } + + +uint32_t gpio_set(PinName pin) +{ + pin_function(pin, (int)PRIMARY_FUNC); + + /* Return the correct mask of the given PIN */ + return (1 << GPIO_PIN_NUMBER(pin)); + +} + +void gpio_init(gpio_t *obj, PinName pin) +{ + obj->pin_num = (uint32_t)NC; + uint32_t result = 0; + enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SUCCESS; + + if (pin >= PA0 && pin <= PA15) { + IRQ_MODE_CHECK(true); + ret = tfm_platform_gpio_init(&result); + if (ret || result) { + return; + } + + obj->pin_num = pin; + /* GPIO is input by default */ + obj->direction = PIN_INPUT; + return; + } +} + +void gpio_mode(gpio_t *obj, PinMode mode) +{ + pin_mode(obj->pin_num, mode); + +} + +void gpio_dir(gpio_t *obj, PinDirection direction) +{ + uint32_t pin_dir = (direction == PIN_INPUT ? 0 : 1); + uint32_t result = 0; + enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SUCCESS; + + IRQ_MODE_CHECK(true); + + ret = tfm_platform_gpio_pin_config(obj->pin_num, pin_dir, &result); + if (ret || result) { + error("gpio_dir failed, error %d, gpio error %d", ret, result); + } + obj->direction = direction; +} + + +int gpio_is_connected(const gpio_t *obj) +{ + if (obj->pin_num == (uint32_t)NC) { + return 0; + } else { + return 1; + } + +} + +void gpio_write(gpio_t *obj, int value) +{ + enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SUCCESS; + uint32_t result = 0; + + IRQ_MODE_CHECK(true); + + ret = tfm_platform_gpio_pin_write(obj->pin_num, (uint32_t)value, &result); + + if (ret || result) { + error("Can not write pin %d; error %d, gpio error %d", + obj->pin_num, ret, result); + } + +} + +int gpio_read(gpio_t *obj) +{ + enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SUCCESS; + uint32_t result = 0; + uint32_t data = 0; + + IRQ_MODE_CHECK(false); + + ret = tfm_platform_gpio_pin_read(obj->pin_num, &data, &result); + + /* The valid return values of this API are 0 and 1 */ + if (ret || result) { + return 0; + } else { + return data; + } +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/gpio_irq_api.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/gpio_irq_api.c new file mode 100644 index 0000000..9d98f8d --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/gpio_irq_api.c @@ -0,0 +1,71 @@ +/* mbed Microcontroller Library + * Copyright (c) 2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file implements APIS defined in hal/gpio_irq_api.h + * Note: Due to a HW limitation, GPIO in Musca-S1 is Secure only, in NS domain, + * GPIO platform service is used. The current implementation of GPIO + * platform service does not support IRQ handling. + */ + +#include +#include "gpio_irq_api.h" +#include "objects.h" +#include "mbed_error.h" + +int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, + uint32_t id) +{ + /* Due to a HW limitation, GPIO in Musca-S1 is Secure only, in NS domain, + * GPIO platform service is used. The current implementation of GPIO + * platform service does not support IRQ handling. + */ + return 0; +} + +void gpio_irq_free(gpio_irq_t *obj) +{ + /* Due to a HW limitation, GPIO in Musca-S1 is Secure only, in NS domain, + * GPIO platform service is used. The current implementation of GPIO + * platform service does not support IRQ handling. + */ +} + +void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) +{ + /* Due to a HW limitation, GPIO in Musca-S1 is Secure only, in NS domain, + * GPIO platform service is used. The current implementation of GPIO + * platform service does not support IRQ handling. + */ +} + +void gpio_irq_enable(gpio_irq_t *obj) +{ + /* Due to a HW limitation, GPIO in Musca-S1 is Secure only, in NS domain, + * GPIO platform service is used. The current implementation of GPIO + * platform service does not support IRQ handling. + */ +} + +void gpio_irq_disable(gpio_irq_t *obj) +{ + /* Due to a HW limitation, GPIO in Musca-S1 is Secure only, in NS domain, + * GPIO platform service is used. The current implementation of GPIO + * platform service does not support IRQ handling. + */ +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/gpio_object.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/gpio_object.h new file mode 100644 index 0000000..bfbc072 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/gpio_object.h @@ -0,0 +1,51 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_GPIO_OBJECT_H +#define MBED_GPIO_OBJECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define GPIO_PIN_NUMBER(pin) ((pin) & 0xF) + +#define PINS_NUMBER (16) + +/** + * \brief Object to store GPIO specific data through the configuration + */ +typedef struct gpio_s { + struct gpio_cmsdk_dev_t *gpio_dev; + uint32_t pin_num; + PinDirection direction; +} gpio_t; + + +struct gpio_irq_s { + /** GPIO is not available in Musca-S1 in non-secure domain, so this dummy + * structure is needed for successful build. + */ + uint32_t dummy; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/i2c_api.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/i2c_api.c new file mode 100644 index 0000000..a811eb0 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/i2c_api.c @@ -0,0 +1,427 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "i2c_api.h" +#include "mbed_error.h" +#include "i2c_ip6510_drv.h" +#include "objects.h" +#include "pinmap.h" +#include "PeripheralNames.h" + +/* Return error codes for the i2c_byte_write api */ +#define BYTE_TRANSFER_ERR_NACK (0) +#define BYTE_TRANSFER_ERR_NONE (1) +#define BYTE_TRANSFER_ERR_TIMEOUT (2) + +/* Macros for frequency configuration */ +#define I2C_SPEED_100KHZ (100000) +#define I2C_SPEED_400KHZ (400000) + +#if DEVICE_I2CSLAVE +/* Return values for slave addressing specified in mbed I2C slave driver */ +#define I2C_SLAVE_READ_ADDRESS (1) +#define I2C_SLAVE_WRITE_ALL_ADDRESS (2) +#define I2C_SLAVE_WRITE_ADDRESS (3) +#define I2C_SLAVE_NOT_ADDRESSED (0) +#endif + +extern const PinMap PinMap_I2C_SDA[]; +extern const PinMap PinMap_I2C_SCL[]; + +/* Extend the return values defined in i2c_api.h */ +enum { + I2C_ERROR_NONE = 0, + /* I2C_ERROR_NO_SLAVE = -1, + * I2C_ERROR_BUS_BUSY = -2, */ + I2C_ERROR_GENERAL = -3 +}; + +void i2c_init(i2c_t *obj, PinName sda, PinName scl) +{ + enum i2c_ip6510_error_t ret; + + /* Determine the I2C to use */ + I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA); + I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL); + I2CName i2c = (I2CName)pinmap_merge(i2c_sda, i2c_scl); + if (i2c == (I2CName)NC) { + error("I2C pinout mapping failed, invalid pins."); + return; + } + + /* Initialize the parent object */ + switch (i2c) { +#ifdef I2C0_IP6510_DEV + case I2C_0: + obj->dev = &I2C0_IP6510_DEV; + break; +#endif +#ifdef I2C1_IP6510_DEV + case I2C_1: + obj->dev = &I2C1_IP6510_DEV; + break; +#endif + default: + error("Failed to initialize I2C, bad reference."); + return; + } + obj->last_address = 0U; + obj->sda = sda; + obj->scl = scl; + obj->byte_state = BYTE_TRANSFER_STATE_NONE; + + /* If already init, uninit */ + if (i2c_ip6510_get_state(obj->dev) == I2C_IP6510_INITIALIZED) { + i2c_ip6510_uninit(obj->dev); + } + + /* Set the GPIO pins */ + pinmap_pinout(sda, PinMap_I2C_SDA); + pinmap_pinout(scl, PinMap_I2C_SCL); + + /* Initialize peripheral */ + ret = i2c_ip6510_init(obj->dev, SystemCoreClock); + i2c_ip6510_set_speed(obj->dev, I2C_IP6510_SPEED_100KHZ); + i2c_ip6510_set_timeout(obj->dev, 0xFFU); + + if (ret != I2C_IP6510_ERR_NONE) { + error("Failed to initialize I2C, error occured in native driver."); + return; + } +} + +void i2c_frequency(i2c_t *obj, int hz) +{ + /* The peripheral only supports 100k and 400k clock in master mode */ + switch (hz) { + case I2C_SPEED_100KHZ: + i2c_ip6510_set_speed(obj->dev, I2C_IP6510_SPEED_100KHZ); + break; + + case I2C_SPEED_400KHZ: + i2c_ip6510_set_speed(obj->dev, I2C_IP6510_SPEED_400KHZ); + break; + + default: + error("Invalid I2C frequency."); + return; + } +} + +void i2c_reset(i2c_t *obj) +{ + i2c_ip6510_uninit(obj->dev); + i2c_init(obj, obj->sda, obj->scl); +} + +int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) +{ + enum i2c_ip6510_error_t ret; + + /* Shifted 8 bit address is used in upper layer */ + address = ((uint32_t)address)>>1; + + ret = i2c_ip6510_master_read(obj->dev, (uint16_t)address, (uint8_t*)data, + stop, (uint32_t*)(&length)); + + if (ret != I2C_IP6510_ERR_NONE) { + return I2C_ERROR_GENERAL; + } + + return length; +} + +int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) +{ + enum i2c_ip6510_error_t ret; + + /* Shifted 8 bit address is used in upper layer */ + address = ((uint32_t)address)>>1; + + /* Parameter checking */ + if (data == NULL || length == 0) { + ret = i2c_ip6510_monitor_slave(obj->dev, (uint16_t)address); + if (ret != I2C_IP6510_ERR_NONE) { + return I2C_ERROR_NO_SLAVE; + } + return length; + } + + ret = i2c_ip6510_master_write(obj->dev, (uint16_t)address, (uint8_t*)data, + stop, (uint32_t*)(&length)); + + if (ret != I2C_IP6510_ERR_NONE) { + return I2C_ERROR_GENERAL; + } + return length; +} + +int i2c_start(i2c_t *obj) +{ + /** \note The peripheral does not support building up the transaction by + * instructions. The functionality is achieved with a software + * state machine. + * The i2c transaction is started later, when the address and the + * first data byte is written. + */ + obj->byte_state = BYTE_TRANSFER_STATE_START; + obj->last_address = 0U; + i2c_ip6510_hold_enable(obj->dev); + + return I2C_ERROR_NONE; +} + +int i2c_stop(i2c_t *obj) +{ + /* Both the master and slave api calls this function */ + if (i2c_ip6510_get_device_mode(obj->dev) == I2C_IP6510_MASTER_MODE) { + + /** \note The peripheral does not support building up the transaction by + * instructions. The functionality is achieved with a software + * state machine. + * STOP condition is generated on hold disable. + */ + i2c_ip6510_hold_disable(obj->dev); + + /* If there was only one byte written (the slave address) before calling + * stop, the state machine is in ADDRESS state. Writing just the address + * is equal to a slave monitoring + */ + if (obj->byte_state == BYTE_TRANSFER_STATE_ADDRESS) { + /* Return value is not needed because signalling to the caller is + * not defined + */ + (void)i2c_ip6510_monitor_slave(obj->dev, obj->last_address); + } + + obj->byte_state = BYTE_TRANSFER_STATE_NONE; + obj->last_address = 0U; + + } else { + /* In slave mode the the I2C controller only writes and reads data from + * the I2C bus. The function just clears the interrupts for + * further adressing detection. + */ + i2c_ip6510_clear_irq(obj->dev, I2C_IP6510_ALL_INTR_MASK); + } + return I2C_ERROR_NONE; +} + +int i2c_byte_read(i2c_t *obj, int last) +{ + uint8_t read_byte = 0U; + uint32_t slave_read_cntr = 1U; + + /* Both the master and slave api calls this function */ + if (i2c_ip6510_get_device_mode(obj->dev) == I2C_IP6510_MASTER_MODE) { + + /** \note The peripheral does not support building up the transaction by + * instructions. The functionality is achieved with a software + * state machine. + */ + switch (obj->byte_state) { + case BYTE_TRANSFER_STATE_ADDRESS: + obj->byte_state = BYTE_TRANSFER_STATE_DATA; + i2c_ip6510_master_byte_read( + obj->dev, obj->last_address, last, true, &read_byte); + return read_byte; + + case BYTE_TRANSFER_STATE_DATA: + i2c_ip6510_master_byte_read( + obj->dev, obj->last_address, last, false, &read_byte); + return read_byte; + + case BYTE_TRANSFER_STATE_NONE: + case BYTE_TRANSFER_STATE_START: + default: + /* Reading is invalid in these states */ + return I2C_ERROR_GENERAL; + } + } else { + /* In slave mode the driver only writes and reads data from the + * I2C controller, no need to track states. + */ + i2c_ip6510_slave_read( + obj->dev, &read_byte, &slave_read_cntr); + return read_byte; + } +} + +int i2c_byte_write(i2c_t *obj, int data) +{ + enum i2c_ip6510_error_t ret = I2C_IP6510_ERR_NONE; + uint32_t slave_write_cntr = 1U; + + /* Both the master and slave api calls this function */ + if (i2c_ip6510_get_device_mode(obj->dev) == I2C_IP6510_MASTER_MODE) { + + /** \note The peripheral does not support building up the transaction by + * instructions. The functionality is achieved with a software + * state machine. + */ + switch (obj->byte_state) { + case BYTE_TRANSFER_STATE_NONE: + /* Writing is invalid before start symbol + * BYTE_TRANSFER_ERR_TIMEOUT is the only error code mbed defines, + * this is the only way to signal an error + */ + return BYTE_TRANSFER_ERR_TIMEOUT; + + case BYTE_TRANSFER_STATE_START: + obj->byte_state = BYTE_TRANSFER_STATE_ADDRESS; + obj->last_address = ((uint32_t)data)>>1; + return BYTE_TRANSFER_ERR_NONE; + + case BYTE_TRANSFER_STATE_ADDRESS: + obj->byte_state = BYTE_TRANSFER_STATE_DATA; + ret = i2c_ip6510_master_byte_write( + obj->dev, obj->last_address, (uint8_t*)&data, true); + break; + + case BYTE_TRANSFER_STATE_DATA: + ret = i2c_ip6510_master_byte_write( + obj->dev, obj->last_address, (uint8_t*)&data, false); + break; + + default: + return BYTE_TRANSFER_ERR_TIMEOUT; + } + } else { + /* In slave mode the driver only writes and reads data from the + * I2C controller, no need to track states. + */ + ret = i2c_ip6510_slave_write( + obj->dev, (uint8_t*)&data, &slave_write_cntr); + } + + if (ret != I2C_IP6510_ERR_NONE) { + /* No need to reset the state machine. The host might try to resend + * the data byte. Also the start and stop functions reset the states. + */ + if (ret == I2C_IP6510_ERR_NACK) { + return BYTE_TRANSFER_ERR_NACK; + } + return BYTE_TRANSFER_ERR_TIMEOUT; + } + return BYTE_TRANSFER_ERR_NONE; +} + +#if DEVICE_I2CSLAVE + +void i2c_slave_mode(i2c_t *obj, int enable_slave) +{ + if (!enable_slave) { + /* Check if master mode is already set */ + if (i2c_ip6510_get_device_mode(obj->dev) != I2C_IP6510_MASTER_MODE) { + /* Set Master Mode */ + i2c_ip6510_set_master_mode(obj->dev); + } + } else { + /* Check if slave mode is already set */ + if (i2c_ip6510_get_device_mode(obj->dev) != I2C_IP6510_SLAVE_MODE) { + /* Set Slave Mode */ + i2c_ip6510_set_slave_mode(obj->dev, obj->last_address); + } + } +} + +int i2c_slave_receive(i2c_t *obj) +{ + uint32_t irq_status = i2c_ip6510_get_irq_status(obj->dev); + enum i2c_ip6510_transf_dir_t dir = i2c_ip6510_get_slave_tranf_dir(obj->dev); + uint32_t transfer_size = i2c_ip6510_get_transfer_size(obj->dev); + + if (irq_status & I2C_IP6510_INTR_DATA_MASK) { + + if (dir == I2C_IP6510_TRANSMITTER) { + /* Slave is adressed for writing */ + return I2C_SLAVE_WRITE_ADDRESS; + } + if ((dir == I2C_IP6510_RECEIVER) && (transfer_size != 0U)) { + /* Slave is adressed for reading */ + return I2C_SLAVE_READ_ADDRESS; + } + } + + if ((irq_status & I2C_IP6510_INTR_COMP_MASK) + && (dir == I2C_IP6510_RECEIVER) && (transfer_size != 0U)) { + /* An I2C transfer is complete with less then FIFO_SIZE-2 bytes */ + return I2C_SLAVE_READ_ADDRESS; + } + + return I2C_SLAVE_NOT_ADDRESSED; +} + +int i2c_slave_read(i2c_t *obj, char *data, int length) +{ + enum i2c_ip6510_error_t ret; + + ret = i2c_ip6510_slave_read( + obj->dev, (uint8_t*)data, (uint32_t*)&length); + i2c_ip6510_clear_irq(obj->dev, I2C_IP6510_ALL_INTR_MASK); + + if (ret != I2C_IP6510_ERR_NONE) { + return 0; + } + + return length; +} + +int i2c_slave_write(i2c_t *obj, const char *data, int length) +{ + enum i2c_ip6510_error_t ret; + + ret = i2c_ip6510_slave_write( + obj->dev, (uint8_t*)data, (uint32_t*)&length); + i2c_ip6510_clear_irq(obj->dev, I2C_IP6510_ALL_INTR_MASK); + + if (ret != I2C_IP6510_ERR_NONE) { + return 0; + } + + return length; +} + +void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) +{ + /* Shifted 8 bit address is used in upper layer */ + i2c_ip6510_set_slave_mode(obj->dev, ((uint16_t)address)>>1); + obj->last_address = address>>1; +} + +const PinMap *i2c_slave_sda_pinmap() +{ + return PinMap_I2C_SDA; +} + +const PinMap *i2c_slave_scl_pinmap() +{ + return PinMap_I2C_SCL; +} + +#endif + +const PinMap *i2c_master_sda_pinmap() +{ + return PinMap_I2C_SDA; +} + +const PinMap *i2c_master_scl_pinmap() +{ + return PinMap_I2C_SCL; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/lp_ticker.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/lp_ticker.c new file mode 100644 index 0000000..6b06f1a --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/lp_ticker.c @@ -0,0 +1,91 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Low-power elapsed time measure and interval ticker, + * using General Purpose Timer \ref timer_gp_dev_t. + */ + +#include "cmsis.h" +#include "device_cfg.h" +#include "timer_gp_drv.h" +#include "lp_ticker_api.h" + +/* Check if the module configuration is right. These definitions + are usually located in device_cfg.h */ +#ifndef GP_TIMER_DEV +#error "Configuration macro GP_TIMER_DEV is undefined!" +#endif + +void lp_ticker_init(void) +{ + timer_gp_init(&GP_TIMER_DEV); + NVIC_EnableIRQ(GP_TIMER_ALARM0_IRQ); + timer_gp_interrupt_disable(&GP_TIMER_DEV, GP_TIMER_ALARM_NR); +} + +void lp_ticker_free(void) +{ + /* This function should stop the ticker from counting, but GP Timer cannot + * be stopped. + */ + timer_gp_interrupt_disable(&GP_TIMER_DEV, GP_TIMER_ALARM_NR); +} + +uint32_t lp_ticker_read(void) +{ + return timer_gp_get_counter(&GP_TIMER_DEV); +} + +void lp_ticker_set_interrupt(timestamp_t timestamp) +{ + timer_gp_set_alarm_value(&GP_TIMER_DEV, GP_TIMER_ALARM_NR, (uint32_t)timestamp); + timer_gp_interrupt_enable(&GP_TIMER_DEV, GP_TIMER_ALARM_NR); +} + +void lp_ticker_disable_interrupt(void) +{ + timer_gp_interrupt_disable(&GP_TIMER_DEV, GP_TIMER_ALARM_NR); +} + +void lp_ticker_clear_interrupt(void) +{ + timer_gp_interrupt_clear(&GP_TIMER_DEV, GP_TIMER_ALARM_NR); +} + +void lp_ticker_fire_interrupt(void) +{ + NVIC_SetPendingIRQ(GP_TIMER_ALARM0_IRQ); +} + +const ticker_info_t* lp_ticker_get_info(void) +{ + static const ticker_info_t info = { + GP_TIMER_FREQ_HZ, + GP_TIMER_BIT_WIDTH + }; + return &info; +} + +#ifndef GP_TIMER_IRQ0_HANDLER +#error "GP_TIMER_IRQ0_HANDLER should be defined, check device_cfg.h!" +#endif +void GP_TIMER_IRQ0_HANDLER(void) +{ + lp_ticker_irq_handler(); +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/mbed_serial_platform.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/mbed_serial_platform.c new file mode 100644 index 0000000..ae49d67 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/mbed_serial_platform.c @@ -0,0 +1,139 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2019 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed_error.h" +#include "mbed_serial_platform.h" +#include "serial_api.h" + +#define UART_DEVICES_NUMBER 2 + +struct uart_irq_t uart_irq[UART_DEVICES_NUMBER]; + +const PinMap PinMap_UART_TX[] = { + {UART0_TX, UART_0, ALTERNATE_FUNC_1}, + {UART1_TX, UART_1, PRIMARY_FUNC}, + {NC, NC, 0} +}; + +const PinMap PinMap_UART_RX[] = { + {UART0_RX, UART_0, ALTERNATE_FUNC_1}, + {UART1_RX, UART_1, PRIMARY_FUNC}, + {NC, NC, 0} +}; + +const PinMap *serial_tx_pinmap() +{ + return PinMap_UART_TX; +} + +const PinMap *serial_rx_pinmap() +{ + return PinMap_UART_RX; +} + +#ifdef UART0_PL011_DEV +#ifndef uart0_tx_irq_handler +#error "uart0_tx_irq_handler should be defined, check device_cfg.h!" +#endif +void uart0_tx_irq_handler(void) +{ + uart_pl011_clear_intr(&UART0_PL011_DEV, UART_PL011_TX_INTR_MASK); + if(uart_irq[UART_0].handler != 0) { + uart_irq[UART_0].handler(uart_irq[UART_0].id, TxIrq); + } +} + +#ifndef uart0_rx_irq_handler +#error "uart0_rx_irq_handler should be defined, check device_cfg.h!" +#endif +void uart0_rx_irq_handler(void) +{ + uart_pl011_clear_intr(&UART0_PL011_DEV, UART_PL011_RX_INTR_MASK); + if(uart_irq[UART_0].handler != 0) { + uart_irq[UART_0].handler(uart_irq[UART_0].id, RxIrq); + } +} + +#ifndef uart0_rx_timeout_irq_handler +#error "uart0_rx_timeout_irq_handler should be defined, check device_cfg.h!" +#endif +void uart0_rx_timeout_irq_handler(void) +{ + if(uart_irq[UART_0].handler != 0) { + uart_irq[UART_0].handler(uart_irq[UART_0].id, RxIrq); + } +} +#endif + +#ifdef UART1_PL011_DEV +#ifndef uart1_tx_irq_handler +#error "uart1_tx_irq_handler should be defined, check device_cfg.h!" +#endif +void uart1_tx_irq_handler(void) +{ + uart_pl011_clear_intr(&UART1_PL011_DEV, UART_PL011_TX_INTR_MASK); + if(uart_irq[UART_1].handler != 0) { + uart_irq[UART_1].handler(uart_irq[UART_1].id, TxIrq); + } +} + +#ifndef uart1_rx_irq_handler +#error "uart1_rx_irq_handler should be defined, check device_cfg.h!" +#endif +void uart1_rx_irq_handler(void) +{ + uart_pl011_clear_intr(&UART1_PL011_DEV, UART_PL011_RX_INTR_MASK); + if(uart_irq[UART_1].handler != 0) { + uart_irq[UART_1].handler(uart_irq[UART_1].id, RxIrq); + } +} + +#ifndef uart1_rx_timeout_irq_handler +#error "uart1_rx_timeout_irq_handler should be defined, check device_cfg.h!" +#endif +void uart1_rx_timeout_irq_handler(void) +{ + if(uart_irq[UART_1].handler != 0) { + uart_irq[UART_1].handler(uart_irq[UART_1].id, RxIrq); + } +} +#endif + +void mbed_uart_platform_init(serial_t *obj, UARTName uart) +{ + switch (uart) { +#ifdef UART0_PL011_DEV + case UART_0: + obj->uart_dev = &UART0_PL011_DEV; + obj->tx_irq = UART0_Tx_IRQn; + obj->rx_irq = UART0_Rx_IRQn; + obj->rx_timeout_irq = UART0_RxTimeout_IRQn; + break; +#endif +#ifdef UART1_PL011_DEV + case UART_1: + obj->uart_dev = &UART1_PL011_DEV; + obj->tx_irq = UART1_Tx_IRQn; + obj->rx_irq = UART1_Rx_IRQn; + obj->rx_timeout_irq = UART1_RxTimeout_IRQn; + break; +#endif + default: + error("serial_init: No uart selected"); + } +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/mbed_serial_platform.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/mbed_serial_platform.h new file mode 100644 index 0000000..15fa825 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/mbed_serial_platform.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018-2019 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MBED_SERIAL_PLATFORM_H__ +#define __MBED_SERIAL_PLATFORM_H__ + +#include "serial_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct uart_irq_t { + uart_irq_handler handler; + uint32_t id; +}; + +/* Handlers registered */ +extern struct uart_irq_t uart_irq[]; + +void mbed_uart_platform_init(serial_t *obj, UARTName uart); + +#ifdef __cplusplus +} +#endif + +#endif /* __SERIAL_PLATFORM_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/mcuboot.bin b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/mcuboot.bin new file mode 100644 index 0000000..ed2cb0a --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/mcuboot.bin Binary files differ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/objects.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/objects.h new file mode 100644 index 0000000..f19fe1d --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/objects.h @@ -0,0 +1,76 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MBED_OBJECTS_H +#define MBED_OBJECTS_H + +#include "cmsis.h" +#include "PeripheralNames.h" +#include "PinNames.h" +#include "platform_description.h" +#include "device_definition.h" +#include "gpio_object.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +struct serial_s { + struct uart_pl011_dev_t *uart_dev; + UARTName uart_index; /* UART device number */ + IRQn_Type tx_irq; + IRQn_Type rx_irq; + IRQn_Type rx_timeout_irq; +}; + +#if DEVICE_FLASH +struct flash_s { + uint8_t dummy; +}; +#endif // DEVICE_FLASH + +#if DEVICE_TRNG +struct trng_s { + /* nothing to be stored for now */ + void *dummy; +}; +#endif // DEVICE_TRNG + +#if DEVICE_I2C || DEVICE_I2CSLAVE +enum byte_transfer_states { + BYTE_TRANSFER_STATE_NONE = 0, + BYTE_TRANSFER_STATE_START, + BYTE_TRANSFER_STATE_ADDRESS, + BYTE_TRANSFER_STATE_DATA, +}; + +struct i2c_s { + struct i2c_ip6510_dev_t *dev; + uint16_t last_address; + PinName sda; + PinName scl; + enum byte_transfer_states byte_state; +}; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/flash_layout.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/flash_layout.h new file mode 100644 index 0000000..9ebc41f --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/flash_layout.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 2018-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __FLASH_LAYOUT_H__ +#define __FLASH_LAYOUT_H__ + +/* Flash layout on Musca-S1 with BL2(multiple image boot, boot from MRAM): + * 0x0A00_0000 BL2 - MCUBoot(128 KB) + * 0x0A02_0000 Secure image primary (320 KB) + * 0x0A07_0000 Non-secure image primary (512 KB) + * 0x0A0F_0000 Secure image secondary (320 KB) + * 0x0A14_0000 Non-secure image secondary (512 KB) + * 0x0A1C_0000 Scratch Area (16 KB) + * 0x0A1C_4000 Secure Storage Area (20 KB) + * 0x0A1C_9000 Internal Trusted Storage Area (16 KB) + * 0x0A1C_D000 NV counters area (4 KB) + * 0x0A1C_E000 Unused + * + * Flash layout on Musca-S1 with BL2(single image boot): + * 0x0A00_0000 BL2 - MCUBoot(128 KB) + * 0x0A02_0000 Primary image area (896 KB): + * 0x0A02_0000 Secure image primary (384 KB) + * 0x0A08_0000 Non-secure image primary (512 KB) + * 0x0A10_0000 Secondary image area (896 KB): + * 0x0A10_0000 Secure image secondary (384 KB) + * 0x0A16_0000 Non-secure image secondary (512 KB) + * 0x0A1E_0000 Secure Storage Area (20 KB) + * 0x0A1E_5000 Internal Trusted Storage Area (16 KB) + * 0x0A1E_9000 NV counters area (4 KB) + * 0x0A1E_A000 TF-M key area (256 bytes) This area is referred to in + * /lib/ext/cryptocell-312-runtime/shared/hw/include/musca_s1/ \ + * dx_reg_base_host.h Do not change one without changing the other. + * 0x0A1E_A100 Unused + * + * Flash layout on Musca-S1 without BL2: + * 0x0A00_0000 Secure image + * 0x0A07_0000 Non-secure image + */ + +/* This header file is included from linker scatter file as well, where only a + * limited C constructs are allowed. Therefore it is not possible to include + * here the platform_base_address.h to access flash related defines. To resolve + * this some of the values are redefined here with different names, these are + * marked with comment. + */ + +/* Size of a Secure and of a Non-secure image */ +#define FLASH_S_PARTITION_SIZE (0x60000) /* S partition: 384 KB */ +#define FLASH_NS_PARTITION_SIZE (0x80000) /* NS partition: 512 KB */ +#define FLASH_MAX_PARTITION_SIZE ((FLASH_S_PARTITION_SIZE > \ + FLASH_NS_PARTITION_SIZE) ? \ + FLASH_S_PARTITION_SIZE : \ + FLASH_NS_PARTITION_SIZE) + +/* Sector size of the flash hardware */ +#define FLASH_AREA_IMAGE_SECTOR_SIZE (0x1000) /* 4KB */ +#define FLASH_TOTAL_SIZE (0x200000) /* MRAM size 2MB */ + +/* Flash layout info for BL2 bootloader */ +#define FLASH_BASE_ADDRESS (0x1A000000) /* MRAM base address */ + +/* Offset and size definitions of the flash partitions that are handled by the + * bootloader. The image swapping is done between IMAGE_PRIMARY and + * IMAGE_SECONDARY, SCRATCH is used as a temporary storage during image + * swapping. + */ +#define FLASH_AREA_BL2_OFFSET (0x0) +#define FLASH_AREA_BL2_SIZE (0x20000) /* 128KB */ + +#if !defined(MCUBOOT_IMAGE_NUMBER) || (MCUBOOT_IMAGE_NUMBER == 1) +/* Secure + Non-secure image primary slot */ +#define FLASH_AREA_0_ID (1) +#define FLASH_AREA_0_OFFSET (FLASH_AREA_BL2_OFFSET + FLASH_AREA_BL2_SIZE) +#define FLASH_AREA_0_SIZE (FLASH_S_PARTITION_SIZE + \ + FLASH_NS_PARTITION_SIZE) +/* Secure + Non-secure secondary slot */ +#define FLASH_AREA_2_ID (FLASH_AREA_0_ID + 1) +#define FLASH_AREA_2_OFFSET (FLASH_AREA_0_OFFSET + FLASH_AREA_0_SIZE) +#define FLASH_AREA_2_SIZE (FLASH_S_PARTITION_SIZE + \ + FLASH_NS_PARTITION_SIZE) + +/* Scratch area */ +#define FLASH_AREA_SCRATCH_ID (FLASH_AREA_2_ID + 1) +#define FLASH_AREA_SCRATCH_OFFSET (FLASH_AREA_2_OFFSET + FLASH_AREA_2_SIZE) +#define FLASH_AREA_SCRATCH_SIZE (4 * FLASH_AREA_IMAGE_SECTOR_SIZE) +/* The maximum number of status entries supported by the bootloader. */ +#define MCUBOOT_STATUS_MAX_ENTRIES ((FLASH_S_PARTITION_SIZE + \ + FLASH_NS_PARTITION_SIZE) / \ + FLASH_AREA_SCRATCH_SIZE) +/* Maximum number of image sectors supported by the bootloader. */ +#define MCUBOOT_MAX_IMG_SECTORS ((FLASH_S_PARTITION_SIZE + \ + FLASH_NS_PARTITION_SIZE) / \ + FLASH_AREA_IMAGE_SECTOR_SIZE) +#elif (MCUBOOT_IMAGE_NUMBER == 2) +/* Secure image primary slot */ +#define FLASH_AREA_0_ID (1) +#define FLASH_AREA_0_OFFSET (FLASH_AREA_BL2_OFFSET + FLASH_AREA_BL2_SIZE) +#define FLASH_AREA_0_SIZE (FLASH_S_PARTITION_SIZE) +/* Non-secure image primary slot */ +#define FLASH_AREA_1_ID (FLASH_AREA_0_ID + 1) +#define FLASH_AREA_1_OFFSET (FLASH_AREA_0_OFFSET + FLASH_AREA_0_SIZE) +#define FLASH_AREA_1_SIZE (FLASH_NS_PARTITION_SIZE) +/* Secure image secondary slot */ +#define FLASH_AREA_2_ID (FLASH_AREA_1_ID + 1) +#define FLASH_AREA_2_OFFSET (FLASH_AREA_1_OFFSET + FLASH_AREA_1_SIZE) +#define FLASH_AREA_2_SIZE (FLASH_S_PARTITION_SIZE) +/* Non-secure image secondary slot */ +#define FLASH_AREA_3_ID (FLASH_AREA_2_ID + 1) +#define FLASH_AREA_3_OFFSET (FLASH_AREA_2_OFFSET + FLASH_AREA_2_SIZE) +#define FLASH_AREA_3_SIZE (FLASH_NS_PARTITION_SIZE) +/* Scratch area */ +#define FLASH_AREA_SCRATCH_ID (FLASH_AREA_3_ID + 1) +#define FLASH_AREA_SCRATCH_OFFSET (FLASH_AREA_3_OFFSET + FLASH_AREA_3_SIZE) +#define FLASH_AREA_SCRATCH_SIZE (4 * FLASH_AREA_IMAGE_SECTOR_SIZE) +/* The maximum number of status entries supported by the bootloader. */ +#define MCUBOOT_STATUS_MAX_ENTRIES (FLASH_MAX_PARTITION_SIZE / \ + FLASH_AREA_SCRATCH_SIZE) +/* Maximum number of image sectors supported by the bootloader. */ +#define MCUBOOT_MAX_IMG_SECTORS (FLASH_MAX_PARTITION_SIZE / \ + FLASH_AREA_IMAGE_SECTOR_SIZE) +#else /* MCUBOOT_IMAGE_NUMBER > 2 */ +#error "Only MCUBOOT_IMAGE_NUMBER 1 and 2 are supported!" +#endif /* MCUBOOT_IMAGE_NUMBER */ + +/* Note: FLASH_SST_AREA_OFFSET, FLASH_ITS_AREA_OFFSET and + * FLASH_NV_COUNTERS_AREA_OFFSET point to offsets in flash, but reads and writes + * to these addresses are redirected to Code SRAM by Driver_Flash.c. + */ +#define FLASH_SST_AREA_OFFSET (FLASH_AREA_SCRATCH_OFFSET + \ + FLASH_AREA_SCRATCH_SIZE) +#define FLASH_SST_AREA_SIZE (0x5000) /* 20 KB */ + +/* Internal Trusted Storage (ITS) Service definitions */ +#define FLASH_ITS_AREA_OFFSET (FLASH_SST_AREA_OFFSET + \ + FLASH_SST_AREA_SIZE) +#define FLASH_ITS_AREA_SIZE (0x4000) /* 16 KB */ + +/* NV Counters definitions */ +#define FLASH_NV_COUNTERS_AREA_OFFSET (FLASH_ITS_AREA_OFFSET + \ + FLASH_ITS_AREA_SIZE) +#define FLASH_NV_COUNTERS_AREA_SIZE (FLASH_AREA_IMAGE_SECTOR_SIZE) + +/* TF-M crypto key area definitions */ +#define FLASH_TFM_CRYPTO_KEY_AREA_OFFSET (FLASH_NV_COUNTERS_AREA_OFFSET + \ + FLASH_NV_COUNTERS_AREA_SIZE) +#define FLASH_TFM_CRYPTO_KEY_AREA_SIZE (0x100) + +/* Offset and size definition in flash area used by assemble.py */ +#define SECURE_IMAGE_OFFSET (0x0) +#define SECURE_IMAGE_MAX_SIZE FLASH_S_PARTITION_SIZE + +#define NON_SECURE_IMAGE_OFFSET (SECURE_IMAGE_OFFSET + \ + SECURE_IMAGE_MAX_SIZE) +#define NON_SECURE_IMAGE_MAX_SIZE FLASH_NS_PARTITION_SIZE + +/* Flash device name used by BL2 + * Name is defined in flash driver file: Driver_Flash_MRAM.c + */ +#define FLASH_DEV_NAME Driver_FLASH0 + +/* Secure Storage (SST) Service definitions + * Note: Further documentation of these definitions can be found in the + * TF-M SST Integration Guide. + */ +#define SST_FLASH_DEV_NAME Driver_FLASH0 + +/* In this target the CMSIS driver requires only the offset from the base + * address instead of the full memory address. + */ +#define SST_FLASH_AREA_ADDR FLASH_SST_AREA_OFFSET +/* Dedicated flash area for SST */ +#define SST_FLASH_AREA_SIZE FLASH_SST_AREA_SIZE +#define SST_SECTOR_SIZE FLASH_AREA_IMAGE_SECTOR_SIZE +/* Number of SST_SECTOR_SIZE per block */ +#define SST_SECTORS_PER_BLOCK (0x1) +/* Specifies the smallest flash programmable unit in bytes */ +#define SST_FLASH_PROGRAM_UNIT (0x1) +/* The maximum asset size to be stored in the SST area */ +#define SST_MAX_ASSET_SIZE (2048) +/* The maximum number of assets to be stored in the SST area */ +#define SST_NUM_ASSETS (10) + +/* Internal Trusted Storage (ITS) Service definitions + * Note: Further documentation of these definitions can be found in the + * TF-M ITS Integration Guide. The ITS should be in the internal flash, but is + * allocated in the external flash just for development platforms that don't + * have internal flash available. + */ +#define ITS_FLASH_DEV_NAME Driver_FLASH0 + +/* In this target the CMSIS driver requires only the offset from the base + * address instead of the full memory address. + */ +#define ITS_FLASH_AREA_ADDR FLASH_ITS_AREA_OFFSET +/* Dedicated flash area for ITS */ +#define ITS_FLASH_AREA_SIZE FLASH_ITS_AREA_SIZE +#define ITS_SECTOR_SIZE FLASH_AREA_IMAGE_SECTOR_SIZE +/* Number of ITS_SECTOR_SIZE per block */ +#define ITS_SECTORS_PER_BLOCK (0x1) +/* Specifies the smallest flash programmable unit in bytes */ +#define ITS_FLASH_PROGRAM_UNIT (0x1) +/* The maximum asset size to be stored in the ITS area */ +#define ITS_MAX_ASSET_SIZE (512) +/* The maximum number of assets to be stored in the ITS area */ +#define ITS_NUM_ASSETS (10) + +/* NV Counters definitions */ +#define TFM_NV_COUNTERS_AREA_ADDR FLASH_NV_COUNTERS_AREA_OFFSET +#define TFM_NV_COUNTERS_AREA_SIZE (0x18) /* 24 Bytes */ +#define TFM_NV_COUNTERS_SECTOR_ADDR FLASH_NV_COUNTERS_AREA_OFFSET +#define TFM_NV_COUNTERS_SECTOR_SIZE FLASH_AREA_IMAGE_SECTOR_SIZE + +/* Use MRAM to store Code data */ +#define S_ROM_ALIAS_BASE (0x1A000000) +#define NS_ROM_ALIAS_BASE (0x0A000000) + +/* FIXME: Use SRAM2 memory to store RW data */ +#define S_RAM_ALIAS_BASE (0x30000000) +#define NS_RAM_ALIAS_BASE (0x20000000) + +#define TOTAL_ROM_SIZE FLASH_TOTAL_SIZE +#define TOTAL_RAM_SIZE (0x80000) /* 512 KB */ + +#endif /* __FLASH_LAYOUT_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/image_macros_preprocessed_ns.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/image_macros_preprocessed_ns.c new file mode 100644 index 0000000..68ffe4a --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/image_macros_preprocessed_ns.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +enum image_attributes { + RE_SECURE_IMAGE_OFFSET = (0x0), + RE_SECURE_IMAGE_MAX_SIZE = (0x60000), + RE_NON_SECURE_IMAGE_OFFSET = ((0x0) + (0x60000)), + RE_NON_SECURE_IMAGE_MAX_SIZE = (0x80000), + RE_SIGN_BIN_SIZE = ((0x80000)), +}; diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/image_macros_preprocessed_s.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/image_macros_preprocessed_s.c new file mode 100644 index 0000000..bcc7223 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/image_macros_preprocessed_s.c @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +enum image_attributes { + RE_SECURE_IMAGE_OFFSET = (0x0), + RE_SECURE_IMAGE_MAX_SIZE = (0x60000), + RE_NON_SECURE_IMAGE_OFFSET = ((0x0) + (0x60000)), + RE_NON_SECURE_IMAGE_MAX_SIZE = (0x80000), + RE_SIGN_BIN_SIZE = ((0x60000)), +}; diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/region_defs.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/region_defs.h new file mode 100644 index 0000000..207ce80 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/partition/region_defs.h @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2017-2020 Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __REGION_DEFS_H__ +#define __REGION_DEFS_H__ + +#include "flash_layout.h" + +#define BL2_HEAP_SIZE (0x0001000) +#define BL2_MSP_STACK_SIZE (0x0001800) + +#define S_HEAP_SIZE (0x0001000) +#define S_MSP_STACK_SIZE_INIT (0x0000400) +#define S_MSP_STACK_SIZE (0x0000800) +#define S_PSP_STACK_SIZE (0x0000800) + +#define NS_HEAP_SIZE (0x0001000) +#define NS_MSP_STACK_SIZE (0x00000A0) +#define NS_PSP_STACK_SIZE (0x0000140) + +/* This size of buffer is big enough to store an attestation + * token produced by initial attestation service + */ +#define PSA_INITIAL_ATTEST_TOKEN_MAX_SIZE (0x250) + +/* + * MRAM MPC granularity is 4 KB on Musca. Alignment + * of partitions is defined in accordance with this constraint. + */ +#ifdef BL2 +#ifndef LINK_TO_SECONDARY_PARTITION +#define S_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_0_OFFSET) +#define S_IMAGE_SECONDARY_PARTITION_OFFSET (FLASH_AREA_2_OFFSET) +#else +#define S_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_2_OFFSET) +#define S_IMAGE_SECONDARY_PARTITION_OFFSET (FLASH_AREA_0_OFFSET) +#endif /* !LINK_TO_SECONDARY_PARTITION */ +#else +#define S_IMAGE_PRIMARY_PARTITION_OFFSET (0x0) +#endif /* BL2 */ + +#ifndef LINK_TO_SECONDARY_PARTITION +#define NS_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_0_OFFSET \ + + FLASH_S_PARTITION_SIZE) +#else +#define NS_IMAGE_PRIMARY_PARTITION_OFFSET (FLASH_AREA_2_OFFSET \ + + FLASH_S_PARTITION_SIZE) +#endif /* !LINK_TO_SECONDARY_PARTITION */ + +/* Boot partition structure if MCUBoot is used: + * 0x0_0000 Bootloader header + * 0x0_0400 Image area + * 0x1_FC00 Trailer + */ +/* IMAGE_CODE_SIZE is the space available for the software binary image. + * It is less than the FLASH_S_PARTITION_SIZE + FLASH_NS_PARTITION_SIZE + * because we reserve space for the image header and trailer introduced + * by the bootloader. + */ +#ifdef BL2 +#define BL2_HEADER_SIZE (0x400) /* 1 KB */ +#define BL2_TRAILER_SIZE (0x800) /* 2 KB */ +#else +/* No header if no bootloader, but keep IMAGE_CODE_SIZE the same */ +#define BL2_HEADER_SIZE (0x0) +#define BL2_TRAILER_SIZE (0xC00) +#endif /* BL2 */ + +#define IMAGE_S_CODE_SIZE \ + (FLASH_S_PARTITION_SIZE - BL2_HEADER_SIZE - BL2_TRAILER_SIZE) +#define IMAGE_NS_CODE_SIZE \ + (FLASH_NS_PARTITION_SIZE - BL2_HEADER_SIZE - BL2_TRAILER_SIZE) + +#define CMSE_VENEER_REGION_SIZE (0x340) + +/* Alias definitions for secure and non-secure areas*/ +#define S_ROM_ALIAS(x) (S_ROM_ALIAS_BASE + (x)) +#define NS_ROM_ALIAS(x) (NS_ROM_ALIAS_BASE + (x)) + +#define S_RAM_ALIAS(x) (S_RAM_ALIAS_BASE + (x)) +#define NS_RAM_ALIAS(x) (NS_RAM_ALIAS_BASE + (x)) + +/* Secure regions */ +#define S_IMAGE_PRIMARY_AREA_OFFSET \ + (S_IMAGE_PRIMARY_PARTITION_OFFSET + BL2_HEADER_SIZE) +#define S_CODE_START (S_ROM_ALIAS(S_IMAGE_PRIMARY_AREA_OFFSET)) +#define S_CODE_SIZE (IMAGE_S_CODE_SIZE - CMSE_VENEER_REGION_SIZE) +#define S_CODE_LIMIT (S_CODE_START + S_CODE_SIZE - 1) + +#define S_DATA_START (S_RAM_ALIAS(0x0)) +#define S_DATA_SIZE (TOTAL_RAM_SIZE / 2) +#define S_DATA_LIMIT (S_DATA_START + S_DATA_SIZE - 1) + +/* CMSE Veneers region */ +#define CMSE_VENEER_REGION_START (S_CODE_LIMIT + 1) + +/* Non-secure regions */ +#define NS_IMAGE_PRIMARY_AREA_OFFSET \ + (NS_IMAGE_PRIMARY_PARTITION_OFFSET + BL2_HEADER_SIZE) +#define NS_CODE_START (NS_ROM_ALIAS(NS_IMAGE_PRIMARY_AREA_OFFSET)) +#define NS_CODE_SIZE (IMAGE_NS_CODE_SIZE) +#define NS_CODE_LIMIT (NS_CODE_START + NS_CODE_SIZE - 1) + +#define NS_DATA_START (NS_RAM_ALIAS(TOTAL_RAM_SIZE / 2)) +#define NS_DATA_SIZE (TOTAL_RAM_SIZE / 2) +#define NS_DATA_LIMIT (NS_DATA_START + NS_DATA_SIZE - 1) + +/* NS partition information is used for MPC and SAU configuration */ +#define NS_PARTITION_START \ + (NS_ROM_ALIAS(NS_IMAGE_PRIMARY_PARTITION_OFFSET)) + +#define NS_PARTITION_SIZE (FLASH_NS_PARTITION_SIZE) + +/* Secondary partition for new images in case of firmware upgrade */ +#define SECONDARY_PARTITION_START \ + (NS_ROM_ALIAS(S_IMAGE_SECONDARY_PARTITION_OFFSET)) +#define SECONDARY_PARTITION_SIZE (FLASH_S_PARTITION_SIZE + \ + FLASH_NS_PARTITION_SIZE) + +/* Code SRAM area */ +#define TOTAL_CODE_SRAM_SIZE (0x00080000) /* 512 KB */ +#define S_CODE_SRAM_ALIAS_BASE (0x1A400000) +#define NS_CODE_SRAM_ALIAS_BASE (0x0A400000) + +#ifdef BL2 +/* Bootloader regions */ +#define BL2_CODE_START (S_ROM_ALIAS(FLASH_AREA_BL2_OFFSET)) +#define BL2_CODE_SIZE (FLASH_AREA_BL2_SIZE) +#define BL2_CODE_LIMIT (BL2_CODE_START + BL2_CODE_SIZE - 1) + +#define BL2_DATA_START (S_RAM_ALIAS(0x0)) +#define BL2_DATA_SIZE (TOTAL_RAM_SIZE) +#define BL2_DATA_LIMIT (BL2_DATA_START + BL2_DATA_SIZE - 1) +#endif /* BL2 */ + +/* Shared data area between bootloader and runtime firmware. + * Shared data area is allocated at the beginning of the RAM, it is overlapping + * with TF-M Secure code's MSP stack + */ +#define BOOT_TFM_SHARED_DATA_BASE S_RAM_ALIAS_BASE +#define BOOT_TFM_SHARED_DATA_SIZE (0x400) +#define BOOT_TFM_SHARED_DATA_LIMIT (BOOT_TFM_SHARED_DATA_BASE + \ + BOOT_TFM_SHARED_DATA_SIZE - 1) + +#endif /* __REGION_DEFS_H__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/pinmap.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/pinmap.c new file mode 100644 index 0000000..c7da0da --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/pinmap.c @@ -0,0 +1,123 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * This file implements APIS defined in hal/pinmap.h + * + * Pin functions are not available in interrupt context, because the + * NS side is only allowed to call TF-M secure functions (veneers) from + * the NS Thread mode. + * + */ + +#include "mbed_assert.h" +#include "mbed_error.h" +#include "device_definition.h" +#include "objects.h" +#include "pinmap.h" +#include "musca_s1_scc_drv.h" +#include "tfm_ioctl_api.h" + +#if DEVICE_I2C || DEVICE_I2CSLAVE +const PinMap PinMap_I2C_SDA[] = { + {I2C0_SDA, I2C_0, ALTERNATE_FUNC_1}, + {I2C1_SDA, I2C_1, PRIMARY_FUNC}, + {NC, NC, 0} +}; + +const PinMap PinMap_I2C_SCL[] = { + {I2C0_SCL, I2C_0, ALTERNATE_FUNC_1}, + {I2C1_SCL, I2C_1, PRIMARY_FUNC}, + {NC, NC, 0} +}; +#endif // DEVICE_I2C || DEVICE_I2CSLAVE + +/** + * \brief Translates between different pin mode enums + * + * \param[in] mode Pin mode to translate \ref PinMode + * + * \return Translated pin mode \ref pinmode_select_t + */ +static enum pinmode_select_t translate_pinmode(PinMode mode) +{ + switch (mode) { + case PullNone: + return PINMODE_NONE; + case PullDown: + return PINMODE_PULL_DOWN; + case PullUp: + return PINMODE_PULL_UP; + default: + return PINMODE_NONE; + } +} + +/** + * \brief Configures the GPIO pin and sets the alternate function + * + * \param[in] pin GPIO pin number \ref PinName + * \param[in] function Alternate function to set \ref PinFunction + */ +void pin_function(PinName pin, int function) +{ + enum gpio_altfunc_t flags; + uint32_t result = 0; + enum tfm_platform_err_t ret = TFM_PLATFORM_ERR_SUCCESS; + + MBED_ASSERT(pin != NC); + + switch (function) { + case PRIMARY_FUNC: + flags = GPIO_MAIN_FUNC; + break; + case ALTERNATE_FUNC_1: + flags = GPIO_ALTFUNC_1; + break; + case ALTERNATE_FUNC_2: + flags = GPIO_ALTFUNC_2; + break; + default: + return; + } + + ret = tfm_platform_set_pin_alt_func(flags, (1u< + +#include "mbed_error.h" +#include "objects.h" +#include "pinmap.h" +#include "serial_api.h" +#include "mbed_serial_platform.h" + +#define STDIO_UART_NOT_INITED 0 +#define STDIO_UART_INITED 1 + +extern const PinMap PinMap_UART_TX[]; +extern const PinMap PinMap_UART_RX[]; + +/* Global variables needed for mbed */ +int stdio_uart_inited = STDIO_UART_NOT_INITED; +serial_t stdio_uart; + + +void serial_init(serial_t *obj, PinName tx, PinName rx) +{ + /* Determine the UART to use */ + UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX); + UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX); + UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx); + if (uart == (UARTName)NC) { + error("Serial pinout mapping failed"); + } + mbed_uart_platform_init(obj, uart); + obj->uart_index = uart; + + /* Pinout the chosen uart */ + pinmap_pinout(tx, PinMap_UART_TX); + pinmap_pinout(rx, PinMap_UART_RX); + + uart_pl011_init(obj->uart_dev, SystemCoreClock); + + uart_pl011_set_baudrate(obj->uart_dev, + MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE); + + uart_pl011_enable(obj->uart_dev); + + if (uart == STDIO_UART) { + stdio_uart_inited = STDIO_UART_INITED; + memcpy(&stdio_uart, obj, sizeof(serial_t)); + } +} + +void serial_free(serial_t *obj) +{ + uart_pl011_uninit(obj->uart_dev); +} + +void serial_baud(serial_t *obj, int baudrate) +{ + if(uart_pl011_set_baudrate(obj->uart_dev,baudrate) != UART_PL011_ERR_NONE) { + error("serial_baud: invalid baudrate"); + } +} + +void serial_format(serial_t *obj, int data_bits, SerialParity parity, + int stop_bits) +{ + enum uart_pl011_wlen_t uart_word_len = UART_PL011_WLEN_8; + enum uart_pl011_parity_t uart_parity = UART_PL011_PARITY_DISABLED; + enum uart_pl011_stopbit_t uart_stop_bits = UART_PL011_STOPBIT_1; + switch (data_bits) { + case 5: + uart_word_len = UART_PL011_WLEN_5; + break; + case 6: + uart_word_len = UART_PL011_WLEN_6; + break; + case 7: + uart_word_len = UART_PL011_WLEN_7; + break; + case 8: + uart_word_len = UART_PL011_WLEN_8; + break; + default: + error("serial_format: unexpected data bits"); + } + switch (parity) { + case ParityNone: + uart_parity = UART_PL011_PARITY_DISABLED; + break; + case ParityOdd: + uart_parity = UART_PL011_PARITY_ODD; + break; + case ParityEven: + uart_parity = UART_PL011_PARITY_EVEN; + break; + case ParityForced1: + uart_parity = UART_PL011_PARITY_STICKY_ONE; + break; + case ParityForced0: + uart_parity = UART_PL011_PARITY_STICKY_ZERO; + break; + default: + error("serial_format: unexpected parity"); + } + switch (stop_bits) { + case 1: + uart_stop_bits = UART_PL011_STOPBIT_1; + break; + case 2: + uart_stop_bits = UART_PL011_STOPBIT_2; + break; + default: + error("serial_format: unexpected stop bit"); + } + (void)uart_pl011_set_format(obj->uart_dev, + uart_word_len, uart_parity, uart_stop_bits); +} + +void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) +{ + uart_irq[obj->uart_index].handler = handler; + uart_irq[obj->uart_index].id = id; +} + +void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) +{ + switch(irq) { + case RxIrq: + if (enable) { + NVIC_EnableIRQ(obj->rx_irq); + uart_pl011_enable_intr(obj->uart_dev, UART_PL011_RX_INTR_MASK); + NVIC_EnableIRQ(obj->rx_timeout_irq); + uart_pl011_enable_intr(obj->uart_dev, UART_PL011_RT_INTR_MASK); + } else { + uart_pl011_disable_intr(obj->uart_dev, UART_PL011_RX_INTR_MASK); + NVIC_DisableIRQ(obj->rx_irq); + uart_pl011_disable_intr(obj->uart_dev, UART_PL011_RT_INTR_MASK); + NVIC_DisableIRQ(obj->rx_timeout_irq); + } + break; + case TxIrq: + if (enable) { + NVIC_EnableIRQ(obj->tx_irq); + uart_pl011_enable_intr(obj->uart_dev, UART_PL011_TX_INTR_MASK); + } else { + uart_pl011_disable_intr(obj->uart_dev, UART_PL011_TX_INTR_MASK); + NVIC_DisableIRQ(obj->tx_irq); + } + break; + default : return; + } +} + +int serial_readable(serial_t *obj) +{ + return (int)uart_pl011_is_readable(obj->uart_dev); +} + +int serial_writable(serial_t *obj) +{ + return (int)uart_pl011_is_writable(obj->uart_dev); +} + +int serial_getc(serial_t *obj) +{ + uint8_t byte = 0; + while(!uart_pl011_is_readable(obj->uart_dev)); + (void)uart_pl011_read(obj->uart_dev, &byte); + return byte; +} + +void serial_putc(serial_t *obj, int c) +{ + while(!uart_pl011_is_writable(obj->uart_dev)); + uart_pl011_write(obj->uart_dev, (uint8_t)c); +} + +void serial_clear(serial_t *obj) +{ + uart_pl011_write(obj->uart_dev, (uint8_t)0); +} + +void serial_pinout_tx(PinName tx) +{ + pinmap_pinout(tx, PinMap_UART_TX); +} + +void serial_break_set(serial_t *obj) +{ + uart_pl011_enable_break(obj->uart_dev); +} + +void serial_break_clear(serial_t *obj) +{ + uart_pl011_disable_break(obj->uart_dev); +} + +void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, + PinName txflow) +{ + error("serial_set_flow_control: Flow control is not supported in MUSCA"); +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/sleep_api.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/sleep_api.c new file mode 100644 index 0000000..d0f38f0 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/sleep_api.c @@ -0,0 +1,48 @@ +/* mbed Microcontroller Library + * Copyright (c) 2019-2020 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "device_cfg.h" +#include "sleep_api.h" +#include "timer_cmsdk_drv.h" + +#if DEVICE_SLEEP + +void hal_sleep(void) +{ + __WFI(); +} + +/* Since there is no power management implemented in Musca, Deep Sleep could + * be supported only by additional software components, registering and managing + * the currently configured IPs. This would also mean a huge implementation + * overhead, that is not intended to be added. Therefore, Deep Sleep is almost + * identical to Sleep, representing a "Waiting For Interrupt" state, and + * disabling the Microsec ticker in addition. + */ +void hal_deepsleep(void) +{ +#ifdef USEC_TIMER_DEV + timer_cmsdk_disable(&USEC_TIMER_DEV); +#endif + __WFI(); +#ifdef USEC_TIMER_DEV + timer_cmsdk_enable(&USEC_TIMER_DEV); +#endif +} + +#endif diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_ioctl_api.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_ioctl_api.h new file mode 100644 index 0000000..345f210 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_ioctl_api.h @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2019-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#ifndef __TFM_IOCTL_API__ +#define __TFM_IOCTL_API__ + +#include +#include +#include +#include "tfm_api.h" +#include "tfm_platform_api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +enum tfm_platform_ioctl_request_types_t { + TFM_PLATFORM_IOCTL_PIN_SERVICE, + TFM_PLATFORM_IOCTL_GPIO_SERVICE, +}; + +/*! + * \enum tfm_gpio_service_type_t + * + * \brief GPIO service types (supported types may vary based on the platform) + */ +enum tfm_gpio_service_type_t { + TFM_GPIO_SERVICE_TYPE_INIT = 0, /*!< Init */ + TFM_GPIO_SERVICE_TYPE_PIN_CONFIG, /*!< Pin config */ + TFM_GPIO_SERVICE_TYPE_PIN_WRITE, /*!< Pin write */ + TFM_GPIO_SERVICE_TYPE_PIN_READ, /*!< Pin read */ + TFM_GPIO_SERVICE_TYPE_PORT_CONFIG, /*!< Port config */ + TFM_GPIO_SERVICE_TYPE_PORT_WRITE, /*!< Port write */ + TFM_GPIO_SERVICE_TYPE_PORT_READ, /*!< Port read */ + TFM_GPIO_SERVICE_TYPE_MAX = INT_MAX /*!< Max to force enum max size */ +}; + +/*! + * \struct tfm_gpio_service_args_t + * + * \brief Argument list for each platform GPIO service + */ +struct tfm_gpio_service_args_t { + enum tfm_gpio_service_type_t type; + union { + struct gpio_config_args { /*!< TFM_GPIO_SERVICE_TYPE_PIN_CONFIG || + TFM_GPIO_SERVICE_TYPE_PORT_CONFIG */ + uint32_t pin_num_or_mask; + uint32_t direction; + } gpio_config; + struct gpio_write_args { /*!< TFM_GPIO_SERVICE_TYPE_PIN_WRITE || + TFM_GPIO_SERVICE_TYPE_PORT_WRITE */ + uint32_t pin_num_or_mask; + uint32_t value; + } gpio_write; + struct gpio_read_args { /*!< TFM_GPIO_SERVICE_TYPE_PIN_READ || + TFM_GPIO_SERVICE_TYPE_PORT_READ */ + uint32_t pin_num_or_mask; + } gpio_read; + } u; +}; + +/*! + * \struct tfm_gpio_service_out_t + * + * \brief Output list for each GPIO platform service + */ +struct tfm_gpio_service_out_t { + union { + uint32_t result; /*!< Generic result */ + struct gpio_read_result { /*!< TFM_GPIO_SERVICE_TYPE_PIN_READ || + TFM_GPIO_SERVICE_TYPE_PORT_READ */ + uint32_t result; + uint32_t data; + } gpio_read_result; + } u; +}; + +/*! + * \enum tfm_pin_service_type_t + * + * \brief Pin service types + */ +enum tfm_pin_service_type_t { + TFM_PIN_SERVICE_TYPE_SET_ALTFUNC = 0, /*!< Set alternate function type */ + TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN, /*!< Set default in function type */ + TFM_PIN_SERVICE_TYPE_SET_PIN_MODE, /*!< Set pin mode function type */ + TFM_PIN_SERVICE_TYPE_MAX = INT_MAX /*!< Max to force enum max size */ +}; + +/*! + * \struct tfm_pin_service_args_t + * + * \brief Argument list for each platform pin service + */ +struct tfm_pin_service_args_t { + enum tfm_pin_service_type_t type; + union { + struct set_altfunc { /*!< TFM_PIN_SERVICE_TYPE_SET_ALTFUNC */ + uint32_t alt_func; + uint64_t pin_mask; + } set_altfunc; + struct set_default_in { /*!< TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN */ + uint32_t alt_func; + uint32_t pin_value; + bool default_in_value; + } set_default_in; + struct set_pin_mode { /*!< TFM_PIN_SERVICE_TYPE_SET_PIN_MODE */ + uint64_t pin_mask; + uint32_t pin_mode; + } set_pin_mode; + } u; +}; + +/*! + * \brief Sets pin alternate function for the given pins + * + * \param[in] alt_func Alternate function to set (allowed values vary + * based on the platform) + * \param[in] pin_mask Pin mask of the selected pins + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t +tfm_platform_set_pin_alt_func(uint32_t alt_func, uint64_t pin_mask, + uint32_t *result); + +/*! + * \brief Sets default in value to use when the alternate function is not + * selected for the pin + * + * \param[in] alt_func Alternate function to use (allowed values vary + * based on the platform) + * \param[in] pin_value Pin value to use + * \param[in] default_in_value Default in value to set + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t +tfm_platform_set_pin_default_in(uint32_t alt_func, uint32_t pin_value, + bool default_in_value, uint32_t *result); + +/*! + * \brief Sets pin mode for the selected pins + * + * \param[in] pin_mask Pin mask of the selected pins + * \param[in] pin_mode Pin mode to set for the selected pins + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t +tfm_platform_set_pin_mode(uint64_t pin_mask, uint32_t pin_mode, + uint32_t *result); + +/*! + * \brief Initializes GPIO module + * + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t tfm_platform_gpio_init(uint32_t *result); + +/*! + * \brief Configures a GPIO pin as input or output + * + * \param[in] pin_num Pin number of the selected pin + * \param[in] direction Direction of the pin: 0 for input, 1 for output + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t +tfm_platform_gpio_pin_config(uint32_t pin_num, uint32_t direction, + uint32_t *result); + +/*! + * \brief Sets state of a selected GPIO pin + * + * \param[in] pin_num Pin number of the selected pin + * \param[in] value Value to set for the pin + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t +tfm_platform_gpio_pin_write(uint32_t pin_num, uint32_t value, uint32_t *result); + +/*! + * \brief Reads state of a selected GPIO pin + * + * \param[in] pin_num Pin number of the selected pin + * \param[in,out] data Bit value read from the IO pin + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t +tfm_platform_gpio_pin_read(uint32_t pin_num, uint32_t *data, uint32_t *result); + +/*! + * \brief Configures GPIO pins as input or output + * + * \param[in] pin_mask Pin mask of the selected pins + * \param[in] direction Direction of the pin: 0 for input, 1 for output + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t +tfm_platform_gpio_port_config(uint32_t pin_mask, uint32_t direction, + uint32_t *result); + +/*! + * \brief Sets state of a selected GPIO pins + * + * \param[in] pin_mask Pin mask of the selected pins + * \param[in] value Value mask to set for the pins + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t +tfm_platform_gpio_port_write(uint32_t pin_mask, uint32_t value, + uint32_t *result); + +/*! + * \brief Reads state of a selected GPIO pins + * + * \param[in] pin_mask Pin mask of the selected pins + * \param[in,out] data Bit value mask read from the IO pins + * \param[out] result Return error value + * + * \return Returns values as specified by the \ref tfm_platform_err_t + */ +enum tfm_platform_err_t +tfm_platform_gpio_port_read(uint32_t pin_mask, uint32_t *data, + uint32_t *result); + +#ifdef __cplusplus +} +#endif + +#endif /* __TFM_IOCTL_API__ */ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_ioctl_ns_api.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_ioctl_ns_api.c new file mode 100644 index 0000000..d834f87 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_ioctl_ns_api.c @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2019-2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include +#include +#include "tfm_platform_api.h" +#include "tfm_ioctl_api.h" + +enum tfm_platform_err_t +tfm_platform_set_pin_alt_func(uint32_t alt_func, uint64_t pin_mask, + uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_pin_service_args_t args; + + if (result == NULL) { + return TFM_PLATFORM_ERR_INVALID_PARAM; + } + + args.type = TFM_PIN_SERVICE_TYPE_SET_ALTFUNC; + args.u.set_altfunc.alt_func = alt_func; + args.u.set_altfunc.pin_mask = pin_mask; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)result; + out_vec.len = sizeof(*result); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_PIN_SERVICE, + &in_vec, + &out_vec); + + return ret; +} + +enum tfm_platform_err_t +tfm_platform_set_pin_default_in(uint32_t alt_func, uint32_t pin_value, + bool default_in_value, uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_pin_service_args_t args; + + if (result == NULL) { + return TFM_PLATFORM_ERR_INVALID_PARAM; + } + + args.type = TFM_PIN_SERVICE_TYPE_SET_DEFAULT_IN; + args.u.set_default_in.alt_func = alt_func; + args.u.set_default_in.pin_value = pin_value; + args.u.set_default_in.default_in_value = default_in_value; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)result; + out_vec.len = sizeof(*result); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_PIN_SERVICE, + &in_vec, + &out_vec); + + return ret; +} + +enum tfm_platform_err_t +tfm_platform_set_pin_mode(uint64_t pin_mask, uint32_t pin_mode, + uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_pin_service_args_t args; + + if (result == NULL) { + return TFM_PLATFORM_ERR_INVALID_PARAM; + } + + args.type = TFM_PIN_SERVICE_TYPE_SET_PIN_MODE; + args.u.set_pin_mode.pin_mask = pin_mask; + args.u.set_pin_mode.pin_mode = pin_mode; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)result; + out_vec.len = sizeof(*result); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_PIN_SERVICE, + &in_vec, + &out_vec); + + return ret; +} + +enum tfm_platform_err_t tfm_platform_gpio_init(uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_gpio_service_args_t args; + struct tfm_gpio_service_out_t out; + + args.type = TFM_GPIO_SERVICE_TYPE_INIT; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)&out; + out_vec.len = sizeof(out); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE, + &in_vec, + &out_vec); + + *result = out.u.result; + + return ret; +} + +enum tfm_platform_err_t +tfm_platform_gpio_pin_config(uint32_t pin_num, uint32_t direction, + uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_gpio_service_args_t args; + struct tfm_gpio_service_out_t out; + + args.type = TFM_GPIO_SERVICE_TYPE_PIN_CONFIG; + args.u.gpio_config.pin_num_or_mask = pin_num; + args.u.gpio_config.direction = direction; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)&out; + out_vec.len = sizeof(out); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE, + &in_vec, + &out_vec); + + *result = out.u.result; + + return ret; +} + +enum tfm_platform_err_t +tfm_platform_gpio_pin_write(uint32_t pin_num, uint32_t value, uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_gpio_service_args_t args; + struct tfm_gpio_service_out_t out; + + args.type = TFM_GPIO_SERVICE_TYPE_PIN_WRITE; + args.u.gpio_write.pin_num_or_mask = pin_num; + args.u.gpio_write.value = value; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)&out; + out_vec.len = sizeof(out); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE, + &in_vec, + &out_vec); + + *result = out.u.result; + + return ret; +} + +enum tfm_platform_err_t +tfm_platform_gpio_pin_read(uint32_t pin_num, uint32_t *data, uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_gpio_service_args_t args; + struct tfm_gpio_service_out_t out; + + args.type = TFM_GPIO_SERVICE_TYPE_PIN_READ; + args.u.gpio_read.pin_num_or_mask = pin_num; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)&out; + out_vec.len = sizeof(out); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE, + &in_vec, + &out_vec); + + *result = out.u.gpio_read_result.result; + *data = out.u.gpio_read_result.data; + + return ret; +} + +enum tfm_platform_err_t +tfm_platform_gpio_port_config(uint32_t pin_mask, uint32_t direction, + uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_gpio_service_args_t args; + struct tfm_gpio_service_out_t out; + + args.type = TFM_GPIO_SERVICE_TYPE_PORT_CONFIG; + args.u.gpio_config.pin_num_or_mask = pin_mask; + args.u.gpio_config.direction = direction; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)&out; + out_vec.len = sizeof(out); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE, + &in_vec, + &out_vec); + + *result = out.u.result; + + return ret; +} + +enum tfm_platform_err_t +tfm_platform_gpio_port_write(uint32_t pin_mask, uint32_t value, + uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_gpio_service_args_t args; + struct tfm_gpio_service_out_t out; + + args.type = TFM_GPIO_SERVICE_TYPE_PORT_WRITE; + args.u.gpio_write.pin_num_or_mask = pin_mask; + args.u.gpio_write.value = value; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)&out; + out_vec.len = sizeof(out); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE, + &in_vec, + &out_vec); + + *result = out.u.result; + + return ret; + +} + +enum tfm_platform_err_t +tfm_platform_gpio_port_read(uint32_t pin_mask, uint32_t *data, uint32_t *result) +{ + enum tfm_platform_err_t ret; + psa_invec in_vec; + psa_outvec out_vec; + struct tfm_gpio_service_args_t args; + struct tfm_gpio_service_out_t out; + + args.type = TFM_GPIO_SERVICE_TYPE_PORT_READ; + args.u.gpio_read.pin_num_or_mask = pin_mask; + + in_vec.base = (const void *)&args; + in_vec.len = sizeof(args); + + out_vec.base = (void *)&out; + out_vec.len = sizeof(out); + + ret = tfm_platform_ioctl(TFM_PLATFORM_IOCTL_GPIO_SERVICE, + &in_vec, + &out_vec); + + *result = out.u.gpio_read_result.result; + *data = out.u.gpio_read_result.data; + + return ret; +} diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_s.axf b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_s.axf new file mode 100644 index 0000000..33fdcff --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_s.axf Binary files differ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_s.bin b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_s.bin new file mode 100644 index 0000000..3fffbc5 --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/tfm_s.bin Binary files differ diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/us_ticker.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/us_ticker.c new file mode 100644 index 0000000..006d7fb --- /dev/null +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/us_ticker.c @@ -0,0 +1,124 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017-2019 Arm Limited + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Supports the High-resolution Ticker for mbed by implementing + * \ref us_ticker_api.h, using a CMSDK Timer \ref timer_cmsdk_dev_t. + */ + +#include "device.h" +#include "mbed_critical.h" +#include "timer_cmsdk_drv.h" +#include "us_ticker_api.h" + +static uint64_t total_ticks = 0; +/* Stores the last reload value, or the last tick value read when a read API + * call occurs from the upper layer, needed to keep total_ticks + * accumulated properly. + */ +static uint32_t previous_ticks = 0; + +static void restart_timer(uint32_t new_reload) +{ + timer_cmsdk_disable(&USEC_TIMER_DEV); + timer_cmsdk_set_reload_value(&USEC_TIMER_DEV, + new_reload); + timer_cmsdk_reset(&USEC_TIMER_DEV); + timer_cmsdk_clear_interrupt(&USEC_TIMER_DEV); + timer_cmsdk_enable_interrupt(&USEC_TIMER_DEV); + timer_cmsdk_enable(&USEC_TIMER_DEV); +} + +static void update_ticker(void) +{ + if (timer_cmsdk_is_interrupt_active(&USEC_TIMER_DEV)) { + total_ticks += previous_ticks; + previous_ticks = TIMER_CMSDK_MAX_RELOAD; + restart_timer(previous_ticks); + } else { + uint32_t tick = timer_cmsdk_get_current_value(&USEC_TIMER_DEV); + + if (tick < previous_ticks) { + uint32_t delta = previous_ticks - tick; + total_ticks += delta; + previous_ticks = tick; + } + } +} + +void us_ticker_init(void) +{ + timer_cmsdk_init(&USEC_TIMER_DEV); + previous_ticks = TIMER_CMSDK_MAX_RELOAD; + NVIC_EnableIRQ(USEC_INTERVAL_IRQ); + restart_timer(previous_ticks); +} + +void us_ticker_free(void) +{ + timer_cmsdk_disable(&USEC_TIMER_DEV); +} + +uint32_t us_ticker_read(void) +{ + core_util_critical_section_enter(); + update_ticker(); + core_util_critical_section_exit(); + + return (uint32_t)(total_ticks >> USEC_REPORTED_SHIFT); +} + +void us_ticker_set_interrupt(timestamp_t timestamp) +{ + uint32_t reload = (timestamp - us_ticker_read()) << USEC_REPORTED_SHIFT; + previous_ticks = reload; + restart_timer(previous_ticks); +} + +void us_ticker_disable_interrupt(void) +{ + timer_cmsdk_disable_interrupt(&USEC_TIMER_DEV); +} + +void us_ticker_clear_interrupt(void) +{ + timer_cmsdk_clear_interrupt(&USEC_TIMER_DEV); +} + +void us_ticker_fire_interrupt(void) +{ + NVIC_SetPendingIRQ(USEC_INTERVAL_IRQ); +} + +const ticker_info_t* us_ticker_get_info() +{ + static const ticker_info_t info = { + USEC_REPORTED_FREQ_HZ, + USEC_REPORTED_BITS + }; + return &info; +} + +#ifndef usec_interval_irq_handler +#error "usec_interval_irq_handler should be defined, check device_cfg.h!" +#endif +void usec_interval_irq_handler(void) +{ + update_ticker(); + us_ticker_irq_handler(); +} diff --git a/targets/TARGET_ARM_SSG/mbed_rtx.h b/targets/TARGET_ARM_SSG/mbed_rtx.h index 91056db..0260893 100644 --- a/targets/TARGET_ARM_SSG/mbed_rtx.h +++ b/targets/TARGET_ARM_SSG/mbed_rtx.h @@ -43,7 +43,7 @@ #define INITIAL_SP (ZBT_SSRAM23_START + ZBT_SSRAM23_SIZE) #endif -#elif defined(TARGET_MUSCA_A1) || defined(TARGET_MUSCA_B1) +#elif defined(TARGET_MUSCA_A1) || defined(TARGET_MUSCA_B1) || defined(TARGET_MUSCA_S1) #if defined(__ARMCC_VERSION) extern uint32_t Image$$ARM_LIB_HEAP$$ZI$$Base[]; @@ -58,6 +58,6 @@ #error "no toolchain defined" #endif -#endif /* defined(TARGET_MUSCA_A1) || defined(TARGET_MUSCA_B1) */ +#endif /* defined(TARGET_MUSCA_A1) || defined(TARGET_MUSCA_B1) || defined(TARGET_MUSCA_S1) */ #endif /* MBED_MBED_RTX_H */ diff --git a/targets/targets.json b/targets/targets.json index 67b8099..35df687 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -4077,6 +4077,66 @@ "ARM_MUSCA_B1" ] }, + "ARM_MUSCA_S1": { + "inherits": [ + "PSA_V8_M" + ], + "default_toolchain": "ARMC6", + "features_add": [ + "EXPERIMENTAL_API" + ], + "forced_reset_timeout": 20, + "release_versions": [ + "5" + ], + "core": "Cortex-M33-NS", + "supported_toolchains": [ + "ARMC6", + "GCC_ARM" + ], + "device_has_add": [ + "INTERRUPTIN", + "I2C", + "I2CSLAVE", + "LPTICKER", + "SERIAL", + "SLEEP", + "USTICKER" + ], + "macros_add": [ + "__STARTUP_CLEAR_BSS", + "MBED_FAULT_HANDLER_DISABLED", + "CMSIS_NVIC_VIRTUAL", + "LPTICKER_DELAY_TICKS=3", + "MBED_MPU_CUSTOM", + "BL2" + ], + "extra_labels_add": [ + "ARM_SSG", + "MUSCA_S1", + "MUSCA_S1_NS" + ], + "post_binary_hook": { + "function": "ArmMuscaS1Code.binary_hook" + }, + "secure_image_filename": "tfm_s.bin", + "tfm_target_name": "MUSCA_S1", + "tfm_bootloader_supported": true, + "tfm_default_toolchain": "ARMCLANG", + "tfm_supported_toolchains": [ + "ARMCLANG", + "GNUARM" + ], + "tfm_delivery_dir": "TARGET_ARM_SSG/TARGET_MUSCA_S1", + "detect_code": [ + "5009" + ] + }, + "ARM_MUSCA_S1_NS": { + "inherits": [ + "ARM_MUSCA_S1" + ] + }, "RZ_A1XX": { "inherits": [ "Target" diff --git a/tools/targets/ARM_MUSCA_S1.py b/tools/targets/ARM_MUSCA_S1.py new file mode 100644 index 0000000..8a38a61 --- /dev/null +++ b/tools/targets/ARM_MUSCA_S1.py @@ -0,0 +1,111 @@ +#!/usr/bin/python +# Copyright (c) 2017-2020 Arm Limited +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from os.path import abspath, basename, dirname, splitext, isdir +from os.path import join as path_join +import re +from argparse import Namespace +from tools.psa.tfm.bin_utils.assemble import Assembly +from tools.psa.tfm.bin_utils.imgtool import do_sign +from tools.psa.tfm.bin_utils.imgtool_lib import version + +SCRIPT_DIR = dirname(abspath(__file__)) +MBED_OS_ROOT = abspath(path_join(SCRIPT_DIR, os.pardir, os.pardir)) +MUSCA_S1_BASE = path_join(MBED_OS_ROOT, 'targets', 'TARGET_ARM_SSG', 'TARGET_MUSCA_S1') + + +def musca_tfm_bin(t_self, non_secure_bin, secure_bin): + + assert os.path.isfile(secure_bin) + assert os.path.isfile(non_secure_bin) + + build_dir = dirname(non_secure_bin) + tempdir = path_join(build_dir, 'temp') + if not isdir(tempdir): + os.makedirs(tempdir) + flash_layout = path_join(MUSCA_S1_BASE, 'partition', 'flash_layout.h') + mcuboot_bin = path_join(MUSCA_S1_BASE, 'mcuboot.bin') + image_macros_s = path_join(MUSCA_S1_BASE, 'partition', 'image_macros_preprocessed_s.c') + image_macros_ns = path_join(MUSCA_S1_BASE, 'partition', 'image_macros_preprocessed_ns.c') + s_bin_name, s_bin_ext = splitext(basename(secure_bin)) + s_signed_bin = path_join(tempdir, s_bin_name + '_signed' + s_bin_ext) + ns_bin_name, ns_bin_ext = splitext(basename(non_secure_bin)) + ns_signed_bin = path_join(tempdir, 'tfm_' + ns_bin_name + '_signed' + ns_bin_ext) + concatenated_bin = path_join(tempdir, s_bin_name + '_' + ns_bin_name + '_concat' + ns_bin_ext) + + assert os.path.isfile(image_macros_s) + assert os.path.isfile(image_macros_ns) + + #1. Run imgtool to sign the secure binary + sign_args = Namespace( + layout=image_macros_s, + key=path_join(SCRIPT_DIR, 'musca_s1-root-rsa-3072.pem'), + public_key_format=None, + align=1, + dependencies=None, + version=version.decode_version('1.0'), + header_size=0x400, + security_counter=None, + rsa_pkcs1_15=False, + included_header=False, + infile=secure_bin, + outfile=s_signed_bin + ) + do_sign(sign_args) + + #2. Run imgtool to sign the non-secure mbed binary + sign_args = Namespace( + layout=image_macros_ns, + key=path_join(SCRIPT_DIR, 'musca_s1-root-rsa-3072_1.pem'), + public_key_format=None, + align=1, + dependencies=None, + version=version.decode_version('1.0'), + header_size=0x400, + security_counter=None, + rsa_pkcs1_15=False, + included_header=False, + infile=non_secure_bin, + outfile=ns_signed_bin + ) + do_sign(sign_args) + + #1. Concatenate signed secure TFM and non-secure mbed binaries + output = Assembly(image_macros_s, concatenated_bin) + output.add_image(s_signed_bin, "SECURE") + output.add_image(ns_signed_bin, "NON_SECURE") + + #3. Concatenate mcuboot and signed binary and overwrite mbed built binary file + mcuboot_image_size = find_bl2_size(flash_layout) + with open(mcuboot_bin, "rb") as mcuboot_fh, open(concatenated_bin, "rb") as concat_fh: + with open(non_secure_bin, "w+b") as out_fh: + out_fh.write(mcuboot_fh.read()) + out_fh.seek(mcuboot_image_size) + out_fh.write(concat_fh.read()) + + +def find_bl2_size(configFile): + bl2_size_re = re.compile(r"^#define\s+FLASH_AREA_BL2_SIZE\s+\({0,1}(0x[0-9a-fA-F]+)\){0,1}") + bl2_size = None + with open(configFile, 'r') as flash_layout_file: + for line in flash_layout_file: + m = bl2_size_re.match(line) + if m is not None: + bl2_size = int(m.group(1), 0) + break + return bl2_size diff --git a/tools/targets/__init__.py b/tools/targets/__init__.py index 79d9819..fd84399 100644 --- a/tools/targets/__init__.py +++ b/tools/targets/__init__.py @@ -711,6 +711,21 @@ ) musca_tfm_bin(t_self, binf, secure_bin) +class ArmMuscaS1Code(object): + """Musca-S1 Hooks""" + @staticmethod + def binary_hook(t_self, resources, elf, binf): + from tools.targets.ARM_MUSCA_S1 import musca_tfm_bin + configured_secure_image_filename = t_self.target.secure_image_filename + secure_bin = find_secure_image( + t_self.notify, + resources, + binf, + configured_secure_image_filename, + FileType.BIN + ) + musca_tfm_bin(t_self, binf, secure_bin) + def find_secure_image(notify, resources, ns_image_path, configured_s_image_filename, image_type): """ Find secure image. """ diff --git a/tools/targets/musca_s1-root-rsa-3072.md b/tools/targets/musca_s1-root-rsa-3072.md new file mode 100644 index 0000000..c7cccb8 --- /dev/null +++ b/tools/targets/musca_s1-root-rsa-3072.md @@ -0,0 +1,11 @@ +# Musca-S1 RSA keypair + +A default RSA key pair is given to the Musca-S1 target. + +Public keys were pre-compiled to `targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/prebuilt/mcuboot.bin` and private key is in `musca_s1-root-rsa-3072.pem` for Secure image and `musca_s1-root-rsa-3072_1.pem` for Non-Secure image. + +DO NOT use them in production code, they are exclusively for testing! + +Private key must be stored in a safe place outside of the repository. + +`tools/psa/tfm/bin_utils/imgtool.py` can be used to generate new key pairs. diff --git a/tools/targets/musca_s1-root-rsa-3072.pem b/tools/targets/musca_s1-root-rsa-3072.pem new file mode 100644 index 0000000..23288bc --- /dev/null +++ b/tools/targets/musca_s1-root-rsa-3072.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG4gIBAAKCAYEAnLrCWr/MxU8gDE9vbFFPXAqrgLhrEMSbK8RSMglLOyeUah3V +TKhcoMB2lXsmBLETfngn1gy06LAtklKK+2n/QhCqVgyDyGVuug1fjvcrKZL8Qi0t ++YD1hSGH6qxAqMvQqDvi0uzwFEgOzyuKS6TNoQVbF2Yd3m5E/kajDdBpv4ytqRZo +Uet5kSDmgQMHiUBVS+vPZ/gxxxxUTlILYOiiUAfRz84SJs2Ogo1OZKn3xyGZJQfd +xdVf9GP6zCvaBlxZZ7AGNemqkkU15aAD/xwCtcdOlEturXOdzm8Js7GPYGyi+s13 +D8wn5jZYs1L3j75JmLfpYP2XV83q0wvfokL3RNOH3uAQA5Ta/LzdvpOzSitY3JYS +8m8jujs3/vwYH3V9VAEOvj0YE7MouTQs1fvFM72HvTvkHdcCPRxyZXJDQzao+uZz +LaRh6AKcOlZNHNF2nIyqXxvrHEr1ubhvQUsnh972lB/d5vGpwgLCT6P8pANa2W94 +/YTw5f09pU0brVtLAgMBAAECggGAG786mltbctEL0PIdPVV10cs3yq2bktfjys9S +Z/ZaQcpDjbfjY9NotrLsK5GmTO1WkKzQDKaqPom2P7HqVhFRdg5CQcKscAV5IWot +sT9T/mO90i9ydLoefWfOyr6dIeUXdzlG8mWtKUIKkSXZsYOnPesXUeCryA3InCXA +RzlPB3Dt68ICTQJ9vrJO7KcvJd7kWvEQAo2frmr3B/iheBInbji8LeiDMShyIu3G +Y67tpWzu0m3+lsAsYTV0GMJosniVulaZ3hYQQazHUk+zDzMSC7zryICrpjEbgzWU +HZI9EGi1B890nwUtdhlCpkr8zoWDb0BjawpftiGz7fRm7q2TQkYAWGzNKm3DZlIS +4LsRACvHnPZ17wUSze9tqP14Pb593WR3nOTiVjrJWm+4Z5hgV3QfoEqW5swOAYl4 +6QmKZsCXAfGkozJiHnYcyaULkGBVegn1LQ5rcb8JUMribQddrHZxCVHrbgwh2zm/ +v9CYfTtpWCnKHq+wF3mwjl6w7m4JAoHBALolVbgs919Dx0xjcPnW5MSxW3ctflI9 +2ZE1BOH/Rtg5gfBwR/aToUM3a/ZgIJHQYhVty2TzUVtthtmLNTRKu2FSqWN8//GJ +wmj4bcNBshMgniHEfkutlBiP9exhdvCZX4bYpdTkJAyvOmUGjEM8QBFsod60u0z7 +Bd0EIXs7PIURP0fNAUXCgSHMPjdICLljhwHinr31VEIU2/xehw8DBIJwkR/rCsPq +xBmlIwPWVjzCRTnYUxQuxCAYf+qvgNylKQKBwQDXi3UGI7t30rYNMdIjMn1GPkhW +o62BOJNCusoXiGnbVOkj8qBayf7kPu10ONBzHcYL7+SQYeVVXQY+DH033ji8oa0J +p1xMGIlx4JZEduQYlk0ke4hUNrcBQczTRA47DmMm2kIdWlaTHtB7aCJNx72IrwWn +lVTY9TWm6+yOPcpV5JfyCMM6GqoRycikgNS5IQug5hl2pFVLw+UTfxo6msYaAOnp +ICUjoeDUKS0Z8+FtzGhAkWTk8GXIiPbfu7RoN1MCgcAcah6Poq2QKTR/AJ76REdf +jwM7SgKCY1aWx9Ua+nDCCOVA4qLZjOeM7yTX0wyltX2Db+MgYdQFdM6k3o8ckFvS +G2AoA6i+Ih0/EM0QhTK9oLkCxo/Q1YpJxY/wqWASkhb26pNF0B2Aoi7zxPAcQ1I0 +VrTO3h/JPHhEqKDDwuMWHO/f8fdDwtEba6YDokdSpVKygvlgXdaiz7RU7ckIDZne +n3hHuwVFqsyMbZzOtSUs2SrgDZmA9zKRA6xjEq9E/yECgcAnm7XecfSCGVNg61XN +J/sDTHCokx1QEKBm88ItPuEM7/aDp5M1+8Z+FN43rDUJ4l/BU8zxhzvISvbZshvU +h15vs1oD2yBHz356UaXrYNmbdwsn+BdeOku4zGmiLPBcg9FOk27wy+f60v/GnaUo +G9tFYbwtRnC4CZ9ZVCM9JDepPv9494lAhSPZbvYS3KW6e0sSvxXQynPuH0paIdIl +EMn0f1R8hW6ttJKHCiYCjeFP9u71ZoJe25oolpqfFHQbbocCgcAuBR4w3Qmnbscm +3b7fyy8n3AXa1gIfYjjPpR35qyp1K9thiLyj66YZIl0ACC/dt08lmI9/lguRoNIQ +AfjzZ8DByZa0caiSiFIMlgNZXdh7N3BUNNbIQk98Wd91gBlWDAiFEhrJKFPpRkmv +FySATPYcq0lcrjJb3IW2GDK4uo/jb4Nb7Cfog95W6T76XcSKHS5O8k1aI4kFPRsr +1wGZw64OkA8VXVaCaEBQ4brZ1YKB3mx4/tDqwn0I6bqkGRX3RJg= +-----END RSA PRIVATE KEY----- diff --git a/tools/targets/musca_s1-root-rsa-3072_1.pem b/tools/targets/musca_s1-root-rsa-3072_1.pem new file mode 100644 index 0000000..1214eb5 --- /dev/null +++ b/tools/targets/musca_s1-root-rsa-3072_1.pem @@ -0,0 +1,39 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIG5AIBAAKCAYEAv7ewn+jI0f4WHVOHl3kcFceZFmzKuC3Kwg1i+euP6ToYQ0fX +u9VivOMzY6ejqFzzI3j9LQchH7lUcCipCNpQfp6OzGhOf0gN6ifoxu+tX51GSrxp +mjBfO8FSkvi8ddQ8J3BAAKYuKH9Z5WBDEdwxCX3PL0E/tlIao0kW8rWznDz7Xiwf +Ioa9rr42Ur3E8FhpNqeAPoGzVJjkXZXtIfC6riH7xBmHVdErTwDYQVjL26maU+ls +Z8t8XfaRBnVS8sB+sWtdMEBAL9gelTwFl3/wBPBOLNU5DpQ9fAMIHQkI8o1EDc+z +lj1aduj27pNk6FfR4vULGGlv6eE9+IlJKOavuKjGQlUtwduMXbJtf/4m6nXZ/R/c +IjukG6et63HfvbQ30eu+CBAceIQcmnXEreXvcxesaXi81jeMDBQhBke9+AqsGQmd +DR1y4T4adOqG2VxKzczGlKf+2guHEbtr8DrjT4JPseSkzbxwPJ2cSfnPKG242m99 +OFdVQypzjbYY/XCnAgMBAAECggGAWmcsjuMumzMEy5RhWlB+KVkC+7uWRg41z5aP +ZwkoxdIiscs1U/nVwvsh9uqMdi5Kap45SFvVx0dVpUPPHYEQtvxems3Owh9AjHuA +PRq09uLLTB+XbmFD7wIExZAsEiXfrbs1Ovkhx+/xfIONbOUXbIHaSk6q0/bYX8nt +28pJpTFuWORWVCoUVMuWAyNANBOEnYSTqSXw4cHs4aJ6fOgup0EYHsro8dMd6HWe +BAZyrqTFxK7L8w/Vl9tWXKTDVfvlj8DHRwWBQhvS1P4XWaEcVopv7Sy4XK7UUeXm +tllsi5byGlNmr9ADK7Gd+eft/y/APyWo6SFPBLiyVLCSJ+6X4/7FwmLGYYt1WysH +/86W55qTRgtHQmb+oPBn8NYDxnYhEYFzGbpoAPD83U4CyGbnoqp5tsmssw8SfvWH +BTUdJiPjVLpHRuH1pwAyHMi+MvIVB6A8f5yWbtVwAho3Q+pIwd62aZqCpelUg9Vp +F1ssr723gQxPJqS/mwm1SfIe0GfNAoHBAMVgHdTANplIZIadWDulggjYXH5qkU+b +nB8bxv35s1Rl8iTQuD/UtxflIaLwciOl1mAfUUqG+6JH8c1OpVIaGmWKDeVThliH +tN8/OGdCPkPOFKyY8MHl83tNpsNk7P3F/WJOxCqxWziK3YoDwSr+l96XokAg/SDu +LoTax3DZPMAd2HSZuBPMGBlIbbfdkAaWzB0QJBSWv6ednt0kue+F1O/sdQ15SXoz +jGzCrEf60HIOWdAnnCCq0iT+ZeZTX1gMhQKBwQD4qVxxlSJUv+w3pGC17IN3uC3K +yq988GVqOND21RdwZ/YeYZrmORjnpXyrpJsbj9IGwYd/hpwkLe8qwOj67mZCXmND +Eca4xE7s4gtAiHXOZKXRgISEs+9giWd/8U7pczVsUwiTS77j6C7nd1f5ZgKajxJd +Tdy4bIWErCKijmpT/IEQVVYb+Ki8khTKxzbaDxWtrHv/iM+7+bgUfsKefDcO6MCb +jmhj/aOSzcmcJNfx1bdqCyxuK6iw583awBtctjsCgcEArcdwvG74I4GPsM48b1fL +48nLtipSAot5rBIi5F7Du91+k1eJwfmhs1I0iWe2txg+ZadtRXcPetRpW2CRQnZl +I12n2m/t62igoabiHFhAxiZeIZEO+UljVP8LgyILX2zBKZs8MHKzZFcvs2KW4yoB +wSQ04M2q0SGkp6iQzRUX3fbpK9BkOFoMJcaVg7t6IbMHx9b8TXxlBklLJF4/r1pg +H1ZLwS82uHdGfkPwt/dnK+Tiwtj9J+3+1D+ArIhffACZAoHBANghRLOIv41QP73h +Rxn5GA//6vVflIaQ4GUiOya/8p6GDhs8FQnUSPxXD3SVHygmqpOqtN44HxEnR8Eu +aZJpkkJPjhFmqwY/wqYMl2Eg+txJCQN+pDA/wWl0JJzFHiS1OZMM3OBCLwoi7lnL +lpC0hMDYaErm+VjnImo9v+DwziRvzbJnqe+oAuncQuw5mUiRYfNRf3mM7ZpiJAjU +YM6mAqkXzwmmDsASXpGkAn+QWo3dh41JZvXfRsF0ya0/2siLrwKBwBBX7YegsNPJ +skp5AAwYDvujDISc3aLxqEc1UHyM5SmKVt1U0/Dsyod0ZBMe27N8t9INFqy+G7hI +Y1sthsk6DyM1hSiZsLBTossJgyu3Tf3e300NTmc6CpFSRqL1L4lcSzKAGNTWvS9H +5q+MpRkZLzug83pmFw0qTWTw8p79cpELM4sklLg8L5cnLDLZyU+Gr5ZshkgpkXJI +egyV0maL40d5fDsX2ZqCZQPrQ7+FhDHKg/jf3Z3lXHwTAKBNrQGN6g== +-----END RSA PRIVATE KEY-----