From 29309f101a4828842c377ff11a3a59908aab05f2 Mon Sep 17 00:00:00 2001 From: edolomb Date: Thu, 17 Jan 2019 15:19:20 +0000 Subject: Updated SAMA drivers (still incomplete) git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12543 110e8d01-0319-4d1e-a829-52ad28d1bb01 --- os/hal/boards/ATSAMA5D27_SOM1/board.c | 289 +++++++ os/hal/boards/ATSAMA5D27_SOM1/board.h | 238 ++++++ os/hal/boards/ATSAMA5D27_SOM1/board.mk | 9 + os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.c | 165 ++++ os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.h | 232 ++++++ os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.mk | 9 + os/hal/boards/ATSAMA5D27_SOM1_SEC/board.c | 229 ++++++ os/hal/boards/ATSAMA5D27_SOM1_SEC/board.h | 236 ++++++ os/hal/boards/ATSAMA5D27_SOM1_SEC/board.mk | 9 + os/hal/ports/SAMA/LLD/CRYPTOv1/sama_aes_lld.c | 20 + os/hal/ports/SAMA/LLD/CRYPTOv1/sama_crypto_lld.c | 7 +- os/hal/ports/SAMA/LLD/CRYPTOv1/sama_gcm_lld.c | 19 + os/hal/ports/SAMA/LLD/CRYPTOv1/sama_sha_lld.c | 16 +- os/hal/ports/SAMA/LLD/CRYPTOv1/sama_tdes_lld.c | 21 + os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c | 26 +- os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h | 12 +- os/hal/ports/SAMA/LLD/I2Cv1/driver.mk | 21 + os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c | 963 +++++++++++++++++++++++ os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.h | 277 +++++++ os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c | 25 +- os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.c | 301 +++++++ os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.h | 49 +- os/hal/ports/SAMA/LLD/RNGv1/driver.mk | 9 + os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c | 175 ++++ os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.h | 113 +++ os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.c | 31 +- os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.h | 55 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c | 2 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h | 2 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c | 4 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c | 60 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_macros.h | 11 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c | 2 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h | 18 + os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c | 2 +- os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sdio.c | 2 +- os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk | 10 + os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c | 4 +- os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h | 8 +- os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c | 205 ++++- os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h | 300 ++++--- os/hal/ports/SAMA/LLD/USARTv1/hal_serial_lld.h | 2 +- os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.c | 66 +- os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.h | 20 + os/hal/ports/SAMA/LLD/xWDGv1/driver.mk | 9 + os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c | 165 ++++ os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.h | 141 ++++ os/hal/ports/SAMA/SAMA5D2x/aic.c | 310 -------- os/hal/ports/SAMA/SAMA5D2x/aic.h | 114 --- os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.c | 12 +- os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.h | 20 +- os/hal/ports/SAMA/SAMA5D2x/hal_lld.c | 10 +- os/hal/ports/SAMA/SAMA5D2x/hal_lld.h | 30 +- os/hal/ports/SAMA/SAMA5D2x/platform.mk | 12 +- os/hal/ports/SAMA/SAMA5D2x/sama_aic.c | 310 ++++++++ os/hal/ports/SAMA/SAMA5D2x/sama_aic.h | 114 +++ os/hal/ports/SAMA/SAMA5D2x/sama_cache.c | 34 +- os/hal/ports/SAMA/SAMA5D2x/sama_cache.h | 5 + os/hal/ports/SAMA/SAMA5D2x/sama_classd.c | 526 +++++++++++++ os/hal/ports/SAMA/SAMA5D2x/sama_classd.h | 301 +++++++ os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.c | 955 ++++++++++++++++++++++ os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.h | 280 +++++++ os/hal/ports/SAMA/SAMA5D2x/sama_onewire.c | 548 +++++++++++++ os/hal/ports/SAMA/SAMA5D2x/sama_onewire.h | 127 +++ os/hal/ports/SAMA/SAMA5D2x/sama_pmc.h | 480 +++++++++++ os/hal/ports/SAMA/SAMA5D2x/sama_rstc.h | 179 +++++ os/hal/ports/SAMA/SAMA5D2x/sama_secumod.c | 6 +- os/hal/ports/SAMA/SAMA5D2x/sama_secumod.h | 11 +- os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.c | 575 ++++++++++++++ os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.h | 364 +++++++++ os/hal/ports/SAMA/SAMA5D2x/sama_trng.c | 190 ----- os/hal/ports/SAMA/SAMA5D2x/sama_trng.h | 106 --- 72 files changed, 9194 insertions(+), 1014 deletions(-) create mode 100644 os/hal/boards/ATSAMA5D27_SOM1/board.c create mode 100644 os/hal/boards/ATSAMA5D27_SOM1/board.h create mode 100644 os/hal/boards/ATSAMA5D27_SOM1/board.mk create mode 100644 os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.c create mode 100644 os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.h create mode 100644 os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.mk create mode 100644 os/hal/boards/ATSAMA5D27_SOM1_SEC/board.c create mode 100644 os/hal/boards/ATSAMA5D27_SOM1_SEC/board.h create mode 100644 os/hal/boards/ATSAMA5D27_SOM1_SEC/board.mk create mode 100644 os/hal/ports/SAMA/LLD/I2Cv1/driver.mk create mode 100644 os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c create mode 100644 os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.h create mode 100644 os/hal/ports/SAMA/LLD/RNGv1/driver.mk create mode 100644 os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c create mode 100644 os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.h create mode 100644 os/hal/ports/SAMA/LLD/xWDGv1/driver.mk create mode 100644 os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c create mode 100644 os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.h delete mode 100644 os/hal/ports/SAMA/SAMA5D2x/aic.c delete mode 100644 os/hal/ports/SAMA/SAMA5D2x/aic.h create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_aic.c create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_aic.h create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_classd.c create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_classd.h create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.c create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.h create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_onewire.c create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_onewire.h create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_rstc.h create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.c create mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.h delete mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_trng.c delete mode 100644 os/hal/ports/SAMA/SAMA5D2x/sama_trng.h (limited to 'os/hal') diff --git a/os/hal/boards/ATSAMA5D27_SOM1/board.c b/os/hal/boards/ATSAMA5D27_SOM1/board.c new file mode 100644 index 000000000..76c87ed9d --- /dev/null +++ b/os/hal/boards/ATSAMA5D27_SOM1/board.c @@ -0,0 +1,289 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 "hal.h" + +#define _PIOA ((Pio*)0xFC038000U) +/* + * SAMA PIO CFGR masks. + */ +#define SAMA_PIO_FUNC_GPIO 0U +#define SAMA_PIO_FUNC_PERIPH_A 1U +#define SAMA_PIO_FUNC_PERIPH_B 2U +#define SAMA_PIO_FUNC_PERIPH_C 3U +#define SAMA_PIO_FUNC_PERIPH_D 4U +#define SAMA_PIO_FUNC_PERIPH_E 5U +#define SAMA_PIO_FUNC_PERIPH_F 6U +#define SAMA_PIO_FUNC_PERIPH_G 7U +#define SAMA_PIO_FUNC(n) (n) +#define SAMA_PIO_DIR_INPUT (0U) +#define SAMA_PIO_DIR_OUTPUT (1U << 8U) +#define SAMA_PIO_PUEN (1U << 9U) +#define SAMA_PIO_PDEN (1U << 10U) +#define SAMA_PIO_IFEN (1U << 12U) +#define SAMA_PIO_IFSCEN (1U << 13U) +#define SAMA_PIO_OPD (1U << 14U) +#define SAMA_PIO_SCHMITT (1U << 15U) +#define SAMA_PIO_DRVSTR_LO (0U << 16U) +#define SAMA_PIO_DRVSTR_ME (2U << 16U) +#define SAMA_PIO_DRVSTR_HI (3U << 16U) + +#define SAMA_PIO_LOW 0U +#define SAMA_PIO_HIGH 1U +/* + * SAMA PIO default SIOSR, MSKR and CFGR values. + */ +#define SAMA_DEFAULT_SIOSR 0x00000000U +#define SAMA_DEFAULT_SIONR 0xFFFFFFFFU +#define SAMA_DEFAULT_MSKR 0xFFFFFFFFU +#define SAMA_DEFAULT_CFGR SAMA_PIO_FUNC_GPIO | SAMA_PIO_PUEN | \ + SAMA_PIO_DIR_INPUT | SAMA_PIO_SCHMITT + +/* + * This macro converts a pin identifier to a bitmask. + */ +#define SAMA_PIN_N(n) (1U << n) + +/** + * @brief SIU/SIUL register initializer type. + */ +typedef struct { + int32_t pio_id; + uint32_t pio_msk; + uint32_t pio_cfg; + uint32_t pio_ods; +} sama_pio_init_t; + +/* + * @brief Initial setup of all defined pads. + * @note All pads are secured when SAMA_HAL_IS_SECURE is set as @p TRUE. + * @note The list is terminated by a {-1, 0, 0, 0} + */ +static const sama_pio_init_t sama_inits[] = { + /* RGB Led Red and Led Blue */ + {SAMA_PIOA, + SAMA_PIN_N(PIOA_LED_BLUE) | SAMA_PIN_N(PIOA_LED_RED), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_OUTPUT | SAMA_PIO_DRVSTR_HI, + SAMA_PIO_LOW}, + /* RGB Led Green */ + {SAMA_PIOB, + SAMA_PIN_N(PIOB_LED_GREEN), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_OUTPUT | SAMA_PIO_DRVSTR_HI, + SAMA_PIO_LOW}, + /* User Button */ + {SAMA_PIOA, + SAMA_PIN_N(PIOA_USER_PB), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_INPUT | SAMA_PIO_PUEN | SAMA_PIO_SCHMITT, + SAMA_PIO_LOW}, + /* QSPI1 */ + {SAMA_PIOB, + SAMA_PIN_N(PIOB_QSPI1_SCK) | SAMA_PIN_N(PIOB_QSPI1_CS) | + SAMA_PIN_N(PIOB_QSPI1_IO0) | SAMA_PIN_N(PIOB_QSPI1_IO1) | + SAMA_PIN_N(PIOB_QSPI1_IO2) | SAMA_PIN_N(PIOB_QSPI1_IO3), + SAMA_PIO_FUNC_PERIPH_D | SAMA_PIO_PUEN, + SAMA_PIO_HIGH}, + /* UART1 */ + {SAMA_PIOD, + SAMA_PIN_N(PIOD_URXD1) | SAMA_PIN_N(PIOD_UTXD1), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + /* UART2 */ + {SAMA_PIOD, + SAMA_PIN_N(PIOD_URXD2) | SAMA_PIN_N(PIOD_UTXD2), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + /* UART4 */ + {SAMA_PIOB, + SAMA_PIN_N(PIOB_URXD4) | SAMA_PIN_N(PIOB_UTXD4), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + /* FLEXSPI4 */ + {SAMA_PIOC, + SAMA_PIN_N(PIOC_SPI_FLEXCOM4_IO0) | + SAMA_PIN_N(PIOC_SPI_FLEXCOM4_IO1) | + SAMA_PIN_N(PIOC_SPI_FLEXCOM4_IO2) | + SAMA_PIN_N(PIOC_SPI_FLEXCOM4_IO3), + SAMA_PIO_FUNC_PERIPH_B, + SAMA_PIO_HIGH}, + {SAMA_PIOD, + SAMA_PIN_N(PIOD_SPI_FLEXCOM4_IO4), + SAMA_PIO_FUNC_PERIPH_B, + SAMA_PIO_HIGH}, + /* IRQ9 */ + {SAMA_PIOC, + SAMA_PIN_N(PIOC_IRQ9), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_INPUT | SAMA_PIO_PDEN, + SAMA_PIO_LOW}, + /* PIOD_IRQ1 Touch */ + {SAMA_PIOD, + SAMA_PIN_N(PIOD_IRQ1), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_INPUT | SAMA_PIO_PUEN | SAMA_PIO_SCHMITT, + SAMA_PIO_HIGH}, + /* LCDC */ + {SAMA_PIOB, + SAMA_PIN_N(PIOB_LCDDAT0) | SAMA_PIN_N(PIOB_LCDDAT1) | + SAMA_PIN_N(PIOB_LCDDAT2) | SAMA_PIN_N(PIOB_LCDDAT3) | + SAMA_PIN_N(PIOB_LCDDAT4) | SAMA_PIN_N(PIOB_LCDDAT5) | + SAMA_PIN_N(PIOB_LCDDAT6) | SAMA_PIN_N(PIOB_LCDDAT7) | + SAMA_PIN_N(PIOB_LCDDAT8) | SAMA_PIN_N(PIOB_LCDDAT9) | + SAMA_PIN_N(PIOB_LCDDAT10) | SAMA_PIN_N(PIOB_LCDDAT11) | + SAMA_PIN_N(PIOB_LCDDAT12) | SAMA_PIN_N(PIOB_LCDDAT13) | + SAMA_PIN_N(PIOB_LCDDAT14) | SAMA_PIN_N(PIOB_LCDDAT15) | + SAMA_PIN_N(PIOB_LCDDAT16) | SAMA_PIN_N(PIOB_LCDDAT17) | + SAMA_PIN_N(PIOB_LCDDAT18) | SAMA_PIN_N(PIOB_LCDDAT19) | + SAMA_PIN_N(PIOB_LCDDAT20), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + {SAMA_PIOC, + SAMA_PIN_N(PIOC_LCDDAT21) | SAMA_PIN_N(PIOC_LCDDAT22) | + SAMA_PIN_N(PIOC_LCDDAT23) | SAMA_PIN_N(PIOC_LCDPWM) | + SAMA_PIN_N(PIOC_LCDDISP) | SAMA_PIN_N(PIOC_LCDVSYNC) | + SAMA_PIN_N(PIOC_LCDHSYNC) | SAMA_PIN_N(PIOC_LCDPCK) | + SAMA_PIN_N(PIOC_LCDDEN), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + /* MMC Slot0 pads -J12 SD card */ + {SAMA_PIOA, + SAMA_PIN_N(PIOA_SDMMC0_CK) | SAMA_PIN_N(PIOA_SDMMC0_CMD) | + SAMA_PIN_N(PIOA_SDMMC0_DAT0) | SAMA_PIN_N(PIOA_SDMMC0_DAT1) | + SAMA_PIN_N(PIOA_SDMMC0_DAT2) | SAMA_PIN_N(PIOA_SDMMC0_DAT3) | + SAMA_PIN_N(PIOA_SDMMC0_DAT4) | SAMA_PIN_N(PIOA_SDMMC0_DAT5) | + SAMA_PIN_N(PIOA_SDMMC0_DAT6) | SAMA_PIN_N(PIOA_SDMMC0_DAT7) | + SAMA_PIN_N(PIOA_SDMMC0_WP) | SAMA_PIN_N(PIOA_SDMMC0_CD) | + SAMA_PIN_N(PIOA_SDMMC0_VDDSEL), + SAMA_PIO_FUNC_PERIPH_A | SAMA_PIO_DRVSTR_HI, + SAMA_PIO_HIGH}, + /* MMC Slot1 pads -J14 MicroSD card */ + {SAMA_PIOA, + SAMA_PIN_N(PIOA_SDMMC1_CK) | SAMA_PIN_N(PIOA_SDMMC1_CMD) | + SAMA_PIN_N(PIOA_SDMMC1_DAT0) | SAMA_PIN_N(PIOA_SDMMC1_DAT1) | + SAMA_PIN_N(PIOA_SDMMC1_DAT2) | SAMA_PIN_N(PIOA_SDMMC1_DAT3) | + SAMA_PIN_N(PIOA_SDMMC1_CD), + SAMA_PIO_FUNC_PERIPH_E | SAMA_PIO_DRVSTR_HI, + SAMA_PIO_HIGH}, + /* list terminated*/ + {-1, 0, 0, 0} +}; + +/** + * @brief Early initialization code. + * @details This initialization must be performed just after stack setup + * and before any other initialization. + */ +void __early_init(void) { + + sama_clock_init(); + /* Configures ETH's pins */ +#if SAMA_HAL_IS_SECURE + palSetGroupMode(PIOD, PAL_PORT_BIT(PIOD_ETH_GTXCK) | PAL_PORT_BIT(PIOD_ETH_GTXEN) | + PAL_PORT_BIT(PIOD_ETH_GRXDV) | PAL_PORT_BIT(PIOD_ETH_GRXER) | + PAL_PORT_BIT(PIOD_ETH_GRX0) | PAL_PORT_BIT(PIOD_ETH_GRX1) | + PAL_PORT_BIT(PIOD_ETH_GTX0) | PAL_PORT_BIT(PIOD_ETH_GTX1) | + PAL_PORT_BIT(PIOD_ETH_GMDC) | PAL_PORT_BIT(PIOD_ETH_GMDIO), + 0U, PAL_SAMA_FUNC_PERIPH_D | PAL_MODE_SECURE); +#else + palSetGroupMode(PIOD, PAL_PORT_BIT(PIOD_ETH_GTXCK) | PAL_PORT_BIT(PIOD_ETH_GTXEN) | + PAL_PORT_BIT(PIOD_ETH_GRXDV) | PAL_PORT_BIT(PIOD_ETH_GRXER) | + PAL_PORT_BIT(PIOD_ETH_GRX0) | PAL_PORT_BIT(PIOD_ETH_GRX1) | + PAL_PORT_BIT(PIOD_ETH_GTX0) | PAL_PORT_BIT(PIOD_ETH_GTX1) | + PAL_PORT_BIT(PIOD_ETH_GMDC) | PAL_PORT_BIT(PIOD_ETH_GMDIO), + 0U, PAL_SAMA_FUNC_PERIPH_D); +#endif +} + +/** + * @brief Board-specific initialization code. + */ +void boardInit(void) { + unsigned i; + +#if SAMA_HAL_IS_SECURE + /* Disabling PMC write protection. */ + pmcDisableWP(); + + /* Enabling port clock. */ + pmcEnablePIO(); + + /* Enabling write protection. */ + pmcEnableWP(); +#endif /* SAMA_HAL_IS_SECURE */ + + /* Configuring all PIO A pads with default configuration. */ +#if SAMA_HAS_PIOA +#if SAMA_HAL_IS_SECURE + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_SIOSR = SAMA_DEFAULT_SIOSR; + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_SIONR = SAMA_DEFAULT_SIONR; +#endif /* SAMA_HAL_IS_SECURE */ + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOA */ + + /* Configuring all PIO B pads with default configuration. */ +#if SAMA_HAS_PIOB +#if SAMA_HAL_IS_SECURE + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_SIOSR = SAMA_DEFAULT_SIOSR; + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_SIONR = SAMA_DEFAULT_SIONR; +#endif /* SAMA_HAL_IS_SECURE */ + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOB */ + + /* Configuring all PIO C pads with default configuration. */ +#if SAMA_HAS_PIOC +#if SAMA_HAL_IS_SECURE + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_SIOSR = SAMA_DEFAULT_SIOSR; + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_SIONR = SAMA_DEFAULT_SIONR; +#endif /* SAMA_HAL_IS_SECURE */ + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOC */ + + /* Configuring all PIO D pads with default configuration. */ +#if SAMA_HAS_PIOD +#if SAMA_HAL_IS_SECURE + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_SIOSR = SAMA_DEFAULT_SIOSR; + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_SIONR = SAMA_DEFAULT_SIONR; +#endif /* SAMA_HAL_IS_SECURE */ + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOD */ + + /* Initialize PIO registers for defined pads.*/ + i = 0; + while (sama_inits[i].pio_id != -1) { +#if SAMA_HAL_IS_SECURE + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_SIOSR = sama_inits[i].pio_msk; + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_MSKR = sama_inits[i].pio_msk; + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_CFGR = sama_inits[i].pio_cfg; + if(sama_inits[i].pio_ods == SAMA_PIO_HIGH) { + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_SODR = sama_inits[i].pio_msk; + } + else { + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_CODR = sama_inits[i].pio_msk; + } +#else + _PIOA->PIO_IO_GROUP[sama_inits[i].pio_id].PIO_MSKR = sama_inits[i].pio_msk; + _PIOA->PIO_IO_GROUP[sama_inits[i].pio_id].PIO_CFGR = sama_inits[i].pio_cfg; + if(sama_inits[i].pio_ods == SAMA_PIO_HIGH) { + _PIOA->PIO_IO_GROUP[sama_inits[i].pio_id].PIO_SODR = sama_inits[i].pio_msk; + } + else { + _PIOA->PIO_IO_GROUP[sama_inits[i].pio_id].PIO_CODR = sama_inits[i].pio_msk; + } +#endif /* SAMA_HAL_IS_SECURE */ + i++; + } +} diff --git a/os/hal/boards/ATSAMA5D27_SOM1/board.h b/os/hal/boards/ATSAMA5D27_SOM1/board.h new file mode 100644 index 000000000..78b37e07a --- /dev/null +++ b/os/hal/boards/ATSAMA5D27_SOM1/board.h @@ -0,0 +1,238 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 _BOARD_H_ +#define _BOARD_H_ + +/* + * Setup for Atmel SAM A5 D27 SOM1-EK1 board. + */ + +/* + * Board identifier. + */ +#define BOARD_ATSAM5D27_SOM1 +#define BOARD_NAME "Atmel SAM A5 D27 SOM1 evaluation kit 1" + +/* + * Ethernet PHY type. + */ +#define BOARD_PHY_ID MII_KSZ8081_ID +#define BOARD_PHY_RMII + +/* + * Board oscillators-related settings. + */ +#if !defined(SAMA_OSCXTCLK) +#define SAMA_OSCXTCLK 32768U +#endif + +#if !defined(SAMA_MOSCXTCLK) +#define SAMA_MOSCXTCLK 24000000U +#endif + +/* + * MCU type as defined in the Atmel header. + */ +#define SAMA5D27 + +/** + * Port identifiers. + */ +#define SAMA_PIOA 0U +#define SAMA_PIOB 1U +#define SAMA_PIOC 2U +#define SAMA_PIOD 3U + +/* + * Forms a line identifier. In this driver the pad number is encoded in the + * lower 5 bits of line and the port in sixth and seventh bits. + */ +#define SAMA_LINE(port, pad) \ + ((uint32_t)((uint32_t)(port << 5U)) | ((uint32_t)(pad))) + +/* + * Decodes a port identifier from a line identifier. + */ +#define SAMA_PORT(line) \ + ((uint32_t)((line & 0xFFFFFFE0U) >> 5U) + +/** + * Decodes a pad identifier from a line identifier. + */ +#define SAMA_PAD(line) \ + ((uint32_t)(line & 0x0000001FU)) + + +/* + * IO pins assignments. + */ +#define PIOA_SDMMC0_CK 0U +#define PIOA_SDMMC0_CMD 1U +#define PIOA_SDMMC0_DAT0 2U +#define PIOA_SDMMC0_DAT1 3U +#define PIOA_SDMMC0_DAT2 4U +#define PIOA_SDMMC0_DAT3 5U +#define PIOA_SDMMC0_DAT4 6U +#define PIOA_SDMMC0_DAT5 7U +#define PIOA_SDMMC0_DAT6 8U +#define PIOA_SDMMC0_DAT7 9U +#define PIOA_LED_RED 10U +#define PIOA_SDMMC0_VDDSEL 11U +#define PIOA_SDMMC0_WP 12U +#define PIOA_SDMMC0_CD 13U +#define PIOA_PIN14 14U +#define PIOA_PIN15 15U +#define PIOA_PIN16 16U +#define PIOA_ONEWIRE 17U +#define PIOA_SDMMC1_DAT0 18U +#define PIOA_SDMMC1_DAT1 19U +#define PIOA_SDMMC1_DAT2 20U +#define PIOA_SDMMC1_DAT3 21U +#define PIOA_SDMMC1_CK 22U +#define PIOA_PIN23 23U +#define PIOA_PIN24 24U +#define PIOA_PIN25 25U +#define PIOA_PIN26 26U +#define PIOA_PIN27 27U +#define PIOA_SDMMC1_CMD 28U +#define PIOA_USER_PB 29U +#define PIOA_SDMMC1_CD 30U +#define PIOA_LED_BLUE 31U + +#define PIOB_PIN0 0U +#define PIOB_LED_GREEN 1U +#define PIOB_PIN2 2U +#define PIOB_URXD4 3U +#define PIOB_UTXD4 4U +#define PIOB_QSPI1_SCK 5U +#define PIOB_QSPI1_CS 6U +#define PIOB_QSPI1_IO0 7U +#define PIOB_QSPI1_IO1 8U +#define PIOB_QSPI1_IO2 9U +#define PIOB_QSPI1_IO3 10U +#define PIOB_LCDDAT0 11U +#define PIOB_LCDDAT1 12U +#define PIOB_LCDDAT2 13U +#define PIOB_LCDDAT3 14U +#define PIOB_LCDDAT4 15U +#define PIOB_LCDDAT5 16U +#define PIOB_LCDDAT6 17U +#define PIOB_LCDDAT7 18U +#define PIOB_LCDDAT8 19U +#define PIOB_LCDDAT9 20U +#define PIOB_LCDDAT10 21U +#define PIOB_LCDDAT11 22U +#define PIOB_LCDDAT12 23U +#define PIOB_LCDDAT13 24U +#define PIOB_LCDDAT14 25U +#define PIOB_LCDDAT15 26U +#define PIOB_LCDDAT16 27U +#define PIOB_LCDDAT17 28U +#define PIOB_LCDDAT18 29U +#define PIOB_LCDDAT19 30U +#define PIOB_LCDDAT20 31U + +#define PIOC_LCDDAT21 0U +#define PIOC_LCDDAT22 1U +#define PIOC_LCDDAT23 2U +#define PIOC_LCDPWM 3U +#define PIOC_LCDDISP 4U +#define PIOC_LCDVSYNC 5U +#define PIOC_LCDHSYNC 6U +#define PIOC_LCDPCK 7U +#define PIOC_LCDDEN 8U +#define PIOC_IRQ9 9U +#define PIOC_PIN10 10U +#define PIOC_PIN11 11U +#define PIOC_PIN12 12U +#define PIOC_PIN13 13U +#define PIOC_PIN14 14U +#define PIOC_PIN15 15U +#define PIOC_PIN16 16U +#define PIOC_PIN17 17U +#define PIOC_PIN18 18U +#define PIOC_PIN19 19U +#define PIOC_PIN20 20U +#define PIOC_PIN21 21U +#define PIOC_PIN22 22U +#define PIOC_PIN23 23U +#define PIOC_PIN24 24U +#define PIOC_PIN25 25U +#define PIOC_PIN26 26U +#define PIOC_PIN27 27U +#define PIOC_SPI_FLEXCOM4_IO0 28U +#define PIOC_SPI_FLEXCOM4_IO1 29U +#define PIOC_SPI_FLEXCOM4_IO2 30U +#define PIOC_SPI_FLEXCOM4_IO3 31U + +#define PIOD_SPI_FLEXCOM4_IO4 0U +#define PIOD_IRQ1 1U +#define PIOD_URXD1 2U +#define PIOD_UTXD1 3U +#define PIOD_TWD1 4U +#define PIOD_TWCK1 5U +#define PIOD_PIO6 6U +#define PIOD_PIO7 7U +#define PIOD_PIN8 8U +#define PIOD_ETH_GTXCK 9U +#define PIOD_ETH_GTXEN 10U +#define PIOD_ETH_GRXDV 11U +#define PIOD_ETH_GRXER 12U +#define PIOD_ETH_GRX0 13U +#define PIOD_ETH_GRX1 14U +#define PIOD_ETH_GTX0 15U +#define PIOD_ETH_GTX1 16U +#define PIOD_ETH_GMDC 17U +#define PIOD_ETH_GMDIO 18U +#define PIOD_PIO19 19U +#define PIOD_PIO20 20U +#define PIOD_PIO21 21U +#define PIOD_PIO22 22U +#define PIOD_URXD2 23U +#define PIOD_UTXD2 24U +#define PIOD_PIO25 25U +#define PIOD_PIO26 26U +#define PIOD_PIO27 27U +#define PIOD_PIO28 28U +#define PIOD_PIO29 29U +#define PIOD_PIN30 30U +#define PIOD_PIN31 31U + +/* + * IO lines assignments. + */ +#define BOARD_LINE(port, pad) \ + ((uint32_t)((uint32_t)(port)) | ((uint32_t)(pad))) + +#define LINE_LED_BLUE BOARD_LINE(PIOA, 31U) +#define LINE_LED_GREEN BOARD_LINE(PIOB, 1U) +#define LINE_LED_RED BOARD_LINE(PIOA, 10U) +#define LINE_USER_PB BOARD_LINE(PIOA, 29U) +#define LINE_IRQ9 BOARD_LINE(PIOC, 9U) +#define LINE_ONEWIRE BOARD_LINE(PIOA, 17U) + +#if !defined(_FROM_ASM_) +#ifdef __cplusplus +extern "C" { +#endif + void boardInit(void); +#ifdef __cplusplus +} +#endif +#endif /* _FROM_ASM_ */ + +#endif /* _BOARD_H_ */ diff --git a/os/hal/boards/ATSAMA5D27_SOM1/board.mk b/os/hal/boards/ATSAMA5D27_SOM1/board.mk new file mode 100644 index 000000000..88d45be90 --- /dev/null +++ b/os/hal/boards/ATSAMA5D27_SOM1/board.mk @@ -0,0 +1,9 @@ +# List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/ATSAMA5D27_SOM1/board.c + +# Required include directories +BOARDINC = $(CHIBIOS)/os/hal/boards/ATSAMA5D27_SOM1 + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.c b/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.c new file mode 100644 index 000000000..74498464e --- /dev/null +++ b/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.c @@ -0,0 +1,165 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 "hal.h" + +#define _PIOA ((Pio*)0xFC038000U) +/* + * SAMA PIO CFGR masks. + */ +#define SAMA_PIO_FUNC_GPIO 0U +#define SAMA_PIO_FUNC_PERIPH_A 1U +#define SAMA_PIO_FUNC_PERIPH_B 2U +#define SAMA_PIO_FUNC_PERIPH_C 3U +#define SAMA_PIO_FUNC_PERIPH_D 4U +#define SAMA_PIO_FUNC_PERIPH_E 5U +#define SAMA_PIO_FUNC_PERIPH_F 6U +#define SAMA_PIO_FUNC_PERIPH_G 7U +#define SAMA_PIO_FUNC(n) (n) +#define SAMA_PIO_DIR_INPUT (0U) +#define SAMA_PIO_DIR_OUTPUT (1U << 8U) +#define SAMA_PIO_PUEN (1U << 9U) +#define SAMA_PIO_PDEN (1U << 10U) +#define SAMA_PIO_IFEN (1U << 12U) +#define SAMA_PIO_IFSCEN (1U << 13U) +#define SAMA_PIO_OPD (1U << 14U) +#define SAMA_PIO_SCHMITT (1U << 15U) +#define SAMA_PIO_DRVSTR_LO (0U << 16U) +#define SAMA_PIO_DRVSTR_ME (2U << 16U) +#define SAMA_PIO_DRVSTR_HI (3U << 16U) + +#define SAMA_PIO_LOW 0U +#define SAMA_PIO_HIGH 1U +/* + * SAMA PIO default SIOSR, MSKR and CFGR values. + */ +#define SAMA_DEFAULT_SIOSR 0x00000000U +#define SAMA_DEFAULT_SIONR 0xFFFFFFFFU +#define SAMA_DEFAULT_MSKR 0xFFFFFFFFU +#define SAMA_DEFAULT_CFGR SAMA_PIO_FUNC_GPIO | SAMA_PIO_PUEN | \ + SAMA_PIO_DIR_INPUT | SAMA_PIO_SCHMITT + +/* + * This macro converts a pin identifier to a bitmask. + */ +#define SAMA_PIN_N(n) (1U << n) + +/** + * @brief SIU/SIUL register initializer type. + */ +typedef struct { + int32_t pio_id; + uint32_t pio_msk; + uint32_t pio_cfg; + uint32_t pio_ods; +} sama_pio_init_t; + +/* + * @brief Initial setup of all defined pads. + * @note The list is terminated by a {-1, 0, 0, 0} + */ +static const sama_pio_init_t sama_inits[] = { + /* RGB Led Red */ + {SAMA_PIOA, + SAMA_PIN_N(PIOA_LED_RED), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_OUTPUT | SAMA_PIO_DRVSTR_HI, + SAMA_PIO_LOW}, + /* UART1 */ + {SAMA_PIOD, + SAMA_PIN_N(PIOD_URXD1) | SAMA_PIN_N(PIOD_UTXD1), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + /* UART2 */ + {SAMA_PIOD, + SAMA_PIN_N(PIOD_URXD2) | SAMA_PIN_N(PIOD_UTXD2), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + /* MMC Slot0 pads -J12 SD card */ + {SAMA_PIOA, + SAMA_PIN_N(PIOA_SDMMC0_CK) | SAMA_PIN_N(PIOA_SDMMC0_CMD) | + SAMA_PIN_N(PIOA_SDMMC0_DAT0) | SAMA_PIN_N(PIOA_SDMMC0_DAT1) | + SAMA_PIN_N(PIOA_SDMMC0_DAT2) | SAMA_PIN_N(PIOA_SDMMC0_DAT3) | + SAMA_PIN_N(PIOA_SDMMC0_DAT4) | SAMA_PIN_N(PIOA_SDMMC0_DAT5) | + SAMA_PIN_N(PIOA_SDMMC0_DAT6) | SAMA_PIN_N(PIOA_SDMMC0_DAT7) | + SAMA_PIN_N(PIOA_SDMMC0_WP) | SAMA_PIN_N(PIOA_SDMMC0_CD) | + SAMA_PIN_N(PIOA_SDMMC0_VDDSEL), + SAMA_PIO_FUNC_PERIPH_A | SAMA_PIO_DRVSTR_HI, + SAMA_PIO_HIGH}, + /* list terminated*/ + {-1, 0, 0, 0} +}; + +/** + * @brief Early initialization code. + * @details This initialization must be performed just after stack setup + * and before any other initialization. + */ +void __early_init(void) { + + sama_clock_init(); + /* Configures ETH's pins */ + palSetGroupMode(PIOD, PAL_PORT_BIT(PIOD_ETH_GTXCK) | PAL_PORT_BIT(PIOD_ETH_GTXEN) | + PAL_PORT_BIT(PIOD_ETH_GRXDV) | PAL_PORT_BIT(PIOD_ETH_GRXER) | + PAL_PORT_BIT(PIOD_ETH_GRX0) | PAL_PORT_BIT(PIOD_ETH_GRX1) | + PAL_PORT_BIT(PIOD_ETH_GTX0) | PAL_PORT_BIT(PIOD_ETH_GTX1) | + PAL_PORT_BIT(PIOD_ETH_GMDC) | PAL_PORT_BIT(PIOD_ETH_GMDIO), + 0U, PAL_SAMA_FUNC_PERIPH_D); +} + +/** + * @brief Board-specific initialization code. + */ +void boardInit(void) { + unsigned i; + + /* Configuring all PIO A pads with default configuration. */ +#if SAMA_HAS_PIOA + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOA */ + + /* Configuring all PIO B pads with default configuration. */ +#if SAMA_HAS_PIOB + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOB */ + + /* Configuring all PIO C pads with default configuration. */ +#if SAMA_HAS_PIOC + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOC */ + + /* Configuring all PIO D pads with default configuration. */ +#if SAMA_HAS_PIOD + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOD */ + + /* Initialize PIO registers for defined pads.*/ + i = 0; + while (sama_inits[i].pio_id != -1) { + _PIOA->PIO_IO_GROUP[sama_inits[i].pio_id].PIO_MSKR = sama_inits[i].pio_msk; + _PIOA->PIO_IO_GROUP[sama_inits[i].pio_id].PIO_CFGR = sama_inits[i].pio_cfg; + if(sama_inits[i].pio_ods == SAMA_PIO_HIGH) { + _PIOA->PIO_IO_GROUP[sama_inits[i].pio_id].PIO_SODR = sama_inits[i].pio_msk; + } + else { + _PIOA->PIO_IO_GROUP[sama_inits[i].pio_id].PIO_CODR = sama_inits[i].pio_msk; + } + i++; + } +} diff --git a/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.h b/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.h new file mode 100644 index 000000000..a22cc1051 --- /dev/null +++ b/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.h @@ -0,0 +1,232 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 _BOARD_H_ +#define _BOARD_H_ + +/* + * Setup for Atmel SAM A5 D27 SOM1-EK1 board. + */ + +/* + * Board identifier. + */ +#define BOARD_ATSAM5D27_SOM1 +#define BOARD_NAME "Atmel SAM A5 D27 SOM1 evaluation kit 1" + +/* + * Ethernet PHY type. + */ +#define BOARD_PHY_ID MII_KSZ8081_ID +#define BOARD_PHY_RMII + +/* + * Board oscillators-related settings. + */ +#if !defined(SAMA_OSCXTCLK) +#define SAMA_OSCXTCLK 32768U +#endif + +#if !defined(SAMA_MOSCXTCLK) +#define SAMA_MOSCXTCLK 24000000U +#endif + +/* + * MCU type as defined in the Atmel header. + */ +#define SAMA5D27 + +/** + * Port identifiers. + */ +#define SAMA_PIOA 0U +#define SAMA_PIOB 1U +#define SAMA_PIOC 2U +#define SAMA_PIOD 3U + +/* + * Forms a line identifier. In this driver the pad number is encoded in the + * lower 5 bits of line and the port in sixth and seventh bits. + */ +#define SAMA_LINE(port, pad) \ + ((uint32_t)((uint32_t)(port << 5U)) | ((uint32_t)(pad))) + +/* + * Decodes a port identifier from a line identifier. + */ +#define SAMA_PORT(line) \ + ((uint32_t)((line & 0xFFFFFFE0U) >> 5U) + +/** + * Decodes a pad identifier from a line identifier. + */ +#define SAMA_PAD(line) \ + ((uint32_t)(line & 0x0000001FU)) + +/* + * IO pins assignments. + */ +#define PIOA_SDMMC0_CK 0U +#define PIOA_SDMMC0_CMD 1U +#define PIOA_SDMMC0_DAT0 2U +#define PIOA_SDMMC0_DAT1 3U +#define PIOA_SDMMC0_DAT2 4U +#define PIOA_SDMMC0_DAT3 5U +#define PIOA_SDMMC0_DAT4 6U +#define PIOA_SDMMC0_DAT5 7U +#define PIOA_SDMMC0_DAT6 8U +#define PIOA_SDMMC0_DAT7 9U +#define PIOA_LED_RED 10U +#define PIOA_SDMMC0_VDDSEL 11U +#define PIOA_SDMMC0_WP 12U +#define PIOA_SDMMC0_CD 13U +#define PIOA_PIN14 14U +#define PIOA_PIN15 15U +#define PIOA_PIN16 16U +#define PIOA_PIN17 17U +#define PIOA_PIN18 18U +#define PIOA_PIN19 19U +#define PIOA_PIN20 20U +#define PIOA_PIN21 21U +#define PIOA_PIN22 22U +#define PIOA_PIN23 23U +#define PIOA_PIN24 24U +#define PIOA_PIN25 25U +#define PIOA_PIN26 26U +#define PIOA_PIN27 27U +#define PIOA_PIN28 28U +#define PIOA_PIN29 29U +#define PIOA_PIN30 30U +#define PIOA_PIN31 31U + +#define PIOB_PIN0 0U +#define PIOB_PIN1 1U +#define PIOB_PIN2 2U +#define PIOB_PIN3 3U +#define PIOB_PIN4 4U +#define PIOB_PIN5 5U +#define PIOB_PIN6 6U +#define PIOB_PIN7 7U +#define PIOB_PIN8 8U +#define PIOB_PIN9 9U +#define PIOB_PIN10 10U +#define PIOB_PIN11 11U +#define PIOB_PIN12 12U +#define PIOB_PIN13 13U +#define PIOB_PIN14 14U +#define PIOB_PIN15 15U +#define PIOB_PIN16 16U +#define PIOB_PIN17 17U +#define PIOB_PIN18 18U +#define PIOB_PIN19 19U +#define PIOB_PIN20 20U +#define PIOB_PIN21 21U +#define PIOB_PIN22 22U +#define PIOB_PIN23 23U +#define PIOB_PIN24 24U +#define PIOB_PIN25 25U +#define PIOB_PIN26 26U +#define PIOB_PIN27 27U +#define PIOB_PIN28 28U +#define PIOB_PIN29 29U +#define PIOB_PIN30 30U +#define PIOB_PIN31 31U + +#define PIOC_PIN0 0U +#define PIOC_PIN1 1U +#define PIOC_PIN2 2U +#define PIOC_PIN3 3U +#define PIOC_PIN4 4U +#define PIOC_PIN5 5U +#define PIOC_PIN6 6U +#define PIOC_PIN7 7U +#define PIOC_PIN8 8U +#define PIOC_PIN9 9U +#define PIOC_PIN10 10U +#define PIOC_PIN11 11U +#define PIOC_PIN12 12U +#define PIOC_PIN13 13U +#define PIOC_PIN14 14U +#define PIOC_PIN15 15U +#define PIOC_PIN16 16U +#define PIOC_PIN17 17U +#define PIOC_PIN18 18U +#define PIOC_PIN19 19U +#define PIOC_PIN20 20U +#define PIOC_PIN21 21U +#define PIOC_PIN22 22U +#define PIOC_PIN23 23U +#define PIOC_PIN24 24U +#define PIOC_PIN25 25U +#define PIOC_PIN26 26U +#define PIOC_PIN27 27U +#define PIOC_PIN28 28U +#define PIOC_PIN29 29U +#define PIOC_PIN30 30U +#define PIOC_PIN31 31U + +#define PIOD_PIO0 0U +#define PIOD_PIN1 1U +#define PIOD_URXD1 2U +#define PIOD_UTXD1 3U +#define PIOD_PIO4 4U +#define PIOD_PIO5 5U +#define PIOD_PIO6 6U +#define PIOD_PIO7 7U +#define PIOD_PIN8 8U +#define PIOD_ETH_GTXCK 9U +#define PIOD_ETH_GTXEN 10U +#define PIOD_ETH_GRXDV 11U +#define PIOD_ETH_GRXER 12U +#define PIOD_ETH_GRX0 13U +#define PIOD_ETH_GRX1 14U +#define PIOD_ETH_GTX0 15U +#define PIOD_ETH_GTX1 16U +#define PIOD_ETH_GMDC 17U +#define PIOD_ETH_GMDIO 18U +#define PIOD_PIO19 19U +#define PIOD_PIO20 20U +#define PIOD_PIO21 21U +#define PIOD_PIO22 22U +#define PIOD_URXD2 23U +#define PIOD_UTXD2 24U +#define PIOD_PIO25 25U +#define PIOD_PIO26 26U +#define PIOD_PIO27 27U +#define PIOD_PIO28 28U +#define PIOD_PIO29 29U +#define PIOD_PIN30 30U +#define PIOD_PIN31 31U + +/* + * IO lines assignments. + */ +#define BOARD_LINE(port, pad) \ + ((uint32_t)((uint32_t)(port)) | ((uint32_t)(pad))) + +#define LINE_LED_RED BOARD_LINE(PIOA, 10U) + +#if !defined(_FROM_ASM_) +#ifdef __cplusplus +extern "C" { +#endif + void boardInit(void); +#ifdef __cplusplus +} +#endif +#endif /* _FROM_ASM_ */ + +#endif /* _BOARD_H_ */ diff --git a/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.mk b/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.mk new file mode 100644 index 000000000..fbc9baba7 --- /dev/null +++ b/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.mk @@ -0,0 +1,9 @@ +# List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.c + +# Required include directories +BOARDINC = $(CHIBIOS)/os/hal/boards/ATSAMA5D27_SOM1_NSEC + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.c b/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.c new file mode 100644 index 000000000..d07ee39e7 --- /dev/null +++ b/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.c @@ -0,0 +1,229 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 "hal.h" + +#define _PIOA ((Pio*)0xFC038000U) + +/*===========================================================================*/ +/* Configuration checks. */ +/*===========================================================================*/ + +#if !SAMA_HAL_IS_SECURE +#error "SAMA PROJECT REQUIRES SECURE CONFIGURATION" +#endif + +/* + * SAMA PIO CFGR masks. + */ +#define SAMA_PIO_FUNC_GPIO 0U +#define SAMA_PIO_FUNC_PERIPH_A 1U +#define SAMA_PIO_FUNC_PERIPH_B 2U +#define SAMA_PIO_FUNC_PERIPH_C 3U +#define SAMA_PIO_FUNC_PERIPH_D 4U +#define SAMA_PIO_FUNC_PERIPH_E 5U +#define SAMA_PIO_FUNC_PERIPH_F 6U +#define SAMA_PIO_FUNC_PERIPH_G 7U +#define SAMA_PIO_FUNC(n) (n) +#define SAMA_PIO_DIR_INPUT (0U) +#define SAMA_PIO_DIR_OUTPUT (1U << 8U) +#define SAMA_PIO_PUEN (1U << 9U) +#define SAMA_PIO_PDEN (1U << 10U) +#define SAMA_PIO_IFEN (1U << 12U) +#define SAMA_PIO_IFSCEN (1U << 13U) +#define SAMA_PIO_OPD (1U << 14U) +#define SAMA_PIO_SCHMITT (1U << 15U) +#define SAMA_PIO_DRVSTR_LO (0U << 16U) +#define SAMA_PIO_DRVSTR_ME (2U << 16U) +#define SAMA_PIO_DRVSTR_HI (3U << 16U) + +#define SAMA_PIO_LOW 0U +#define SAMA_PIO_HIGH 1U +/* + * SAMA PIO default SIOSR, MSKR and CFGR values. + */ +#define SAMA_DEFAULT_SIOSR 0x00000000U +#define SAMA_DEFAULT_SIONR 0xFFFFFFFFU +#define SAMA_DEFAULT_MSKR 0xFFFFFFFFU +#define SAMA_DEFAULT_CFGR SAMA_PIO_FUNC_GPIO | SAMA_PIO_PUEN | \ + SAMA_PIO_DIR_INPUT | SAMA_PIO_SCHMITT + +/* + * This macro converts a pin identifier to a bitmask. + */ +#define SAMA_PIN_N(n) (1U << n) + +/** + * @brief SIU/SIUL register initializer type. + */ +typedef struct { + int32_t pio_id; + uint32_t pio_msk; + uint32_t pio_cfg; + uint32_t pio_ods; +} sama_pio_init_t; + +/* + * @brief Initial setup of all defined pads. + * @note All pads are secured. + * @note The list is terminated by a {-1, 0, 0, 0} + */ +static const sama_pio_init_t sama_inits[] = { + /* RGB Led Blue */ + {SAMA_PIOA, + SAMA_PIN_N(PIOA_LED_BLUE), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_OUTPUT | SAMA_PIO_DRVSTR_HI, + SAMA_PIO_LOW}, + /* User Button */ + {SAMA_PIOA, + SAMA_PIN_N(PIOA_USER_PB), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_INPUT | SAMA_PIO_PUEN | SAMA_PIO_SCHMITT, + SAMA_PIO_LOW}, + /* QSPI1 */ + {SAMA_PIOB, + SAMA_PIN_N(PIOB_QSPI1_SCK) | SAMA_PIN_N(PIOB_QSPI1_CS) | + SAMA_PIN_N(PIOB_QSPI1_IO0) | SAMA_PIN_N(PIOB_QSPI1_IO1) | + SAMA_PIN_N(PIOB_QSPI1_IO2) | SAMA_PIN_N(PIOB_QSPI1_IO3), + SAMA_PIO_FUNC_PERIPH_D | SAMA_PIO_PUEN, + SAMA_PIO_HIGH}, + /* UART4 */ + {SAMA_PIOB, + SAMA_PIN_N(PIOB_URXD4) | SAMA_PIN_N(PIOB_UTXD4), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + /* FLEXSPI4 */ + {SAMA_PIOC, + SAMA_PIN_N(PIOC_SPI_FLEXCOM4_IO0) | + SAMA_PIN_N(PIOC_SPI_FLEXCOM4_IO1) | + SAMA_PIN_N(PIOC_SPI_FLEXCOM4_IO2) | + SAMA_PIN_N(PIOC_SPI_FLEXCOM4_IO3), + SAMA_PIO_FUNC_PERIPH_B, + SAMA_PIO_HIGH}, + {SAMA_PIOD, + SAMA_PIN_N(PIOD_SPI_FLEXCOM4_IO4), + SAMA_PIO_FUNC_PERIPH_B, + SAMA_PIO_HIGH}, + /* IRQ9 */ + {SAMA_PIOC, + SAMA_PIN_N(PIOC_IRQ9), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_INPUT | SAMA_PIO_PUEN | SAMA_PIO_SCHMITT, + SAMA_PIO_LOW}, + /* PIOD_IRQ1 Touch */ + {SAMA_PIOD, + SAMA_PIN_N(PIOD_IRQ1), + SAMA_PIO_FUNC_GPIO | SAMA_PIO_DIR_INPUT | SAMA_PIO_PUEN | SAMA_PIO_SCHMITT, + SAMA_PIO_HIGH}, + /* LCDC */ + {SAMA_PIOB, + SAMA_PIN_N(PIOB_LCDDAT0) | SAMA_PIN_N(PIOB_LCDDAT1) | + SAMA_PIN_N(PIOB_LCDDAT2) | SAMA_PIN_N(PIOB_LCDDAT3) | + SAMA_PIN_N(PIOB_LCDDAT4) | SAMA_PIN_N(PIOB_LCDDAT5) | + SAMA_PIN_N(PIOB_LCDDAT6) | SAMA_PIN_N(PIOB_LCDDAT7) | + SAMA_PIN_N(PIOB_LCDDAT8) | SAMA_PIN_N(PIOB_LCDDAT9) | + SAMA_PIN_N(PIOB_LCDDAT10) | SAMA_PIN_N(PIOB_LCDDAT11) | + SAMA_PIN_N(PIOB_LCDDAT12) | SAMA_PIN_N(PIOB_LCDDAT13) | + SAMA_PIN_N(PIOB_LCDDAT14) | SAMA_PIN_N(PIOB_LCDDAT15) | + SAMA_PIN_N(PIOB_LCDDAT16) | SAMA_PIN_N(PIOB_LCDDAT17) | + SAMA_PIN_N(PIOB_LCDDAT18) | SAMA_PIN_N(PIOB_LCDDAT19) | + SAMA_PIN_N(PIOB_LCDDAT20), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + {SAMA_PIOC, + SAMA_PIN_N(PIOC_LCDDAT21) | SAMA_PIN_N(PIOC_LCDDAT22) | + SAMA_PIN_N(PIOC_LCDDAT23) | SAMA_PIN_N(PIOC_LCDPWM) | + SAMA_PIN_N(PIOC_LCDDISP) | SAMA_PIN_N(PIOC_LCDVSYNC) | + SAMA_PIN_N(PIOC_LCDHSYNC) | SAMA_PIN_N(PIOC_LCDPCK) | + SAMA_PIN_N(PIOC_LCDDEN), + SAMA_PIO_FUNC_PERIPH_A, + SAMA_PIO_HIGH}, + /* list terminated*/ + {-1, 0, 0, 0} +}; + +/** + * @brief Early initialization code. + * @details This initialization must be performed just after stack setup + * and before any other initialization. + */ +void __early_init(void) { + + sama_clock_init(); +} + +/** + * @brief Board-specific initialization code. + */ +void boardInit(void) { + unsigned i; + + /* Disabling PMC write protection. */ + pmcDisableWP(); + + /* Enabling port clock. */ + pmcEnablePIO(); + + /* Enabling write protection. */ + pmcEnableWP(); + + _PIOA->S_PIO_WPMR = PIO_WPMR_WPKEY_PASSWD; + + /* Configuring all PIO A pads with default configuration. */ +#if SAMA_HAS_PIOA + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_SIOSR = SAMA_DEFAULT_SIOSR; + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_SIONR = SAMA_DEFAULT_SIONR; + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOA].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOA */ + + /* Configuring all PIO B pads with default configuration. */ +#if SAMA_HAS_PIOB + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_SIOSR = SAMA_DEFAULT_SIOSR; + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_SIONR = SAMA_DEFAULT_SIONR; + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOB].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOB */ + + /* Configuring all PIO C pads with default configuration. */ +#if SAMA_HAS_PIOC + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_SIOSR = SAMA_DEFAULT_SIOSR; + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_SIONR = SAMA_DEFAULT_SIONR; + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOC].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOC */ + + /* Configuring all PIO D pads with default configuration. */ +#if SAMA_HAS_PIOD + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_SIOSR = SAMA_DEFAULT_SIOSR; + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_SIONR = SAMA_DEFAULT_SIONR; + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_MSKR = SAMA_DEFAULT_MSKR; + _PIOA->PIO_PIO_[SAMA_PIOD].S_PIO_CFGR = SAMA_DEFAULT_CFGR; +#endif /* SAMA_HAS_PIOD */ + + /* Initialize PIO registers for defined pads.*/ + i = 0; + while (sama_inits[i].pio_id != -1) { + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_SIOSR = sama_inits[i].pio_msk; + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_MSKR = sama_inits[i].pio_msk; + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_CFGR = sama_inits[i].pio_cfg; + if(sama_inits[i].pio_ods == SAMA_PIO_HIGH) { + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_SODR = sama_inits[i].pio_msk; + } + else { + _PIOA->PIO_PIO_[sama_inits[i].pio_id].S_PIO_CODR = sama_inits[i].pio_msk; + } + i++; + } +} diff --git a/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.h b/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.h new file mode 100644 index 000000000..5e7ffb214 --- /dev/null +++ b/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.h @@ -0,0 +1,236 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 _BOARD_H_ +#define _BOARD_H_ + +/* + * Setup for Atmel SAM A5 D27 SOM1-EK1 board. + */ + +/* + * Board identifier. + */ +#define BOARD_ATSAM5D27_SOM1 +#define BOARD_NAME "Atmel SAM A5 D27 SOM1 evaluation kit 1" + +/* + * Ethernet PHY type. + */ +#define BOARD_PHY_ID MII_KSZ8081_ID +#define BOARD_PHY_RMII + +/* + * Board oscillators-related settings. + */ +#if !defined(SAMA_OSCXTCLK) +#define SAMA_OSCXTCLK 32768U +#endif + +#if !defined(SAMA_MOSCXTCLK) +#define SAMA_MOSCXTCLK 24000000U +#endif + +/* + * MCU type as defined in the Atmel header. + */ +#define SAMA5D27 + +/** + * Port identifiers. + */ +#define SAMA_PIOA 0U +#define SAMA_PIOB 1U +#define SAMA_PIOC 2U +#define SAMA_PIOD 3U + +/* + * Forms a line identifier. In this driver the pad number is encoded in the + * lower 5 bits of line and the port in sixth and seventh bits. + */ +#define SAMA_LINE(port, pad) \ + ((uint32_t)((uint32_t)(port << 5U)) | ((uint32_t)(pad))) + +/* + * Decodes a port identifier from a line identifier. + */ +#define SAMA_PORT(line) \ + ((uint32_t)((line & 0xFFFFFFE0U) >> 5U) + +/** + * Decodes a pad identifier from a line identifier. + */ +#define SAMA_PAD(line) \ + ((uint32_t)(line & 0x0000001FU)) + + +/* + * IO pins assignments. + */ +#define PIOA_PIN0 0U +#define PIOA_PIN1 1U +#define PIOA_PIN2 2U +#define PIOA_PIN3 3U +#define PIOA_PIN4 4U +#define PIOA_PIN5 5U +#define PIOA_PIN6 6U +#define PIOA_PIN7 7U +#define PIOA_PIN8 8U +#define PIOA_PIN9 9U +#define PIOA_PIN10 10U +#define PIOA_PIN11 11U +#define PIOA_PIN12 12U +#define PIOA_PIN13 13U +#define PIOA_PIN14 14U +#define PIOA_PIN15 15U +#define PIOA_PIN16 16U +#define PIOA_ONEWIRE 17U +#define PIOA_PIN18 18U +#define PIOA_PIN19 19U +#define PIOA_PIN20 20U +#define PIOA_PIN21 21U +#define PIOA_PIN22 22U +#define PIOA_PIN23 23U +#define PIOA_PIN24 24U +#define PIOA_PIN25 25U +#define PIOA_PIN26 26U +#define PIOA_PIN27 27U +#define PIOA_PIN28 28U +#define PIOA_USER_PB 29U +#define PIOA_PIN30 30U +#define PIOA_LED_BLUE 31U + +#define PIOB_PIN0 0U +#define PIOB_PIN1 1U +#define PIOB_PIN2 2U +#define PIOB_URXD4 3U +#define PIOB_UTXD4 4U +#define PIOB_QSPI1_SCK 5U +#define PIOB_QSPI1_CS 6U +#define PIOB_QSPI1_IO0 7U +#define PIOB_QSPI1_IO1 8U +#define PIOB_QSPI1_IO2 9U +#define PIOB_QSPI1_IO3 10U +#define PIOB_LCDDAT0 11U +#define PIOB_LCDDAT1 12U +#define PIOB_LCDDAT2 13U +#define PIOB_LCDDAT3 14U +#define PIOB_LCDDAT4 15U +#define PIOB_LCDDAT5 16U +#define PIOB_LCDDAT6 17U +#define PIOB_LCDDAT7 18U +#define PIOB_LCDDAT8 19U +#define PIOB_LCDDAT9 20U +#define PIOB_LCDDAT10 21U +#define PIOB_LCDDAT11 22U +#define PIOB_LCDDAT12 23U +#define PIOB_LCDDAT13 24U +#define PIOB_LCDDAT14 25U +#define PIOB_LCDDAT15 26U +#define PIOB_LCDDAT16 27U +#define PIOB_LCDDAT17 28U +#define PIOB_LCDDAT18 29U +#define PIOB_LCDDAT19 30U +#define PIOB_LCDDAT20 31U + +#define PIOC_LCDDAT21 0U +#define PIOC_LCDDAT22 1U +#define PIOC_LCDDAT23 2U +#define PIOC_LCDPWM 3U +#define PIOC_LCDDISP 4U +#define PIOC_LCDVSYNC 5U +#define PIOC_LCDHSYNC 6U +#define PIOC_LCDPCK 7U +#define PIOC_LCDDEN 8U +#define PIOC_IRQ9 9U +#define PIOC_PIN10 10U +#define PIOC_PIN11 11U +#define PIOC_PIN12 12U +#define PIOC_PIN13 13U +#define PIOC_PIN14 14U +#define PIOC_PIN15 15U +#define PIOC_PIN16 16U +#define PIOC_PIN17 17U +#define PIOC_PIN18 18U +#define PIOC_PIN19 19U +#define PIOC_PIN20 20U +#define PIOC_PIN21 21U +#define PIOC_PIN22 22U +#define PIOC_PIN23 23U +#define PIOC_PIN24 24U +#define PIOC_PIN25 25U +#define PIOC_PIN26 26U +#define PIOC_PIN27 27U +#define PIOC_SPI_FLEXCOM4_IO0 28U +#define PIOC_SPI_FLEXCOM4_IO1 29U +#define PIOC_SPI_FLEXCOM4_IO2 30U +#define PIOC_SPI_FLEXCOM4_IO3 31U + +#define PIOD_SPI_FLEXCOM4_IO4 0U +#define PIOD_IRQ1 1U +#define PIOD_PIN2 2U +#define PIOD_PIN3 3U +#define PIOD_TWD1 4U +#define PIOD_TWCK1 5U +#define PIOD_PIO6 6U +#define PIOD_PIO7 7U +#define PIOD_PIN8 8U +#define PIOD_PIN9 9U +#define PIOD_PIO10 10U +#define PIOD_PIO11 11U +#define PIOD_PIN12 12U +#define PIOD_PIN13 13U +#define PIOD_PIN14 14U +#define PIOD_PIN15 15U +#define PIOD_PIN16 16U +#define PIOD_PIN17 17U +#define PIOD_PIN18 18U +#define PIOD_PIO19 19U +#define PIOD_PIO20 20U +#define PIOD_PIO21 21U +#define PIOD_PIO22 22U +#define PIOD_PIN23 23U +#define PIOD_PIO24 24U +#define PIOD_PIO25 25U +#define PIOD_PIO26 26U +#define PIOD_PIO27 27U +#define PIOD_PIO28 28U +#define PIOD_PIO29 29U +#define PIOD_PIN30 30U +#define PIOD_PIN31 31U + +/* + * IO lines assignments. + */ +#define BOARD_LINE(port, pad) \ + ((uint32_t)((uint32_t)(port)) | ((uint32_t)(pad))) + +#define LINE_LED_BLUE BOARD_LINE(PIOA, 31U) +#define LINE_USER_PB BOARD_LINE(PIOA, 29U) +#define LINE_IRQ9 BOARD_LINE(PIOC, 9U) +#define LINE_ONEWIRE BOARD_LINE(PIOA, 17U) + +#if !defined(_FROM_ASM_) +#ifdef __cplusplus +extern "C" { +#endif + void boardInit(void); +#ifdef __cplusplus +} +#endif +#endif /* _FROM_ASM_ */ + +#endif /* _BOARD_H_ */ diff --git a/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.mk b/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.mk new file mode 100644 index 000000000..11f46f92d --- /dev/null +++ b/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.mk @@ -0,0 +1,9 @@ +# List of all the board related files. +BOARDSRC = $(CHIBIOS)/os/hal/boards/ATSAMA5D27_SOM1_SEC/board.c + +# Required include directories +BOARDINC = $(CHIBIOS)/os/hal/boards/ATSAMA5D27_SOM1_SEC + +# Shared variables +ALLCSRC += $(BOARDSRC) +ALLINC += $(BOARDINC) diff --git a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_aes_lld.c b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_aes_lld.c index 0ed4af4a2..a6cb4ee12 100644 --- a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_aes_lld.c +++ b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_aes_lld.c @@ -165,9 +165,29 @@ cryerror_t sama_aes_lld_process_dma(CRYDriver *cryp, aesparams *params, cryerror_t ret; osalDbgAssert(cryp->thread == NULL, "already waiting"); + osalDbgAssert(!((uint32_t) in & (L1_CACHE_BYTES - 1)), "in address not cache aligned"); + osalDbgAssert(!((uint32_t) out & (L1_CACHE_BYTES - 1)), "out address not cache aligned"); + +#if 0 + osalDbgAssert(!(indata_len & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); +#endif + + /* + * If size is not multiple of cache line, clean cache region is required. + * TODO: remove when size assert works + */ + if (indata_len & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) out, indata_len); + } osalMutexLock(&cryp->mutex); + cacheCleanRegion((uint8_t *) in, indata_len); + + cryp->out = out; + cryp->in = in; + cryp->len = indata_len; + //set chunk size cryp->dmachunksize = DMA_CHUNK_SIZE_4; diff --git a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_crypto_lld.c b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_crypto_lld.c index a4e19d7c7..764b1b915 100644 --- a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_crypto_lld.c +++ b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_crypto_lld.c @@ -19,8 +19,6 @@ #include "sama_crypto_lld.h" - - #if defined(SAMA_DMA_REQUIRED) static void crypto_lld_serve_read_interrupt(CRYDriver *cryp, uint32_t flags); static void crypto_lld_serve_write_interrupt(CRYDriver *cryp, uint32_t flags); @@ -50,7 +48,7 @@ static void crypto_lld_serve_write_interrupt(CRYDriver *cryp, uint32_t flags); * @note This macro is meant to be used in the low level drivers * implementation only. * - * @param[in] spip pointer to the @p SPIDriver object + * @param[in] cryp pointer to the @p CRYDriver object * * @notapi */ @@ -132,6 +130,9 @@ static void crypto_lld_serve_read_interrupt(CRYDriver *cryp, uint32_t flags) { (void)flags; #endif + /* D-Cache L1 is enabled */ + cacheInvalidateRegion(cryp->out, cryp->len); + /* Stop everything.*/ dmaChannelDisable(cryp->dmarx); /* Portable CRY ISR code defined in the high level driver, note, it is diff --git a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_gcm_lld.c b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_gcm_lld.c index 2496c03d3..3e9471a2a 100644 --- a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_gcm_lld.c +++ b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_gcm_lld.c @@ -36,8 +36,27 @@ static cryerror_t sama_gcm_lld_process_dma(CRYDriver *cryp,cgmcontext * cxt) { #if defined(SAMA_DMA_REQUIRED) + osalDbgAssert(!((uint32_t) cxt->in & (L1_CACHE_BYTES - 1)), "in address not cache aligned"); + osalDbgAssert(!((uint32_t) cxt->out & (L1_CACHE_BYTES - 1)), "out address not cache aligned"); osalDbgAssert(cryp->thread == NULL, "already waiting"); +#if 0 + osalDbgAssert(!(cxt->c_size & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); +#endif + + cacheCleanRegion((uint8_t *) cxt->in, cxt->c_size); + + /* + * If size is not multiple of cache line, clean cache region is required. + * TODO: remove when size assert works + */ + if (cxt->c_size & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) cxt->out, cxt->c_size); + } + + cryp->out = cxt->out; + cryp->in = cxt->in; + cryp->len = cxt->c_size; //set chunk size cryp->dmachunksize = DMA_CHUNK_SIZE_4; diff --git a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_sha_lld.c b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_sha_lld.c index b88386366..cf38e75d0 100644 --- a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_sha_lld.c +++ b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_sha_lld.c @@ -357,10 +357,22 @@ static uint32_t processBlockPolling(const uint8_t *data,uint32_t len, uint32_t b return processed; } -static uint32_t processBlockDMA(CRYDriver *cryp, const uint8_t *data,uint32_t len, uint32_t block_size) -{ +static uint32_t processBlockDMA(CRYDriver *cryp, const uint8_t *data,uint32_t len, uint32_t block_size) { + + osalDbgAssert(!((uint32_t) data & (L1_CACHE_BYTES - 1)), "data address not cache aligned"); + +#if 0 + osalDbgAssert(!(block_size & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); +#endif + uint32_t processed = 0; + cryp->out = 0; + cryp->in = data; + cryp->len = len; + + cacheCleanRegion((uint8_t *) data, len); + while ((len - processed) >= block_size) { // load data in the sha input registers diff --git a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_tdes_lld.c b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_tdes_lld.c index fbe000e47..bfbfffe7a 100644 --- a/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_tdes_lld.c +++ b/os/hal/ports/SAMA/LLD/CRYPTOv1/sama_tdes_lld.c @@ -142,11 +142,32 @@ cryerror_t sama_tdes_lld_dma(CRYDriver *cryp, tdes_config_t *params, bool encrypt, const uint8_t *data, size_t data_len, uint8_t * out, const uint8_t *iv) { + osalDbgAssert(!((uint32_t) data & (L1_CACHE_BYTES - 1)), "data address not cache aligned"); + osalDbgAssert(!((uint32_t) out & (L1_CACHE_BYTES - 1)), "out address not cache aligned"); + +#if 0 + osalDbgAssert(!(data_len & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); +#endif + + /* + * If size is not multiple of cache line, clean cache region is required. + * TODO: remove when size assert works + */ + if (data_len & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) out, data_len); + } + uint32_t mode = 0; uint32_t *vectors = (uint32_t *) iv; osalMutexLock(&cryp->mutex); + cacheCleanRegion((uint8_t *) data, data_len); + + cryp->out = out; + cryp->in = data; + cryp->len = data_len; + cryp->dmachunksize = DMA_CHUNK_SIZE_1; cryp->dmawith = DMA_DATA_WIDTH_WORD; diff --git a/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c b/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c index 28e2e38e5..fa925e88a 100644 --- a/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c +++ b/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c @@ -95,9 +95,9 @@ OSAL_IRQ_HANDLER(dmaHandler) { OSAL_IRQ_PROLOGUE(); #if SAMA_HAL_IS_SECURE - Xdmac *xdmac = XDMAC0; -#else Xdmac *xdmac = XDMAC1; +#else + Xdmac *xdmac = XDMAC0; #endif /* SAMA_HAL_IS_SECURE */ uint32_t chan, gis; @@ -137,10 +137,10 @@ OSAL_IRQ_HANDLER(dmaHandler) { void dmaInit(void) { #if SAMA_HAL_IS_SECURE - Xdmac *xdmac = XDMAC0; - mtxConfigPeriphSecurity(MATRIX0, ID_XDMAC0, SECURE_PER); -#else Xdmac *xdmac = XDMAC1; + mtxConfigPeriphSecurity(MATRIX0, ID_XDMAC1, SECURE_PER); +#else + Xdmac *xdmac = XDMAC0; #endif /* SAMA_HAL_IS_SECURE */ uint8_t chan; @@ -160,9 +160,9 @@ void dmaInit(void) { /* Setting aic source handler */ #if SAMA_HAL_IS_SECURE - aicSetSourceHandler(ID_XDMAC0, dmaHandler); -#else aicSetSourceHandler(ID_XDMAC1, dmaHandler); +#else + aicSetSourceHandler(ID_XDMAC0, dmaHandler); #endif /* SAMA_HAL_IS_SECURE */ } @@ -248,13 +248,13 @@ sama_dma_channel_t* dmaChannelAllocate(uint32_t priority, /* Setting AIC and enabling DMA clocks required by the current channel set.*/ #if SAMA_HAL_IS_SECURE - aicSetSourcePriority(ID_XDMAC0, priority); - aicEnableInt(ID_XDMAC0); - pmcEnableXDMAC0(); -#else aicSetSourcePriority(ID_XDMAC1, priority); aicEnableInt(ID_XDMAC1); pmcEnableXDMAC1(); +#else + aicSetSourcePriority(ID_XDMAC0, priority); + aicEnableInt(ID_XDMAC0); + pmcEnableXDMAC0(); #endif /* SAMA_HAL_IS_SECURE */ /* Enabling channel's interrupt */ @@ -290,6 +290,10 @@ void dmaChannelRelease(sama_dma_channel_t *dmachp) { /* Disables interrupt */ (dmachp)->xdmac->XDMAC_GID = XDMAC_GID_ID0 << ((dmachp)->chid); + /* Clear dma descriptor */ + (dmachp)->xdmac->XDMAC_CHID[((dmachp)->chid)].XDMAC_CNDA = 0; + (dmachp)->xdmac->XDMAC_CHID[((dmachp)->chid)].XDMAC_CNDC = 0; + /* Marks the stream as not allocated.*/ (dmachp)->state = SAMA_DMA_FREE; } diff --git a/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h b/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h index 7918d834d..4e3ccf089 100644 --- a/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h +++ b/os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h @@ -146,11 +146,11 @@ typedef struct { /** * @brief Returns the number of transfers to be performed. * @note This function can be invoked in both ISR or thread context. - * @pre The channel must have been allocated using @p dmaChannelAllocate(). - * @post After use the channel can be released using @p dmaChannelRelease(). + * @pre The stream must have been allocated using @p dmaChannelAllocate(). + * @post After use the stream can be released using @p dmaChannelRelease(). * - * @param[in] dmachp pointer to a @p sama_dma_channel_t structure - * @return The number of transfers to be performed. + * @param[in] dmachp pointer to a @p sama_dma_channel_t structure + * @return The number of transfers to be performed. * * @special */ @@ -214,7 +214,7 @@ typedef struct { * @special */ #define dmaChannelEnable(dmachp) { \ - (dmachp)->xdmac->XDMAC_GE |= (XDMAC_GE_EN0 << ((dmachp)->chid)); \ + (dmachp)->xdmac->XDMAC_GE = (XDMAC_GE_EN0 << ((dmachp)->chid)); \ } /** @@ -229,7 +229,7 @@ typedef struct { * @special */ #define dmaChannelDisable(dmachp) { \ - (dmachp)->xdmac->XDMAC_GD |= XDMAC_GD_DI0 << ((dmachp)->chid); \ + (dmachp)->xdmac->XDMAC_GD = XDMAC_GD_DI0 << ((dmachp)->chid); \ while ((((dmachp)->xdmac->XDMAC_GS) & (XDMAC_GS_ST0 << (dmachp)->chid)) == 1) { \ ; \ } \ diff --git a/os/hal/ports/SAMA/LLD/I2Cv1/driver.mk b/os/hal/ports/SAMA/LLD/I2Cv1/driver.mk new file mode 100644 index 000000000..2534798aa --- /dev/null +++ b/os/hal/ports/SAMA/LLD/I2Cv1/driver.mk @@ -0,0 +1,21 @@ +ifeq ($(USE_HAL_I2C_FALLBACK),yes) + # Fallback SW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + else + PLATFORMSRC += $(CHIBIOS)/os/hal/lib/fallback/I2C/hal_i2c_lld.c + endif + PLATFORMINC += $(CHIBIOS)/os/hal/lib/fallback/I2C +else + # Default HW driver. + ifeq ($(USE_SMART_BUILD),yes) + ifneq ($(findstring HAL_USE_I2C TRUE,$(HALCONF)),) + PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c + endif + else + PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c + endif + PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/I2Cv1 +endif diff --git a/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c b/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c new file mode 100644 index 000000000..490364452 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c @@ -0,0 +1,963 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 I2Cv1/hal_i2c_lld.c + * @brief SAMA I2C subsystem low level driver source. + * + * @addtogroup I2C + * @{ + */ + +#include "hal.h" + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/* SAMA5D2 Clock offset. */ +#define TWI_CLK_OFFSET 3 + +/* Mask for 10-bit address. */ +#define TWI_ADDR_MASK_10 0x380 + +/* Mask for 10-bit address case for DADR field. */ +#define TWI_ADDR_10_DADR_MASK 0x78 +#define TWI_ADDR_10_IADR_MASK 0xFF + +/* Mask for internal address check. */ +#define TWI_INTERNAL_ADDR_MASK 0xFF + +/* Mask for TWI errors interrupt. */ +#define TWI_ERROR_MASK (TWI_SR_OVRE | TWI_SR_UNRE | \ + TWI_SR_NACK | TWI_SR_ARBLST | \ + TWI_SR_TOUT | TWI_SR_PECERR) + +/*===========================================================================*/ +/* Driver local macros. */ +/*===========================================================================*/ +#if !defined ROUND_INT_DIV +#define ROUND_INT_DIV(n,d) (((n) + ((d)-1)) / (d)) +#endif + +/** + * @brief Enable write protection on TWI registers block. + * + * @param[in] i2cp pointer to a TWI register block + * + * @notapi + */ +#define twiEnableWP(i2cp) { \ + i2cp->TWI_WPMR = TWI_WPMR_WPKEY_PASSWD | TWI_WPMR_WPEN; \ +} + +/** + * @brief Disable write protection on TWI registers block. + * + * @param[in] i2cp pointer to a TWI register block + * + * @notapi + */ +#define twiDisableWP(i2cp) { \ + i2cp->TWI_WPMR = TWI_WPMR_WPKEY_PASSWD; \ +} + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** @brief I2C0 driver identifier.*/ +#if SAMA_I2C_USE_TWIHS0 || defined(__DOXYGEN__) +I2CDriver I2CD0; +#endif + +/** @brief I2C1 driver identifier.*/ +#if SAMA_I2C_USE_TWIHS1 || defined(__DOXYGEN__) +I2CDriver I2CD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Read a byte from TWI_RHR register. + * + * @param[in] reg pointer to the target register + * @param[in] value pointer to the transmit variable + * + * @notapi + */ +static inline void i2c_lld_read_byte(volatile const void* reg, uint8_t* value) { + *value = *(volatile const uint8_t*)reg; +} + +/** + * @brief Write a byte to TWI_THR register. + * + * @param[in] reg pointer to the target register + * @param[in] value pointer to the receive variable + * + * @notapi + */ +static inline void i2c_lld_write_byte(volatile void* reg, uint8_t value) { + *(volatile uint8_t*)reg = value; +} + +/** + * @brief Read bytes. + * @note Disables WRITE PROTECTION before using + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_read_bytes(I2CDriver *i2cp) { + + if (i2cp->rxbytes == 1) { + + /* Starts and stops the operation for 1 byte read.*/ + i2cp->i2c->TWI_CR = TWI_CR_START | TWI_CR_STOP; + i2cp->i2c->TWI_IER = TWI_IER_TXCOMP; + while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0); + + i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, i2cp->rxbuf); + } + + if (i2cp->rxbytes == 2) { + + /* Starts the operation.*/ + i2cp->i2c->TWI_CR = TWI_CR_START; + i2cp->i2c->TWI_IER = TWI_IER_TXCOMP; + while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0); + + /* Stops the operation and read penultimate byte. */ + i2cp->i2c->TWI_CR = TWI_CR_STOP; + + i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, &i2cp->rxbuf[0]); + + while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0); + + /* Read last byte. */ + i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, &i2cp->rxbuf[1]); + } + + if (i2cp->rxbytes > 2) { + + /* RX DMA setup.*/ + dmaChannelSetDestination(i2cp->dmarx, i2cp->rxbuf); + dmaChannelSetTransactionSize(i2cp->dmarx, i2cp->rxbytes -2); + + /* Starts the operation.*/ + i2cp->i2c->TWI_CR = TWI_CR_START; + + /* Start the DMA. */ + dmaChannelEnable(i2cp->dmarx); + } +} + +/** + * @brief Write bytes. + * @note Disables WRITE PROTECTION before using + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_write_bytes(I2CDriver *i2cp) { + + size_t txsize = i2cp->txbytes; + + if (txsize == 1) { + + i2c_lld_write_byte(&i2cp->i2c->TWI_THR, i2cp->txbuf[0]); + + /* Enable TXCOMP interrupt. */ + i2cp->i2c->TWI_IER = TWI_IER_TXCOMP; + + i2cp->i2c->TWI_CR = TWI_CR_STOP; + + /* Starts and stops the operation for 1 byte write.*/ + while ((i2cp->i2c->TWI_SR & TWI_SR_TXRDY) == 0); + } + + if (txsize > 1) { + /* RX DMA setup.*/ + dmaChannelSetSource(i2cp->dmatx, i2cp->txbuf); + dmaChannelSetTransactionSize(i2cp->dmatx, (txsize - 1)); + dmaChannelEnable(i2cp->dmatx); + } +} + +/** + * @brief Set operation mode of I2C hardware. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_set_opmode(I2CDriver *i2cp) { + + switch (i2cp->config->op_mode) { + case OPMODE_I2C: + i2cp->i2c->TWI_CR = TWI_CR_SMBDIS; + break; + case OPMODE_SMBUS: + i2cp->i2c->TWI_CR = TWI_CR_SMBEN; + break; + } +} + +/** + * @brief DMA RX end IRQ handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] flags pre-shifted content of the ISR register + * + * @notapi + */ +static void i2c_lld_serve_rx_interrupt(I2CDriver *i2cp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(SAMA_I2C_DMA_ERROR_HOOK) + if ((flags & (XDMAC_CIS_RBEIS | XDMAC_CIS_ROIS)) != 0) { + SAMA_I2C_DMA_ERROR_HOOK(i2cp); + } +#else + (void)flags; +#endif + + /* DMA channel disable. */ + dmaChannelDisable(i2cp->dmarx); + + /* Cache is enabled */ + cacheInvalidateRegion(i2cp->rxbuf, i2cp->rxbytes - 1); + + /* Wait for RXRDY flag. */ + while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0); + + /* Stops the operation and read the last 2 bytes.*/ + i2cp->i2c->TWI_CR = TWI_CR_STOP; + i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, &i2cp->rxbuf[i2cp->rxbytes - 2]); + + /* Wait for the last byte. */ + while ((i2cp->i2c->TWI_SR & TWI_SR_RXRDY) == 0); + + /* Enable TXCOMP interrupt. */ + i2cp->i2c->TWI_IER = TWI_IER_TXCOMP; + + /* Read the last byte. */ + i2c_lld_read_byte(&i2cp->i2c->TWI_RHR, &i2cp->rxbuf[i2cp->rxbytes - 1]); + +} + + +/** + * @brief DMA TX end IRQ handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_serve_tx_interrupt(I2CDriver *i2cp, uint32_t flags) { + + const uint8_t tx_last_byte = i2cp->txbuf[i2cp->txbytes - 1]; + /* DMA errors handling.*/ +#if defined(SAMA_I2C_DMA_ERROR_HOOK) + if ((flags & (XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) != 0) { + SAMA_I2C_DMA_ERROR_HOOK(i2cp); + } +#else + (void)flags; +#endif + + dmaChannelDisable(i2cp->dmatx); + + /* Wait for the TX ready flag. */ + while ((i2cp->i2c->TWI_SR & TWI_SR_TXRDY) == 0); + + /* Stops the operation and transmit the last byte.*/ + i2cp->i2c->TWI_CR = TWI_CR_STOP; + + i2cp->i2c->TWI_IER = TWI_IER_TXCOMP; + + i2c_lld_write_byte(&i2cp->i2c->TWI_THR, tx_last_byte); +} + +/** + * @brief I2C interrupts handler. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t flags) { + + /* Used only in 1/2 bytes transmissions in order to wake up the thread. */ + if (flags & TWI_SR_TXCOMP) { + _i2c_wakeup_isr(i2cp); + } + + i2cp->errors = I2C_NO_ERROR; + + if (flags & TWI_SR_OVRE) /* Overrun error. */ + i2cp->errors |= I2C_OVERRUN; + + if (flags & TWI_SR_UNRE) /* Underrun error. */ + i2cp->errors |= I2C_OVERRUN; + + if (flags & TWI_SR_NACK) { /* Acknowledge fail. */ + i2cp->i2c->TWI_CR = TWI_CR_STOP; /* Setting stop bit. */ + i2cp->errors |= I2C_ACK_FAILURE; + } + + if (flags & TWI_SR_ARBLST) /* Arbitration lost. */ + i2cp->errors |= I2C_ARBITRATION_LOST; + + if (flags & TWI_SR_TOUT) /* SMBus Timeout. */ + i2cp->errors |= I2C_TIMEOUT; + + if (flags & TWI_SR_PECERR) /* PEC error. */ + i2cp->errors |= I2C_PEC_ERROR; + + /* If some error has been identified then sends wakes the waiting thread.*/ + if (i2cp->errors != I2C_NO_ERROR) + _i2c_wakeup_error_isr(i2cp); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if SAMA_I2C_USE_TWIHS0 || defined(__DOXYGEN__) +/** + * @brief TWIHS0 interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(SAMA_TWIHS0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uint32_t sr = I2CD0.i2c->TWI_SR; + + I2CD0.i2c->TWI_IDR = TWI_IDR_TXCOMP; + + i2c_lld_serve_interrupt(&I2CD0, sr); + aicAckInt(); + + OSAL_IRQ_EPILOGUE(); +} +#endif /* SAMA_I2C_USE_TWIHS0 */ + +#if SAMA_I2C_USE_TWIHS1 || defined(__DOXYGEN__) +/** + * @brief TWIHS1 interrupt handler. + * + * @notapi + */ +OSAL_IRQ_HANDLER(SAMA_TWIHS1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uint32_t sr = I2CD1.i2c->TWI_SR; + + I2CD1.i2c->TWI_IDR = TWI_IDR_TXCOMP; + + i2c_lld_serve_interrupt(&I2CD1, sr); + aicAckInt(); + + OSAL_IRQ_EPILOGUE(); +} + +#endif /* SAMA_I2C_USE_TWIHS1 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level I2C driver initialization. + * + * @notapi + */ +void i2c_lld_init(void) { + +#if SAMA_I2C_USE_TWIHS0 +#if SAMA_HAL_IS_SECURE + mtxConfigPeriphSecurity(MATRIX1, ID_TWIHS0, SECURE_PER); +#endif /* SAMA_HAL_IS_SECURE */ + /* Driver initialization.*/ + i2cObjectInit(&I2CD0); + I2CD0.thread = NULL; + I2CD0.i2c = TWIHS0; + I2CD0.dmarx = NULL; + I2CD0.dmatx = NULL; + I2CD0.rxdmamode = XDMAC_CC_TYPE_PER_TRAN | + XDMAC_CC_MBSIZE_SIXTEEN | + XDMAC_CC_DSYNC_PER2MEM | + XDMAC_CC_PROT_SEC | + XDMAC_CC_CSIZE_CHK_1 | + XDMAC_CC_DWIDTH_BYTE | + XDMAC_CC_SIF_AHB_IF1 | + XDMAC_CC_DIF_AHB_IF0 | + XDMAC_CC_SAM_FIXED_AM | + XDMAC_CC_DAM_INCREMENTED_AM | + XDMAC_CC_PERID(PERID_TWIHS0_RX); + I2CD0.txdmamode = XDMAC_CC_TYPE_PER_TRAN | + XDMAC_CC_MBSIZE_SIXTEEN | + XDMAC_CC_DSYNC_MEM2PER | + XDMAC_CC_PROT_SEC | + XDMAC_CC_CSIZE_CHK_1 | + XDMAC_CC_DWIDTH_BYTE | + XDMAC_CC_SIF_AHB_IF0 | + XDMAC_CC_DIF_AHB_IF1 | + XDMAC_CC_SAM_INCREMENTED_AM | + XDMAC_CC_DAM_FIXED_AM | + XDMAC_CC_PERID(PERID_TWIHS0_TX); +#endif /* SAMA_I2C_USE_TWIHS0 */ + +#if SAMA_I2C_USE_TWIHS1 +#if SAMA_HAL_IS_SECURE + mtxConfigPeriphSecurity(MATRIX1, ID_TWIHS1, SECURE_PER); +#endif /* SAMA_HAL_IS_SECURE */ + /* Driver initialization.*/ + i2cObjectInit(&I2CD1); + I2CD1.thread = NULL; + I2CD1.i2c = TWIHS1; + I2CD1.dmarx = NULL; + I2CD1.dmatx = NULL; + I2CD1.rxdmamode = XDMAC_CC_TYPE_PER_TRAN | + XDMAC_CC_MBSIZE_SIXTEEN | + XDMAC_CC_DSYNC_PER2MEM | + XDMAC_CC_PROT_SEC | + XDMAC_CC_CSIZE_CHK_1 | + XDMAC_CC_DWIDTH_BYTE | + XDMAC_CC_SIF_AHB_IF1 | + XDMAC_CC_DIF_AHB_IF0 | + XDMAC_CC_SAM_FIXED_AM | + XDMAC_CC_DAM_INCREMENTED_AM | + XDMAC_CC_PERID(PERID_TWIHS1_RX); + I2CD1.txdmamode = XDMAC_CC_TYPE_PER_TRAN | + XDMAC_CC_MBSIZE_SIXTEEN | + XDMAC_CC_DSYNC_MEM2PER | + XDMAC_CC_PROT_SEC | + XDMAC_CC_CSIZE_CHK_1 | + XDMAC_CC_DWIDTH_BYTE | + XDMAC_CC_SIF_AHB_IF0 | + XDMAC_CC_DIF_AHB_IF1 | + XDMAC_CC_SAM_INCREMENTED_AM | + XDMAC_CC_DAM_FIXED_AM | + XDMAC_CC_PERID(PERID_TWIHS1_TX); +#endif /* SAMA_I2C_USE_TWIHS1 */ +} + +/** + * @brief Configures and activates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_start(I2CDriver *i2cp) { + + uint32_t ck_div, clh_div, hold; + + /* If in stopped state then enables the I2C and DMA clocks.*/ + if (i2cp->state == I2C_STOP) { + +#if SAMA_I2C_USE_TWIHS0 + if (&I2CD0 == i2cp) { + + i2cp->dmarx = dmaChannelAllocate(SAMA_I2C_TWIHS0_DMA_IRQ_PRIORITY, + (sama_dmaisr_t)i2c_lld_serve_rx_interrupt, + (void *)i2cp); + osalDbgAssert(i2cp->dmarx != NULL, "no channel allocated"); + + i2cp->dmatx = dmaChannelAllocate(SAMA_I2C_TWIHS0_DMA_IRQ_PRIORITY, + (sama_dmaisr_t)i2c_lld_serve_tx_interrupt, + (void *)i2cp); + osalDbgAssert(i2cp->dmatx != NULL, "no channel allocated"); + + pmcEnableTWIHS0(); + /* To prevent spurious interrupt */ + aicSetIntSourceType(ID_TWIHS0, EXT_NEGATIVE_EDGE); + aicSetSourcePriority(ID_TWIHS0, SAMA_I2C_TWIHS0_IRQ_PRIORITY); + aicSetSourceHandler(ID_TWIHS0, SAMA_TWIHS0_HANDLER); + aicEnableInt(ID_TWIHS0); + } +#endif /* SAMA_I2C_USE_TWIHS0 */ + +#if SAMA_I2C_USE_TWIHS1 + if (&I2CD1 == i2cp) { + + i2cp->dmarx = dmaChannelAllocate(SAMA_I2C_TWIHS1_DMA_IRQ_PRIORITY, + (sama_dmaisr_t)i2c_lld_serve_rx_interrupt, + (void *)i2cp); + osalDbgAssert(i2cp->dmarx != NULL, "no channel allocated"); + + i2cp->dmatx = dmaChannelAllocate(SAMA_I2C_TWIHS1_DMA_IRQ_PRIORITY, + (sama_dmaisr_t)i2c_lld_serve_tx_interrupt, + (void *)i2cp); + osalDbgAssert(i2cp->dmatx != NULL, "no channel allocated"); + + pmcEnableTWIHS1(); + /* To prevent spurious interrupt */ + aicSetIntSourceType(ID_TWIHS1, EXT_NEGATIVE_EDGE); + aicSetSourcePriority(ID_TWIHS1, SAMA_I2C_TWIHS1_IRQ_PRIORITY); + aicSetSourceHandler(ID_TWIHS1, SAMA_TWIHS1_HANDLER); + aicEnableInt(ID_TWIHS1); + } +#endif /* SAMA_I2C_USE_TWIHS1 */ + } + + /* Set mode */ + dmaChannelSetMode(i2cp->dmarx, i2cp->rxdmamode); + dmaChannelSetSource(i2cp->dmarx, &i2cp->i2c->TWI_RHR); + + dmaChannelSetMode(i2cp->dmatx, i2cp->txdmamode); + dmaChannelSetDestination(i2cp->dmatx, &i2cp->i2c->TWI_THR); + + /* Disable write protection. */ + twiDisableWP(i2cp->i2c); + + /* TWI software reset */ + i2cp->i2c->TWI_CR = TWI_CR_SWRST; + + /* TWI set operation mode. */ + i2c_lld_set_opmode(i2cp); + + /* Configure dummy slave address */ + i2cp->i2c->TWI_MMR = 0; + + /* Compute clock */ + for (ck_div = 0; ck_div < 7; ck_div++) { + clh_div = ((SAMA_TWIHSxCLK / i2cp->config->clock_speed) - 2 * (TWI_CLK_OFFSET)) >> ck_div; + if (clh_div <= 511) { + break; + } + } + + /* Compute holding time (I2C spec requires 300ns) */ + hold = TWI_CWGR_HOLD(ROUND_INT_DIV((uint32_t)(0.3 * SAMA_TWIHSxCLK), 1000000) - 3); + + /* Configure clock */ + i2cp->i2c->TWI_CWGR = TWI_CWGR_CKDIV(ck_div) | + TWI_CWGR_CHDIV(clh_div >> 1) | + TWI_CWGR_CLDIV(clh_div >> 1) | + hold; + + /* Clear status flag */ + i2cp->i2c->TWI_SR; + + /* Enable Interrupt. */ + i2cp->i2c->TWI_IER = TWI_ERROR_MASK; + + /* Set master mode */ + i2cp->i2c->TWI_CR = TWI_CR_SVDIS; + i2cp->i2c->TWI_CR = TWI_CR_MSEN; + + /* Enable write protection. */ + twiEnableWP(i2cp->i2c); +} + +/** + * @brief Deactivates the I2C peripheral. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +void i2c_lld_stop(I2CDriver *i2cp) { + + /* If not in stopped state then disables the I2C clock.*/ + if (i2cp->state != I2C_STOP) { + + /* Disable write protection. */ + twiDisableWP(i2cp->i2c); + + /* I2C disable.*/ + + /* Disable interrupts. */ + i2cp->i2c->TWI_IDR = TWI_ERROR_MASK; + + /* TWI software reset. */ + i2cp->i2c->TWI_CR = TWI_CR_SWRST; + i2cp->i2c->TWI_MMR = 0; + + /* DMA channel release. */ + dmaChannelRelease(i2cp->dmatx); + dmaChannelRelease(i2cp->dmarx); + +#if SAMA_I2C_USE_TWIHS0 + if (&I2CD0 == i2cp) { + pmcDisableTWIHS0(); + } +#endif + +#if SAMA_I2C_USE_TWIHS1 + if (&I2CD1 == i2cp) { + pmcDisableTWIHS1(); + } +#endif + + /* Enable write protection. */ + twiEnableWP(i2cp->i2c); + } + + i2cp->txbuf = NULL; + i2cp->rxbuf = NULL; + i2cp->txbytes = 0; + i2cp->rxbytes = 0; +} + +/** + * @brief Receives data via the I2C bus as master. + * @details + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + + osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "rxbuf address not cache aligned"); + +#if 0 + osalDbgAssert(!(rxbytes & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); +#endif + + i2cp->txbuf = NULL; + i2cp->rxbuf = rxbuf; + i2cp->txbytes = 0; + i2cp->rxbytes = rxbytes; + + /* + * If size is not multiple of cache line, clean cache region is required. + * TODO: remove when size assert works + */ + if (rxbytes & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) rxbuf, rxbytes); + } + + systime_t start, end; + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Disable write protection. */ + twiDisableWP(i2cp->i2c); + + /* Compute device address and/or internal address. */ + i2cp->i2c->TWI_MMR = 0; + + if ((addr & TWI_ADDR_MASK_10) != 0) { + /* 10-bit address. */ + if (i2cp->config->op_mode == OPMODE_I2C) { + + /* Store 2 slave device address MSB bits in MMR_DADR with 11110 mask. Configure number of internal slave address bytes in MMR_IADRSZ as 1. */ + i2cp->i2c->TWI_MMR = TWI_MMR_DADR((addr >> 8) | TWI_ADDR_10_DADR_MASK) | + TWI_MMR_IADRSZ_1_BYTE | TWI_MMR_MREAD; + i2cp->i2c->TWI_IADR = TWI_ADDR_10_IADR_MASK & addr; + + } else if (i2cp->config->op_mode == OPMODE_SMBUS) + osalDbgAssert((addr & TWI_ADDR_MASK_10) != 0, "10-bit address not supported in SMBus mode"); + + } else { + /* 7-bit address. */ + /* Store slave device address in MMR_DADR. */ + i2cp->i2c->TWI_MMR |= TWI_MMR_DADR(addr); + + /* Configure read direction. */ + i2cp->i2c->TWI_MMR |= TWI_MMR_MREAD; + } + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(SAMA_I2C_BUSY_TIMEOUT)); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { + osalSysLock(); + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if (i2cp->i2c->TWI_SR & (TWI_SR_TXCOMP | TWI_SR_RXRDY)) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) + return MSG_TIMEOUT; + + osalSysUnlock(); + } + + i2c_lld_read_bytes(i2cp); + + /* Enable write protection. */ + twiEnableWP(i2cp->i2c); + + /* Waits for the operation completion or a timeout.*/ + return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); +} + +/** + * @brief Transmits data via the I2C bus as master. + * @details When performing reading through write you can not write more than + * 3 bytes of data to I2C slave. This is SAMA platform limitation. + * Internal address bytes must be set in txbuf from LSB (position 0 of the buffer) to MSB + * (position 1 or 2 of the buffer depending from the number of internal address bytes. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * @param[in] addr slave device address + * @param[in] txbuf pointer to the transmit buffer + * @param[in] txbytes number of bytes to be transmitted + * @param[out] rxbuf pointer to the receive buffer + * @param[in] rxbytes number of bytes to be received + * @param[in] timeout the number of ticks before the operation timeouts, + * the following special values are allowed: + * - @a TIME_INFINITE no timeout. + * . + * @return The operation status. + * @retval MSG_OK if the function succeeded. + * @retval MSG_RESET if one or more I2C errors occurred, the errors can + * be retrieved using @p i2cGetErrors(). + * @retval MSG_TIMEOUT if a timeout occurred before operation end. After a + * timeout the driver must be stopped and restarted + * because the bus is in an uncertain state. + * + * @notapi + */ +msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout) { + + osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "txbuf address not cache aligned"); + osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "rxbuf address not cache aligned"); + +#if 0 + osalDbgAssert(!(rxbytes & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); +#endif + + i2cp->txbuf = txbuf; + i2cp->rxbuf = rxbuf; + i2cp->txbytes = txbytes; + i2cp->rxbytes = rxbytes; + + /* Cache is enabled */ + cacheCleanRegion((uint8_t *)i2cp->txbuf, txbytes); + + /* + * If size is not multiple of cache line, clean cache region is required. + * TODO: remove when size assert works + */ + if (rxbytes & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) rxbuf, rxbytes); + } + + systime_t start, end; + + /* Resetting error flags for this transfer.*/ + i2cp->errors = I2C_NO_ERROR; + + /* Disable write protection. */ + twiDisableWP(i2cp->i2c); + + /* prepare to read through write operation */ + if (rxbytes > 0){ + + osalDbgAssert(txbytes <= 3, "Number of internal address bytes not supported. Max number of internal address bytes is 3."); + + i2cp->i2c->TWI_MMR = 0; + + /* Compute slave address and internal addresses. */ + + /* Internal address of I2C slave was set in special Atmel registers. + * Now we must call read function. The I2C cell automatically sends + * bytes from IADR register to bus and issues repeated start. */ + + if ((addr & TWI_ADDR_MASK_10) != 0) { + /* 10-bit address. */ + if (i2cp->config->op_mode == OPMODE_I2C) { + + uint16_t mem_addr = 0; + + osalDbgAssert(txbytes <= 2, "Number of internal address bytes not supported"); + + /* Store 2 slave device address MSB bits in MMR_DADR with 11110 mask. Configure number of internal slave address bytes in + * MMR_IADRSZ as 1 + slave internal addresses. */ + i2cp->i2c->TWI_MMR = TWI_MMR_DADR((addr >> 8) | TWI_ADDR_10_DADR_MASK) | + TWI_MMR_IADRSZ(txbytes + 1); + + if(txbytes == 1) + mem_addr = i2cp->txbuf[0]; + + else if(txbytes == 2) + mem_addr = i2cp->txbuf[0] | (i2cp->txbuf[1] << 8); + + /* Store the rest of the 10-bit address in IADR register. Also store the internal slave address bytes. */ + i2cp->i2c->TWI_IADR = (TWI_ADDR_10_IADR_MASK & addr) | (mem_addr << 8); + + } else if (i2cp->config->op_mode == OPMODE_SMBUS) + osalDbgAssert((addr & TWI_ADDR_MASK_10) != 0, "10-bit address not supported in SMBus mode"); + + } else { + /* 7-bit address. */ + i2cp->i2c->TWI_MMR |= txbytes << 8; + + /* Store internal slave address in TWI_IADR registers */ + i2cp->i2c->TWI_IADR = 0; + while (txbytes > 0){ + i2cp->i2c->TWI_IADR = (i2cp->i2c->TWI_IADR << 8); + i2cp->i2c->TWI_IADR |= *(txbuf++); + txbytes--; + } + /* Store slave device address in MMR_DADR. */ + i2cp->i2c->TWI_MMR |= TWI_MMR_DADR(addr); + } + + #if 0 + osalDbgAssert(!(rxbytes & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); + #endif + + /* Configure read direction. */ + i2cp->i2c->TWI_MMR |= TWI_MMR_MREAD; + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(SAMA_I2C_BUSY_TIMEOUT)); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { + osalSysLock(); + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if (i2cp->i2c->TWI_SR & (TWI_SR_TXCOMP | TWI_SR_RXRDY)) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) + return MSG_TIMEOUT; + + osalSysUnlock(); + } + + i2c_lld_read_bytes(i2cp); + + /* Enable write protection. */ + twiEnableWP(i2cp->i2c); + + /* Waits for the operation completion or a timeout.*/ + return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + + } else { + /* Compute device slave address. Internal slave address are sent as data. */ + + i2cp->i2c->TWI_MMR = 0; + + if ((addr & TWI_ADDR_MASK_10) != 0) { + /* 10-bit address. */ + if (i2cp->config->op_mode == OPMODE_I2C) { + + /* Store 2 slave device address MSB bits in MMR_DADR with 11110 mask. Configure number of internal slave address bytes in MMR_IADRSZ as 1. */ + i2cp->i2c->TWI_MMR = TWI_MMR_DADR((addr >> 8) | TWI_ADDR_10_DADR_MASK) | + TWI_MMR_IADRSZ_1_BYTE; + i2cp->i2c->TWI_IADR = TWI_ADDR_10_IADR_MASK & addr; + + } else if (i2cp->config->op_mode == OPMODE_SMBUS) + osalDbgAssert((addr & TWI_ADDR_MASK_10) != 0, "10-bit address not supported in SMBus mode"); + + } else { + /* 7-bit address. */ + /* Store slave device address in MMR_DADR. */ + i2cp->i2c->TWI_MMR |= TWI_MMR_DADR(addr); + } + + /* Releases the lock from high level driver.*/ + osalSysUnlock(); + + /* Calculating the time window for the timeout on the busy bus condition.*/ + start = osalOsGetSystemTimeX(); + end = osalTimeAddX(start, OSAL_MS2I(SAMA_I2C_BUSY_TIMEOUT)); + + /* Waits until BUSY flag is reset or, alternatively, for a timeout + condition.*/ + while (true) { + osalSysLock(); + + /* If the bus is not busy then the operation can continue, note, the + loop is exited in the locked state.*/ + if (i2cp->i2c->TWI_SR & (TWI_SR_TXCOMP | TWI_SR_RXRDY)) + break; + + /* If the system time went outside the allowed window then a timeout + condition is returned.*/ + if (!osalTimeIsInRangeX(osalOsGetSystemTimeX(), start, end)) + return MSG_TIMEOUT; + + osalSysUnlock(); + } + + i2c_lld_write_bytes(i2cp); + + /* Enable write protection. */ + twiEnableWP(i2cp->i2c); + + /* Waits for the operation completion or a timeout.*/ + return osalThreadSuspendTimeoutS(&i2cp->thread, timeout); + } +} + +#endif /* HAL_USE_I2C */ + +/** @} */ diff --git a/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.h b/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.h new file mode 100644 index 000000000..1d3538852 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.h @@ -0,0 +1,277 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 I2Cv1/hal_i2c_lld.h + * @brief SAMA I2C subsystem low level driver header. + * + * @addtogroup I2C + * @{ + */ + +#ifndef HAL_I2C_LLD_H +#define HAL_I2C_LLD_H + +#if HAL_USE_I2C || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief I2C0 driver enable switch. + * @details If set to @p TRUE the support for TWIHS0 is included. + * @note The default is @p FALSE. + */ +#if !defined(SAMA_I2C_USE_TWIHS0) || defined(__DOXYGEN__) +#define SAMA_I2C_USE_TWIHS0 FALSE +#endif + +/** + * @brief I2C1 driver enable switch. + * @details If set to @p TRUE the support for TWIHS1 is included. + * @note The default is @p FALSE. + */ +#if !defined(SAMA_I2C_USE_TWIHS1) || defined(__DOXYGEN__) +#define SAMA_I2C_USE_TWIHS1 FALSE +#endif + +/** + * @brief I2C timeout on busy condition in milliseconds. + */ +#if !defined(SAMA_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__) +#define SAMA_I2C_BUSY_TIMEOUT 50 +#endif + +/** + * @brief I2C0 interrupt priority level setting. + */ +#if !defined(SAMA_I2C_TWIHS0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define SAMA_I2C_TWIHS0_IRQ_PRIORITY 6 +#endif + +/** + * @brief I2C1 interrupt priority level setting. + */ +#if !defined(SAMA_I2C_TWIHS1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define SAMA_I2C_TWIHS1_IRQ_PRIORITY 6 +#endif + +/** +* @brief I2C0 DMA IRQ priority (0..7|lowest..highest). +* @note The priority level is used for both the TX and RX DMA channels. +*/ +#if !defined(SAMA_I2C_TWIHS0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define SAMA_I2C_TWIHS0_DMA_IRQ_PRIORITY 6 +#endif + +/** +* @brief I2C1 DMA IRQ priority (0..7|lowest..highest). +* @note The priority level is used for both the TX and RX DMA streams. +*/ +#if !defined(SAMA_I2C_TWIHS1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define SAMA_I2C_TWIHS1_DMA_IRQ_PRIORITY 6 +#endif + +/** + * @brief I2C DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(SAMA_I2C_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define SAMA_I2C_DMA_ERROR_HOOK(i2cp) osalSysHalt("DMA failure") +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/** @brief error checks */ + +#if !SAMA_I2C_USE_TWIHS0 && !SAMA_I2C_USE_TWIHS1 +#error "I2C driver activated but no TWIHS peripheral assigned" +#endif + +#if !defined(SAMA_DMA_REQUIRED) +#define SAMA_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type representing an I2C address. + */ +typedef uint32_t i2caddr_t; + +/** + * @brief Type of I2C driver condition flags. + */ +typedef uint32_t i2cflags_t; + +/** + * @brief Supported modes for the I2C bus. + */ +typedef enum { + OPMODE_I2C = 1, + OPMODE_SMBUS = 2, +} i2copmode_t; + +/** + * @brief Type of I2C driver configuration structure. + */ +typedef struct { + /* End of the mandatory fields.*/ + i2copmode_t op_mode; /**< @brief Specifies the I2C mode. */ + uint32_t clock_speed; /**< @brief Specifies the clock frequency. + @note Must be set to a value lower + than 400kHz. */ +} I2CConfig; + +/** + * @brief Type of a structure representing an I2C driver. + */ +typedef struct I2CDriver I2CDriver; + +/** + * @brief Structure representing an I2C driver. + */ +struct I2CDriver { + /** + * @brief Driver state. + */ + i2cstate_t state; + /** + * @brief Current configuration data. + */ + const I2CConfig *config; + /** + * @brief Error flags. + */ + i2cflags_t errors; +#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) + /** + * @brief Mutex protecting the bus. + */ + mutex_t mutex; +#endif /* I2C_USE_MUTUAL_EXCLUSION */ +#if defined(I2C_DRIVER_EXT_FIELDS) + I2C_DRIVER_EXT_FIELDS +#endif + /* End of the mandatory fields.*/ + /** + * @brief Thread waiting for I/O completion. + */ + thread_reference_t thread; + /** + * @brief Number of bytes in TX phase. + */ + size_t txbytes; + /** + * @brief Number of bytes in RX phase. + */ + size_t rxbytes; + /** + * @brief Pointer to the TX buffer location. + */ + const uint8_t *txbuf; + /** + * @brief Pointer to the RX buffer location. + */ + uint8_t *rxbuf; + /** + * @brief Receive DMA stream. + */ + sama_dma_channel_t *dmarx; + /** + * @brief Transmit DMA stream. + */ + sama_dma_channel_t *dmatx; + /** + * @brief RX DMA mode bit mask. + */ + uint32_t rxdmamode; + /** + * @brief TX DMA mode bit mask. + */ + uint32_t txdmamode; + /** + * @brief Pointer to the TWIHSx registers block. + */ + Twi *i2c; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Get errors from I2C driver. + * + * @param[in] i2cp pointer to the @p I2CDriver object + * + * @notapi + */ +#define i2c_lld_get_errors(i2cp) ((i2cp)->errors) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +#if SAMA_I2C_USE_TWIHS0 +extern I2CDriver I2CD0; +#endif + +#if SAMA_I2C_USE_TWIHS1 +extern I2CDriver I2CD1; +#endif + +#endif /* !defined(__DOXYGEN__) */ + +#ifdef __cplusplus +extern "C" { +#endif + void i2c_lld_init(void); + void i2c_lld_start(I2CDriver *i2cp); + void i2c_lld_stop(I2CDriver *i2cp); + msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr, + const uint8_t *txbuf, size_t txbytes, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); + msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr, + uint8_t *rxbuf, size_t rxbytes, + sysinterval_t timeout); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_I2C */ + +#endif /* HAL_I2C_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c b/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c index 862a7618c..86edb1877 100644 --- a/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c +++ b/os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c @@ -33,8 +33,18 @@ /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ +/* + * @brief Buffer size. + */ #define BUFFER_SIZE ((((SAMA_MAC_BUFFERS_SIZE - 1) | 3) + 1) / 4) +/* + * @brief NO CACHE attribute + */ +#if !defined(NO_CACHE) +#define NO_CACHE __attribute__((section (".nocache"))) +#endif + /* MII divider optimal value.*/ #if (SAMA_GMAC0CLK <= 20000000) #define GMAC_CLK GMAC_NCFGR_CLK_MCK_8 @@ -73,17 +83,28 @@ MACDriver ETHD0; static const uint8_t default_mac_address[] = {0x54, 0x54, 0x08, 0x34, 0x1f, 0x3a}; +/* + * In terms of AMBA AHB operation, the descriptors are read from memory using + * a single 32-bit AHB access. The descriptors should be aligned at 32-bit + * boundaries and the descriptors are written to using two individual non + * sequential accesses. + */ + /* Rx descriptor list */ -ALIGNED_VAR(8) +NO_CACHE ALIGNED_VAR(4) static sama_eth_rx_descriptor_t __eth_rd[SAMA_MAC_RECEIVE_BUFFERS]; /* Tx descriptor list */ -ALIGNED_VAR(8) +NO_CACHE ALIGNED_VAR(4) static sama_eth_tx_descriptor_t __eth_td[SAMA_MAC_TRANSMIT_BUFFERS]; +NO_CACHE ALIGNED_VAR(4) static sama_eth_tx_descriptor_t __eth_td1[1]; +NO_CACHE ALIGNED_VAR(4) static sama_eth_tx_descriptor_t __eth_td2[1]; +NO_CACHE static uint32_t __eth_rb[SAMA_MAC_RECEIVE_BUFFERS][BUFFER_SIZE]; +NO_CACHE static uint32_t __eth_tb[SAMA_MAC_TRANSMIT_BUFFERS][BUFFER_SIZE]; /*===========================================================================*/ diff --git a/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.c b/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.c index 81f8d6cd0..dbf5c36a4 100644 --- a/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.c +++ b/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.c @@ -29,10 +29,36 @@ /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ +#define __PIOA ((Pio *)0xFC038000U) +#define EVENTS_NUMBER (4 * 32) + +/** + * @brief PIOA interrupt priority level setting. + */ +#define SAMA_PIOA_IRQ_PRIORITY 2 + +/** + * @brief PIOB interrupt priority level setting. + */ +#define SAMA_PIOB_IRQ_PRIORITY 2 + +/** + * @brief PIOC interrupt priority level setting. + */ +#define SAMA_PIOC_IRQ_PRIORITY 2 + +/** + * @brief PIOD interrupt priority level setting. + */ +#define SAMA_PIOD_IRQ_PRIORITY 2 /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ +/** + * @brief Event records for the GPIO interrupts. + */ +palevent_t _pal_events[EVENTS_NUMBER]; /*===========================================================================*/ /* Driver local variables and types. */ @@ -45,10 +71,167 @@ /*===========================================================================*/ /* Driver interrupt handlers. */ /*===========================================================================*/ +/** + * @brief PIOA interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(SAMA_PIOA_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uint32_t sr, imr, is; + uint8_t i, j; + + sr = pal_lld_read_status(PIOA); + imr = pal_lld_read_int_mask(PIOA); + + is = sr & imr; + for (j = 0, i = 0; i < 32; i++, j++) { + if (!(is & (0x1 << j))) { + continue; + } +#if (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) + if (_pal_events[i].cb != NULL) { + _pal_events[i].cb(&is); + } +#endif + } + aicAckInt(); + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief PIOB interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(SAMA_PIOB_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uint32_t sr, imr, is; + uint8_t i, j; + + sr = pal_lld_read_status(PIOB); + imr = pal_lld_read_int_mask(PIOB); + + is = sr & imr; + for (j = 0, i = 32; i < 64; i++, j++) { + if (!(is & (0x1 << j))) { + continue; + } +#if (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) + if (_pal_events[i].cb != NULL) { + _pal_events[i].cb(&is); + } +#endif + } + aicAckInt(); + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief PIOC interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(SAMA_PIOC_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + uint32_t sr, imr, is; + uint8_t i, j; + + sr = pal_lld_read_status(PIOC); + imr = pal_lld_read_int_mask(PIOC); + + is = sr & imr; + for (j = 0, i = 64; i < 96; i++, j++) { + if (!(is & (0x1 << j))) { + continue; + } +#if (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) + if (_pal_events[i].cb != NULL) { + _pal_events[i].cb(&is); + } +#endif + } + aicAckInt(); + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief PIOD interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(SAMA_PIOD_HANDLER) { + OSAL_IRQ_PROLOGUE(); + + uint32_t sr, imr, is; + uint8_t i, j; + + sr = pal_lld_read_status(PIOD); + imr = pal_lld_read_int_mask(PIOD); + + is = sr & imr; + for (j = 0, i = 96; i < 128; i++, j++) { + if (!(is & (0x1 << j))) { + continue; + } +#if (PAL_USE_CALLBACKS == TRUE) || defined(__DOXYGEN__) + if (_pal_events[i].cb != NULL) { + _pal_events[i].cb(&is); + } +#endif + } + aicAckInt(); + OSAL_IRQ_EPILOGUE(); +} /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ +/** + * @brief PAL driver initialization. + * + * @notapi + */ +void _pal_lld_init(void) { + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) + unsigned i; + + for (i = 0; i < EVENTS_NUMBER; i++) { + _pal_init_event(i); + } + + /* + * Clears status register + */ + pal_lld_read_status(PIOA); + pal_lld_read_status(PIOB); + pal_lld_read_status(PIOC); + pal_lld_read_status(PIOD); + + aicSetSourcePriority(ID_PIOA, SAMA_PIOA_IRQ_PRIORITY); + aicSetSourceHandler(ID_PIOA, SAMA_PIOA_HANDLER); + aicEnableInt(ID_PIOA); + + aicSetSourcePriority(ID_PIOB, SAMA_PIOB_IRQ_PRIORITY); + aicSetSourceHandler(ID_PIOB, SAMA_PIOB_HANDLER); + aicEnableInt(ID_PIOB); + + aicSetSourcePriority(ID_PIOC, SAMA_PIOC_IRQ_PRIORITY); + aicSetSourceHandler(ID_PIOC, SAMA_PIOC_HANDLER); + aicEnableInt(ID_PIOC); + + aicSetSourcePriority(ID_PIOD, SAMA_PIOD_IRQ_PRIORITY); + aicSetSourceHandler(ID_PIOD, SAMA_PIOD_HANDLER); + aicEnableInt(ID_PIOD); +#endif /* #if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) */ +} /** * @brief Pads mode setup. @@ -82,5 +265,123 @@ void _pal_lld_setgroupmode(ioportid_t port, port->CFGR = cfgr; } +#if SAMA_HAL_IS_SECURE +/** + * @brief Configures debouncing time for pads. + * + * @param[in] db_time debouncing time + * + * @api + */ +void pal_lld_cfg_debouncing_time(uint32_t db_time) { + + /* + * Debouncing time configuration only in SECURE STATE + */ + __PIOA->S_PIO_SCDR = db_time & 0x3FFF; +} +#endif + +/** + * @brief Reads/Clears Interrupt Status Register. + * + * @param[in] port port identifier + * + * @api + */ +uint32_t pal_lld_read_status(ioportid_t port) { + return port->ISR; +} + +/** + * @brief Reads Interrupt Mask Register. + * + * @param[in] port port identifier + * + * @api + */ +uint32_t pal_lld_read_int_mask(ioportid_t port) { + return port->IMR; +} + +/** + * @brief Reads Configuration Register. + * + * @param[in] port port identifier + * + * @api + */ +uint32_t pal_lld_read_cfgr(ioportid_t port) { + return port->CFGR; +} + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT || defined(__DOXYGEN__) +/** + * @brief Pad event enable. + * @note Programming an unknown or unsupported mode is silently ignored. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * @param[in] mode pad event mode + * + * @notapi + */ +void _pal_lld_enablepadevent(ioportid_t port, + iopadid_t pad, + ioeventmode_t mode) { + + port->MSKR = pad; + port->CFGR |= mode; + port->IER = pad; +} + +/** + * @brief Returns a PAL event structure associated to a pad. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +palevent_t* pal_lld_get_pad_event(ioportid_t port, iopadid_t pad) { + + palevent_t* palevt = NULL; + + if (port == PIOA) { + palevt = &_pal_events[pad]; + } + else if (port == PIOB) { + palevt = &_pal_events[32 + pad]; + } + else if (port == PIOC) { + palevt = &_pal_events[64 + pad]; + } + else { + palevt = &_pal_events[96 + pad]; + } + + return palevt; +} + +/** + * @brief Pad event disable. + * @details This function disables previously programmed event callbacks. + * + * @param[in] port port identifier + * @param[in] pad pad number within the port + * + * @notapi + */ +void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad) { + + port->IDR |= pad; + +#if PAL_USE_CALLBACKS || PAL_USE_WAIT + /* Callback cleared and/or thread reset.*/ + _pal_clear_event(pad); +#endif +} +#endif /* PAL_USE_CALLBACKS || PAL_USE_WAIT */ + #endif /* HAL_USE_PAL */ /** @} */ diff --git a/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.h b/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.h index e2ede7c52..53386ba5b 100644 --- a/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.h +++ b/os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.h @@ -30,6 +30,9 @@ /*===========================================================================*/ /* Unsupported modes and specific modes */ /*===========================================================================*/ +/* Specifies palInit() without parameter, required until all platforms will + be updated to the new style.*/ +#define PAL_NEW_INIT #undef PAL_MODE_RESET #undef PAL_MODE_UNCONNECTED @@ -102,7 +105,8 @@ PAL_SAMA_IFSCEN_MASK | \ PAL_SAMA_OPD_MASK | \ PAL_SAMA_SCHMITT_MASK | \ - PAL_SAMA_DRVSTR_MASK + PAL_SAMA_DRVSTR_MASK | \ + PAL_SAMA_EVTSEL_MASK #if SAMA_HAL_IS_SECURE #define PAL_SAMA_SECURE_MASK (1U << 31U) @@ -146,7 +150,7 @@ */ #define PAL_MODE_INPUT_PULLDOWN (PAL_SAMA_DIR_INPUT | \ PAL_SAMA_SCHMITT | \ - PAL_SAMA_PUEN_PULLDOWN) + PAL_SAMA_PDEN_PULLDOWN) /** * @brief Analog input mode. @@ -365,13 +369,12 @@ typedef uint32_t iopadid_t; /* Implementation, some of the following macros could be implemented as */ /* functions, if so please put them in pal_lld.c. */ /*===========================================================================*/ - /** - * @brief PIO ports subsystem initialization. + * @brief GPIO ports subsystem initialization. * * @notapi */ -#define pal_lld_init(config) +#define pal_lld_init() _pal_lld_init() /** * @brief Reads an I/O port. @@ -497,7 +500,8 @@ typedef uint32_t iopadid_t; * * @notapi */ -#define pal_lld_enablepadevent(port, pad, mode) +#define pal_lld_enablepadevent(port, pad, mode) \ + _pal_lld_enablepadevent(port, pad, mode) /** * @brief Pad event disable. @@ -508,17 +512,8 @@ typedef uint32_t iopadid_t; * * @notapi */ -#define pal_lld_disablepadevent(port, pad) - -/** - * @brief Returns a PAL event structure associated to a pad. - * - * @param[in] port port identifier - * @param[in] pad pad number within the port - * - * @notapi - */ -#define pal_lld_get_pad_event(port, pad) +#define pal_lld_disablepadevent(port, pad) \ + _pal_lld_disablepadevent(port, pad) /** * @brief Returns a PAL event structure associated to a line. @@ -527,14 +522,32 @@ typedef uint32_t iopadid_t; * * @notapi */ -#define pal_lld_get_line_event(line) +#define pal_lld_get_line_event(line) \ + &_pal_events[PAL_PAD(line)] + +#if !defined(__DOXYGEN__) +extern palevent_t _pal_events[4 * 32]; +#endif #ifdef __cplusplus extern "C" { #endif + void _pal_lld_init(void); void _pal_lld_setgroupmode(ioportid_t port, ioportmask_t mask, iomode_t mode); + void _pal_lld_enablepadevent(ioportid_t port, + iopadid_t pad, + ioeventmode_t mode); + void _pal_lld_disablepadevent(ioportid_t port, iopadid_t pad); + palevent_t* pal_lld_get_pad_event(ioportid_t port, iopadid_t pad); + /* LLD only functions */ +#if SAMA_HAL_IS_SECURE + void pal_lld_cfg_debouncing_time(uint32_t db_time); +#endif + uint32_t pal_lld_read_status(ioportid_t port); + uint32_t pal_lld_read_int_mask(ioportid_t port); + uint32_t pal_lld_read_cfgr(ioportid_t port); #ifdef __cplusplus } #endif diff --git a/os/hal/ports/SAMA/LLD/RNGv1/driver.mk b/os/hal/ports/SAMA/LLD/RNGv1/driver.mk new file mode 100644 index 000000000..163c48a70 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/RNGv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_TRNG TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/RNGv1 diff --git a/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c b/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c new file mode 100644 index 000000000..6d8fde7d6 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c @@ -0,0 +1,175 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 hal_trng_lld.c + * @brief STM32 TRNG subsystem low level driver source. + * + * @addtogroup TRNG + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief TRNGD0 driver identifier. + */ +#if (SAMA_TRNG_USE_TRNG0 == TRUE) || defined(__DOXYGEN__) +TRNGDriver TRNGD0; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +static const TRNGConfig default_cfg = {0}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level TRNG driver initialization. + * + * @notapi + */ +void trng_lld_init(void) { + +#if SAMA_TRNG_USE_TRNG0 == TRUE + +#if SAMA_HAL_IS_SECURE + mtxConfigPeriphSecurity(MATRIX1, ID_TRNG, SECURE_PER); +#endif /* SAMA_HAL_IS_SECURE */ + + /* Driver initialization.*/ + trngObjectInit(&TRNGD0); + TRNGD0.trng = TRNG; +#endif +} + +/** + * @brief Configures and activates the TRNG peripheral. + * + * @param[in] trngp pointer to the @p TRNGDriver object + * + * @notapi + */ +void trng_lld_start(TRNGDriver *trngp) { + + /* There is no real configuration but setting up a valid pointer anyway.*/ + if (trngp->config == NULL) { + trngp->config = &default_cfg; + } + + if (trngp->state == TRNG_STOP) { + /* Enables the peripheral.*/ +#if SAMA_TRNG_USE_TRNG0 == TRUE + if (&TRNGD0 == trngp) { + pmcEnableTRNG0(); + } +#endif + } + /* Configures the peripheral.*/ + trngp->trng->TRNG_CR = TRNG_CR_ENABLE | TRNG_CR_KEY_PASSWD; +} + +/** + * @brief Deactivates the TRNG peripheral. + * + * @param[in] trngp pointer to the @p TRNGDriver object + * + * @notapi + */ +void trng_lld_stop(TRNGDriver *trngp) { + + if (trngp->state == TRNG_READY) { + /* Resets the peripheral.*/ + trngp->trng->TRNG_CR = TRNG_CR_KEY_PASSWD; + + /* Disables the peripheral.*/ +#if SAMA_TRNG_USE_TRNG0 == TRUE + if (&TRNGD0 == trngp) { + pmcDisableTRNG0(); + } +#endif + } +} + +/** + * @brief True random numbers generator. + * @note The function is blocking and likely performs polled waiting + * inside the low level implementation. + * + * @param[in] trngp pointer to the @p TRNGDriver object + * @param[in] size size of output buffer + * @param[out] out output buffer + * @return The operation status. + * @retval false if a random number has been generated. + * @retval true if an HW error occurred. + * + * @api + */ +bool trng_lld_generate(TRNGDriver *trngp, size_t size, uint8_t *out) { + + while (true) { + uint32_t r, tmo; + size_t i; + + /* Waiting for a random number in data register.*/ + tmo = SAMA_DATA_FETCH_ATTEMPTS; + while ((tmo > 0) && ((trngp->trng->TRNG_ISR & TRNG_ISR_DATRDY) == 0)) { + tmo--; + if (tmo == 0) { + return true; + } + } + + /* Getting the generated random number.*/ + r = trngp->trng->TRNG_ODATA; + + /* Writing in the output buffer.*/ + for (i = 0; i < sizeof (uint32_t) / sizeof (uint8_t); i++) { + *out++ = (uint8_t)r; + r = r >> 8; + size--; + if (size == 0) { + return false; + } + } + } +} + +#endif /* HAL_USE_TRNG == TRUE */ + +/** @} */ diff --git a/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.h b/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.h new file mode 100644 index 000000000..146635db4 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.h @@ -0,0 +1,113 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 hal_trng_lld.h + * @brief SAMA TRNG subsystem low level driver header. + * + * @addtogroup TRNG + * @{ + */ + +#ifndef HAL_TRNG_LLD_H +#define HAL_TRNG_LLD_H + +#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name SAMA configuration options + * @{ + */ +/** + * @brief TRNGD0 driver enable switch. + * @details If set to @p TRUE the support for TRNGD0 is included. + * @note The default is @p FALSE. + */ +#if !defined(SAMA_TRNG_USE_TRNG0) || defined(__DOXYGEN__) +#define SAMA_TRNG_USE_TRNG0 FALSE +#endif + +/** + * @brief TRNGD0 data available timeout counter. + * @details Number of status register fetches before failing. + */ +#if !defined(SAMA_DATA_FETCH_ATTEMPTS) || defined(__DOXYGEN__) +#define SAMA_DATA_FETCH_ATTEMPTS 1000 +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !SAMA_TRNG_USE_TRNG0 +#error "TRNG driver activated but no RNG peripheral assigned" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Low level fields of the TRNG configuration structure. + */ +#define trng_lld_config_fields \ + /* Dummy configuration, it is not needed.*/ \ + uint32_t dummy + +/** + * @brief Low level fields of the TRNG driver structure. + */ +#define trng_lld_driver_fields \ + /* Pointer to the RNG registers block.*/ \ + Trng *trng; + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if (SAMA_TRNG_USE_TRNG0 == TRUE) && !defined(__DOXYGEN__) +extern TRNGDriver TRNGD0; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void trng_lld_init(void); + void trng_lld_start(TRNGDriver *trngp); + void trng_lld_stop(TRNGDriver *trngp); + bool trng_lld_generate(TRNGDriver *trngp, size_t size, uint8_t *out); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_TRNG == TRUE */ + +#endif /* HAL_TRNG_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.c b/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.c index 174996b8e..691a3cc15 100644 --- a/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.c +++ b/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.c @@ -106,8 +106,6 @@ static void rtc_enter_init(void) { /* Stop RTC_TIMR and RTC_CALR */ RTCD0.rtc->RTC_CR |= RTC_CR_UPDCAL; RTCD0.rtc->RTC_CR |= RTC_CR_UPDTIM; - while ((RTCD0.rtc->RTC_SR & RTC_SR_ACKUPD) == 0) - ; } /** @@ -364,8 +362,7 @@ void rtc_lld_init(void) { /** * @brief Set current time. - * @note Fractional part will be silently ignored. There is no possibility - * to set it on STM32 platform. + * @note Fractional part will be silently ignored. * @note The function can be called from any context. * * @param[in] rtcp pointer to RTC driver structure @@ -384,15 +381,35 @@ void rtc_lld_set_time(RTCDriver *rtcp, const RTCDateTime *timespec) { /* Disable write protection */ // syscDisableWP(); + /* Synchronization on a second periodic event polling the RTC_SR.SEC status bit */ + wait: while ((rtcp->rtc->RTC_SR & RTC_SR_SEC) == 0); + /* Entering a reentrant critical zone.*/ sts = osalSysGetStatusAndLockX(); - /* Synchronization on a second periodic event polling the RTC_SR.SEC status bit */ - while ((rtcp->rtc->RTC_SR & RTC_SR_SEC) == 0) - ; + if (!(rtcp->rtc->RTC_SR & RTC_SR_SEC)) { + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); + goto wait; + } + /* Writing the registers.*/ rtc_enter_init(); + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); + + while ((RTCD0.rtc->RTC_SR & RTC_SR_ACKUPD) == 0); + + /* Entering a reentrant critical zone.*/ + sts = osalSysGetStatusAndLockX(); + + if (!(rtcp->rtc->RTC_SR & RTC_SR_SEC)) { + /* Leaving a reentrant critical zone.*/ + osalSysRestoreStatusX(sts); + goto wait; + } + /* Clear ACKUPD status flag */ rtcp->rtc->RTC_SCCR = RTC_SCCR_ACKCLR; diff --git a/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.h b/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.h index a5d4b8918..7b5fb3cd2 100644 --- a/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.h +++ b/os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.h @@ -79,17 +79,6 @@ /* Driver data structures and types. */ /*===========================================================================*/ -/** - * @brief FileStream specific methods. - */ -#define _rtc_driver_methods \ - _file_stream_methods - -/** - * @brief Type of an RTC alarm number. - */ -typedef uint32_t rtcalarm_t; - /** * @brief Type of an RTC event. */ @@ -106,7 +95,7 @@ typedef void (*rtccb_t)(RTCDriver *rtcp, rtcevent_t event); /** * @brief Type of a structure representing an RTC alarm time stamp. */ -typedef struct { +typedef struct hal_rtc_alarm { /** * @brief Type of an alarm as encoded in RTC registers. */ @@ -114,37 +103,14 @@ typedef struct { uint32_t calralrm; } RTCAlarm; -#if RTC_HAS_STORAGE || defined(__DOXYGEN__) /** - * @extends FileStream - * - * @brief @p RTCDriver virtual methods table. + * @brief Implementation-specific @p RTCDriver fields. */ -struct RTCDriverVMT { - _rtc_driver_methods -}; -#endif - -/** - * @brief Structure representing an RTC driver. - */ -struct RTCDriver { -#if RTC_HAS_STORAGE || defined(__DOXYGEN__) - /** - * @brief Virtual Methods Table. - */ - const struct RTCDriverVMT *vmt; -#endif - /* End of the mandatory fields.*/ - /** - * @brief Pointer to the RTC registers block. - */ - Rtc *rtc; - /** - * @brief Callback pointer. - */ - rtccb_t callback; -}; +#define rtc_lld_driver_fields \ + /* Pointer to the RTC registers block.*/ \ + Rtc *rtc; \ + /* Callback pointer.*/ \ + rtccb_t callback /*===========================================================================*/ /* Driver macros. */ @@ -182,13 +148,6 @@ struct RTCDriver { /* External declarations. */ /*===========================================================================*/ -#if !defined(__DOXYGEN__) -extern RTCDriver RTCD0; -#if RTC_HAS_STORAGE -extern struct RTCDriverVMT _rtc_lld_vmt; -#endif -#endif - #ifdef __cplusplus extern "C" { #endif diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c index a337ee6d7..d019da05a 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c @@ -1,7 +1,7 @@ #include #include "hal.h" -#if (HAL_USE_SDMMC == TRUE) +#if (SAMA_USE_SDMMC == TRUE) #include "sama_sdmmc_lld.h" #include "ch_sdmmc_device.h" diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h index 29f1119da..2370d36a9 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h @@ -99,7 +99,7 @@ typedef struct _SdmmcCommand { /** Command index */ uint8_t bCmd; /** Command return status */ - uint8_t bStatus; + volatile uint8_t bStatus; } sSdmmcCommand; diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c index 4323b5876..dbfa8bd7a 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c @@ -1,7 +1,7 @@ #include #include "hal.h" -#if (HAL_USE_SDMMC == TRUE) +#if (SAMA_USE_SDMMC == TRUE) #include "sama_sdmmc_lld.h" #include "ch_sdmmc_device.h" @@ -145,7 +145,7 @@ uint8_t Cmd1(SdmmcDriver *drv, bool * hc) /* Tell the MMC device which voltage the host supplies to the VDD line * (MMC card) or VCC line (e.MMC device). * TODO get this board-specific value from platform code. On the - * SAMA5D2-XULT board, VDD is 3.3V ± 1%. */ + * SAMA5D2-XULT board, VDD is 3.3V � 1%. */ arg |= SD_OCR_VDD_32_33 | SD_OCR_VDD_33_34; /* Fill command */ diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c index 5861508b2..7bdd136e0 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c @@ -1,7 +1,7 @@ #include #include "hal.h" -#if (HAL_USE_SDMMC == TRUE) +#if (SAMA_USE_SDMMC == TRUE) #include "sama_sdmmc_lld.h" #include "ch_sdmmc_device.h" @@ -148,29 +148,7 @@ uint8_t sdmmc_device_lowlevelcfg(SdmmcDriver *driver) break; } - - if (res) { - //check res - res = IS_CACHE_ALIGNED(driver->config->data_buf); - TRACE_DEBUG_2("check data buf %d %08x\r\n", res, driver->config->data_buf); - res &= IS_CACHE_ALIGNED(driver->config->data_buf_size); - TRACE_DEBUG_2("check data_buf_size %d %08x\r\n", res, - driver->config->data_buf_size); - res &= IS_CACHE_ALIGNED(driver->card.EXT); - TRACE_DEBUG_2("check libExt %d %08x\r\n", res, driver->card.EXT); - - - if (!res) { - TRACE_WARNING("WARNING: buffers are not aligned on data cache lines. Please fix this before enabling DMA.\n\r"); - driver->use_polling = true; - } else { - driver->use_polling = false; - } - - } - return res; - } bool sdmmc_device_initialize(SdmmcDriver *driver) @@ -890,8 +868,12 @@ void sdmmc_device_deInit(SdmmcDriver *drv) * anticipated reading had to be supported, the data * cache lines would need to be invalidated twice: both * now and upon Transfer Complete. */ - cacheInvalidateRegion(driver->cmd.pData, len); - + if(((uint32_t) driver->cmd.pData & (L1_CACHE_BYTES - 1)) || (len & (L1_CACHE_BYTES - 1))) { + cacheCleanInvalidateRegion(driver->cmd.pData, len); + } + else { + cacheInvalidateRegion(driver->cmd.pData, len); + } } } @@ -1310,7 +1292,7 @@ void sdmmc_device_deInit(SdmmcDriver *drv) do { - now = chVTTimeElapsedSinceX(time); + now = chVTGetSystemTimeX(); /* chVTTimeElapsedSinceX(time) */ if (now >= end) { f = 1; @@ -1328,18 +1310,18 @@ void sdmmc_device_deInit(SdmmcDriver *drv) } } - void sdmmc_device_checkTimeCount(SdmmcDriver *driver) - { - if (driver->timeout_elapsed != -1) { +void sdmmc_device_checkTimeCount(SdmmcDriver *driver) +{ + if (driver->timeout_elapsed != -1) { - driver->timeout_elapsed = 0; - driver->now = chVTTimeElapsedSinceX( driver->time); - if (driver->now >= driver->timeout_ticks ) { - driver->timeout_elapsed = 1; - } + driver->timeout_elapsed = 0; + driver->now = chVTTimeElapsedSinceX(driver->time); + if (driver->now >= driver->timeout_ticks ) { + driver->timeout_elapsed = 1; + } - } - } + } +} static void calibrate_zout(Sdmmc * regs) { @@ -1575,12 +1557,6 @@ static uint8_t sdmmc_build_dma_table( SdmmcDriver *driver ) line[1], line[0] & SDMMC_DMA0DL_ATTR_END ? '.' : ' '); #endif } - /* Clean the underlying cache lines, to ensure the DMA gets our table - * when it reads from RAM. - * CPU access to the table is write-only, peripheral/DMA access is read- - * only, hence there is no need to invalidate. */ - cacheCleanRegion(driver->config->dma_table, (uint32_t)line - (uint32_t)driver->config->dma_table); - return rc; } diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_macros.h b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_macros.h index 52f82fd03..c973d1e4a 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_macros.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_macros.h @@ -2,12 +2,21 @@ #define CH_SDMMC_MACROS_H_ - +#if !defined(CACHE_ALIGNED) #define CACHE_ALIGNED __attribute__((aligned(L1_CACHE_BYTES))) +#endif +/* + * @brief NO CACHE attribute + */ +#if !defined(NO_CACHE) +#define NO_CACHE __attribute__((section (".nocache"))) +#endif #define IS_CACHE_ALIGNED(x) ((((uint32_t)(x)) & (L1_CACHE_BYTES - 1)) == 0) +#if !defined(ROUND_INT_DIV) #define ROUND_INT_DIV(n,d) (((n) + ((d)-1)) / (d)) +#endif #define ROUND_UP_MULT(x,m) (((x) + ((m)-1)) & ~((m)-1)) #define CEIL_INT_DIV(n,d) (((n) + (d) - 1) / (d)) #define ABS_DIFF(a,b) ((a) < (b) ? (b) - (a) : (a) - (b)) diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c index 5ddbdaed9..7720b4ba3 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c @@ -1,7 +1,7 @@ #include #include "hal.h" -#if (HAL_USE_SDMMC == TRUE) +#if (SAMA_USE_SDMMC == TRUE) #include "sama_sdmmc_lld.h" #include "ch_sdmmc_device.h" diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h index adbd63a41..8c71753f3 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h @@ -20,7 +20,24 @@ typedef enum #define CAPS0_MASK (SDMMC_CA0R_V33VSUP | SDMMC_CA0R_V30VSUP | \ SDMMC_CA0R_V18VSUP | SDMMC_CA0R_SLTYPE_Msk | \ SDMMC_CA0R_ED8SUP) +/* SOM1 */ +#if defined(BOARD_ATSAM5D27_SOM1) +#define BOARD_SDMMC0_CAPS0 (SDMMC_CA0R_V33VSUP | \ + SDMMC_CA0R_V18VSUP | \ + SDMMC_CA0R_SLTYPE_REMOVABLECARD | \ + SDMMC_CA0R_ED8SUP) + +#define BOARD_SDMMC1_CAPS0 (SDMMC_CA0R_V33VSUP | \ + SDMMC_CA0R_SLTYPE_REMOVABLECARD) +#elif defined(BOARD_ATSAM5D2_XULT) +#define BOARD_SDMMC0_CAPS0 (SDMMC_CA0R_V33VSUP | \ + SDMMC_CA0R_V18VSUP | \ + SDMMC_CA0R_SLTYPE_EMBEDDED | \ + SDMMC_CA0R_ED8SUP) +#define BOARD_SDMMC1_CAPS0 (SDMMC_CA0R_V33VSUP | \ + SDMMC_CA0R_SLTYPE_REMOVABLECARD) +#else #define BOARD_SDMMC0_CAPS0 (SDMMC_CA0R_V33VSUP | \ SDMMC_CA0R_V18VSUP | \ SDMMC_CA0R_SLTYPE_EMBEDDED | \ @@ -28,5 +45,6 @@ typedef enum #define BOARD_SDMMC1_CAPS0 (SDMMC_CA0R_V33VSUP | \ SDMMC_CA0R_SLTYPE_REMOVABLECARD) +#endif #endif /* CH_SDMMC_SAMA5D2_H_ */ diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c index ed2286bbc..d1e0f4532 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c @@ -1,7 +1,7 @@ #include #include "hal.h" -#if (HAL_USE_SDMMC == TRUE) +#if (SAMA_USE_SDMMC == TRUE) #include "sama_sdmmc_lld.h" #include "ch_sdmmc_device.h" #include "ch_sdmmc_cmds.h" diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sdio.c b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sdio.c index c9916620a..a7cd77a15 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sdio.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sdio.c @@ -1,6 +1,6 @@ #include "hal.h" -#if (HAL_USE_SDMMC == TRUE) +#if (SAMA_USE_SDMMC == TRUE) #include "sama_sdmmc_lld.h" #include "ch_sdmmc_device.h" diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk b/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk index 32695db51..49c64f5fc 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk @@ -1,3 +1,12 @@ +# Configuration files directory +ifeq ($(CONFDIR),) + CONFDIR = . +endif + +MCUCONF := $(strip $(shell cat $(CONFDIR)/mcuconf.h | egrep -e "\#define")) + +ifneq ($(findstring SAMA_USE_SDMMC TRUE,$(MCUCONF)),) + PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c \ $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c \ $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sdio.c \ @@ -8,3 +17,4 @@ PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c \ PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1 +endif diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c index 8ea88a347..725d52415 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c @@ -25,7 +25,7 @@ #include "hal.h" #include "ccportab.h" -#if (HAL_USE_SDMMC == TRUE) || defined(__DOXYGEN__) +#if (SAMA_USE_SDMMC == TRUE) || defined(__DOXYGEN__) #include #include "sama_sdmmc_lld.h" #include "ch_sdmmc_device.h" @@ -314,6 +314,6 @@ bool CC_WEAK sdmmcGetInstance(uint8_t index, SdmmcDriver **sdmmcp) return false; } -#endif /* HAL_USE_SDMMC == TRUE */ +#endif /* SAMA_USE_SDMMC == TRUE */ /** @} */ diff --git a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h index a340f7786..1526f7ccc 100644 --- a/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h +++ b/os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h @@ -25,7 +25,7 @@ #ifndef SAMA_SDMMC_LLD_H #define SAMA_SDMMC_LLD_H -#if (HAL_USE_SDMMC == TRUE) || defined(__DOXYGEN__) +#if (SAMA_USE_SDMMC == TRUE) || defined(__DOXYGEN__) #include "ch_sdmmc.h" @@ -76,8 +76,6 @@ typedef struct { sdmmcslots_t slot_id; uint8_t * bp; - uint8_t * data_buf; - uint32_t data_buf_size; uint32_t * dma_table; uint32_t dma_table_size; @@ -87,7 +85,7 @@ typedef struct { struct SamaSDMMCDriver { - sdmmcstate_t state; + volatile sdmmcstate_t state; const SamaSDMMCConfig *config; Sdmmc * regs; /* set of SDMMC hardware registers */ @@ -160,7 +158,7 @@ bool sdmmcGetInstance(uint8_t index, SdmmcDriver **sdmmcp) ; } #endif -#endif /* HAL_USE_SDMMC == TRUE */ +#endif /* SAMA_USE_SDMMC == TRUE */ #endif /* SAMA_SDMMC_LLD_H */ diff --git a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c index ccacf5e70..95625ca07 100644 --- a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c +++ b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c @@ -56,7 +56,6 @@ spip->SPI_WPMR = SPI_WPMR_WPKEY_PASSWD; \ } - /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ @@ -114,8 +113,8 @@ SPIDriver FSPID4; /* Driver local variables and types. */ /*===========================================================================*/ -static const uint8_t dummytx = 0xFFU; -static uint8_t dummyrx; +static const CACHE_ALIGNED uint8_t dummytx = 0xFFU; +CACHE_ALIGNED static uint8_t dummyrx; /*===========================================================================*/ /* Driver local functions. */ @@ -142,6 +141,13 @@ static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) { dmaChannelDisable(spip->dmatx); dmaChannelDisable(spip->dmarx); +#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE) + /* D-Cache is enabled */ + /* No operation for dummyrx */ + if ((uint32_t) spip->rxbuf != (uint32_t) &dummyrx) + cacheInvalidateRegion(spip->rxbuf, spip->rxbytes); +#endif + /* Portable SPI ISR code defined in the high level driver, note, it is a macro.*/ _spi_isr_code(spip); @@ -156,7 +162,6 @@ static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) { static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) { /* DMA errors handling.*/ - #if defined(SAMA_SPI_DMA_ERROR_HOOK) (void)spip; if ((flags & (XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) != 0) { @@ -189,6 +194,7 @@ void spi_lld_init(void) { /* Driver initialization.*/ spiObjectInit(&SPID0); SPID0.spi = SPI0; + SPID0.flexcom = NULL; SPID0.dmarx = NULL; SPID0.dmatx = NULL; SPID0.rxdmamode = XDMAC_CC_TYPE_PER_TRAN | @@ -222,6 +228,7 @@ void spi_lld_init(void) { /* Driver initialization.*/ spiObjectInit(&SPID1); SPID1.spi = SPI1; + SPID1.flexcom = NULL; SPID1.dmarx = NULL; SPID1.dmatx = NULL; SPID1.rxdmamode = XDMAC_CC_TYPE_PER_TRAN | @@ -443,6 +450,15 @@ void spi_lld_start(SPIDriver *spip) { (sama_dmaisr_t)spi_lld_serve_tx_interrupt, (void *)spip); osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); + +#if SAMA_SPI0_USE_GCLK +#if SAMA_SPI0_GCLK_DIV > 256 + #error "SPI0 GCLK divider out of range" +#endif + pmcConfigGclk(ID_SPI0, SAMA_SPI0_GCLK_SOURCE, SAMA_SPI0_GCLK_DIV); + pmcEnableGclk(ID_SPI0); +#endif /* SAMA_SPI0_USE_GCLK */ + /* Enable SPI0 clock */ pmcEnableSPI0(); } @@ -458,6 +474,15 @@ void spi_lld_start(SPIDriver *spip) { (sama_dmaisr_t)spi_lld_serve_tx_interrupt, (void *)spip); osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); + +#if SAMA_SPI1_USE_GCLK +#if SAMA_SPI1_GCLK_DIV > 256 + #error "SPI1 GCLK divider out of range" +#endif + pmcConfigGclk(ID_SPI1, SAMA_SPI1_GCLK_SOURCE, SAMA_SPI1_GCLK_DIV); + pmcEnableGclk(ID_SPI1); +#endif /* SAMA_SPI1_USE_GCLK */ + /* Enable SPI1 clock */ pmcEnableSPI1(); } @@ -475,6 +500,15 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; + +#if SAMA_FSPI0_USE_GCLK +#if SAMA_FSPI0_GCLK_DIV > 256 + #error "FSPI0 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM0, SAMA_FSPI0_GCLK_SOURCE, SAMA_FSPI0_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM0); +#endif /* SAMA_FSPI0_USE_GCLK */ + /* Enable FLEXCOM0 clock */ pmcEnableFLEXCOM0(); } @@ -492,6 +526,15 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; + +#if SAMA_FSPI1_USE_GCLK +#if SAMA_FSPI1_GCLK_DIV > 256 + #error "FSPI1 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM1, SAMA_FSPI1_GCLK_SOURCE, SAMA_FSPI1_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM1); +#endif /* SAMA_FSPI1_USE_GCLK */ + /* Enable FLEXCOM1 clock */ pmcEnableFLEXCOM1(); } @@ -509,6 +552,15 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; + +#if SAMA_FSPI2_USE_GCLK +#if SAMA_FSPI2_GCLK_DIV > 256 + #error "FSPI2 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM2, SAMA_FSPI2_GCLK_SOURCE, SAMA_FSPI2_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM2); +#endif /* SAMA_FSPI2_USE_GCLK */ + /* Enable FLEXCOM2 clock */ pmcEnableFLEXCOM2(); } @@ -526,6 +578,15 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; + +#if SAMA_FSPI3_USE_GCLK +#if SAMA_FSPI3_GCLK_DIV > 256 + #error "FSPI3 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM3, SAMA_FSPI3_GCLK_SOURCE, SAMA_FSPI3_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM3); +#endif /* SAMA_FSPI3_USE_GCLK */ + /* Enable FLEXCOM3 clock */ pmcEnableFLEXCOM3(); } @@ -543,7 +604,16 @@ void spi_lld_start(SPIDriver *spip) { osalDbgAssert(spip->dmatx != NULL, "no channel allocated"); /* Enabling SPI on FLEXCOM */ spip->flexcom->FLEX_MR = FLEX_MR_OPMODE_SPI; - /* Enable FLEXCOM4 clock */ + +#if SAMA_FSPI4_USE_GCLK +#if SAMA_FSPI4_GCLK_DIV > 256 + #error "FSPI4 GCLK divider out of range" +#endif + pmcConfigGclk(ID_FLEXCOM4, SAMA_FSPI4_GCLK_SOURCE, SAMA_FSPI4_GCLK_DIV); + pmcEnableGclk(ID_FLEXCOM4); +#endif /* SAMA_FSPI4_USE_GCLK */ + + /* Enable FLEXCOM4 clock */ pmcEnableFLEXCOM4(); } #endif /* SAMA_SPI_USE_FLEXCOM4 */ @@ -605,20 +675,32 @@ void spi_lld_stop(SPIDriver *spip) { if (&SPID0 == spip) /* Disable SPI0 clock */ pmcDisableSPI0(); +#if SAMA_SPI0_USE_GCLK + pmcDisableGclk(ID_SPI0); +#endif /* SAMA_SPI0_USE_GCLK */ + +#endif /* SAMA_SPI_USE_SPI0 */ -#endif /* SAMA_SPI_USE_SPI1 */ #if SAMA_SPI_USE_SPI1 if (&SPID1 == spip) /* Disable SPI1 clock */ pmcDisableSPI1(); -#endif /* SAMA_SPI_USE_FLEXCOM0 */ +#if SAMA_SPI1_USE_GCLK + pmcDisableGclk(ID_SPI1); +#endif /* SAMA_SPI1_USE_GCLK */ + +#endif /* SAMA_SPI_USE_SPI1 */ #if SAMA_SPI_USE_FLEXCOM0 if (&FSPID0 == spip) /* Disable FLEXCOM0 clock */ pmcDisableFLEXCOM0(); +#if SAMA_FSPI0_USE_GCLK + pmcDisableGclk(ID_FLEXCOM0); +#endif /* SAMA_FSPI0_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM0 */ #if SAMA_SPI_USE_FLEXCOM1 @@ -626,6 +708,10 @@ void spi_lld_stop(SPIDriver *spip) { /* Disable FLEXCOM1 clock */ pmcDisableFLEXCOM1(); +#if SAMA_FSPI1_USE_GCLK + pmcDisableGclk(ID_FLEXCOM1); +#endif /* SAMA_FSPI1_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM1 */ #if SAMA_SPI_USE_FLEXCOM2 @@ -633,6 +719,10 @@ void spi_lld_stop(SPIDriver *spip) { /* Disable FLEXCOM2 clock */ pmcDisableFLEXCOM2(); +#if SAMA_FSPI2_USE_GCLK + pmcDisableGclk(ID_FLEXCOM2); +#endif /* SAMA_FSPI2_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM2 */ #if SAMA_SPI_USE_FLEXCOM3 @@ -640,6 +730,10 @@ void spi_lld_stop(SPIDriver *spip) { /* Disable FLEXCOM3 clock */ pmcDisableFLEXCOM3(); +#if SAMA_FSPI3_USE_GCLK + pmcDisableGclk(ID_FLEXCOM3); +#endif /* SAMA_FSPI3_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM3 */ #if SAMA_SPI_USE_FLEXCOM4 @@ -647,8 +741,16 @@ void spi_lld_stop(SPIDriver *spip) { /* Disable FLEXCOM4 clock */ pmcDisableFLEXCOM4(); +#if SAMA_FSPI4_USE_GCLK + pmcDisableGclk(ID_FLEXCOM4); +#endif /* SAMA_FSPI4_USE_GCLK */ + #endif /* SAMA_SPI_USE_FLEXCOM4 */ } + + spip->txbuf = NULL; + spip->rxbuf = NULL; + spip->rxbytes = 0; } #if (SPI_SELECT_MODE == (SPI_SELECT_MODE_LLD || SPI_SELECT_MODE_PAD || \ @@ -695,12 +797,35 @@ void spi_lld_unselect(SPIDriver *spip) { void spi_lld_exchange(SPIDriver *spip, size_t n, const void *txbuf, void *rxbuf) { + spip->txbuf = txbuf; + spip->rxbuf = rxbuf; + spip->rxbytes = n; + +#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE) + + osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "txbuf address not cache aligned"); + osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "rxbuf address not cache aligned"); + + /* + * If size is not multiple of cache line, clean cache region is required. + */ + if (n & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) rxbuf, n); + } + /* Cache is enabled */ + cacheCleanRegion((uint8_t *) txbuf, n); +#endif /* SAMA_SPI_CACHE_USER_MANAGED */ + /* Writing channel */ + /* Change mode to incremented address for dummytx */ + dmaChannelSetMode(spip->dmatx, spip->txdmamode | XDMAC_CC_SAM_INCREMENTED_AM); dmaChannelSetSource(spip->dmatx, txbuf); dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR); dmaChannelSetTransactionSize(spip->dmatx, n); /* Reading channel */ + /* Change mode to incremented address */ + dmaChannelSetMode(spip->dmarx, spip->rxdmamode | XDMAC_CC_DAM_INCREMENTED_AM); dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR); dmaChannelSetDestination(spip->dmarx, rxbuf); dmaChannelSetTransactionSize(spip->dmarx, n); @@ -724,17 +849,37 @@ void spi_lld_exchange(SPIDriver *spip, size_t n, */ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { + spip->txbuf = txbuf; + spip->rxbuf = &dummyrx; + spip->rxbytes = n; + +#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE) + + osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned"); + + /* Cache is enabled */ + cacheCleanRegion((uint8_t *) txbuf, n); +#endif /* SAMA_SPI_CACHE_USER_MANAGED */ + /* Writing channel */ + + /* Change mode to incremented address for dummytx */ + dmaChannelSetMode(spip->dmatx, spip->txdmamode | XDMAC_CC_SAM_INCREMENTED_AM); + dmaChannelSetSource(spip->dmatx, txbuf); dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR); dmaChannelSetTransactionSize(spip->dmatx, n); /* Reading channel */ + + /* Change mode from incremented to fixed address for dummyrx */ + dmaChannelSetMode(spip->dmarx, spip->rxdmamode & ~XDMAC_CC_DAM_INCREMENTED_AM); + dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR); dmaChannelSetDestination(spip->dmarx, &dummyrx); dmaChannelSetTransactionSize(spip->dmarx, n); - /* Enable write protection. */ + /* Enable channel. */ dmaChannelEnable(spip->dmarx); dmaChannelEnable(spip->dmatx); @@ -759,12 +904,33 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) { */ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { + spip->rxbuf = rxbuf; + spip->rxbytes = n; + +#if (SAMA_SPI_CACHE_USER_MANAGED == FALSE) + + osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned"); + + /* + * If size is not multiple of cache line, clean cache region is required. + */ + if (n & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) rxbuf, n); + } +#endif /* SAMA_SPI_CACHE_USER_MANAGED */ + /* Writing channel */ + /* Change mode from incremented to fixed address for dummytx */ + dmaChannelSetMode(spip->dmatx, spip->txdmamode & ~XDMAC_CC_SAM_INCREMENTED_AM); + dmaChannelSetSource(spip->dmatx, &dummytx); dmaChannelSetDestination(spip->dmatx, &spip->spi->SPI_TDR); dmaChannelSetTransactionSize(spip->dmatx, n); /* Reading channel */ + /* Change mode to incremented address */ + dmaChannelSetMode(spip->dmarx, spip->rxdmamode | XDMAC_CC_DAM_INCREMENTED_AM); + dmaChannelSetSource(spip->dmarx, &spip->spi->SPI_RDR); dmaChannelSetDestination(spip->dmarx, rxbuf); dmaChannelSetTransactionSize(spip->dmarx, n); @@ -773,6 +939,29 @@ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) { dmaChannelEnable(spip->dmatx); } +/** + * @brief Exchanges one frame using a polled wait. + * @details This synchronous function exchanges one frame using a polled + * synchronization method. This function is useful when exchanging + * small amount of data on high speed channels, usually in this + * situation is much more efficient just wait for completion using + * polling than suspending the thread waiting for an interrupt. + * + * @param[in] spip pointer to the @p SPIDriver object + * @param[in] frame the data frame to send over the SPI bus + * @return The received data frame from the SPI bus. + */ +uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) { + + while((spip->spi->SPI_SR & SPI_SR_TXEMPTY) == 1); + + spip->spi->SPI_TDR = (uint8_t) frame; + + while((spip->spi->SPI_SR & SPI_SR_RDRF) == 0); + + return (uint16_t) spip->spi->SPI_RDR; +} + #endif /* HAL_USE_SPI */ /** @} */ diff --git a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h index f9be8bdee..df448eaec 100644 --- a/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h +++ b/os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h @@ -25,7 +25,7 @@ #ifndef HAL_SPI_LLD_H #define HAL_SPI_LLD_H -#if HAL_USE_SPI || defined(__DOXYGEN__) +#if (HAL_USE_SPI == TRUE) || defined(__DOXYGEN__) /*===========================================================================*/ /* Driver constants. */ @@ -52,15 +52,58 @@ #define SAMA_SPI_USE_SPI0 FALSE #endif +/** + * @brief SPI0 Generic clock enable. + * @details If set to @p TRUE the support for GCLK SPI0 is included. + */ +#if !defined(SAMA_SPI0_USE_GCLK) || defined(__DOXYGEN__) +#define SAMA_SPI0_USE_GCLK FALSE +#endif + +/** + * @brief SPI0 Generic clock source. + */ +#if !defined(SAMA_SPI0_GCLK_SOURCE) || defined(__DOXYGEN__) +#define SAMA_SPI0_GCLK_SOURCE SAMA_GCLK_MCK_CLK +#endif + +/** + * @brief SPI0 Generic clock div. + */ +#if !defined(SAMA_SPI0_GCLK_DIV) || defined(__DOXYGEN__) +#define SAMA_SPI0_GCLK_DIV 21 +#endif + /** * @brief SPI1 driver enable switch. * @details If set to @p TRUE the support for SPI1 is included. - * @note The default is @p FALSE. */ #if !defined(SAMA_SPI_USE_SPI1) || defined(__DOXYGEN__) #define SAMA_SPI_USE_SPI1 FALSE #endif +/** + * @brief SPI1 Generic clock enable. + * @details If set to @p TRUE the support for GCLK SPI1 is included. + */ +#if !defined(SAMA_SPI1_USE_GCLK) || defined(__DOXYGEN__) +#define SAMA_SPI1_USE_GCLK FALSE +#endif + +/** + * @brief SPI1 Generic clock source. + */ +#if !defined(SAMA_SPI1_GCLK_SOURCE) || defined(__DOXYGEN__) +#define SAMA_SPI1_GCLK_SOURCE SAMA_GCLK_MCK_CLK +#endif + +/** + * @brief SPI1 Generic clock div. + */ +#if !defined(SAMA_SPI1_GCLK_DIV) || defined(__DOXYGEN__) +#define SAMA_SPI1_GCLK_DIV 21 +#endif + /** * @brief SPI FLEXCOM0 driver enable switch. * @details If set to @p TRUE the support for FLEXCOM0 is included. @@ -69,6 +112,28 @@ #define SAMA_SPI_USE_FLEXCOM0 FALSE #endif +/** + * @brief FSPI0 Generic clock enable. + * @details If set to @p TRUE the support for GCLK FSPI0 is included. + */ +#if !defined(SAMA_FSPI0_USE_GCLK) || defined(__DOXYGEN__) +#define SAMA_FSPI0_USE_GCLK FALSE +#endif + +/** + * @brief FSPI0 Generic clock source. + */ +#if !defined(SAMA_FSPI0_GCLK_SOURCE) || defined(__DOXYGEN__) +#define SAMA_FSPI0_GCLK_SOURCE SAMA_GCLK_MCK_CLK +#endif + +/** + * @brief FSPI0 Generic clock div. + */ +#if !defined(SAMA_FSPI0_GCLK_DIV) || defined(__DOXYGEN__) +#define SAMA_FSPI0_GCLK_DIV 21 +#endif + /** * @brief SPI FLEXCOM1 driver enable switch. * @details If set to @p TRUE the support for FLEXCOM1 is included. @@ -77,6 +142,28 @@ #define SAMA_SPI_USE_FLEXCOM1 FALSE #endif +/** + * @brief FSPI1 Generic clock enable. + * @details If set to @p TRUE the support for GCLK FSPI1 is included. + */ +#if !defined(SAMA_FSPI1_USE_GCLK) || defined(__DOXYGEN__) +#define SAMA_FSPI1_USE_GCLK FALSE +#endif + +/** + * @brief FSPI1 Generic clock source. + */ +#if !defined(SAMA_FSPI1_GCLK_SOURCE) || defined(__DOXYGEN__) +#define SAMA_FSPI1_GCLK_SOURCE SAMA_GCLK_MCK_CLK +#endif + +/** + * @brief FSPI1 Generic clock div. + */ +#if !defined(SAMA_FSPI1_GCLK_DIV) || defined(__DOXYGEN__) +#define SAMA_FSPI1_GCLK_DIV 21 +#endif + /** * @brief SPI FLEXCOM2 driver enable switch. * @details If set to @p TRUE the support for FLEXCOM2 is included. @@ -85,6 +172,28 @@ #define SAMA_SPI_USE_FLEXCOM2 FALSE #endif +/** + * @brief FSPI2 Generic clock enable. + * @details If set to @p TRUE the support for GCLK FSPI2 is included. + */ +#if !defined(SAMA_FSPI2_USE_GCLK) || defined(__DOXYGEN__) +#define SAMA_FSPI2_USE_GCLK FALSE +#endif + +/** + * @brief FSPI2 Generic clock source. + */ +#if !defined(SAMA_FSPI2_GCLK_SOURCE) || defined(__DOXYGEN__) +#define SAMA_FSPI2_GCLK_SOURCE SAMA_GCLK_MCK_CLK +#endif + +/** + * @brief FSPI2 Generic clock div. + */ +#if !defined(SAMA_FSPI2_GCLK_DIV) || defined(__DOXYGEN__) +#define SAMA_FSPI2_GCLK_DIV 21 +#endif + /** * @brief SPI FLEXCOM3 driver enable switch. * @details If set to @p TRUE the support for FLEXCOM3 is included. @@ -93,6 +202,28 @@ #define SAMA_SPI_USE_FLEXCOM3 FALSE #endif +/** + * @brief FSPI3 Generic clock enable. + * @details If set to @p TRUE the support for GCLK FSPI3 is included. + */ +#if !defined(SAMA_FSPI3_USE_GCLK) || defined(__DOXYGEN__) +#define SAMA_FSPI3_USE_GCLK FALSE +#endif + +/** + * @brief FSPI3 Generic clock source. + */ +#if !defined(SAMA_FSPI3_GCLK_SOURCE) || defined(__DOXYGEN__) +#define SAMA_FSPI3_GCLK_SOURCE SAMA_GCLK_MCK_CLK +#endif + +/** + * @brief FSPI3 Generic clock div. + */ +#if !defined(SAMA_FSPI3_GCLK_DIV) || defined(__DOXYGEN__) +#define SAMA_FSPI3_GCLK_DIV 21 +#endif + /** * @brief SPI FLEXCOM4 driver enable switch. * @details If set to @p TRUE the support for FLEXCOM4 is included. @@ -101,6 +232,28 @@ #define SAMA_SPI_USE_FLEXCOM4 FALSE #endif +/** + * @brief FSPI4 Generic clock enable. + * @details If set to @p TRUE the support for GCLK FSPI4 is included. + */ +#if !defined(SAMA_FSPI4_USE_GCLK) || defined(__DOXYGEN__) +#define SAMA_FSPI4_USE_GCLK FALSE +#endif + +/** + * @brief FSPI4 Generic clock source. + */ +#if !defined(SAMA_FSPI4_GCLK_SOURCE) || defined(__DOXYGEN__) +#define SAMA_FSPI4_GCLK_SOURCE SAMA_GCLK_MCK_CLK +#endif + +/** + * @brief FSPI4 Generic clock div. + */ +#if !defined(SAMA_FSPI4_GCLK_DIV) || defined(__DOXYGEN__) +#define SAMA_FSPI4_GCLK_DIV 21 +#endif + /** * @brief SPI0 DMA interrupt priority level setting. */ @@ -151,6 +304,22 @@ #endif /** @} */ +/** + * @brief SPI DMA error hook. + * @note The default action for DMA errors is a system halt because DMA + * error can only happen because programming errors. + */ +#if !defined(SAMA_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__) +#define SAMA_SPI_DMA_ERROR_HOOK(spip) osalSysHalt("DMA failure") +#endif + +/** + * @brief SPI cache managing. + */ +#if !defined(SAMA_SPI_CACHE_USER_MANAGED) || defined(__DOXYGEN__) +#define SAMA_SPI_CACHE_USER_MANAGED FALSE +#endif + /*===========================================================================*/ /* Derived constants and error checks. */ /*===========================================================================*/ @@ -230,106 +399,36 @@ /* Driver data structures and types. */ /*===========================================================================*/ -/** - * @brief Type of a structure representing an SPI driver. - */ -typedef struct SPIDriver SPIDriver; +#define spi_lld_driver_fields \ + /* Pointer to the SPIx registers block.*/ \ + Spi *spi; \ + /* Pointer to the FLEXCOMx registers block.*/ \ + Flexcom *flexcom; \ + /* Receive DMA stream.*/ \ + sama_dma_channel_t *dmarx; \ + /* Transmit DMA stream.*/ \ + sama_dma_channel_t *dmatx; \ + /* RX DMA mode bit mask.*/ \ + uint32_t rxdmamode; \ + /* TX DMA mode bit mask.*/ \ + uint32_t txdmamode; \ + /* Pointer to the TX buffer location.*/ \ + const uint8_t *txbuf; \ + /* Pointer to the RX buffer location.*/ \ + uint8_t *rxbuf; \ + /* Number of bytes in RX phase.*/ \ + size_t rxbytes; /** - * @brief SPI notification callback type. - * - * @param[in] spip pointer to the @p SPIDriver object triggering the - * callback - */ -typedef void (*spicallback_t)(SPIDriver *spip); - -/** - * @brief Driver configuration structure. - */ -typedef struct { -#if (SPI_SUPPORTS_CIRCULAR == TRUE) || defined(__DOXYGEN__) - /** - * @brief Enables the circular buffer mode. - */ - bool circular; -#endif - /** - * @brief Operation complete callback or @p NULL. - */ - spicallback_t end_cb; - /* End of the mandatory fields.*/ - /** - * @brief The chip select line number. - */ - uint16_t npcs; - /** - * @brief SPI MR register initialization data. - */ - uint32_t mr; - /** - * @brief SPI CSR register initialization data. - */ + * @brief Low level fields of the SPI configuration structure. + */ +#define spi_lld_config_fields \ + /* The chip select line number.*/ \ + uint8_t npcs; \ + /* SPI MR register initialization data.*/ \ + uint32_t mr; \ + /* SPI CSR register initialization data.*/ \ uint32_t csr; -} SPIConfig; - -/** - * @brief Structure representing an SPI driver. - * @note Implementations may extend this structure to contain more, - * architecture dependent, fields. - */ -struct SPIDriver { - /** - * @brief Driver state. - */ - spistate_t state; - /** - * @brief Current configuration data. - */ - const SPIConfig *config; -#if SPI_USE_WAIT || defined(__DOXYGEN__) - /** - * @brief Waiting thread. - */ - thread_reference_t thread; -#endif /* SPI_USE_WAIT */ -#if SPI_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__) - /** - * @brief Mutex protecting the bus. - */ - mutex_t mutex; -#endif /* SPI_USE_MUTUAL_EXCLUSION */ -#if defined(SPI_DRIVER_EXT_FIELDS) - SPI_DRIVER_EXT_FIELDS -#endif - /* End of the mandatory fields.*/ - /** - * @brief Pointer to the SPIx registers block. - */ - Spi *spi; -#if SAMA_SPI_USE_FLEXCOM - /** - * @brief Pointer to the FLEXCOMx registers block. - */ - Flexcom *flexcom; -#endif - /** - * @brief Receive DMA stream. - */ - sama_dma_channel_t *dmarx; - /** - * @brief Transmit DMA stream. - */ - sama_dma_channel_t *dmatx; - /** - * @brief RX DMA mode bit mask. - */ - uint32_t rxdmamode; - /** - * @brief TX DMA mode bit mask. - */ - uint32_t txdmamode; -}; - /*===========================================================================*/ /* Driver macros. */ @@ -371,7 +470,7 @@ extern SPIDriver FSPID4; #ifdef __cplusplus extern "C" { #endif -void spi_lld_init(void); + void spi_lld_init(void); void spi_lld_start(SPIDriver *spip); void spi_lld_stop(SPIDriver *spip); void spi_lld_select(SPIDriver *spip); @@ -381,6 +480,7 @@ void spi_lld_init(void); const void *txbuf, void *rxbuf); void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf); void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf); + uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame); #ifdef __cplusplus } diff --git a/os/hal/ports/SAMA/LLD/USARTv1/hal_serial_lld.h b/os/hal/ports/SAMA/LLD/USARTv1/hal_serial_lld.h index 552d54b1a..5a028e522 100644 --- a/os/hal/ports/SAMA/LLD/USARTv1/hal_serial_lld.h +++ b/os/hal/ports/SAMA/LLD/USARTv1/hal_serial_lld.h @@ -25,7 +25,7 @@ #ifndef HAL_SERIAL_LLD_H #define HAL_SERIAL_LLD_H -#if HAL_USE_SERIAL || defined(__DOXYGEN__) +#if (HAL_USE_SERIAL == TRUE) || defined(__DOXYGEN__) /*===========================================================================*/ /* Driver constants. */ diff --git a/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.c b/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.c index 8415366a7..eaa53d928 100644 --- a/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.c +++ b/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.c @@ -29,7 +29,12 @@ /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ - +/* + * @brief NO CACHE attribute + */ +#if !defined(NO_CACHE) +#define NO_CACHE __attribute__((section (".nocache"))) +#endif /*===========================================================================*/ /* Driver local macros. */ /*===========================================================================*/ @@ -140,9 +145,11 @@ UARTDriver FUARTD4; /* Driver local variables and types. */ /*===========================================================================*/ /** - * @brief Linked List view0 word aligned + * @brief Linked List view0 word aligned + * @note The descriptor is word-aligned and the two least significant + * register bits 1:0 are ignored. */ - ALIGNED_VAR(4) static lld_view0 descriptor0; +NO_CACHE ALIGNED_VAR(4) static lld_view0 descriptor0; /*===========================================================================*/ /* Driver local functions. */ @@ -173,7 +180,10 @@ static uartflags_t translate_errors(uint32_t isr) { * @param[in] uartp pointer to the @p UARTDriver object */ static void uart_enter_rx_idle_loop(UARTDriver *uartp) { - + + /* In this zone driver always cleans cache */ + cacheCleanRegion((uint32_t *) &uartp->rxbuf, sizeof(uartp->rxbuf)); + /* Disabling BIE interrupt if rx callback is null */ if (uartp->config->rxchar_cb == NULL) uartp->dmarx->xdmac->XDMAC_CHID[uartp->dmarx->chid].XDMAC_CID = XDMAC_CID_BID; @@ -365,11 +375,17 @@ static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) { #endif if (uartp->rxstate == UART_RX_IDLE) { +#if (SAMA_UART_CACHE_USER_MANAGED == FALSE) + cacheInvalidateRegion((uint32_t *)&uartp->rxbuf, sizeof(uartp->rxbuf)); +#endif /* Receiver in idle state, a callback is generated, if enabled, for each received character and then the driver stays in the same state.*/ _uart_rx_idle_code(uartp); } else { +#if (SAMA_UART_CACHE_USER_MANAGED == FALSE) + cacheInvalidateRegion(uartp->rxbufp, uartp->rxbytes); +#endif /* Receiver in active state, a callback is generated, if enabled, after a completed transfer.*/ dmaChannelDisable(uartp->dmarx); @@ -1328,6 +1344,9 @@ void uart_lld_stop(UARTDriver *uartp) { } #endif } + uartp->txbufp = NULL; + uartp->rxbufp = NULL; + uartp->rxbytes = 0; } /** @@ -1343,6 +1362,19 @@ void uart_lld_stop(UARTDriver *uartp) { */ void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) { + uartp->txbufp = txbuf; + +#if (SAMA_UART_CACHE_USER_MANAGED == FALSE) + + osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned"); + +#if 0 + osalDbgAssert(!(n & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); +#endif + /* Cache is enabled */ + cacheCleanRegion((uint8_t *) txbuf, n); +#endif /* SAMA_UART_CACHE_USER_MANAGED */ + /* TX DMA channel preparation.*/ dmaChannelSetSource(uartp->dmatx, txbuf); dmaChannelSetTransactionSize(uartp->dmatx, n); @@ -1377,6 +1409,8 @@ void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) { */ size_t uart_lld_stop_send(UARTDriver *uartp) { + uartp->txbufp = NULL; + dmaChannelDisable(uartp->dmatx); return dmaChannelGetTransactionSize(uartp->dmatx); @@ -1395,6 +1429,26 @@ size_t uart_lld_stop_send(UARTDriver *uartp) { */ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) { + uartp->rxbufp = rxbuf; + uartp->rxbytes = n; + +#if (SAMA_UART_CACHE_USER_MANAGED == FALSE) + + osalDbgAssert(!((uint32_t) rxbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned"); + +#if 0 + osalDbgAssert(!(n & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); +#endif + + /* + * If size is not multiple of cache line, clean cache region is required. + * TODO: remove when size assert works + */ + if (n & (L1_CACHE_BYTES - 1)) { + cacheCleanRegion((uint8_t *) rxbuf, n); + } +#endif /* SAMA_UART_CACHE_USER_MANAGED */ + /* Stopping previous activity (idle state).*/ dmaChannelDisable(uartp->dmarx); @@ -1437,8 +1491,12 @@ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) { * @notapi */ size_t uart_lld_stop_receive(UARTDriver *uartp) { + size_t n; + uartp->rxbufp = NULL; + uartp->rxbytes = 0; + dmaChannelDisable(uartp->dmarx); n = dmaChannelGetTransactionSize(uartp->dmarx); uart_enter_rx_idle_loop(uartp); diff --git a/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.h b/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.h index 6c20da1c4..1f299e650 100644 --- a/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.h +++ b/os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.h @@ -277,6 +277,13 @@ #if !defined(SAMA_UART_DMA_ERROR_HOOK) || defined(__DOXYGEN__) #define SAMA_UART_DMA_ERROR_HOOK(uartp) osalSysHalt("DMA failure") #endif + +/** + * @brief UART cache managing. + */ +#if !defined(SAMA_UART_CACHE_USER_MANAGED) || defined(__DOXYGEN__) +#define SAMA_UART_CACHE_USER_MANAGED FALSE +#endif /** @} */ /*===========================================================================*/ @@ -564,7 +571,20 @@ struct UARTDriver { /** * @brief Default receive buffer while into @p UART_RX_IDLE state. */ + CACHE_ALIGNED volatile uint16_t rxbuf; + /** + * @brief Pointer to the TX buffer location. + */ + const uint8_t *txbufp; + /** + * @brief Pointer to the RX buffer location. + */ + uint8_t *rxbufp; + /** + * @brief Number of bytes in RX phase. + */ + size_t rxbytes; }; /*===========================================================================*/ diff --git a/os/hal/ports/SAMA/LLD/xWDGv1/driver.mk b/os/hal/ports/SAMA/LLD/xWDGv1/driver.mk new file mode 100644 index 000000000..797b95112 --- /dev/null +++ b/os/hal/ports/SAMA/LLD/xWDGv1/driver.mk @@ -0,0 +1,9 @@ +ifeq ($(USE_SMART_BUILD),yes) +ifneq ($(findstring HAL_USE_WDG TRUE,$(HALCONF)),) +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c +endif +else +PLATFORMSRC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c +endif + +PLATFORMINC += $(CHIBIOS)/os/hal/ports/SAMA/LLD/xWDGv1 diff --git a/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c b/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c new file mode 100644 index 000000000..e7c274e8c --- /dev/null +++ b/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c @@ -0,0 +1,165 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 WDGv1/hal_wdg_lld.c + * @brief WDG Driver subsystem low level driver source. + * + * @addtogroup WDG + * @{ + */ + +#include "hal.h" + +#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ +/** + * @brief WDG driver identifier. + */ +WDGDriver WDGD0; + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +/** + * @brief Local function that computes the period + * for WDT_MR_WDV and WDT_MR_VDD registers. + * + * @param[in] period period to be computed. + * + * @notapi + */ +static uint32_t wdt_compute_period(uint32_t period) { + + uint32_t value; + value = period * (SAMA_SLOW_CLK >> 7) / 1000; + if (value > 0xfff) + value = 0xfff; + + return value; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ +/** + * @brief WDG IRQ handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(SAMA_WDG_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + /* Read status register. */ + uint32_t sr = WDT->WDT_SR; + + if (WDGD0.config->callback != NULL) { + if (sr & WDT_SR_WDERR) { + WDGD0.config->callback(&WDGD0, WDG_ERROR); + } + + else + WDGD0.config->callback(&WDGD0, WDG_UNDERFLOW); + } + + aicAckInt(); + OSAL_IRQ_EPILOGUE(); +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level WDG driver initialization. + * + * @notapi + */ +void wdg_lld_init(void) { + +#if SAMA_HAL_IS_SECURE + mtxConfigPeriphSecurity(MATRIX1, ID_WDT, SECURE_PER); +#endif + + WDGD0.state = WDG_STOP; + WDGD0.wdg = WDT; +} + +/** + * @brief Configures and activates the WDT peripheral. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @notapi + */ +void wdg_lld_start(WDGDriver *wdgp) { + + (void) wdgp; + + /* Read status register. */ + WDT->WDT_SR; + + /* Write configuration */ + WDT->WDT_MR = (wdgp->config->mode & ~(WDT_MR_WDDIS | WDT_MR_WDD_Msk | WDT_MR_WDV_Msk)) | + WDT_MR_WDV(wdt_compute_period(wdgp->config->counter)) | + WDT_MR_WDD(wdt_compute_period(wdgp->config->delta)); + + aicSetSourcePriority(ID_WDT, SAMA_WDG_IRQ_PRIORITY); + aicSetSourceHandler(ID_WDT, SAMA_WDG_HANDLER); + aicEnableInt(ID_WDT); +} + +/** + * @brief Deactivates the WDG peripheral. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @notapi + */ +void wdg_lld_stop(WDGDriver *wdgp) { + + (void) wdgp; + WDT->WDT_MR = WDT_MR_WDDIS; +} + +/** + * @brief Reloads the WDG counter. + * + * @param[in] wdgp pointer to the @p WDGDriver object + * + * @notapi + */ +void wdg_lld_reset(WDGDriver * wdgp) { + + (void) wdgp; + WDT->WDT_CR = WDT_CR_KEY_PASSWD | WDT_CR_WDRSTT; +} + +#endif /* HAL_USE_WDG == TRUE */ + +/** @} */ diff --git a/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.h b/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.h new file mode 100644 index 000000000..0904c55fb --- /dev/null +++ b/os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.h @@ -0,0 +1,141 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 WDGv1/hal_wdg_lld.h + * @brief WDG Driver subsystem low level driver header. + * + * @addtogroup WDG + * @{ + */ + +#ifndef HAL_WDG_LLD_H +#define HAL_WDG_LLD_H + +#if (HAL_USE_WDG == TRUE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ +/** + * @name Configuration options + * @{ + */ +/* + * WDG driver system settings. + */ +#define SAMA_WDG_IRQ_PRIORITY 4 +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ +/** + * @brief Type of an WDG event. + */ +typedef enum { + WDG_ERROR = 0, /** Watchdog fault error. */ + WDG_UNDERFLOW = 1 /** Watchdog underflow error. */ +} wdgevent_t; + +/** + * @brief Type of a structure representing an WDG driver. + */ +typedef struct WDGDriver WDGDriver; + +/** + * @brief Type of a generic WDG callback. + */ +typedef void (*wdgcb_t)(WDGDriver *wdgp, wdgevent_t event); + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Callback pointer. + */ + wdgcb_t callback; + /** + * @brief Configuration of the WDT modes. + */ + uint32_t mode; + /** + * @brief Configuration of the WDT counter. + */ + uint32_t counter; + /** + * @brief Configuration of the WDT delta. + */ + uint32_t delta; +} WDGConfig; + +/** + * @brief Structure representing an WDG driver. + */ +struct WDGDriver { + /** + * @brief Driver state. + */ + wdgstate_t state; + /** + * @brief Current configuration data. + */ + const WDGConfig *config; + /* End of the mandatory fields.*/ + /** + * @brief Pointer to the WDT registers block. + */ + Wdt *wdg; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if !defined(__DOXYGEN__) +extern WDGDriver WDGD0; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void wdg_lld_init(void); + void wdg_lld_start(WDGDriver *wdgp); + void wdg_lld_stop(WDGDriver *wdgp); + void wdg_lld_reset(WDGDriver *wdgp); +#ifdef __cplusplus +} +#endif + +#endif /* HAL_USE_WDG == TRUE */ + +#endif /* HAL_WDG_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/aic.c b/os/hal/ports/SAMA/SAMA5D2x/aic.c deleted file mode 100644 index d961c58fd..000000000 --- a/os/hal/ports/SAMA/SAMA5D2x/aic.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio - - 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 SAMA5D2x/aic.c - * @brief SAMA AIC support code. - * - * @addtogroup SAMA5D2x_AIC - * @{ - */ - -#include "hal.h" - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local macros. */ -/*===========================================================================*/ - -/** - * @brief Enable write protection on AIC registers block. - * - * @param[in] aicp pointer to a AIC register block - * - * @notapi - */ -#define aicEnableWP(aicp) { \ - aicp->AIC_WPMR = AIC_WPMR_WPKEY_PASSWD | AIC_WPMR_WPEN; \ -} - -/** - * @brief Disable write protection on AIC registers block. - * - * @param[in] aicp pointer to a AIC register block - * - * @notapi - */ -#define aicDisableWP(aicp) { \ - aicp->AIC_WPMR = AIC_WPMR_WPKEY_PASSWD; \ -} - -/** - * @brief Checks if a IRQ priority is within the valid range. - * @param[in] prio IRQ priority - * - * @retval The check result. - * @retval FALSE invalid IRQ priority. - * @retval TRUE correct IRQ priority. - */ -#define SAMA_IRQ_IS_VALID_PRIORITY(prio) ((prio) <= 7U) - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -static OSAL_IRQ_HANDLER(aicSpuriousHandler) { - OSAL_IRQ_PROLOGUE(); - osalSysHalt("Spurious interrupt"); - OSAL_IRQ_EPILOGUE(); -} - -static OSAL_IRQ_HANDLER(aicUnexpectedHandler) { - OSAL_IRQ_PROLOGUE(); - osalSysHalt("Unexpected interrupt"); - OSAL_IRQ_EPILOGUE(); -} - -/** - * @brief AIC Initialization. - * @note Better reset everything in the AIC. - * - * @notapi - */ -void aicInit(void) { - -#if SAMA_HAL_IS_SECURE - Aic *aic = SAIC; -#else - Aic *aic = AIC; -#endif - - aicDisableWP(aic); - - aic->AIC_SPU = (uint32_t)aicSpuriousHandler; - aic->AIC_SSR = 0; - aic->AIC_SVR = (uint32_t)aicUnexpectedHandler; - - unsigned i; - /* Disable all interrupts */ - for (i = 1; i < ID_PERIPH_COUNT; i++) { - aic->AIC_SSR = i; - aic->AIC_IDCR = AIC_IDCR_INTD; - - /* Changes type */ - aic->AIC_SMR = AIC_SMR_SRCTYPE(EXT_NEGATIVE_EDGE); - - /* Clear pending interrupt */ - aic->AIC_ICCR = AIC_ICCR_INTCLR; - - /* Changes type */ - aic->AIC_SMR = AIC_SMR_SRCTYPE(INT_LEVEL_SENSITIVE); - - /* Default handler */ - aic->AIC_SVR = (uint32_t)aicUnexpectedHandler; - } - aicEnableWP(aic); -} - -/** - * @brief Configures an interrupt in the AIC. - * @note Source cannot be ID_SAIC_FIQ (0). - * - * @param[in] source interrupt source to configure - * @param[in] priority priority level of the selected source. - */ -void aicSetSourcePriority(uint32_t source, uint8_t priority) { - -#if SAMA_HAL_IS_SECURE - Aic *aic = SAIC; -#else - Aic *aic = AIC; -#endif - - osalDbgCheck(source != ID_SAIC_FIQ); - osalDbgAssert(SAMA_IRQ_IS_VALID_PRIORITY(priority), "invalid irq priority"); - /* Disable write protection */ - aicDisableWP(aic); - /* Set source id */ - aic->AIC_SSR = source; - /* Disable the interrupt first */ - aic->AIC_IDCR = AIC_IDCR_INTD; - /* Configure priority */ - aic->AIC_SMR = AIC_SMR_PRIOR(priority); - /* Clear interrupt */ - aic->AIC_ICCR = AIC_ICCR_INTCLR; - /* Enable write protection */ - aicEnableWP(aic); -} - -/** - * @brief Configures type of interrupt in the AIC. - * - * @param[in] source interrupt source to configure - * @param[in] type type interrupt of the selected source. - */ -void aicSetIntSourceType(uint32_t source, uint8_t type) { - -#if SAMA_HAL_IS_SECURE - Aic *aic = SAIC; -#else - Aic *aic = AIC; -#endif - /* Disable write protection */ - aicDisableWP(aic); - /* Set source id */ - aic->AIC_SSR = source; - /* Disable the interrupt first */ - aic->AIC_IDCR = AIC_IDCR_INTD; - /* Configure priority */ - aic->AIC_SMR = AIC_SMR_SRCTYPE(type); - /* Clear interrupt */ - aic->AIC_ICCR = AIC_ICCR_INTCLR; - /* Enable write protection */ - aicEnableWP(aic); -} - -/** - * @brief Sets the source handler of an interrupt. - * - * @param[in] source interrupt source to configure - * @param[in] handler handler for the interrupt source selected - */ -void aicSetSourceHandler(uint32_t source, bool (*handler)(void)) { - -#if SAMA_HAL_IS_SECURE - Aic *aic = SAIC; -#else - Aic *aic = AIC; -#endif - - /* Disable write protection */ - aicDisableWP(aic); - /* Select source and assign handler */ - aic->AIC_SSR = AIC_SSR_INTSEL(source); - aic->AIC_SVR = (uint32_t)handler; - /* Enable write protection */ - aicEnableWP(aic); -} - -/** - * @brief Sets the spurious handler of an interrupt. - * - * @param[in] handler handler for the interrupt - */ -void aicSetSpuriousHandler(bool (*handler)(void)) { - -#if SAMA_HAL_IS_SECURE - Aic *aic = SAIC; -#else - Aic *aic = AIC; -#endif - - /* Disable write protection */ - aicDisableWP(aic); - /* Assign handler */ - aic->AIC_SPU = (uint32_t)handler; - /* Enable write protection */ - aicEnableWP(aic); -} - -/** - * @brief Enables interrupts coming from the source. - * - * @param[in] source interrupt source to enable - */ -void aicEnableInt(uint32_t source) { - -#if SAMA_HAL_IS_SECURE - Aic *aic = SAIC; -#else - Aic *aic = AIC; -#endif - - aic->AIC_SSR = AIC_SSR_INTSEL(source); - aic->AIC_IECR = AIC_IECR_INTEN; -} - -/** - * @brief Disables interrupts coming from the selected source. - * - * @param[in] source interrupt source to disable - */ -void aicDisableInt(uint32_t source) { - -#if SAMA_HAL_IS_SECURE - Aic *aic = SAIC; -#else - Aic *aic = AIC; -#endif - - aic->AIC_SSR = AIC_SSR_INTSEL(source); - aic->AIC_IDCR = AIC_IDCR_INTD; -} - -/** - * @brief Clears interrupts coming from the selected source. - * - * @param[in] source interrupt source to Clear - */ -void aicClearInt(uint32_t source) { - -#if SAMA_HAL_IS_SECURE - Aic *aic = SAIC; -#else - Aic *aic = AIC; -#endif - - aic->AIC_SSR = AIC_SSR_INTSEL(source); - aic->AIC_ICCR = AIC_ICCR_INTCLR; -} - -/** - * @brief Sets interrupts coming from the selected source. - * - * @param[in] source interrupt source to Set - */ -void aicSetInt(uint32_t source) { - -#if SAMA_HAL_IS_SECURE - Aic *aic = SAIC; -#else - Aic *aic = AIC; -#endif - - aic->AIC_SSR = AIC_SSR_INTSEL(source); - aic->AIC_ISCR = AIC_ISCR_INTSET; -} - -/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/aic.h b/os/hal/ports/SAMA/SAMA5D2x/aic.h deleted file mode 100644 index a4f220754..000000000 --- a/os/hal/ports/SAMA/SAMA5D2x/aic.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio - - 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 SAMA5D2x/aic.h - * @brief SAMA AIC support macros and structures. - * - * @addtogroup SAMA5D2x_AIC - * @{ - */ - -#ifndef AIC_H -#define AIC_H - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ -/** - * @name INTERRUPT SOURCE TYPE mode macros - * @{ - */ -/** - * @brief High-level sensitive for internal source. - * Low-level sensitive for external source. - */ -#define INT_LEVEL_SENSITIVE 0x0U - -/** - * @brief Negative-edge triggered for external source. - */ -#define EXT_NEGATIVE_EDGE 0x1U - -/** - * @brief High-level sensitive for internal source. - * High-level sensitive for external source. - */ -#define EXT_HIGH_LEVEL 0x2U - -/** - * @brief Positive-edge triggered for external source. - */ -#define EXT_POSITIVE_EDGE 0x3U -/** @} */ - -/** - * @brief AIC unique redirect key. - */ -#define AIC_REDIR_KEY 0x5B6C0E26U - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/** - * @brief Acknowledge the current interrupt. - */ -#if SAMA_HAL_IS_SECURE -#define aicAckInt() { \ - SAIC->AIC_EOICR = AIC_EOICR_ENDIT; \ -} -#else -#define aicAckInt() { \ - AIC->AIC_EOICR = AIC_EOICR_ENDIT; \ -} -#endif - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -#ifdef __cplusplus -extern "C" { -#endif - void aicInit(void); - void aicSetSourcePriority(uint32_t source, uint8_t priority); - void aicSetIntSourceType(uint32_t source, uint8_t type); - void aicSetSourceHandler(uint32_t source, bool (*handler)(void)); - void aicSetSpuriousHandler(bool (*handler)(void)); - void aicEnableInt(uint32_t source); - void aicDisableInt(uint32_t source); - void aicClearInt(uint32_t source); - void aicSetInt(uint32_t source); -#ifdef __cplusplus -} -#endif - -#endif /* AIC_H */ - -/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.c b/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.c index b62e4654c..ad422f265 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.c +++ b/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.c @@ -1528,7 +1528,7 @@ cryerror_t cry_lld_HMACSHA256_update(CRYDriver *cryp, const uint8_t *in) { uint8_t i; cryerror_t res; - uint32_t buffer[16]; + CACHE_ALIGNED uint32_t buffer[16]; if (hmacsha256ctxp->kipad == 0) { @@ -1576,8 +1576,8 @@ cryerror_t cry_lld_HMACSHA256_final(CRYDriver *cryp, uint8_t i; cryerror_t res; - uint32_t buffer[16]; //max block size for sha256 - uint8_t digest[32]; + CACHE_ALIGNED uint32_t buffer[16]; //max block size for sha256 + CACHE_ALIGNED uint8_t digest[32]; //H( k1pad || m ) @@ -1668,7 +1668,7 @@ cryerror_t cry_lld_HMACSHA512_update(CRYDriver *cryp, cryerror_t res; uint8_t i; - uint32_t buffer[32]; +CACHE_ALIGNED uint32_t buffer[32]; if (hmacsha512ctxp->kipad == 0) { @@ -1714,8 +1714,8 @@ cryerror_t cry_lld_HMACSHA512_final(CRYDriver *cryp, uint8_t i; cryerror_t res; - uint32_t buffer[32]; //max block size for sha256 - uint8_t digest[64]; + CACHE_ALIGNED uint32_t buffer[32]; //max block size for sha256 + CACHE_ALIGNED uint8_t digest[64]; //H( k1pad || m ) diff --git a/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.h b/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.h index 1bacbc80b..5e5ce362d 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.h +++ b/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.h @@ -123,10 +123,10 @@ typedef enum { CRY_SHA_512, CRY_HMACSHA_1, - CRY_HMACSHA_224, - CRY_HMACSHA_256, - CRY_HMACSHA_384, - CRY_HMACSHA_512, + CRY_HMACSHA_224, + CRY_HMACSHA_256, + CRY_HMACSHA_384, + CRY_HMACSHA_512, }shadalgo_t; @@ -211,6 +211,18 @@ struct CRYDriver { * @brief Size of transient key. */ size_t key0_size; + /** + * @brief Pointer to the in buffer location. + */ + const uint8_t *in; + /** + * @brief Pointer to the out buffer location. + */ + uint8_t *out; + /** + * @brief Number of bytes. + */ + size_t len; #if (HAL_CRY_USE_FALLBACK == TRUE) || defined(__DOXYGEN__) /** * @brief Key buffer for the fall-back implementation. diff --git a/os/hal/ports/SAMA/SAMA5D2x/hal_lld.c b/os/hal/ports/SAMA/SAMA5D2x/hal_lld.c index f45928b56..623d20b7a 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/hal_lld.c +++ b/os/hal/ports/SAMA/SAMA5D2x/hal_lld.c @@ -76,12 +76,16 @@ void hal_lld_init(void) { /* Configures PMC and RTC as secure */ //mtxConfigPeriphSecurity(MATRIX1, ID_SYSC, SECURE_PER); - //mtxConfigPeriphSecurity(MATRIX0, ID_PMC, SECURE_PER); + mtxConfigPeriphSecurity(MATRIX0, ID_PMC, SECURE_PER); mtxConfigPeriphSecurity(MATRIX1, ID_SFC, SECURE_PER); mtxConfigPeriphSecurity(MATRIX1, ID_SFR, SECURE_PER); - mtxConfigPeriphSecurity(MATRIX0, ID_L2CC, SECURE_PER); + + /* It isn't necessary to make L2CC secure. L2C-310 cache + * controller is secure mode aware.*/ + /*mtxConfigPeriphSecurity(MATRIX0, ID_L2CC, SECURE_PER);*/ + mtxConfigPeriphSecurity(MATRIX1, ID_SFRBU, SECURE_PER); - mtxConfigPeriphSecurity(MATRIX1, ID_CHIPID, SECURE_PER); + /*mtxConfigPeriphSecurity(MATRIX1, ID_CHIPID, SECURE_PER);*/ /* Enabling matrix clock */ pmcEnableH32MX(); diff --git a/os/hal/ports/SAMA/SAMA5D2x/hal_lld.h b/os/hal/ports/SAMA/SAMA5D2x/hal_lld.h index 0f0a4fec5..5c5669ecd 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/hal_lld.h +++ b/os/hal/ports/SAMA/SAMA5D2x/hal_lld.h @@ -175,6 +175,17 @@ #define SAMA_MCK_PLLADIV2 (1 << 12) /**< PLLA is divided by 2. */ +/** + * @name PCM_PCR register bits definitions + * @{ + */ +#define SAMA_GCLK_SLOW_CLK (0x0u << 8) /**< GCLK Slow clock is selected */ +#define SAMA_GCLK_MAIN_CLK (0x1u << 8) /**< GCLK GMain clock is selected */ +#define SAMA_GCLK_PLLA_CLK (0x2u << 8) /**< GCLK PLLACK is selected */ +#define SAMA_GCLKUPLL_CLK (0x3u << 8) /**< GCLK UPLL Clock is selected */ +#define SAMA_GCLK_MCK_CLK (0x4u << 8) /**< GCLK Master Clock is selected */ +#define SAMA_GCLK_AUDIO_CLK (0x5u << 8) /**< GCLK Audio PLL clock is selected */ + /** @} */ /*===========================================================================*/ @@ -458,6 +469,7 @@ /** * @brief UARTx clock. + * TODO: Work only with PERIPH CLOCK */ #define SAMA_UART0CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO) #define SAMA_UART1CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO) @@ -467,6 +479,7 @@ /** * @brief FLEXCOMx clock. + * TODO: Work only with PERIPH CLOCK */ #define SAMA_FLEXCOM0CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO) #define SAMA_FLEXCOM1CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO) @@ -476,15 +489,23 @@ /** * @brief TCx clock. + * TODO: Work only with PERIPH CLOCK */ #define SAMA_TC0CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO) #define SAMA_TC1CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO) /** * @brief GMAC0 clock. + * TODO: Work only with PERIPH CLOCK */ #define SAMA_GMAC0CLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO) +/** + * @brief TWIHSx clock. + * TODO: Work only with PERIPH CLOCK + */ +#define SAMA_TWIHSxCLK (SAMA_MCK / SAMA_H64MX_H32MX_RATIO) + /*===========================================================================*/ /* Driver data structures and types. */ /*===========================================================================*/ @@ -499,13 +520,16 @@ /* Various helpers.*/ #include "sama_pmc.h" -#include "aic.h" +#include "sama_aic.h" #include "sama_matrix.h" #include "sama_xdmac.h" #include "sama_cache.h" -#include "hal_tc_lld.h" +#include "sama_tc_lld.h" +#include "sama_lcdc.h" #include "sama_secumod.h" -#include "sama_trng.h" +#include "sama_onewire.h" +#include "sama_classd.h" +#include "sama_rstc.h" #ifdef __cplusplus extern "C" { diff --git a/os/hal/ports/SAMA/SAMA5D2x/platform.mk b/os/hal/ports/SAMA/SAMA5D2x/platform.mk index 026f8c445..67f8976da 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/platform.mk +++ b/os/hal/ports/SAMA/SAMA5D2x/platform.mk @@ -2,12 +2,14 @@ PLATFORMSRC := $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/hal_lld.c \ $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/hal_st_lld.c \ - $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/aic.c \ + $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_aic.c \ $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_matrix.c \ $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.c \ - $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_trng.c \ + $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.c \ + $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_classd.c \ + $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.c \ $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_cache.c \ - $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/hal_tc_lld.c \ + $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.c \ $(CHIBIOS)/os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.c # Required include directories. @@ -28,13 +30,17 @@ endif # Drivers compatible with the platform. include $(CHIBIOS)/os/hal/ports/SAMA/LLD/DMAv1/driver.mk +include $(CHIBIOS)/os/hal/ports/SAMA/LLD/I2Cv1/driver.mk include $(CHIBIOS)/os/hal/ports/SAMA/LLD/MACv1/driver.mk include $(CHIBIOS)/os/hal/ports/SAMA/LLD/PIOv1/driver.mk +include $(CHIBIOS)/os/hal/ports/SAMA/LLD/QUADSPIv1/driver.mk include $(CHIBIOS)/os/hal/ports/SAMA/LLD/SPIv1/driver.mk include $(CHIBIOS)/os/hal/ports/SAMA/LLD/RTCv1/driver.mk +include $(CHIBIOS)/os/hal/ports/SAMA/LLD/xWDGv1/driver.mk include $(CHIBIOS)/os/hal/ports/SAMA/LLD/USARTv1/driver.mk include $(CHIBIOS)/os/hal/ports/SAMA/LLD/CRYPTOv1/driver.mk include $(CHIBIOS)/os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk +include $(CHIBIOS)/os/hal/ports/SAMA/LLD/RNGv1/driver.mk # Shared variables ALLCSRC += $(PLATFORMSRC) diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_aic.c b/os/hal/ports/SAMA/SAMA5D2x/sama_aic.c new file mode 100644 index 000000000..e47336bb5 --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_aic.c @@ -0,0 +1,310 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/aic.c + * @brief SAMA AIC support code. + * + * @addtogroup SAMA5D2x_AIC + * @{ + */ + +#include "hal.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local macros. */ +/*===========================================================================*/ + +/** + * @brief Enable write protection on AIC registers block. + * + * @param[in] aicp pointer to a AIC register block + * + * @notapi + */ +#define aicEnableWP(aicp) { \ + aicp->AIC_WPMR = AIC_WPMR_WPKEY_PASSWD | AIC_WPMR_WPEN; \ +} + +/** + * @brief Disable write protection on AIC registers block. + * + * @param[in] aicp pointer to a AIC register block + * + * @notapi + */ +#define aicDisableWP(aicp) { \ + aicp->AIC_WPMR = AIC_WPMR_WPKEY_PASSWD; \ +} + +/** + * @brief Checks if a IRQ priority is within the valid range. + * @param[in] prio IRQ priority + * + * @retval The check result. + * @retval FALSE invalid IRQ priority. + * @retval TRUE correct IRQ priority. + */ +#define SAMA_IRQ_IS_VALID_PRIORITY(prio) ((prio) <= 7U) + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +static OSAL_IRQ_HANDLER(aicSpuriousHandler) { + OSAL_IRQ_PROLOGUE(); + osalSysHalt("Spurious interrupt"); + OSAL_IRQ_EPILOGUE(); +} + +static OSAL_IRQ_HANDLER(aicUnexpectedHandler) { + OSAL_IRQ_PROLOGUE(); + osalSysHalt("Unexpected interrupt"); + OSAL_IRQ_EPILOGUE(); +} + +/** + * @brief AIC Initialization. + * @note Better reset everything in the AIC. + * + * @notapi + */ +void aicInit(void) { + +#if SAMA_HAL_IS_SECURE + Aic *aic = SAIC; +#else + Aic *aic = AIC; +#endif + + aicDisableWP(aic); + + aic->AIC_SPU = (uint32_t)aicSpuriousHandler; + aic->AIC_SSR = 0; + aic->AIC_SVR = (uint32_t)aicUnexpectedHandler; + + unsigned i; + /* Disable all interrupts */ + for (i = 1; i < ID_PERIPH_COUNT; i++) { + aic->AIC_SSR = i; + aic->AIC_IDCR = AIC_IDCR_INTD; + + /* Changes type */ + aic->AIC_SMR = AIC_SMR_SRCTYPE(EXT_NEGATIVE_EDGE); + + /* Clear pending interrupt */ + aic->AIC_ICCR = AIC_ICCR_INTCLR; + + /* Changes type */ + aic->AIC_SMR = AIC_SMR_SRCTYPE(INT_LEVEL_SENSITIVE); + + /* Default handler */ + aic->AIC_SVR = (uint32_t)aicUnexpectedHandler; + } + aicEnableWP(aic); +} + +/** + * @brief Configures an interrupt in the AIC. + * @note Source cannot be ID_SAIC_FIQ (0). + * + * @param[in] source interrupt source to configure + * @param[in] priority priority level of the selected source. + */ +void aicSetSourcePriority(uint32_t source, uint8_t priority) { + +#if SAMA_HAL_IS_SECURE + Aic *aic = SAIC; +#else + Aic *aic = AIC; +#endif + + osalDbgCheck(source != ID_SAIC_FIQ); + osalDbgAssert(SAMA_IRQ_IS_VALID_PRIORITY(priority), "invalid irq priority"); + /* Disable write protection */ + aicDisableWP(aic); + /* Set source id */ + aic->AIC_SSR = source; + /* Disable the interrupt first */ + aic->AIC_IDCR = AIC_IDCR_INTD; + /* Configure priority */ + aic->AIC_SMR |= AIC_SMR_PRIOR(priority); + /* Clear interrupt */ + aic->AIC_ICCR = AIC_ICCR_INTCLR; + /* Enable write protection */ + aicEnableWP(aic); +} + +/** + * @brief Configures type of interrupt in the AIC. + * + * @param[in] source interrupt source to configure + * @param[in] type type interrupt of the selected source. + */ +void aicSetIntSourceType(uint32_t source, uint8_t type) { + +#if SAMA_HAL_IS_SECURE + Aic *aic = SAIC; +#else + Aic *aic = AIC; +#endif + /* Disable write protection */ + aicDisableWP(aic); + /* Set source id */ + aic->AIC_SSR = source; + /* Disable the interrupt first */ + aic->AIC_IDCR = AIC_IDCR_INTD; + /* Configure priority */ + aic->AIC_SMR |= AIC_SMR_SRCTYPE(type); + /* Clear interrupt */ + aic->AIC_ICCR = AIC_ICCR_INTCLR; + /* Enable write protection */ + aicEnableWP(aic); +} + +/** + * @brief Sets the source handler of an interrupt. + * + * @param[in] source interrupt source to configure + * @param[in] handler handler for the interrupt source selected + */ +void aicSetSourceHandler(uint32_t source, bool (*handler)(void)) { + +#if SAMA_HAL_IS_SECURE + Aic *aic = SAIC; +#else + Aic *aic = AIC; +#endif + + /* Disable write protection */ + aicDisableWP(aic); + /* Select source and assign handler */ + aic->AIC_SSR = AIC_SSR_INTSEL(source); + aic->AIC_SVR = (uint32_t)handler; + /* Enable write protection */ + aicEnableWP(aic); +} + +/** + * @brief Sets the spurious handler of an interrupt. + * + * @param[in] handler handler for the interrupt + */ +void aicSetSpuriousHandler(bool (*handler)(void)) { + +#if SAMA_HAL_IS_SECURE + Aic *aic = SAIC; +#else + Aic *aic = AIC; +#endif + + /* Disable write protection */ + aicDisableWP(aic); + /* Assign handler */ + aic->AIC_SPU = (uint32_t)handler; + /* Enable write protection */ + aicEnableWP(aic); +} + +/** + * @brief Enables interrupts coming from the source. + * + * @param[in] source interrupt source to enable + */ +void aicEnableInt(uint32_t source) { + +#if SAMA_HAL_IS_SECURE + Aic *aic = SAIC; +#else + Aic *aic = AIC; +#endif + + aic->AIC_SSR = AIC_SSR_INTSEL(source); + aic->AIC_IECR = AIC_IECR_INTEN; +} + +/** + * @brief Disables interrupts coming from the selected source. + * + * @param[in] source interrupt source to disable + */ +void aicDisableInt(uint32_t source) { + +#if SAMA_HAL_IS_SECURE + Aic *aic = SAIC; +#else + Aic *aic = AIC; +#endif + + aic->AIC_SSR = AIC_SSR_INTSEL(source); + aic->AIC_IDCR = AIC_IDCR_INTD; +} + +/** + * @brief Clears interrupts coming from the selected source. + * + * @param[in] source interrupt source to Clear + */ +void aicClearInt(uint32_t source) { + +#if SAMA_HAL_IS_SECURE + Aic *aic = SAIC; +#else + Aic *aic = AIC; +#endif + + aic->AIC_SSR = AIC_SSR_INTSEL(source); + aic->AIC_ICCR = AIC_ICCR_INTCLR; +} + +/** + * @brief Sets interrupts coming from the selected source. + * + * @param[in] source interrupt source to Set + */ +void aicSetInt(uint32_t source) { + +#if SAMA_HAL_IS_SECURE + Aic *aic = SAIC; +#else + Aic *aic = AIC; +#endif + + aic->AIC_SSR = AIC_SSR_INTSEL(source); + aic->AIC_ISCR = AIC_ISCR_INTSET; +} + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_aic.h b/os/hal/ports/SAMA/SAMA5D2x/sama_aic.h new file mode 100644 index 000000000..a4f220754 --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_aic.h @@ -0,0 +1,114 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/aic.h + * @brief SAMA AIC support macros and structures. + * + * @addtogroup SAMA5D2x_AIC + * @{ + */ + +#ifndef AIC_H +#define AIC_H + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ +/** + * @name INTERRUPT SOURCE TYPE mode macros + * @{ + */ +/** + * @brief High-level sensitive for internal source. + * Low-level sensitive for external source. + */ +#define INT_LEVEL_SENSITIVE 0x0U + +/** + * @brief Negative-edge triggered for external source. + */ +#define EXT_NEGATIVE_EDGE 0x1U + +/** + * @brief High-level sensitive for internal source. + * High-level sensitive for external source. + */ +#define EXT_HIGH_LEVEL 0x2U + +/** + * @brief Positive-edge triggered for external source. + */ +#define EXT_POSITIVE_EDGE 0x3U +/** @} */ + +/** + * @brief AIC unique redirect key. + */ +#define AIC_REDIR_KEY 0x5B6C0E26U + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/** + * @brief Acknowledge the current interrupt. + */ +#if SAMA_HAL_IS_SECURE +#define aicAckInt() { \ + SAIC->AIC_EOICR = AIC_EOICR_ENDIT; \ +} +#else +#define aicAckInt() { \ + AIC->AIC_EOICR = AIC_EOICR_ENDIT; \ +} +#endif + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + void aicInit(void); + void aicSetSourcePriority(uint32_t source, uint8_t priority); + void aicSetIntSourceType(uint32_t source, uint8_t type); + void aicSetSourceHandler(uint32_t source, bool (*handler)(void)); + void aicSetSpuriousHandler(bool (*handler)(void)); + void aicEnableInt(uint32_t source); + void aicDisableInt(uint32_t source); + void aicClearInt(uint32_t source); + void aicSetInt(uint32_t source); +#ifdef __cplusplus +} +#endif + +#endif /* AIC_H */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_cache.c b/os/hal/ports/SAMA/SAMA5D2x/sama_cache.c index ac08363ce..0ed58a887 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/sama_cache.c +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_cache.c @@ -45,13 +45,13 @@ void cacheInvalidateRegion(void *start, uint32_t length) { uint32_t mva; /* Invalidate L1 D-Cache */ - for (mva = start_addr & ~L1_CACHE_BYTES; mva < end_addr; mva += L1_CACHE_BYTES) { + for (mva = start_addr & ~(L1_CACHE_BYTES-1); mva < end_addr; mva += L1_CACHE_BYTES) { L1C_InvalidateDCacheMVA((uint32_t *)mva); } #if ARM_SUPPORTS_L2CC #if SAMA_L2CC_ASSUME_ENABLED || SAMA_L2CC_ENABLE /* Invalidate L2 Cache */ - for (mva = start_addr & ~L2_CACHE_BYTES; mva < end_addr; mva += L2_CACHE_BYTES) { + for (mva = start_addr & ~(L2_CACHE_BYTES-1); mva < end_addr; mva += L2_CACHE_BYTES) { L2C_InvPa((uint32_t *)mva); } #endif @@ -71,17 +71,43 @@ void cacheCleanRegion(void *start, uint32_t length) { uint32_t mva; /* Clean L1 D-Cache */ - for (mva = start_addr & ~L1_CACHE_BYTES; mva < end_addr; mva += L1_CACHE_BYTES) { + for (mva = start_addr & ~(L1_CACHE_BYTES-1); mva < end_addr; mva += L1_CACHE_BYTES) { L1C_CleanDCacheMVA((uint32_t *)mva); } #if ARM_SUPPORTS_L2CC #if SAMA_L2CC_ASSUME_ENABLED || SAMA_L2CC_ENABLE /* Invalidate L2 Cache */ - for (mva = start_addr & ~L2_CACHE_BYTES; mva < end_addr; mva += L2_CACHE_BYTES) { + for (mva = start_addr & ~(L2_CACHE_BYTES-1); mva < end_addr; mva += L2_CACHE_BYTES) { L2C_CleanPa((uint32_t *)mva); } #endif #endif } +/** + * @brief Clean and Invalidate D-Cache Region + * + * @param[in] start Pointer to beginning of memory region. + * @param[in] length Length of the memory location. + */ +void cacheCleanInvalidateRegion(void *start, uint32_t length) { + + uint32_t start_addr = (uint32_t)start; + uint32_t end_addr = start_addr + length; + uint32_t mva; + + /* Clean L1 D-Cache */ + for (mva = start_addr & ~(L1_CACHE_BYTES-1); mva < end_addr; mva += L1_CACHE_BYTES) { + L1C_CleanInvalidateDCacheMVA((uint32_t *)mva); + } +#if ARM_SUPPORTS_L2CC +#if SAMA_L2CC_ASSUME_ENABLED || SAMA_L2CC_ENABLE + /* Invalidate L2 Cache */ + for (mva = start_addr & ~(L2_CACHE_BYTES-1); mva < end_addr; mva += L2_CACHE_BYTES) { + L2C_CleanInvPa((uint32_t *)mva); + } +#endif +#endif +} + /** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_cache.h b/os/hal/ports/SAMA/SAMA5D2x/sama_cache.h index 1608a023c..25be583ff 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/sama_cache.h +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_cache.h @@ -30,11 +30,16 @@ #define L1_CACHE_BYTES 32u #define L2_CACHE_BYTES 32u +#define CACHE_ALIGNED ALIGNED_VAR(L1_CACHE_BYTES) +#define NO_CACHE __attribute__((section (".nocache"))) + + #ifdef __cplusplus extern "C" { #endif extern void cacheInvalidateRegion(void *start, uint32_t length); extern void cacheCleanRegion(void *start, uint32_t length); + extern void cacheCleanInvalidateRegion(void *start, uint32_t length); #ifdef __cplusplus } #endif diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_classd.c b/os/hal/ports/SAMA/SAMA5D2x/sama_classd.c new file mode 100644 index 000000000..37a3ce689 --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_classd.c @@ -0,0 +1,526 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/sama_classd.c + * @brief SAMA CLASSD support code. + * + * @addtogroup SAMA5D2x_CLASSD + * @{ + */ + +#include "hal.h" + +#if SAMA_USE_CLASSD || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local macros. */ +/*===========================================================================*/ + +/** + * @brief Enable write protection on CLASSD Mode Register + * and Interpolator Mode Register. + * + * @param[in] classdp pointer to a CLASSD register block + * + * @notapi + */ +#define classdEnableWP(classdp) { \ + classdp->CLASSD_WPMR = CLASSD_WPMR_WPKEY_PASSWD | CLASSD_WPMR_WPEN; \ +} + +/** + * @brief Disable write protection on CLASSD Mode Register + * and Interpolator Mode Register. + * + * @param[in] classdp pointer to a CLASSD register block + * + * @notapi + */ +#define classdDisableWP(classdp) { \ + classdp->CLASSD_WPMR = CLASSD_WPMR_WPKEY_PASSWD; \ +} + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ +/** + * @brief CLASSD driver identifier. + */ +CLASSDDriver CLASSDD0; + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ +/** + * @brief Type of a structure representing PMC Audio configuration. + */ +typedef struct { + /** + * @brief Loop Divider Ratio. + */ + uint32_t nd; + + /** + * @brief Fractional Loop Divider Setting. + */ + uint32_t fracr; + + /** + * @brief Output Divider Ratio for PMC Clock. + */ + uint32_t qdpmc; + + /** + * @brief Divider Value. + */ + uint32_t div; + + /** + * @brief Output Divider Ratio for Pad Clock. + */ + uint32_t qdaudio; +} pmcAudioConf; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +/** + * @brief Configure DSPClock. + * + * @param[in] dsp_clk DSP clock type (12.288 MHz or 11.2896 MHz). + */ +static void dspclkConfigure(uint32_t dsp_clk) { + pmcAudioConf cfg; + + /* Pad Clock: not used */ + cfg.div = 0; + cfg.qdaudio = 0; + + /* PMC Clock: */ + /* 12Mhz * (ND + 1 + FRACR/2^22) / (QDPMC + 1) = 8 * DSPCLK */ + switch (dsp_clk) { + case CLASSD_INTPMR_DSPCLKFREQ_12M288: +#if SAMA_MOSCXTCLK == 12000000 + /* 12Mhz * (56 + 1 + 1442841/2^22) / (6 + 1) = 8 * 12.288Mhz */ + cfg.nd = 56; + cfg.fracr = 1442841; + cfg.qdpmc = 6; +#elif SAMA_MOSCXTCLK == 24000000 + /* 24Mhz * (56 + 1 + 1442841/2^22) / (6 + 1) = 8 * 12.288Mhz */ + cfg.nd = 27; + cfg.fracr = 2796203; + cfg.qdpmc = 6; +#else + #error "FREQUENCY NOT SUPPORTED BY CLASSD" +#endif + break; + + case CLASSD_INTPMR_DSPCLKFREQ_11M2896: +#if SAMA_MOSCXTCLK == 12000000 + /* 12Mhz * (59 + 1 + 885837/2^22) / (7 + 1) = 8 * 11.2896Mhz */ + cfg.nd = 59; + cfg.fracr = 885837; + cfg.qdpmc = 7; +#elif SAMA_MOSCXTCLK == 24000000 + /* 24Mhz * (59 + 1 + 885837/2^22) / (7 + 1) = 8 * 11.2896Mhz */ + cfg.nd = 28; + cfg.fracr = 699050; + cfg.qdpmc = 7; +#else + #error "FREQUENCY NOT SUPPORTED BY CLASSD" +#endif + break; + + default: + osalDbgAssert(NULL, "errore mask configuration"); + } + + /* Configure and enable the generic clock. */ + pmcConfigAudio(cfg.nd, cfg.qdpmc, cfg.fracr, cfg.div, cfg.qdaudio); + pmcEnableAudio(true, false); +} + +/** + * @brief Shared end-of-tx service routine. + * + * @param[in] classdp pointer to the @p CLASSDDriver object + * @param[in] flags pre-shifted content of the ISR register + */ +static void classd_lld_serve_tx_interrupt(CLASSDDriver *classdp, uint32_t flags) { + + /* DMA errors handling.*/ +#if defined(SAMA_CLASSD_DMA_ERROR_HOOK) + (void)classdp; + if ((flags & (XDMAC_CIS_WBEIS | XDMAC_CIS_ROIS)) != 0) { + SAMA_CLASSD_DMA_ERROR_HOOK(classdp); + } +#else + (void)flags; +#endif + + if(classdp->config->callback != NULL) { + classdp->config->callback(classdp); + } + classdMuteChannel(classdp, false, false); + classdp->state = CLASSD_READY; +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level CLASSD driver initialization. + * + * @notapi + */ +void classd_lld_init(void) { +#if SAMA_HAL_IS_SECURE + mtxConfigPeriphSecurity(MATRIX1, ID_CLASSD, SECURE_PER); +#endif /* SAMA_HAL_IS_SECURE */ + /* Driver initialization. */ + classdObjectInit(&CLASSDD0); + CLASSDD0.classd = CLASSD; + CLASSDD0.dmatx = NULL; + CLASSDD0.txdmamode = XDMAC_CC_TYPE_PER_TRAN | + XDMAC_CC_MBSIZE_SINGLE | + XDMAC_CC_DSYNC_MEM2PER | + XDMAC_CC_PROT_SEC | + XDMAC_CC_CSIZE_CHK_1 | + XDMAC_CC_DWIDTH_WORD | + XDMAC_CC_SIF_AHB_IF0 | + XDMAC_CC_DIF_AHB_IF1 | + XDMAC_CC_SAM_INCREMENTED_AM | + XDMAC_CC_DAM_FIXED_AM | + XDMAC_CC_PERID(PERID_CLASSD_TX); +} + +/** + * @brief Configures and activates the CLASSD peripheral. + * + * @param[in] classdp pointer to the @p CLASSDDriver object + * + * @notapi + */ +void classd_lld_start(CLASSDDriver *classdp) { + + uint8_t i; + uint32_t dsp_clk_set, frame_set; + + /* Configures the peripheral.*/ + if (classdp->state == CLASSD_STOP) { + + if (&CLASSDD0 == classdp) { + classdp->dmatx = dmaChannelAllocate(SAMA_CLASSD_DMA_IRQ_PRIORITY, + (sama_dmaisr_t)classd_lld_serve_tx_interrupt, + (void *)classdp); + osalDbgAssert(classdp->dmatx != NULL, "no channel allocated"); + } + } + + /* Set DMA channel mode. */ + dmaChannelSetMode(classdp->dmatx, classdp->txdmamode); + + /* Set CLASSD DSP clock and Sample rate. */ + for(i = 0; i < 8; i++) { + if ((audio_info[i].rate) == (classdp->config->frame)) { + dsp_clk_set = audio_info[i].dsp_clk; + frame_set = audio_info[i].sample_rate; + break; + } + } + + /* Enable the CLASSD0 clock. */ + pmcEnableCLASSD0(); + + /* Configure PMC Audio structure. */ + dspclkConfigure(dsp_clk_set); + + /* Disable the CLASSD generic clock for now. */ + pmcDisableGclkCLASSD0(); + + /* Configure the CLASSD generic clock */ + pmcConfigGclk(ID_CLASSD, PMC_PCR_GCKCSS_AUDIO_CLK, 1); + + /* Disable write protection. */ + classdDisableWP(classdp->classd); + + /* Perform soft reset. */ + CLASSD->CLASSD_CR = CLASSD_CR_SWRST; + CLASSD->CLASSD_IDR = CLASSD_IDR_DATRDY; + + /* Clean CLASSD Registers. */ + classdp->classd->CLASSD_MR = 0; + classdp->classd->CLASSD_INTPMR = 0; + + /* CLASSD configuration. */ + classdp->classd->CLASSD_MR = classdp->config->left | + classdp->config->right | + classdp->config->left_mute | + classdp->config->right_mute | + classdp->config->pwm_mode | + classdp->config->non_overlap | + classdp->config->novrval; + + classdp->classd->CLASSD_INTPMR = classdp->config->attl | + classdp->config->attr | + classdp->config->deemp | + classdp->config->swap | + classdp->config->eqcfg | + classdp->config->mono | + classdp->config->mono_mode | + dsp_clk_set | frame_set; + + /* Enable CLASSD generic clock. */ + pmcEnableGclkCLASSD0(); + + /* Enable write protection. */ + classdEnableWP(classdp->classd); +} + +/** + * @brief Deactivates the CLASSD peripheral. + * + * @param[in] classdp pointer to the @p CLASSDDriver object + * + * @notapi + */ +void classd_lld_stop(CLASSDDriver *classdp) { + + /* Disable clocks. */ + pmcDisableAudio(); + pmcDisableGclkCLASSD0(); + pmcDisableCLASSD0(); + + /* Disable write protection. */ + classdDisableWP(classdp->classd); + + /* Reset CLASSD. */ + classdp->classd->CLASSD_INTPMR = 0; + classdp->classd->CLASSD_MR = 0; + + /* Enable write protection. */ + classdEnableWP(classdp->classd); + + /* Release and disable DMA channel. */ + dmaChannelRelease(classdp->dmatx); +} + +/** + * + * @brief Starts a CLASSD playback. + * + * @param[in] classdp pointer to the @p CLASSDDriver + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void classd_lld_send_audio(CLASSDDriver *classdp, const void *txbuf) { + + /* Get DMA transfert size. */ + size_t n = ((struct wav_header *)txbuf)->subchunk2_size / 4; + + osalDbgAssert(!((uint32_t) txbuf & (L1_CACHE_BYTES - 1)), "address not cache aligned"); + +#if 0 + osalDbgAssert(!(n & (L1_CACHE_BYTES - 1)), "size not multiple of cache line"); +#endif + + /* L1 is enabled */ + cacheCleanRegion((uint8_t *) txbuf, n); + + /* Get source address. */ + uint32_t addrSource = sizeof(struct wav_header); + + /* Unmute left and right channel */ + classdMuteChannel(classdp, false, false); + + /* Writing channel */ + dmaChannelSetSource(classdp->dmatx, txbuf + addrSource); + dmaChannelSetDestination(classdp->dmatx, &classdp->classd->CLASSD_THR); + dmaChannelSetTransactionSize(classdp->dmatx, n); + + /* DMA start transfer. */ + dmaChannelEnable(classdp->dmatx); +} + +/** + * @brief CLASSD mute/unmute channels. + * + * @param[in] classdp pointer to the @p CLASSDDriver object + * + * @iclass + */ +void classd_mute_channel(CLASSDDriver *classdp, bool left, bool right) { + + /* Disable write protection. */ + classdDisableWP(classdp->classd); + + /* Mute or unmute left channel. */ + if (left) + classdp->classd->CLASSD_MR |= CLASSD_MR_LMUTE; + else + classdp->classd->CLASSD_MR &= ~CLASSD_MR_LMUTE; + + /* Mute or unmute right channel. */ + if (right) + classdp->classd->CLASSD_MR |= CLASSD_MR_RMUTE; + else + classdp->classd->CLASSD_MR &= ~CLASSD_MR_RMUTE; + + /* Enable write protection. */ + classdEnableWP(classdp->classd); +} + +/** + * + * @brief CLASSD Driver initialization. + * + * @init + */ +void classdInit(void) { + + classd_lld_init(); +} + +/** + * + * @brief Initializes the standard part of a @p CLASSDDriver structure. + * + * @param[out] classdp pointer to a @p CLASSDDriver object + * + * @init + */ +void classdObjectInit(CLASSDDriver *classdp) { + classdp->state = CLASSD_STOP; + classdp->config = NULL; +} + +/** + * @brief Configures and activates the CLASSD peripheral. + * + * @param[in] classdp pointer to a @p CLASSDDriver object + * @param[in] config pointer to a @p CLASSDConfig object + * + * @api + */ +void classdStart(CLASSDDriver *classdp, const CLASSDConfig *config) { + + osalDbgCheck((classdp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((classdp->state == CLASSD_STOP) || (classdp->state == CLASSD_READY), + "invalid state"); + classdp->config = config; + classd_lld_start(classdp); + classdp->state = CLASSD_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the CLASSD peripheral. + * + * @param[in] classdp pointer to the @p CLASSDDriver object + * + * @api + */ +void classdStop(CLASSDDriver *classdp) { + + osalDbgCheck(classdp != NULL); + + osalSysLock(); + + osalDbgAssert((classdp->state == CLASSD_STOP) || (classdp->state == CLASSD_READY || (classdp->state == CLASSD_ACTIVE)), + "invalid state"); + + classd_lld_stop(classdp); + classdp->config = NULL; + classdp->state = CLASSD_STOP; + + osalSysUnlock(); +} + +/** + * + * @brief Starts a CLASSD playback. + * + * @param[in] classdp pointer to the @p CLASSDDriver + * @param[in] txbuf the pointer to the transmit buffer + * + * @note This function can be used only in syslock state. todo: control comment! + * + * @notapi + */ +void classdSendAudioI(CLASSDDriver *classdp, const void *txbuf) { + + (classdp)->state = CLASSD_ACTIVE; + classd_lld_send_audio(classdp, txbuf); +} + +/** + * + * @brief Starts a CLASSD playback. + * + * @param[in] classdp pointer to the @p CLASSDDriver + * @param[in] txbuf the pointer to the transmit buffer + * + * @notapi + */ +void classdSendAudio(CLASSDDriver *classdp, const void *txbuf) { + + osalSysLock(); + osalDbgAssert(classdp->state == CLASSD_READY, "not ready"); + classdSendAudioI(classdp, txbuf); + osalSysUnlock(); +} + +/** + * + * @brief Set the sample frame from the structure of a wav file. + * + * @param[in] classdconfigp pointer to the @p CLASSDConfig + * @param[in] music_file pointer to the wav file + * + * @notapi + */ +void classdSetSampleFrame(CLASSDConfig *classdconfigp, uint8_t *music_file) { + classdconfigp->frame = ((struct wav_header*)music_file)->sample_rate; +} + +/** + * @brief Mute/unmute CLASSD channel. + * + * @param[in] classdp pointer to the @p CLASSDDriver object + * + * @iclass + */ +void classdMuteChannel(CLASSDDriver *classdp, bool left, bool right) { + classd_mute_channel(classdp, left, right); +} + +#endif /* SAMA_USE_CLASSD */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_classd.h b/os/hal/ports/SAMA/SAMA5D2x/sama_classd.h new file mode 100644 index 000000000..212e4fab6 --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_classd.h @@ -0,0 +1,301 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/sama_classd.h + * @brief SAMA CLASSD support macros and structures. + * + * @addtogroup SAMA5D2x_CLASSD + * @{ + */ + +#ifndef SAMA_CLASSD_LLD_H +#define SAMA_CLASSD_LLD_H + +/** + * @brief Using the CLASSD driver. + */ +#if !defined(SAMA_USE_CLASSD) || defined(__DOXYGEN__) +#define SAMA_USE_CLASSD FALSE +#endif + +#if SAMA_USE_CLASSD || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ + +/** + * @brief CLASSD DMA interrupt priority level setting. + */ +#if !defined(SAMA_CLASSD_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define SAMA_CLASSD_DMA_IRQ_PRIORITY 4 +#endif + +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if !defined(SAMA_DMA_REQUIRED) +#define SAMA_DMA_REQUIRED +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + CLASSD_UNINIT = 0, /**< Not initialized. */ + CLASSD_STOP = 1, /**< Stopped. */ + CLASSD_READY = 2, /**< Ready. */ + CLASSD_ACTIVE = 3, /**< Exchanging data. */ +} classdstate_t; + +/** + * @brief Structure representing audio info. + */ +static const struct { + /** + * @brief Contains the value of the Sample Rate. + */ + uint32_t rate; + /** + * @brief Contains a mask of the Sample Rate. + */ + uint32_t sample_rate; + /** + * @brief Contains a mask of the DSP Clock. + */ + uint32_t dsp_clk; +} audio_info[] = { + {8000, CLASSD_INTPMR_FRAME_FRAME_8K, CLASSD_INTPMR_DSPCLKFREQ_12M288}, + {16000, CLASSD_INTPMR_FRAME_FRAME_16K, CLASSD_INTPMR_DSPCLKFREQ_12M288}, + {32000, CLASSD_INTPMR_FRAME_FRAME_32K, CLASSD_INTPMR_DSPCLKFREQ_12M288}, + {48000, CLASSD_INTPMR_FRAME_FRAME_48K, CLASSD_INTPMR_DSPCLKFREQ_12M288}, + {96000, CLASSD_INTPMR_FRAME_FRAME_96K, CLASSD_INTPMR_DSPCLKFREQ_12M288}, + {22050, CLASSD_INTPMR_FRAME_FRAME_22K, CLASSD_INTPMR_DSPCLKFREQ_11M2896}, + {44100, CLASSD_INTPMR_FRAME_FRAME_44K, CLASSD_INTPMR_DSPCLKFREQ_11M2896}, + {88200, CLASSD_INTPMR_FRAME_FRAME_88K, CLASSD_INTPMR_DSPCLKFREQ_11M2896}, +}; + +/** + * @brief Type of a structure representing Standard WAV file header information. + */ +struct wav_header { + /** + * @brief Contains the letters "RIFF" in ASCII form. + */ + uint32_t chunk_id; + /** + * @brief Size of the rest of the chunk following this number. + */ + uint32_t chunk_size; + /** + * @brief Contains the letters "WAVE". + */ + uint32_t format; + /** + * @brief Contains the letters "fmt ". + */ + uint32_t subchunk1_id; + /** + * @brief 16 for PCM. This is the size of the rest of the Subchunk which follows this number. + */ + uint32_t subchunk1_size; + /** + * @brief PCM = 1 (i.e. Linear quantization). Values other than 1 indicate some form of compression. + */ + uint16_t audio_format; + /** + * @brief Mono = 1, Stereo = 2, etc. + */ + uint16_t num_channels; + /** + * @brief 8000, 44100, etc. + */ + uint32_t sample_rate; + /** + * @brief SampleRate * NumChannels * BitsPerSample/8 + */ + uint32_t byte_rate; + /** + * @brief NumChannels * BitsPerSample/8 + */ + uint16_t block_align; + /** + * @brief 8 bits = 8, 16 bits = 16, etc. + */ + uint16_t bits_per_sample; + /** + * @brief Contains the letters "data". + */ + uint32_t subchunk2_id; + /** + * @brief Number of bytes in the data. + */ + uint32_t subchunk2_size; +}; + +/** + * @brief Type of a structure representing an CLASSD driver. + */ +typedef struct CLASSDDriver CLASSDDriver; + +/** + * @brief Type of a generic CLASSD callback. + */ +typedef void (*classdcb_t)(CLASSDDriver *classdp); + +/** + * @brief Driver configuration structure. + * @note It could be empty on some architectures. + */ +typedef struct { + /** + * @brief Callback pointer. + */ + classdcb_t callback; + /** + * @brief Configuration of the CLASSD left channel. + */ + uint32_t left; + /** + * @brief Configuration of the CLASSD right channel. + */ + uint32_t right; + /** + * @brief Configuration of the CLASSD left channel mute. + */ + uint32_t left_mute; + /** + * @brief Configuration of the CLASSD right channel mute. + */ + uint32_t right_mute; + /** + * @brief Configuration of the CLASSD PWM modulation type. + */ + uint32_t pwm_mode; + /** + * @brief Configuration of the CLASSD Non-Overlapping. + */ + uint32_t non_overlap; + /** + * @brief Configuration of the CLASSD Non-Overlapping value. + */ + uint32_t novrval; + /** + * @brief Configuration of the CLASSD left channel attenuation. + */ + uint32_t attl; + /** + * @brief Configuration of the CLASSD right channel attenuation. + */ + uint32_t attr; + /** + * @brief Configuration of the CLASSD de-emphasis filter. + */ + uint32_t deemp; + /** + * @brief Configuration of the CLASSD swap left right channel. + */ + uint32_t swap; + /** + * @brief Configuration of the CLASSD sample frequency. + */ + uint32_t frame; + /** + * @brief Configuration of the CLASSD EQ config. + */ + uint32_t eqcfg; + /** + * @brief Configuration of the CLASSD mono signal. + */ + uint32_t mono; + /** + * @brief Configuration of the CLASSD mono mode. + */ + uint32_t mono_mode; +} CLASSDConfig; + +/** + * @brief Structure representing an CLASSD driver. + */ +struct CLASSDDriver { + /** + * @brief Driver state. + */ + classdstate_t state; + /** + * @brief Current configuration data. + */ + const CLASSDConfig *config; + /** + * @brief Pointer to the WDT registers block. + */ + Classd *classd; + /** + * @brief Transmit DMA stream. + */ + sama_dma_channel_t *dmatx; + /** + * @brief TX DMA mode bit mask. + */ + uint32_t txdmamode; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ +extern CLASSDDriver CLASSDD0; + +#ifdef __cplusplus +extern "C" { +#endif + void classdInit(void); + void classdObjectInit(CLASSDDriver *classdp); + void classdStart(CLASSDDriver *classdp, const CLASSDConfig *config); + void classdStop(CLASSDDriver *classdp); + void classdSetSampleFrame(CLASSDConfig *classdconfigp, uint8_t *music_file); + void classdSendAudioI(CLASSDDriver *classdp, const void *txbuf); + void classdSendAudio(CLASSDDriver *classdp, const void *txbuf); + void classdMuteChannel(CLASSDDriver *classdp, bool left, bool right); +#ifdef __cplusplus +} +#endif + +#endif /* SAMA_USE_CLASSD */ + +#endif /* SAMA_CLASSD_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.c b/os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.c new file mode 100644 index 000000000..761c5b66b --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.c @@ -0,0 +1,955 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/sama_lcdc.c + * @brief SAMA LCDC support code. + * + * @addtogroup SAMA5D2x_LCDC + * @{ + */ + +#include "hal.h" + +#if (SAMA_USE_LCDC) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ +/* + * @brief NO CACHE attribute + */ +#if !defined(NO_CACHE) +#define NO_CACHE __attribute__((section (".nocache"))) +#endif +/*===========================================================================*/ +/* Driver local macros. */ +/*===========================================================================*/ +/* + * @name Configuration Macros + * @{ + */ +/* + * @brief Transfer Descriptor Fetch Enable + */ +#define LCDC_CTRL_DFETCH (0x1u << 0) +/* + * @brief Channel Enable Register + */ +#define LCDC_CHER_CHEN (0x1u << 0) +/* + * @brief Channel Disable Register + */ +#define LCDC_CHDR_CHDIS (0x1u << 0) +/* + * @brief Update Overlay Attributes Enable Register + */ +#define LCDC_CHER_UPDATEEN (0x1u << 1) +/* + * @brief Blender DMA Layer Enable + */ +#define LCDC_CFG_DMA (0x1u << 8) +/* + * @brief Blender Overlay Layer Enable + */ +#define LCDC_CFG_OVR (0x1u << 7) +/* + * @brief Pixel Stride + */ +#define LCDC_CFG_PSTRIDE_Pos 0 +#define LCDC_CFG_PSTRIDE_Msk (0xffffffffu << LCDC_CFG_PSTRIDE_Pos) +#define LCDC_CFG_PSTRIDE(value) ((LCDC_CFG_PSTRIDE_Msk & ((value) << \ + LCDC_CFG_PSTRIDE_Pos))) +/* + * @brief Horizontal Stride + */ +#define LCDC_CFG_XSTRIDE_Pos 0 +#define LCDC_CFG_XSTRIDE_Msk (0xffffffffu << LCDC_CFG_XSTRIDE_Pos) +#define LCDC_CFG_XSTRIDE(value) ((LCDC_CFG_XSTRIDE_Msk & ((value) << \ + LCDC_CFG_XSTRIDE_Pos))) +/* + * @brief Hardware Rotation Optimization Disable + */ +#define LCDC_CFG_ROTDIS (0x1u << 12) + +/* + * @brief Horizontal Window Position + */ +#define LCDC_CFG_XPOS_Pos 0 +#define LCDC_CFG_XPOS_Msk (0x7ffu << LCDC_CFG_XPOS_Pos) +#define LCDC_CFG_XPOS(value) ((LCDC_CFG_XPOS_Msk & ((value) << LCDC_CFG_XPOS_Pos))) + +/* + * @brief Vertical Window Position + */ +#define LCDC_CFG_YPOS_Pos 16 +#define LCDC_CFG_YPOS_Msk (0x7ffu << LCDC_CFG_YPOS_Pos) +#define LCDC_CFG_YPOS(value) ((LCDC_CFG_YPOS_Msk & ((value) << LCDC_CFG_YPOS_Pos))) + +/* + * @brief Horizontal Window Size + */ +#define LCDC_CFG_XSIZE_Pos 0 +#define LCDC_CFG_XSIZE_Msk (0x7ffu << LCDC_CFG_XSIZE_Pos) +#define LCDC_CFG_XSIZE(value) ((LCDC_CFG_XSIZE_Msk & ((value) << LCDC_CFG_XSIZE_Pos))) + +/* + * @brief Vertical Window Size + */ +#define LCDC_CFG_YSIZE_Pos 16 +#define LCDC_CFG_YSIZE_Msk (0x7ffu << LCDC_CFG_YSIZE_Pos) +#define LCDC_CFG_YSIZE(value) ((LCDC_CFG_YSIZE_Msk & ((value) << LCDC_CFG_YSIZE_Pos))) + +/* + * @brief Horizontal image Size in Memory + */ +#define LCDC_CFG_XMEMSIZE_Pos 0 +#define LCDC_CFG_XMEMSIZE_Msk (0x7ffu << LCDC_CFG_XMEMSIZE_Pos) +#define LCDC_CFG_XMEMSIZE(value) ((LCDC_CFG_XMEMSIZE_Msk & ((value) << LCDC_CFG_XMEMSIZE_Pos))) + +/* + * @brief Vertical image Size in Memory + */ +#define LCDC_CFG_YMEMSIZE_Pos 16 +#define LCDC_CFG_YMEMSIZE_Msk (0x7ffu << LCDC_CFG_YMEMSIZE_Pos) +#define LCDC_CFG_YMEMSIZE(value) ((LCDC_CFG_YMEMSIZE_Msk & ((value) << LCDC_CFG_YMEMSIZE_Pos))) + +/** @} */ + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ +LCDCDriver LCDCD0; + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ +/** + * @brief DMA Channel Descriptor. + */ +typedef struct { + /** + * @brief Frame Buffer base address register. + */ + uint32_t addr; + /** + * @brief Transfer Control register. + */ + uint32_t ctrl; + /** + * @brief Next Descriptor Address register. + */ + uint32_t next; +} lcdc_dma_descriptor_t; + +/* Variable layer data */ +typedef struct { + lcdc_dma_descriptor_t *dma_desc; + lcdc_dma_descriptor_t *dma_u_desc; + lcdc_dma_descriptor_t *dma_v_desc; + void *buffer; + uint8_t bpp; + uint8_t num_colors; +} layerdata_t; + +/* + * @brief Hardware info about the layers + */ +typedef struct { + layerdata_t *data; + bool stride_supported; + /* regs: _ER, _DR, _SR, _IER, _IDR, _IMR, _ISR */ + volatile uint32_t *reg_enable; + /* regs: blender */ + volatile uint32_t *reg_blender; + /* _HEAD, _ADDRESS, _CONTROL, _NEXT */ + volatile uint32_t *reg_dma_head; + /* _HEAD, _ADDRESS, _CONTROL, _NEXT */ + volatile uint32_t *reg_dma_u_head; + /* _HEAD, _ADDRESS, _CONTROL, _NEXT */ + volatile uint32_t *reg_dma_v_head; + /* regs: _CFG0, _CFG1 (RGB mode...) */ + volatile uint32_t *reg_cfg; + /* X Y register, W H register */ + volatile uint32_t *reg_win; + /* regs: stride */ + volatile uint32_t *reg_stride; + /* regs: RGB Default, RGB Key, RGB Mask */ + volatile uint32_t *reg_color; + /* regs: scale */ + volatile uint32_t *reg_scale; + /* regs: CLUT */ + volatile uint32_t *reg_clut; +} layerinfo_t; + +/* Base Layer */ +static layerdata_t lcdd_base; +/* OVR1 Layer */ +static layerdata_t lcdd_ovr1; +/* OVR2 Layer */ +static layerdata_t lcdd_ovr2; +/* HEO Layer */ +static layerdata_t lcdd_heo; +/* HCC Layer */ +static layerdata_t lcdd_hcc; + +/* + * @brief DMA descriptor + * @note The DMA Channel Descriptor (DSCR) must be aligned on a 64-bit boundary. + */ +ALIGNED_VAR(8) +/* DMA descriptor for Base Layer */ +NO_CACHE static lcdc_dma_descriptor_t base_dma_desc; + +ALIGNED_VAR(8) +/* DMA descriptor for OVR1 Layer */ +NO_CACHE static lcdc_dma_descriptor_t ovr1_dma_desc; + +ALIGNED_VAR(8) +/* DMA descriptor for OVR2 Layer */ +NO_CACHE static lcdc_dma_descriptor_t ovr2_dma_desc; + +ALIGNED_VAR(8) +/* DMA descriptor for HEO Layer */ +NO_CACHE static lcdc_dma_descriptor_t heo_dma_desc; +ALIGNED_VAR(8) +/* DMA descriptor for HEO U-UV Layer */ +NO_CACHE static lcdc_dma_descriptor_t heo_dma_u_desc; +ALIGNED_VAR(8) +/* DMA descriptor for HEO V Layer */ +NO_CACHE static lcdc_dma_descriptor_t heo_dma_v_desc; + +ALIGNED_VAR(8) +/* DMA descriptor for HCC Layer */ +NO_CACHE static lcdc_dma_descriptor_t hcc_dma_desc; + +/** + * @brief Information about layers + */ +static const layerinfo_t lcdd_layers[] = { + /* 0: LCDD_CONTROLLER */ + { + .stride_supported = false, + .reg_enable = &LCDC->LCDC_LCDEN, + }, + + /* 1: LCDD_BASE */ + { + .data = &lcdd_base, + .stride_supported = false, + .reg_enable = &LCDC->LCDC_BASECHER, + .reg_blender = &LCDC->LCDC_BASECFG4, + .reg_dma_head = &LCDC->LCDC_BASEHEAD, + .reg_cfg = &LCDC->LCDC_BASECFG0, + .reg_stride = &LCDC->LCDC_BASECFG2, + .reg_color = &LCDC->LCDC_BASECFG3, + .reg_clut = &LCDC->LCDC_BASECLUT[0] + }, + + /* 2: LCDD_OVR1 */ + { + .data = &lcdd_ovr1, + .stride_supported = true, + .reg_enable = &LCDC->LCDC_OVR1CHER, + .reg_blender = &LCDC->LCDC_OVR1CFG9, + .reg_dma_head = &LCDC->LCDC_OVR1HEAD, + .reg_cfg = &LCDC->LCDC_OVR1CFG0, + .reg_win = &LCDC->LCDC_OVR1CFG2, + .reg_stride = &LCDC->LCDC_OVR1CFG4, + .reg_color = &LCDC->LCDC_OVR1CFG6, + .reg_clut = &LCDC->LCDC_OVR1CLUT[0], + }, + + /* 3: LCDD_HEO */ + { + .data = &lcdd_heo, + .stride_supported = true, + .reg_enable = &LCDC->LCDC_HEOCHER, + .reg_blender = &LCDC->LCDC_HEOCFG12, + .reg_dma_head = &LCDC->LCDC_HEOHEAD, + .reg_dma_u_head = &LCDC->LCDC_HEOUHEAD, + .reg_dma_v_head = &LCDC->LCDC_HEOVHEAD, + .reg_cfg = &LCDC->LCDC_HEOCFG0, + .reg_win = &LCDC->LCDC_HEOCFG2, + .reg_stride = &LCDC->LCDC_HEOCFG5, + .reg_color = &LCDC->LCDC_HEOCFG9, + .reg_scale = &LCDC->LCDC_HEOCFG13, + .reg_clut = &LCDC->LCDC_HEOCLUT[0], + }, + + /* 4: LCDD_OVR2 */ + { + .data = &lcdd_ovr2, + .stride_supported = true, + .reg_enable = &LCDC->LCDC_OVR2CHER, + .reg_blender = &LCDC->LCDC_OVR2CFG9, + .reg_dma_head = &LCDC->LCDC_OVR2HEAD, + .reg_cfg = &LCDC->LCDC_OVR2CFG0, + .reg_win = &LCDC->LCDC_OVR2CFG2, + .reg_stride = &LCDC->LCDC_OVR2CFG4, + .reg_color = &LCDC->LCDC_OVR2CFG6, + .reg_clut = &LCDC->LCDC_OVR2CLUT[0], + } + , + /* 5: N/A */ + { + .data = NULL, + }, + + /* 6: LCDD_CUR */ + { + .data = &lcdd_hcc, + .stride_supported = false, + }, +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +/* + * @brief Clear DMA channel descriptor + * + * @param[in] descp pointer to lcdc_dma_descriptor + * @param[in] dma_regp pointer to LCDC leyer register + * + * @notapi + */ +static void clear_dma_desc(lcdc_dma_descriptor_t *descp, volatile uint32_t *dma_regp) { + /* Modify descriptor */ + if (descp) { + descp->ctrl &= ~LCDC_CTRL_DFETCH; + descp->next = (uint32_t)descp; + //cacheCleanRegion(descp, sizeof(lcdc_dma_descriptor_t)); + } + + /* Modify registers */ + dma_regp[2] &= ~LCDC_CTRL_DFETCH; + dma_regp[3] = (uint32_t)descp; +} + +/** + * @brief Computing scaling factor. + * + * @param[in] layerp pointer to a layerinfo_t struct + * @param[out] xfactorp pointer to xfactor scaling factor + * @param[out] yfactorp pointer to yfactor scaling factor + * + * @notapi + */ +static void compute_scaling_factors(const layerinfo_t *layerp, + uint16_t* xfactorp, uint16_t* yfactorp) +{ + uint16_t xmemsize, ymemsize; + uint16_t xsize, ysize; + +#ifdef LCDC_HEOCFG41_XPHIDEF + uint16_t xfactor_1st, yfactor_1st; +#endif + + xmemsize = (layerp->reg_win[2] & LCDC_CFG_XMEMSIZE_Msk) >> LCDC_CFG_XMEMSIZE_Pos; + ymemsize = (layerp->reg_win[2] & LCDC_CFG_YMEMSIZE_Msk) >> LCDC_CFG_YMEMSIZE_Pos; + xsize = (layerp->reg_win[1] & LCDC_CFG_XSIZE_Msk) >> LCDC_CFG_XSIZE_Pos; + ysize = (layerp->reg_win[1] & LCDC_CFG_YSIZE_Msk) >> LCDC_CFG_YSIZE_Pos; + +#ifdef LCDC_HEOCFG41_XPHIDEF + /* we assume that XPHIDEF & YPHIDEF are 0 */ + xfactor_1st = (2048 * xmemsize / xsize) + 1; + yfactor_1st = (2048 * ymemsize / ysize) + 1; + + if ((xfactor_1st * xsize / 2048) > xmemsize) + *xfactorp = xfactor_1st - 1; + else + *xfactorp = xfactor_1st; + + if ((yfactor_1st * ysize / 2048) > ymemsize) + *yfactorp = yfactor_1st - 1; + else + *yfactorp = yfactor_1st; +#else + *xfactorp = 1024 * (xmemsize + 1) / (xsize + 1); + *yfactorp = 1024 * (ymemsize + 1) / (ysize + 1); +#endif +} + +/** + * @brief Configures LCDC layers according to configuration struct. + * + * @param[in] listp pointer to a LCDCLayerConfig array + * @param[in] length length of array + * + * @notapi + */ +void layer_config(LCDCLayerConfig *listp, size_t length) { + uint8_t i; + uint8_t bpp_bit; + uint8_t bpp; + uint32_t index; + + uint32_t padding = 0; + uint32_t src_w, src_h, img_w, img_h; + uint32_t bits_per_row, bytes_per_row; + + LCDCLayerConfig *layerp; + + for (i = 0; i < length; i++) { + index = listp[i].layer_id; + + osalDbgAssert((index != LCDD_CONTROLLER) || (index != LCDD_CUR), "This is not a real layer"); + + layerp = &listp[i]; + uint16_t w, h, x, y; + + bpp = layerp->bpp; + w = layerp->width; + h = layerp->height; + x = layerp->x_pos; + y = layerp->y_pos; + img_w = layerp->w_img; + img_h = layerp->h_img; + + /* Bpp settings */ + lcdd_layers[index].reg_cfg[1] = layerp->bpp; + bpp = bpp >> 4; + + if (bpp == 1 || bpp < 5) { + bpp_bit = 16; + } + else if (bpp == 5 || bpp == 6) { + bpp_bit = 18; + } + else if (bpp == 7 || bpp == 8) { + bpp_bit = 19; + } + else if (bpp == 9 || bpp == 10) { + bpp_bit = 24; + } + else if (bpp == 11) { + bpp_bit = 25; + } + else if (bpp == 12 || bpp == 13) { + bpp_bit = 32; + } + else { + bpp_bit = 12; + } + + /* Set display buffer & mode */ + bits_per_row = img_w * bpp_bit; + bytes_per_row = bits_per_row >> 3; + + if (bits_per_row & 0x7) { + bytes_per_row++; + } + if (bytes_per_row & 0x3) { + padding = 4 - (bytes_per_row & 0x3); + } + /* No rotation optimization */ + lcdd_layers[index].reg_cfg[0] |= LCDC_CFG_ROTDIS; + + /* Configure PSTRIDE if supported */ + if (lcdd_layers[index].stride_supported) + lcdd_layers[index].reg_stride[1] = LCDC_CFG_PSTRIDE(0); + /* Configure XSTRIDE if supported */ + lcdd_layers[index].reg_stride[0] = LCDC_CFG_XSTRIDE(padding); + + /* Set window & position */ + if (lcdd_layers[index].reg_win) { + + /* Re - calculate to eliminate hardware overflow */ + if (x + w > LCDCD0.config->width) { + w = LCDCD0.config->width - x; + } + if (y + h > LCDCD0.config->height) { + h = LCDCD0.config->height - y; + } + + if (w == 0) + w++; + + if (h == 0) + h++; + + lcdd_layers[index].reg_win[0] = LCDC_CFG_XPOS(x) | LCDC_CFG_YPOS(y); + lcdd_layers[index].reg_win[1] = LCDC_CFG_XSIZE(w - 1) | LCDC_CFG_YSIZE(h - 1); + } + + /* Scaling setup, only HEO layer has scaling register */ + if (lcdd_layers[index].reg_win && lcdd_layers[index].reg_scale) { + src_w = img_w; + src_h = img_h; + + lcdd_layers[index].reg_win[2] = LCDC_CFG_XMEMSIZE(src_w - 1) | + LCDC_CFG_YMEMSIZE(src_h - 1); + /* Scaled */ + if (w != src_w || h != src_h) { + uint16_t scale_w, scale_h; + compute_scaling_factors(&lcdd_layers[index], &scale_w, &scale_h); + lcdd_layers[index].reg_scale[0] = LCDC_HEOCFG13_YFACTOR(scale_h) | + LCDC_HEOCFG13_XFACTOR(scale_w) | + LCDC_HEOCFG13_SCALEN; + } + /* Disable scaling */ + else { + lcdd_layers[index].reg_scale[0] = 0; + } + } + + /* Configure Descriptor */ + lcdd_layers[index].data->dma_desc->addr = (uint32_t)layerp->buffer; + lcdd_layers[index].data->dma_desc->ctrl = LCDC_CTRL_DFETCH; + lcdd_layers[index].data->dma_desc->next = (uint32_t)lcdd_layers[index].data->dma_desc; + + lcdd_layers[index].reg_dma_head[1] = (uint32_t)lcdd_layers[index].data->dma_desc->addr; + lcdd_layers[index].reg_dma_head[2] = LCDC_CTRL_DFETCH; + lcdd_layers[index].reg_dma_head[3] = (uint32_t)lcdd_layers[index].data->dma_desc; + + /* Configure layer */ + lcdd_layers[index].reg_enable[0] = LCDC_CHER_UPDATEEN; + lcdd_layers[index].reg_blender[0] |= LCDC_CFG_DMA | LCDC_CFG_OVR; + } +} + +/** + * @brief Enable Display. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + */ +static void lcdc_on(LCDCDriver *lcdcp) { + + uint32_t pixel_clock = lcdcp->config->framerate; + pixel_clock *= lcdcp->config->timing_hpw + lcdcp->config->timing_hbp + + lcdcp->config->width + lcdcp->config->timing_hfp; + pixel_clock *= lcdcp->config->timing_vpw + lcdcp->config->timing_vbp + + lcdcp->config->height + lcdcp->config->timing_vfp; + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + /* Configure LCD timing parameters, signal polarity and clock period. */ + if( LCDC->LCDC_LCDCFG0 & LCDC_LCDCFG0_CLKSEL) { + LCDC->LCDC_LCDCFG0 = LCDC_LCDCFG0_CLKDIV((SAMA_MCK * 2) / pixel_clock - 2) | + LCDC_LCDCFG0_CGDISHEO | LCDC_LCDCFG0_CGDISOVR1 | + LCDC_LCDCFG0_CGDISOVR2 | LCDC_LCDCFG0_CGDISBASE | + LCDC_LCDCFG0_CLKPWMSEL | LCDC_LCDCFG0_CLKSEL; + } + else { + LCDC->LCDC_LCDCFG0 = LCDC_LCDCFG0_CLKDIV(SAMA_MCK / pixel_clock - 2) | + LCDC_LCDCFG0_CGDISBASE | LCDC_LCDCFG0_CGDISHEO | + LCDC_LCDCFG0_CLKPWMSEL; + } + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + LCDC->LCDC_LCDCFG1 = LCDC_LCDCFG1_VSPW(lcdcp->config->timing_vpw - 1) | + LCDC_LCDCFG1_HSPW(lcdcp->config->timing_hpw - 1); + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + LCDC->LCDC_LCDCFG2 = LCDC_LCDCFG2_VBPW(lcdcp->config->timing_vbp) | + LCDC_LCDCFG2_VFPW(lcdcp->config->timing_vfp - 1); + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + LCDC->LCDC_LCDCFG3 = LCDC_LCDCFG3_HBPW(lcdcp->config->timing_hbp - 1) | + LCDC_LCDCFG3_HFPW(lcdcp->config->timing_hfp - 1); + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + LCDC->LCDC_LCDCFG4 = LCDC_LCDCFG4_RPF(lcdcp->config->height - 1) | + LCDC_LCDCFG4_PPL(lcdcp->config->width - 1); + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + LCDC->LCDC_LCDCFG5 = LCDC_LCDCFG5_GUARDTIME(30) | LCDC_LCDCFG5_MODE_OUTPUT_24BPP | + LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS | LCDC_LCDCFG5_VSPOL | + LCDC_LCDCFG5_HSPOL; + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + LCDC->LCDC_LCDCFG6 = LCDC_LCDCFG6_PWMCVAL(0xF0) | LCDC_LCDCFG6_PWMPOL | + LCDC_LCDCFG6_PWMPS(6); + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + + /* Enable the Pixel Clock. */ + LCDC->LCDC_LCDEN = LCDC_LCDEN_CLKEN; + + /* Poll to check that clock is running. */ + while (!(LCDC->LCDC_LCDSR & LCDC_LCDSR_CLKSTS)); + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + /* Enable Horizontal and Vertical Synchronization. */ + LCDC->LCDC_LCDEN = LCDC_LCDEN_SYNCEN; + /* Poll to check that the synchronization is up. */ + while (!(LCDC->LCDC_LCDSR & LCDC_LCDSR_LCDSTS)); + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + /* Enable the display power signal. */ + LCDC->LCDC_LCDEN = LCDC_LCDEN_DISPEN; + /* Poll to check that the power signal is activated. */ + while (!(LCDC->LCDC_LCDSR & LCDC_LCDSR_DISPSTS)); + + /* Wait for clock domain synchronization to be complete. */ + while ((LCDC->LCDC_LCDSR & LCDC_LCDSR_SIPSTS)); + + /* Enable backlight */ + LCDC->LCDC_LCDEN = LCDC_LCDEN_PWMEN; +} + +/** + * @brief Disable Display. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + */ +static void lcdc_off(void) { + + /* Disable all DMA channel descriptors */ + clear_dma_desc(&base_dma_desc, &LCDC->LCDC_BASEADDR); + clear_dma_desc(&ovr1_dma_desc, &LCDC->LCDC_OVR1ADDR); + clear_dma_desc(&ovr2_dma_desc, &LCDC->LCDC_OVR2ADDR); + clear_dma_desc(&heo_dma_desc, &LCDC->LCDC_HEOADDR); + clear_dma_desc(&heo_dma_u_desc, &LCDC->LCDC_HEOUADDR); + clear_dma_desc(&heo_dma_v_desc, &LCDC->LCDC_HEOVADDR); + + /* Disable DMA channels */ + LCDC->LCDC_BASECHDR = LCDC_BASECHDR_CHDIS; + LCDC->LCDC_OVR1CHDR = LCDC_OVR1CHDR_CHDIS; + LCDC->LCDC_OVR2CHDR = LCDC_OVR2CHDR_CHDIS; + LCDC->LCDC_HEOCHDR = LCDC_HEOCHDR_CHDIS; + LCDC->LCDC_BASECFG4 = 0; + + /* Poll CHSR until the channel is successfully disabled. */ + while (LCDC->LCDC_BASECHSR & LCDC_BASECHSR_CHSR); + while (LCDC->LCDC_OVR1CHSR & LCDC_OVR1CHSR_CHSR); + while (LCDC->LCDC_OVR2CHSR & LCDC_OVR1CHSR_CHSR); + while (LCDC->LCDC_HEOCHSR & LCDC_HEOCHSR_CHSR); + + /* Disable backlight */ + LCDC->LCDC_LCDDIS = LCDC_LCDDIS_PWMDIS; + /* Poll PWMSTS: field of the LCDC_LCDSR register to verify that the PWM + is no activated. */ + while (LCDC->LCDC_LCDSR & LCDC_LCDSR_PWMSTS); + + /* Disable the DISP signal. */ + LCDC->LCDC_LCDDIS = LCDC_LCDDIS_DISPDIS; + /* Poll DISPSTS field of the LCDC_LCDSR register to verify that the DISP + is no longer activated. */ + while (LCDC->LCDC_LCDSR & LCDC_LCDSR_DISPSTS); + + /* Disable the hsync and vsync signals. */ + LCDC->LCDC_LCDDIS = LCDC_LCDDIS_SYNCDIS; + /* Poll LCDSTS field of the LCDC_LCDSR register to check that the + synchronization is off. */ + while (LCDC->LCDC_LCDSR & LCDC_LCDSR_LCDSTS); + + /* Disable the Pixel clock. */ + LCDC->LCDC_LCDDIS = LCDC_LCDDIS_CLKDIS; + /* Poll CLKSTS field of the LCDC_LCDSR register to check that Pixel Clock + is disabled. */ + while (LCDC->LCDC_LCDSR & LCDC_LCDSR_CLKSTS); +} + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level LCDC driver initialization. + * + * @notapi + */ +void lcdc_lld_init(void) { +#if SAMA_HAL_IS_SECURE + mtxConfigPeriphSecurity(MATRIX0, ID_LCDC, SECURE_PER); +#endif /* SAMA_HAL_IS_SECURE */ + + /* Driver initialization.*/ + lcdcObjectInit(&LCDCD0); + LCDCD0.lcdc = LCDC; + + /* Reset layer information */ + lcdd_base.bpp = 0; + lcdd_base.buffer = NULL; + lcdd_base.dma_desc = &base_dma_desc; + + lcdd_ovr1.bpp = 0; + lcdd_ovr1.buffer = NULL; + lcdd_ovr1.dma_desc = &ovr1_dma_desc; + + lcdd_ovr2.bpp = 0; + lcdd_ovr2.buffer = NULL; + lcdd_ovr2.dma_desc = &ovr2_dma_desc; + + lcdd_heo.bpp = 0; + lcdd_heo.buffer = NULL; + lcdd_heo.dma_desc = &heo_dma_desc; + lcdd_heo.dma_u_desc = &heo_dma_u_desc; + lcdd_heo.dma_v_desc = &heo_dma_v_desc; + + lcdd_hcc.bpp = 0; + lcdd_base.buffer = NULL; + lcdd_hcc.dma_desc = &hcc_dma_desc; + + /* Disable LCD controller */ + lcdc_off(); + + /* Timing Engine Configuration */ + + /* Disable interrupt */ + LCDC->LCDC_LCDIDR = 0xFFFFFFFF; + + /* Base */ + LCDC->LCDC_BASECFG0 = LCDC_BASECFG0_DLBO | LCDC_BASECFG0_BLEN_AHB_INCR16; + + /* Overlay 1, GA 0xFF */ + LCDC->LCDC_OVR1CFG0 = LCDC_OVR1CFG0_DLBO | LCDC_OVR1CFG0_BLEN_AHB_BLEN_INCR16 | + LCDC_OVR1CFG0_ROTDIS; + + LCDC->LCDC_OVR1CFG9 = LCDC_OVR1CFG9_GA(0xFF) | LCDC_OVR1CFG9_GAEN; + + /* Overlay 2, GA 0xFF */ + LCDC->LCDC_OVR2CFG0 = LCDC_OVR2CFG0_DLBO | LCDC_OVR2CFG0_BLEN_AHB_INCR16 | + LCDC_OVR2CFG0_ROTDIS; + LCDC->LCDC_OVR2CFG9 = LCDC_OVR2CFG9_GA(0xFF) | LCDC_OVR2CFG9_GAEN; + + /* High End Overlay, GA 0xFF */ + LCDC->LCDC_HEOCFG0 = LCDC_HEOCFG0_DLBO | LCDC_HEOCFG0_BLEN_AHB_BLEN_INCR16 | + LCDC_HEOCFG0_ROTDIS; + LCDC->LCDC_HEOCFG12 = LCDC_HEOCFG12_GA(0xFF) | LCDC_HEOCFG12_GAEN; + LCDC->LCDC_HEOCFG14 = LCDC_HEOCFG14_CSCRY(0x94) | LCDC_HEOCFG14_CSCRU(0xCC) | + LCDC_HEOCFG14_CSCRV(0) | LCDC_HEOCFG14_CSCYOFF; + LCDC->LCDC_HEOCFG15 = LCDC_HEOCFG15_CSCGY(0x94) | LCDC_HEOCFG15_CSCGU(0x387) | + LCDC_HEOCFG15_CSCGV(0x3CD) | LCDC_HEOCFG15_CSCUOFF; + LCDC->LCDC_HEOCFG16 = LCDC_HEOCFG16_CSCBY(0x94)| LCDC_HEOCFG16_CSCBU(0) | + LCDC_HEOCFG16_CSCBV(0x102) | LCDC_HEOCFG16_CSCVOFF; +} + +/** + * @brief Configures and activates the LCDC peripheral. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + * + * @notapi + */ +void lcdc_lld_start(LCDCDriver *lcdcp) { + + /* Enable the LCDC peripheral clock. */ + pmcEnableLCDC(); + + /* Configure overlays */ + layer_config(lcdcp->config->listp, lcdcp->config->length); + +} + +/** + * @brief Deactivates the LCDC peripheral. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + * + * @notapi + */ +void lcdc_lld_stop(LCDCDriver *lcdcp) { + + if (lcdcp->state == LCDC_READY) { + + /* Disable display. */ + lcdc_off(); + + /* Disable the LCDC clock. */ + pmcDisableLCDC(); + } +} + +/** + * + * @brief Initializes the standard part of a @p LCDCDriver structure. + * + * @param[out] lcdcp pointer to a @p LCDCDriver object + * + * @init + */ +void lcdcObjectInit(LCDCDriver *lcdcp) { + lcdcp->state = LCDC_STOP; + lcdcp->config = NULL; +} + +/** + * @brief LCDC driver initialization. + * + * @notapi + */ +void lcdcInit(void) { + + lcdc_lld_init(); +} + +/** + * @brief Configures and activates the LCDC peripheral. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + * @param[in] configp pointer to the LCDCConfig struct + * + * @api + */ +void lcdcStart(LCDCDriver *lcdcp, const LCDCConfig *configp) { + + osalDbgCheck(lcdcp != NULL); + + osalSysLock(); + osalDbgAssert((lcdcp->state == LCDC_STOP) , "invalid state"); + lcdcp->config = configp; + lcdc_lld_start(lcdcp); + lcdcp->state = LCDC_READY; + osalSysUnlock(); + + /* Enable display. */ + lcdc_on(lcdcp); +} + +/** + * @brief Deactivates the LCDC peripheral. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + * + * @api + */ +void lcdcStop(LCDCDriver *lcdcp) { + + osalDbgCheck(lcdcp != NULL); + + osalSysLock(); + osalDbgAssert((lcdcp->state == LCDC_READY), "invalid state"); + + lcdc_lld_stop(lcdcp); + lcdcp->state = LCDC_STOP; + osalSysUnlock(); +} + +void lcdcShowLayer(LCDCDriver *lcdcp, uint8_t id, bool enable) { + (void)lcdcp; + + if(enable) { + lcdd_layers[id].reg_enable[0] = LCDC_CHER_CHEN; + } + else { + lcdd_layers[id].reg_enable[1] = LCDC_CHDR_CHDIS; + } +} + +/* + * @brief brief Set the backlight of the LCD. + * + * param[in] level Backlight brightness level [1..255], + * 255 means maximum brightness. + * + * @api + */ +void lcdcSetBacklight(uint32_t level) { + uint32_t cfg = LCDC->LCDC_LCDCFG6 & ~LCDC_LCDCFG6_PWMCVAL_Msk; + LCDC->LCDC_LCDCFG6 = cfg | LCDC_LCDCFG6_PWMCVAL(level); +} + +#if (TRUE == LCDC_USE_MUTUAL_EXCLUSION) + +/** + * @brief Gains exclusive access to the LCDC module. + * @details This function tries to gain ownership to the LCDC module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p LCDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + * + * @sclass + */ +void lcdcAcquireBusS(LCDCDriver *lcdcp) { + + osalDbgCheckClassS(); + osalDbgCheck(lcdcp == &LCDCD0); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxLockS(&lcdcp->lock); +#else + chSemWaitS(&lcdcp->lock); +#endif +} + +/** + * @brief Gains exclusive access to the LCDC module. + * @details This function tries to gain ownership to the LTDC module, if the + * module is already being used then the invoking thread is queued. + * @pre In order to use this function the option + * @p LCDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + * + * @api + */ +void lcdcAcquireBus(LCDCDriver *lcdcp) { + + osalSysLock(); + lcdcAcquireBusS(lcdcp); + osalSysUnlock(); +} + +/** + * @brief Releases exclusive access to the LCDC module. + * @pre In order to use this function the option + * @p LCDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + * + * @sclass + */ +void lcdcReleaseBusS(LCDCDriver *lcdcp) { + + osalDbgCheckClassS(); + osalDbgCheck(lcdcp == &LCDCD0); + +#if (TRUE == CH_CFG_USE_MUTEXES) + chMtxUnlockS(&lcdcp->lock); +#else + chSemSignalI(&lcdcp->lock); +#endif +} + +/** + * @brief Releases exclusive access to the LCDC module. + * @pre In order to use this function the option + * @p LCDC_USE_MUTUAL_EXCLUSION must be enabled. + * + * @param[in] lcdcp pointer to the @p LCDCDriver object + * + * @api + */ +void lcdcReleaseBus(LCDCDriver *lcdcp) { + + osalSysLock(); + lcdcReleaseBusS(lcdcp); + osalSysUnlock(); +} + +#endif /* LCDC_USE_MUTUAL_EXCLUSION */ + +#endif /* SAMA_USE_LCDC == TRUE */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.h b/os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.h new file mode 100644 index 000000000..4a9237024 --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.h @@ -0,0 +1,280 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/sama_lcdc.h + * @brief SAMA LCDC support macros and structures. + * + * @addtogroup SAMA5D2x_LCDC + * @{ + */ + +#ifndef SAMA_LCDC_LLD_H +#define SAMA_LCDC_LLD_H + +/** + * @brief Using the LCDC driver. + */ +#if !defined(SAMA_USE_LCDC) || defined(__DOXYGEN__) +#define SAMA_USE_LCDC FALSE +#endif + +#if (SAMA_USE_LCDC) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name LCDC ID LAYERS + * @{ + */ +/* LCD controller ID, no display, configuration ONLY */ +#define LCDD_CONTROLLER 0 + +/* LCD base layer, display fixed size image */ +#define LCDD_BASE 1 + +/* LCD Overlay 1 */ +#define LCDD_OVR1 2 + +/* LCD Overlay 2 */ +#define LCDD_OVR2 4 + +/* LCD HighEndOverlay, support resize */ +#define LCDD_HEO 3 + +/* LCD Cursor, max size 128x128 */ +#define LCDD_CUR 6 +/** @} */ + +/** + * @name BPP MODE + * @{ + */ +#define LCDC_CFG_RGBMODE_12BPP_RGB_444 (0x0u << 4) +#define LCDC_CFG_RGBMODE_16BPP_ARGB_4444 (0x1u << 4) +#define LCDC_CFG_RGBMODE_16BPP_RGBA_4444 (0x2u << 4) +#define LCDC_CFG_RGBMODE_16BPP_RGB_565 (0x3u << 4) +#define LCDC_CFG_RGBMODE_16BPP_TRGB_1555 (0x4u << 4) +#define LCDC_CFG_RGBMODE_18BPP_RGB_666 (0x5u << 4) +#define LCDC_CFG_RGBMODE_18BPP_RGB_666PACKED (0x6u << 4) +#define LCDC_CFG_RGBMODE_19BPP_TRGB_1666 (0x7u << 4) +#define LCDC_CFG_RGBMODE_19BPP_TRGB_PACKED (0x8u << 4) +#define LCDC_CFG_RGBMODE_24BPP_RGB_888 (0x9u << 4) +#define LCDC_CFG_RGBMODE_24BPP_RGB_888_PACKED (0xAu << 4) +#define LCDC_CFG_RGBMODE_25BPP_TRGB_1888 (0xBu << 4) +#define LCDC_CFG_RGBMODE_32BPP_ARGB_8888 (0xCu << 4) +#define LCDC_CFG_RGBMODE_32BPP_RGBA_8888 (0xDu << 4) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ +/** + * @brief LCDC_USE_WAIT. + */ +#if !defined(LCDC_USE_WAIT) || defined(__DOXYGEN__) +#define LCDC_USE_WAIT FALSE +#endif + +/** + * @brief LCDC_USE_MUTUAL_EXCLUSION. + */ +#if !defined(LCDC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__) +#define LCDC_USE_MUTUAL_EXCLUSION FALSE +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + LCDC_UNINIT = 0, /**< Not initialized.*/ + LCDC_STOP = 1, /**< Stopped.*/ + LCDC_READY = 2, /**< Ready.*/ + LCDC_ACTIVE = 3, /**< Executing commands.*/ +} lcdcstate_t; + +/** + * @brief Type of a structure representing an LCDC driver. + */ +typedef struct LCDCDriver LCDCDriver; + +/** + * @brief LCD display layer information. + */ +typedef struct { + /** + * @brief Display image buffer. + */ + void *buffer; + /** + * @brief Display image width. + */ + uint16_t width; + /** + * @brief Display image height. + */ + uint16_t height; + /** + * @brief Display image x position. + */ + uint16_t x_pos; + /** + * @brief Display image y_pos. + */ + uint16_t y_pos; + /** + * @brief Horizontal image Size in Memory. + */ + uint16_t w_img; + /** + * @brief Vertical image Size in Memory. + */ + uint16_t h_img; + /** + * @brief BPP mode. + */ + uint8_t bpp; + /** + * @brief Layer ID. + */ + uint8_t layer_id; +} LCDCLayerConfig; + +/** + * @brief Driver LCD configuration structure. + */ +typedef struct { + /** + * @brief Display image width. + */ + uint16_t width; + /** + * @brief Display image height. + */ + uint16_t height; + /** + * @brief Frame rate in Hz. + */ + uint8_t framerate; + /** + * @brief Vertical front porch in number of lines. + */ + uint8_t timing_vfp; + /** + * @brief Vertical back porch in number of lines. + */ + uint8_t timing_vbp; + /** + * @brief Vertical pulse width in number of lines. + */ + uint8_t timing_vpw; + /** + * @brief Horizontal front porch in LCDDOTCLK cycles. + */ + uint8_t timing_hfp; + /** + * @brief Horizontal back porch in LCDDOTCLK cycles. + */ + uint8_t timing_hbp; + /** + * @brief Horizontal pulse width in LCDDOTCLK cycles. + */ + uint8_t timing_hpw; + /** + * @brief lenght of LCDCLayerConfig array + * @note Number of layers to configure + */ + size_t length; + /** + * @brief pointer to LCDCLayerConfig array + */ + LCDCLayerConfig *listp; +} LCDCConfig; + +/** + * @brief Structure representing an LCDC driver. + */ +struct LCDCDriver { + /** + * @brief Driver state. + */ + lcdcstate_t state; + /** + * @brief Current configuration lcd data. + */ + const LCDCConfig *config; + /** + * @brief Pointer to the LCDC registers block. + */ + Lcdc *lcdc; + /* Multithreading stuff.*/ +#if (LCDC_USE_WAIT == TRUE) || defined(__DOXYGEN__) + thread_t *thread; +#endif /* LCDC_USE_WAIT */ +#if (LCDC_USE_MUTUAL_EXCLUSION == TRUE) +#if (CH_CFG_USE_MUTEXES == TRUE) + mutex_t lock; +#elif (CH_CFG_USE_SEMAPHORES == TRUE) + semaphore_t lock; +#endif +#endif /* LCDC_USE_MUTUAL_EXCLUSION */ +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern LCDCDriver LCDCD0; + +#ifdef __cplusplus +extern "C" { +#endif + void lcdcObjectInit(LCDCDriver *lcdcp); + void lcdcInit(void); + void lcdcStart(LCDCDriver *lcdcp, const LCDCConfig *configp); + void lcdcStop(LCDCDriver *lcdcp); + void lcdcShowLayer(LCDCDriver *lcdcp, uint8_t id, bool enable); + void lcdcSetBacklight(uint32_t level); +#if (LCDC_USE_MUTUAL_EXCLUSION) + void lcdcAcquireBusS(LCDCDriver *lcdcp); + void lcdcAcquireBus(LCDCDriver *lcdcp); + void lcdcReleaseBusS(LCDCDriver *lcdcp); + void lcdcReleaseBus(LCDCDriver *lcdcp); +#endif /* LCDC_USE_MUTUAL_EXCLUSION */ + +#ifdef __cplusplus +} +#endif + +#endif /* SAMA_USE_LCDC */ + +#endif /* SAMA_LCDC_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.c b/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.c new file mode 100644 index 000000000..97c0477da --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.c @@ -0,0 +1,548 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/sama_onewire.c + * @brief SAMA ONEWIRE support code. + * + * @addtogroup SAMA5D2x_ONEWIRE + * @{ + */ + +#include "hal.h" + +#if (SAMA_USE_ONEWIRE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ +/** + * @name Delays in standard speed mode. + * @{ + */ +#define A US2RTC(SAMA_PCK, 6) +#define B US2RTC(SAMA_PCK, 64) +#define C US2RTC(SAMA_PCK, 60) +#define D US2RTC(SAMA_PCK, 10) +#define E US2RTC(SAMA_PCK, 9) +#define F US2RTC(SAMA_PCK, 55) +#define G US2RTC(SAMA_PCK, 0) +#define H US2RTC(SAMA_PCK, 480) +#define I US2RTC(SAMA_PCK, 70) +#define J US2RTC(SAMA_PCK, 410) +/** @} */ + +#if SAMA_HAL_IS_SECURE +#define PAD_INPUT_MODE PAL_SAMA_FUNC_GPIO | \ + PAL_SAMA_DIR_INPUT | \ + PAL_SAMA_OPD_OPENDRAIN | \ + PAL_SAMA_PUEN_PULLUP | \ + PAL_MODE_SECURE + +#define PAD_OUTPUT_MODE PAL_SAMA_FUNC_GPIO | \ + PAL_SAMA_DIR_OUTPUT | \ + PAL_SAMA_OPD_OPENDRAIN | \ + PAL_SAMA_PUEN_PULLUP | \ + PAL_MODE_SECURE +#else +#define PAD_INPUT_MODE PAL_SAMA_FUNC_GPIO | \ + PAL_SAMA_DIR_INPUT | \ + PAL_SAMA_OPD_OPENDRAIN | \ + PAL_SAMA_PUEN_PULLUP + +#define PAD_OUTPUT_MODE PAL_SAMA_FUNC_GPIO | \ + PAL_SAMA_DIR_OUTPUT | \ + PAL_SAMA_OPD_OPENDRAIN | \ + PAL_SAMA_PUEN_PULLUP +#endif /* SAMA_HAL_IS_SECURE */ + +/*===========================================================================*/ +/* Driver local macros. */ +/*===========================================================================*/ + +/** + * @brief Set ONEWIRE pin in output mode. + * + * @param[in] onewp pointer to a ONEWIRE driver. + * + * @notapi + */ +#define onewireSetPinOutput(onewp) { \ + palSetLineMode(onewp->config->line, PAD_OUTPUT_MODE); \ +} + +/** + * @brief Set ONEWIRE pin in input mode. + * + * @param[in] onewp pointer to a ONEWIRE driver. + * + * @notapi + */ +#define onewireSetPinInput(onewp) { \ + palSetLineMode(onewp->config->line, PAD_INPUT_MODE); \ +} + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ +ONEWIREDriver ONEWD0; + +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +/** + * @brief Low level ONEWIRE driver initialization. + * + * @notapi + */ +void onewire_lld_init(void) { + + onewireObjectInit(&ONEWD0); +} + +/** + * @brief Configures and activates the ONEWIRE pin. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * + * @notapi + */ +void onewire_lld_start(ONEWIREDriver *onewp) { + + /* Set the ONEWIRE pin in output mode. */ + onewireSetPinOutput(onewp); + +} + +/** + * @brief Deactivates the ONEWIRE driver. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * + * @notapi + */ +void onewire_lld_stop(ONEWIREDriver *onewp) { + (void) onewp; +} + +/** + * @brief Send a Reset on ONEWIRE pin. + * The reset detect the slave presence on the pin + * and ready it for a command. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @return result result of the reset, if 0 a slave is detected + * + * @notapi + */ +bool onewire_lld_reset(ONEWIREDriver *onewp) { + + bool result = TRUE; + + /* At the beginning set the pin in output mode. */ + onewireSetPinOutput(onewp); + + /* Wait 0 microseconds. */ + chSysPolledDelayX(G); + /* Drives pin low. */ + palClearLine(onewp->config->line); + /* Wait 480 microseconds. */ + chSysPolledDelayX(H); + /* Drives pin high. */ + palSetLine(onewp->config->line); + /* Wait 70 microseconds. */ + chSysPolledDelayX(I); + /* Set the pin in input mode. */ + onewireSetPinInput(onewp); + /* Read the pin logic state. */ + result = palReadLine(onewp->config->line); + /* Wait 410 microseconds. */ + chSysPolledDelayX(J); + + return result; +} + +/** + * @brief Write a bit through ONEWIRE pin. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @param[in] value bit value to write + * + * @notapi + */ +void onewire_lld_write_bit(ONEWIREDriver *onewp, uint8_t value) { + + osalDbgAssert((value == 0u) || (value == 1u), + "invalid value"); + + /* Set the pin in output mode. */ + onewireSetPinOutput(onewp); + + if (value) { + /* Write '1' bit */ + /* Drives pin low. */ + palClearLine(onewp->config->line); + /* Wait 6 microsecond. */ + chSysPolledDelayX(A); + /* Drives pin high. */ + palSetLine(onewp->config->line); + /* Wait 64 microseconds to complete the time slot and recovery. */ + chSysPolledDelayX(B); + } + else { + /* Write '0' bit */ + /* Drives pin low. */ + palClearLine(onewp->config->line); + /* Wait 60 microsecond. */ + chSysPolledDelayX(C); + /* Drives pin high. */ + palSetLine(onewp->config->line); + /* Wait 10 microseconds for recovery. */ + chSysPolledDelayX(D); + } +} + +/** + * @brief Read a bit through ONEWIRE pin. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @return value bit read + * + * @notapi + */ +uint8_t onewire_lld_read_bit(ONEWIREDriver *onewp) { + + uint8_t value; + + /* At the beginning set the pin in output mode. */ + onewireSetPinOutput(onewp); + + /* Drives pin low. */ + palClearLine(onewp->config->line); + /* Wait 6 microsecond. */ + chSysPolledDelayX(A); + /* Drives pin high. */ + palSetLine(onewp->config->line); + /* Wait 9 microseconds. */ + chSysPolledDelayX(E); + /* Set the pin in input mode. */ + onewireSetPinInput(onewp); + /* Read the pin logic state. */ + value = palReadLine(onewp->config->line); + /* Wait 55 microseconds. */ + chSysPolledDelayX(F); + + return value; +} + +/** + * @brief Write a byte through ONEWIRE pin. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @param[in] byte byte to write + * + * @notapi + */ +void onewire_lld_write_byte(ONEWIREDriver *onewp, uint8_t byte) { + + uint8_t i; + + /* Loop to write each bit in the byte, LS-bit first */ + for (i = 0; i < 8; i++) { + onewire_lld_write_bit(onewp, (byte & 0x01)); + /* Shift the data byte for the next bit */ + byte >>= 1; + } +} + +/** + * @brief Read a byte through ONEWIRE pin. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * return value byte read + * + * @notapi + */ +uint8_t onewire_lld_read_byte(ONEWIREDriver *onewp) { + + uint8_t i; + uint8_t value = 0; + + for (i = 0; i < 8; i++) { + /* Shift the result to get it ready for the next bit */ + value >>= 1; + /* If result is one, then set MS bit */ + if (onewire_lld_read_bit(onewp)) + value |= 0x80; + } + return value; +} + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ +/** + * @brief ONEWIRE driver initialization. + * + * @api + */ +void onewireInit(void) { + + onewire_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p ONEWIREDriver structure. + * + * @param[out] onewp pointer to the @p ONEWIREDriver object + * + * @init + */ +void onewireObjectInit(ONEWIREDriver *onewp) { + + onewp->state = ONEW_STOP; + onewp->config = NULL; + + osalMutexObjectInit(&onewp->mutex); +} + +/** + * @brief Configures and activates the ONEWIRE pin. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @param[in] config pointer to the @p ONEWIREConfig object + * + * @api + */ +void onewireStart(ONEWIREDriver *onewp, const ONEWIREConfig *config) { + + osalDbgCheck((onewp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((onewp->state == ONEW_STOP) || (onewp->state == ONEW_READY), + "invalid state"); + onewp->config = config; + onewire_lld_start(onewp); + onewp->state = ONEW_READY; + osalSysUnlock(); + +} + +/** + * @brief Deactivates the ONEWIRE driver. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * + * @api + */ +void onewireStop(ONEWIREDriver *onewp) { + + osalDbgCheck(onewp != NULL); + + osalSysLock(); + + osalDbgAssert((onewp->state == ONEW_STOP) || (onewp->state == ONEW_READY), + "invalid state"); + + onewire_lld_stop(onewp); + onewp->config = NULL; + onewp->state = ONEW_STOP; + + osalSysUnlock(); +} + +/** + * @brief Write a block of bytes through ONEWIRE pin. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @param[in] txbuf the pointer to the transmit buffer + * @param[in] n number of bytes to write + * + * @api + */ +void onewireWriteBlockI(ONEWIREDriver *onewp, uint8_t *txbuf, size_t n) { + + uint32_t i; + (onewp)->state = ONEW_ACTIVE; + for (i = 0; i < n; i++) { + onewire_lld_write_byte(onewp, txbuf[i]); + } +} + +/** + * @brief Write a block of bytes through ONEWIRE pin. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @param[in] txbuf the pointer to the transmit buffer + * @param[in] n number of bytes to write + * + * @api + */ +void onewireWriteBlock(ONEWIREDriver *onewp, uint8_t *txbuf, size_t n) { + + osalDbgCheck(onewp != NULL); + + osalSysLock(); + osalDbgAssert(onewp->state == ONEW_READY, "not ready"); + onewireWriteBlockI(onewp, txbuf, n); + + (onewp)->state = ONEW_READY; + osalSysUnlock(); +} + +/** + * @brief Read a block of bytes through ONEWIRE pin. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @param[out]rxbuf pointer to the receive buffer + * @param[in] n number of bytes to read + * + * @api + */ +void onewireReadBlockI(ONEWIREDriver *onewp, uint8_t *rxbuf, size_t n) { + + uint32_t i; + (onewp)->state = ONEW_ACTIVE; + for (i = 0; i < n; i++) { + rxbuf[i] = onewire_lld_read_byte(onewp); + } +} + +/** + * @brief Read a block of bytes through ONEWIRE pin. + * + * @param[in] onewirep pointer to the @p ONEWIREDriver object + * @param[out]rxbuf pointer to the receive buffer + * @param[in] n number of bytes to read + * + * @api + */ +void onewireReadBlock(ONEWIREDriver *onewp, uint8_t *rxbuf, size_t n) { + + osalDbgCheck(onewp != NULL); + +// osalSysLock(); + osalDbgAssert(onewp->state == ONEW_READY, "not ready"); + onewireReadBlockI(onewp, rxbuf, n); + (onewp)->state = ONEW_READY; +// osalSysUnlock(); +} + +/** + * @brief Send a Reset on ONEWIRE pin. + * The reset detect the slave presence on the pin + * and ready it for a command. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @return result result of the reset, if 0 a slave is detected + * + * @api + */ +bool onewireReset(ONEWIREDriver *onewp) { + + bool detect = TRUE; + + osalDbgCheck(onewp != NULL); + + osalSysLock(); + osalDbgAssert(onewp->state == ONEW_READY, + "invalid state"); + detect = onewire_lld_reset(onewp); + osalSysUnlock(); + + return detect; +} + +/* + * @brief Sends a command. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @param[in] cmdp pointer command byte + * + * @api + */ +void onewireCommandI(ONEWIREDriver *onewp, uint8_t *cmdp, size_t n) { + + uint32_t i; + (onewp)->state = ONEW_ACTIVE; + for (i = 0; i < n; i++) { + onewire_lld_write_byte(onewp, cmdp[i]); + } +} + +/* + * @brief Sends a command. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * @param[in] cmdp pointer to command + * + * @api + */ +void onewireCommand(ONEWIREDriver *onewp, uint8_t *cmdp, size_t n) { + + osalDbgCheck((onewp != NULL) && (cmdp != NULL)); + +// osalSysLock(); + + osalDbgAssert(onewp->state == ONEW_READY, "not ready"); + + onewireCommandI(onewp, cmdp, n); + (onewp)->state = ONEW_READY; +// osalSysUnlock(); +} + + +/** + * @brief Gains exclusive access to the ONEWIRE bus. + * @details This function tries to gain ownership to the ONEWIRE bus, if the bus + * is already being used then the invoking thread is queued. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * + * @api + */ +void onewireAcquireBus(ONEWIREDriver *onewp) { + + osalDbgCheck(onewp != NULL); + + osalMutexLock(&onewp->mutex); +} + +/** + * @brief Releases exclusive access to the ONEWIRE bus. + * + * @param[in] onewp pointer to the @p ONEWIREDriver object + * + * @api + */ +void onewireReleaseBus(ONEWIREDriver *onewp) { + + osalDbgCheck(onewp != NULL); + + osalMutexUnlock(&onewp->mutex); +} + +#endif /* SAMA_USE_ONEWIRE == TRUE */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.h b/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.h new file mode 100644 index 000000000..b8edb1185 --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.h @@ -0,0 +1,127 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/sama_onewire.h + * @brief SAMA ONEWIRE support macros and structures. + * + * @addtogroup SAMA5D2x_ONEWIRE + * @{ + */ + +#ifndef SAMA_ONEWIRE_LLD_H +#define SAMA_ONEWIRE_LLD_H + +/** + * @brief Using the ONEWIRE driver. + */ +#if !defined(SAMA_USE_ONEWIRE) || defined(__DOXYGEN__) +#define SAMA_USE_ONEWIRE FALSE +#endif + +#if (SAMA_USE_ONEWIRE) || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ +/** + * @brief Driver state machine possible states. + */ +typedef enum { + ONEW_UNINIT = 0, /**< Not initialized. */ + ONEW_STOP = 1, /**< Stopped. */ + ONEW_READY = 2, /**< Active. */ + ONEW_ACTIVE = 3 /**< Active. */ +} onewstate_t; + +/** + * @brief Type of a structure representing a ONEWIRE driver. + */ +typedef struct ONEWIREDriver ONEWIREDriver; + +/** + * @brief Driver configuration structure. + */ +typedef struct { + /** + * @brief Line for the data IO + */ + uint32_t line; +} ONEWIREConfig; + + +/** + * @brief Structure representing an ONEWIRE driver. + */ +struct ONEWIREDriver { + /** + * @brief Driver state. + */ + onewstate_t state; + /** + * @brief Current configuration data. + */ + const ONEWIREConfig *config; + /** + * @brief Mutex protecting the bus. + */ + mutex_t mutex; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +extern ONEWIREDriver ONEWD0; + +#ifdef __cplusplus +extern "C" { +#endif + void onewireInit(void); + void onewireObjectInit(ONEWIREDriver *onewp); + void onewireStart(ONEWIREDriver *onewp, const ONEWIREConfig *config); + void onewireStop(ONEWIREDriver *onewp); + bool onewireReset(ONEWIREDriver *onewp); + void onewireCommand(ONEWIREDriver *onewp, uint8_t *cmdp, size_t n); + void onewireWriteBlock(ONEWIREDriver *onewp, uint8_t *txbuf, size_t n); + void onewireReadBlock(ONEWIREDriver *onewp, uint8_t *rxbuf, size_t n); + void onewireAcquireBus(ONEWIREDriver *onewp); + void onewireReleaseBus(ONEWIREDriver *onewp); +#ifdef __cplusplus +} +#endif + +#endif /* SAMA_USE_ONEWIRE */ + +#endif /* SAMA_ONEWIRE_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_pmc.h b/os/hal/ports/SAMA/SAMA5D2x/sama_pmc.h index 8fc57b261..bf0fb7441 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/sama_pmc.h +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_pmc.h @@ -49,6 +49,7 @@ * @name Generic PMC operations * @{ */ +#if SAMA_HAL_IS_SECURE /** * @brief Enable write protection on PMC registers block. * @@ -122,6 +123,387 @@ PMC->PMC_PCDR1 = (mask); \ pmcEnableWP(); \ } + +/** + * @brief Enables the generic clock of a peripheral. + * + * @param[in] mask ID peripherals + * + * @api + */ +#define pmcEnableGclk(id) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + pmcDisableWP(); \ + PMC->PMC_PCR = PMC_PCR_PID(id); \ + uint32_t pcr = PMC->PMC_PCR; \ + PMC->PMC_PCR = pcr | PMC_PCR_CMD | PMC_PCR_GCKEN; \ + while (!(PMC->PMC_SR & PMC_SR_GCKRDY)); \ + pmcEnableWP(); \ +} + +/** + * @brief Disable the generic clock of a peripheral. + * + * @param[in] mask ID peripherals + * + * @api + */ +#define pmcDisableGclk(id) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + pmcDisableWP(); \ + PMC->PMC_PCR = PMC_PCR_PID(id); \ + uint32_t pcr = PMC->PMC_PCR; \ + PMC->PMC_PCR = PMC_PCR_CMD | (pcr & ~(PMC_PCR_GCKEN)); \ + pmcEnableWP(); \ +} + +/** + * @brief Configure the generic clock of a peripheral. + * + * @param[in] id ID peripherals mask + * @param[in] clock_source Clock source + * @param[in] div Divider + * + * @api + */ + +#define pmcConfigGclk(id, clock_source, div) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + osalDbgCheck(!(clock_source & ~PMC_PCR_GCKCSS_Msk)); \ + osalDbgCheck((div > 0)); \ + osalDbgCheck(!(div << PMC_PCR_GCKDIV_Pos & ~PMC_PCR_GCKDIV_Msk)); \ + pmcDisableGclk(id); \ + pmcDisableWP(); \ + PMC->PMC_PCR = PMC_PCR_PID(id); \ + uint32_t pcr = PMC->PMC_PCR & ~(PMC_PCR_GCKCSS_Msk | PMC_PCR_GCKDIV_Msk); \ + PMC->PMC_PCR = pcr | clock_source | PMC_PCR_CMD | PMC_PCR_GCKDIV(div - 1);\ + pmcEnableWP(); \ +} + +/** + * @brief Enable the peripheral clock of a peripheral. + * + * @param[in] id ID peripherals mask + * + * @api + */ +#define pmcEnablePeripheral(id) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + pmcDisableWP(); \ + PMC->PMC_PCR = PMC_PCR_PID(id); \ + uint32_t pcr = PMC->PMC_PCR; \ + PMC->PMC_PCR = pcr | PMC_PCR_CMD | PMC_PCR_EN; \ + pmcEnableWP(); \ +} + +/** + * @brief Disable the peripheral clock of a peripheral. + * + * @param[in] id ID peripherals mask + * + * @api + */ +#define pmcDisablePeripheral(id) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + pmcDisableWP(); \ + PMC->PMC_PCR = PMC_PCR_PID(id); \ + PMC->PMC_PCR = (PMC->PMC_PCR & ~PMC_PCR_EN) | PMC_PCR_CMD; \ + pmcEnableWP(); \ +} + + +/** + * @brief Configure the Audio clock. + * + * @param[in] nd Loop Divider Ratio + * @param[in] qdpmc Output Divider Ratio for PMC Clock + * @param[in] fracr Fractional Loop Divider Setting + * @param[in] div Divider Value + * @param[in] qaudio Output Divider Ratio for Pad Clock + * + * @api + */ +#define pmcConfigAudio(nd,qdpmc,fracr,div,qdaudio) { \ + /* Reset audio clock */ \ + pmcDisableWP(); \ + PMC->PMC_AUDIO_PLL0 &= ~PMC_AUDIO_PLL0_RESETN; \ + PMC->PMC_AUDIO_PLL0 |= PMC_AUDIO_PLL0_RESETN; \ + /* Configure values */ \ + PMC->PMC_AUDIO_PLL0 = (PMC->PMC_AUDIO_PLL0 & \ + ~PMC_AUDIO_PLL0_PLLFLT_Msk & \ + ~PMC_AUDIO_PLL0_ND_Msk & \ + ~PMC_AUDIO_PLL0_QDPMC_Msk) | \ + PMC_AUDIO_PLL0_PLLFLT_STD | \ + PMC_AUDIO_PLL0_ND(nd) | \ + PMC_AUDIO_PLL0_QDPMC(qdpmc); \ + PMC->PMC_AUDIO_PLL1 = (PMC->PMC_AUDIO_PLL1 & \ + ~PMC_AUDIO_PLL1_FRACR_Msk & \ + ~PMC_AUDIO_PLL1_DIV_Msk & \ + ~PMC_AUDIO_PLL1_QDAUDIO_Msk) | \ + PMC_AUDIO_PLL1_FRACR(fracr) | \ + PMC_AUDIO_PLL1_DIV(div)| \ + PMC_AUDIO_PLL1_QDAUDIO(qdaudio); \ + pmcEnableWP(); \ +} + +/** + * @brief Enable the audio clock of a audio peripheral. + * + * @param[in] pmcClock If set TRUE enable the PMC clock + * @param[in] padClock If set TRUE enable the PAD clock + * + * @api + */ +#define pmcEnableAudio(pmcClock, padClock) { \ + pmcDisableWP(); \ + uint32_t bits = PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN; \ + uint32_t nbits = 0; \ + if(padClock) \ + bits |= PMC_AUDIO_PLL0_PADEN; \ + else \ + nbits |= PMC_AUDIO_PLL0_PADEN; \ + if(pmcClock) \ + bits |= PMC_AUDIO_PLL0_PMCEN; \ + else \ + nbits |= PMC_AUDIO_PLL0_PMCEN; \ + PMC->PMC_AUDIO_PLL0 = (PMC->PMC_AUDIO_PLL0 & ~nbits) | bits; \ + /* Wait for the Audio PLL Startup Time (tSTART = 100 usec) */ \ + chSysPolledDelayX(US2RTC(SAMA_PCK, 100)); \ + pmcEnableWP(); \ +} + +/** + * @brief Disable the audio clock of a audio peripheral. + * + * @api + */ +#define pmcDisableAudio(){ \ + pmcDisableWP(); \ + PMC->PMC_AUDIO_PLL0 &= ~(PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN | \ + PMC_AUDIO_PLL0_PADEN | PMC_AUDIO_PLL0_PMCEN); \ + pmcEnableWP(); \ +} +#else +#include "tsclient.h" + +static inline uint32_t readPMCr(uint32_t regOffset) +{ + sec_reg_val_t secr; + + secr.reg = regOffset; + secr.value = 0; + (void) tsInvoke0((ts_service_t)TS_FC_PMC_RD, + (ts_params_area_t)&secr, sizeof secr, TS_TIMEINT_1000_US); + return secr.value; +} + +static inline void writePMCr(uint32_t regOffset, uint32_t v) +{ + sec_reg_val_t secr; + + secr.reg = regOffset; + secr.value = v; + (void) tsInvoke0((ts_service_t)TS_FC_PMC_WR, + (ts_params_area_t)&secr, sizeof secr, TS_TIMEINT_1000_US); + return; +} + +/** + * @brief Enables the clock of one or more peripheral having ID from 2 to + * 31. + * + * @param[in] mask PCER0 peripherals mask + * + * @api + */ +#define pmcEnablePidLow(mask) { \ + writePMCr(offsetof(Pmc, PMC_PCER0), (mask)); \ +} + +/** + * @brief Disables the clock of one or more peripheral having ID from 2 to + * 31. + * + * @param[in] mask PCDR0 peripherals mask + * + * @api + */ +#define pmcDisablePidLow(mask) { \ + writePMCr(offsetof(Pmc, PMC_PCDR0), (mask)); \ +} + +/** + * @brief Enables the clock of one or more peripheral having ID from 32 to + * 63. + * + * @param[in] mask PCER1 peripherals mask + * + * @api + */ +#define pmcEnablePidHigh(mask) { \ + writePMCr(offsetof(Pmc, PMC_PCER1), (mask)); \ +} + +/** + * @brief Disables the clock of one or more peripheral having ID from 32 to + * 63. + * + * @param[in] mask PCDR1 peripherals mask + * + * @api + */ +#define pmcDisablePidHigh(mask) { \ + writePMCr(offsetof(Pmc, PMC_PCDR1), (mask)); \ +} + +/** + * @brief Enables the generic clock of a peripheral. + * + * @param[in] mask ID peripherals + * + * @api + */ +#define pmcEnableGclk(id) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + writePMCr(offsetof(Pmc, PMC_PCR), PMC_PCR_PID(id)); \ + uint32_t pcr = readPMCr(offsetof(Pmc, PMC_PCR)); \ + writePMCr(offsetof(Pmc, PMC_PCR), pcr | PMC_PCR_CMD | PMC_PCR_GCKEN); \ + while (!(readPMCr(offsetof(Pmc, PMC_SR)) & PMC_SR_GCKRDY)); \ +} + +/** + * @brief Disable the generic clock of a peripheral. + * + * @param[in] mask ID peripherals + * + * @api + */ +#define pmcDisableGclk(id) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + writePMCr(offsetof(Pmc, PMC_PCR), PMC_PCR_PID(id)); \ + uint32_t pcr = readPMCr(offsetof(Pmc, PMC_PCR)); \ + writePMCr(offsetof(Pmc, PMC_PCR), PMC_PCR_CMD | (pcr & ~(PMC_PCR_GCKEN)));\ +} + +/** + * @brief Configure the generic clock of a peripheral. + * + * @param[in] id ID peripherals mask + * @param[in] clock_source Clock source + * @param[in] div Divider + * + * @api + */ + +#define pmcConfigGclk(id, clock_source, div) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + osalDbgCheck(!(clock_source & ~PMC_PCR_GCKCSS_Msk)); \ + osalDbgCheck((div > 0)); \ + osalDbgCheck(!(div << PMC_PCR_GCKDIV_Pos & ~PMC_PCR_GCKDIV_Msk)); \ + pmcDisableGclk(id); \ + writePMCr(offsetof(Pmc, PMC_PCR), PMC_PCR_PID(id)); \ + uint32_t pcr = readPMCr(offsetof(Pmc, PMC_PCR) & ~(PMC_PCR_GCKCSS_Msk | PMC_PCR_GCKDIV_Msk); \ + writePMCr(offsetof(Pmc, PMC_PCR), pcr | clock_source | PMC_PCR_CMD | PMC_PCR_GCKDIV(div - 1));\ +} + +/** + * @brief Enable the peripheral clock of a peripheral. + * + * @param[in] id ID peripherals mask + * + * @api + */ +#define pmcEnablePeripheral(id) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + writePMCr(offsetof(Pmc, PMC_PCR), PMC_PCR_PID(id)); \ + uint32_t pcr = readPMCr(offsetof(Pmc, PMC_PCR)); \ + writePMCr(offsetof(Pmc, PMC_PCR), pcr | PMC_PCR_CMD | PMC_PCR_EN); \ +} + +/** + * @brief Disable the peripheral clock of a peripheral. + * + * @param[in] id ID peripherals mask + * + * @api + */ +#define pmcDisablePeripheral(id) { \ + osalDbgCheck(id < ID_PERIPH_COUNT); \ + writePMCr(offsetof(Pmc, PMC_PCR), PMC_PCR_PID(id)); \ + uint32_t pcr = readPMCr(offsetof(Pmc, PMC_PCR)); \ + writePMCr(offsetof(Pmc, PMC_PCR), (pcr & ~PMC_PCR_EN) | PMC_PCR_CMD); \ +} + + +/** + * @brief Configure the Audio clock. + * + * @param[in] nd Loop Divider Ratio + * @param[in] qdpmc Output Divider Ratio for PMC Clock + * @param[in] fracr Fractional Loop Divider Setting + * @param[in] div Divider Value + * @param[in] qaudio Output Divider Ratio for Pad Clock + * + * @api + */ +#define pmcConfigAudio(nd,qdpmc,fracr,div,qdaudio) { \ + /* Reset audio clock */ \ + writePMCr(offsetof(Pmc, PMC_AUDIO_PLL0), readPMCr(offsetof(Pmc, PMC_AUDIO_PLL0)) & ~PMC_AUDIO_PLL0_RESETN);\ + writePMCr(offsetof(Pmc, PMC_AUDIO_PLL0), readPMCr(offsetof(Pmc, PMC_AUDIO_PLL0)) | PMC_AUDIO_PLL0_RESETN);\ + /* Configure values */ \ + writePMCr(offsetof(Pmc, PMC_AUDIO_PLL0), (readPMCr(offsetof(Pmc, PMC_AUDIO_PLL0)) &\ + ~PMC_AUDIO_PLL0_PLLFLT_Msk & \ + ~PMC_AUDIO_PLL0_ND_Msk & \ + ~PMC_AUDIO_PLL0_QDPMC_Msk) | \ + PMC_AUDIO_PLL0_PLLFLT_STD | \ + PMC_AUDIO_PLL0_ND(nd) | \ + PMC_AUDIO_PLL0_QDPMC(qdpmc)); \ + writePMCr(offsetof(Pmc, PMC_AUDIO_PLL1), (readPMCr(offsetof(Pmc, PMC_AUDIO_PLL1)) &\ + ~PMC_AUDIO_PLL1_FRACR_Msk & \ + ~PMC_AUDIO_PLL1_DIV_Msk & \ + ~PMC_AUDIO_PLL1_QDAUDIO_Msk) | \ + PMC_AUDIO_PLL1_FRACR(fracr) | \ + PMC_AUDIO_PLL1_DIV(div)| \ + PMC_AUDIO_PLL1_QDAUDIO(qdaudio)); \ +} + +/** + * @brief Enable the audio clock of a audio peripheral. + * + * @param[in] pmcClock If set TRUE enable the PMC clock + * @param[in] padClock If set TRUE enable the PAD clock + * + * @api + */ +#define pmcEnableAudio(pmcClock, padClock) { \ + uint32_t bits = PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN; \ + uint32_t nbits = 0; \ + if(padClock) \ + bits |= PMC_AUDIO_PLL0_PADEN; \ + else \ + nbits |= PMC_AUDIO_PLL0_PADEN; \ + if(pmcClock) \ + bits |= PMC_AUDIO_PLL0_PMCEN; \ + else \ + nbits |= PMC_AUDIO_PLL0_PMCEN; \ + writePMCr(offsetof(Pmc, PMC_AUDIO_PLL0), (readPMCr(offsetof(Pmc, PMC_AUDIO_PLL0)) & ~nbits) | bits);\ + /* Wait for the Audio PLL Startup Time (tSTART = 100 usec) */ \ + chSysPolledDelayX(US2RTC(SAMA_PCK, 100)); \ +} + +/** + * @brief Disable the audio clock of a audio peripheral. + * + * @api + */ +#define pmcDisableAudio(){ \ + writePMCr(offsetof(Pmc, PMC_AUDIO_PLL0), readPMCr(offsetof(Pmc, PMC_AUDIO_PLL0)) & \ + ~(PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN | \ + PMC_AUDIO_PLL0_PADEN | PMC_AUDIO_PLL0_PMCEN)); \ +} + +#endif + /** @} */ /** @@ -518,6 +900,34 @@ */ #define pmcDisableSDMMC1() pmcDisablePidHigh(ID_SDMMC1_MSK) +/** + * @brief Enables the CLASSD peripheral clock. + * + * @api + */ +#define pmcEnableCLASSD0() pmcEnablePidHigh(ID_CLASSD_MSK) + +/** + * @brief Disables the CLASSD peripheral clock. + * + * @api + */ +#define pmcDisableCLASSD0() pmcDisablePidHigh(ID_CLASSD_MSK) + +/** + * @brief Enables the CLASSD generic clock. + * + * @api + */ +#define pmcEnableGclkCLASSD0() pmcEnableGclk(ID_CLASSD) + +/** + * @brief Disables the CLASSD generic clock. + * + * @api + */ +#define pmcDisableGclkCLASSD0() pmcDisableGclk(ID_CLASSD) + /** * @brief Enables the TRNG peripheral clock. * @@ -532,6 +942,76 @@ */ #define pmcDisableTRNG0() pmcDisablePidHigh(ID_TRNG_MSK) +/** + * @brief Enables the QSPI0 peripheral clock. + * + * @api + */ +#define pmcEnableQSPI0() pmcEnablePidHigh(ID_QSPI0_MSK) + +/** + * @brief Disables the QSPI0 peripheral clock. + * + * @api + */ +#define pmcDisableQSPI0() pmcDisablePidHigh(ID_QSPI0_MSK) + +/** + * @brief Enables the QSPI1 peripheral clock. + * + * @api + */ +#define pmcEnableQSPI1() pmcEnablePidHigh(ID_QSPI1_MSK) + +/** + * @brief Disables the QSPI1 peripheral clock. + * + * @api + */ +#define pmcDisableQSPI1() pmcDisablePidHigh(ID_QSPI1_MSK) + +/** + * @brief Enables the LCDC peripheral clock. + * + * @api + */ +#define pmcEnableLCDC() pmcEnablePidHigh(ID_LCDC_MSK) + +/** + * @brief Disables the LCDC peripheral clock. + * + * @api + */ +#define pmcDisableLCDC() pmcDisablePidHigh(ID_LCDC_MSK) + +/** + * @brief Enables the TWIHS0 peripheral clock. + * + * @api + */ +#define pmcEnableTWIHS0() pmcEnablePidLow(ID_TWIHS0_MSK) + +/** + * @brief Disables the TWIHS0 peripheral clock. + * + * @api + */ +#define pmcDisableTWIHS0() pmcDisablePidLow(ID_TWIHS0_MSK) + +/** + * @brief Enables the TWIHS1 peripheral clock. + * + * @api + */ +#define pmcEnableTWIHS1() pmcEnablePidLow(ID_TWIHS1_MSK) + +/** + * @brief Disables the TWIHS1 peripheral clock. + * + * @api + */ +#define pmcDisableTWIHS1() pmcDisablePidLow(ID_TWIHS1_MSK) + /** @} */ /*===========================================================================*/ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_rstc.h b/os/hal/ports/SAMA/SAMA5D2x/sama_rstc.h new file mode 100644 index 000000000..e390e5eb2 --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_rstc.h @@ -0,0 +1,179 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/sama_rstc.h + * @brief SAMA RSTC helper driver header. + * + * @addtogroup SAMA5D2x_RSTC + * @{ + */ + +#ifndef _SAMA_RSTC_ +#define _SAMA_RSTC_ + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ +/** + * @name RESET SOURCE MACROS + * @{ + */ +/** + * @brief No access allowed. + */ +#define RSTC_GENERAL 0x0U + +/** + * @brief Only write access allowed. + */ +#define RSTC_WKUP 0x1U + +/** + * @brief Only read access allowed. + */ +#define RSTC_WDT 0x2U + +/** + * @brief Read and Write access allowed. + */ +#define RSTC_SOFT 0x3U + +/** + * @brief Read and Write access allowed. + */ +#define RSTC_USER 0x4U +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ +/** + * @name Generic RSTC operations + * @{ + */ +/** + * @brief Enable/Disable the detection of a low level on the pin NRST + * as User Reset. + * @param[in] enable + */ +#define rstcSetUserResetEnable(enable) { \ + if (enable) { \ + RSTC->RSTC_MR |= RSTC_MR_URSTEN | RSTC_MR_KEY_PASSWD; \ + } else { \ + RSTC->RSTC_MR &= ~RSTC_MR_URSTEN; \ + RSTC->RSTC_MR |= RSTC_MR_KEY_PASSWD; \ + } \ +} + +/** + * @brief Enable/Disable the interrupt of a User Reset. + * @param[in] enable + */ +#define rstcSetUserResetInterruptEnable(enable) { \ + if (enable) { \ + RSTC->RSTC_MR |= RSTC_MR_URSTIEN | RSTC_MR_KEY_PASSWD; \ + } else { \ + RSTC->RSTC_MR &= ~RSTC_MR_URSTIEN; \ + RSTC->RSTC_MR |= RSTC_MR_KEY_PASSWD; \ + } \ +} + +/** + * @brief Perform a processor and peripheral reset. + * + * @notapi + */ +#define rstcResetProcessorAndPeripheral() { \ + RSTC->RSTC_CR = RSTC_CR_PERRST | RSTC_CR_PROCRST | RSTC_MR_KEY_PASSWD; \ +} + +/** + * @brief Perform a processor reset. + * + * @notapi + */ +#define rstcResetProcessor() { \ + RSTC->RSTC_CR = RSTC_CR_PROCRST | RSTC_CR_KEY_PASSWD; \ +} + +/** + * @brief Perform a peripheral reset. + * + * @notapi + */ +#define rstcResetPeripheral() { \ + RSTC->RSTC_CR = RSTC_CR_PERRST | RSTC_MR_KEY_PASSWD; \ +} + +/** + * @brief Report the cause of the last processor reset. + * + * @param[out] status Cause of the reset + * + * @notapi + */ +#define rstcGetStatus(status) { \ + uint32_t sr = RSTC->RSTC_SR & RSTC_SR_RSTTYP_Msk; \ + switch (sr) { \ + case RSTC_SR_RSTTYP_GENERAL_RST: \ + status = RSTC_GENERAL; \ + break; \ + case RSTC_SR_RSTTYP_WKUP_RST: \ + status = RSTC_WKUP; \ + break; \ + case RSTC_SR_RSTTYP_WDT_RST: \ + status = RSTC_WDT; \ + break; \ + case RSTC_SR_RSTTYP_SOFT_RST: \ + status = RSTC_SOFT; \ + break; \ + case RSTC_SR_RSTTYP_USER_RST: \ + status = RSTC_USER; \ + break; \ + default: \ + break; \ + } \ +} + +/** @} */ + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif + +#endif /* SAMA_RSTC_H */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.c b/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.c index 4cf1d527a..35fbab578 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.c +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.c @@ -24,7 +24,7 @@ #include "hal.h" -#if HAL_USE_SECUMOD || defined(__DOXYGEN__) +#if SAMA_USE_SECUMOD || defined(__DOXYGEN__) /*===========================================================================*/ /* Driver local definitions. */ @@ -274,9 +274,11 @@ void sec_lld_start(SECDriver *secp) { /* * Configure interrupts */ + aicSetIntSourceType(ID_SECUMOD, INT_LEVEL_SENSITIVE); aicSetSourcePriority(ID_SECUMOD, SAMA_SECUMOD_IRQ_PRIORITY); aicSetSourceHandler(ID_SECUMOD, SAMA_SECUMOD_HANDLER); + aicSetIntSourceType(ID_SECURAM, INT_LEVEL_SENSITIVE); aicSetSourcePriority(ID_SECURAM, SAMA_SECURAM_IRQ_PRIORITY); aicSetSourceHandler(ID_SECURAM, SAMA_SECURAM_HANDLER); @@ -592,6 +594,6 @@ uint32_t secumodWriteInternalMemory(uint8_t *data, uint32_t addr, uint32_t size) return i; } -#endif /* HAL_USE_SECUMOD */ +#endif /* SAMA_USE_SECUMOD */ /** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.h b/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.h index 5ac8c3c11..c5247af89 100644 --- a/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.h +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_secumod.h @@ -25,7 +25,14 @@ #ifndef SAMA_SECUMOD_LLD_H #define SAMA_SECUMOD_LLD_H -#if HAL_USE_SECUMOD || defined(__DOXYGEN__) +/** + * @brief Using the SECUMOD driver. + */ +#if !defined(SAMA_USE_SECUMOD) || defined(__DOXYGEN__) +#define SAMA_USE_SECUMOD FALSE +#endif + +#if SAMA_USE_SECUMOD || defined(__DOXYGEN__) #include /*===========================================================================*/ @@ -558,7 +565,7 @@ extern "C" { } #endif -#endif /* HAL_USE_SECUMOD */ +#endif /* SAMA_USE_SECUMOD */ #endif /* SAMA_SECUMOD_LLD_H */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.c b/os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.c new file mode 100644 index 000000000..5251efd17 --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.c @@ -0,0 +1,575 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/sama_tc_lld.c + * @brief SAMA TC support code. + * + * @addtogroup TC + * @{ + */ + +#include "hal.h" + +#if SAMA_USE_TC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver local macros. */ +/*===========================================================================*/ + +/** + * @brief Enable write protection on TC registers block. + * + * @param[in] tcp pointer to a TC register block + * + * @notapi + */ +#define tcEnableWP(tcp) { \ + tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD | TC_WPMR_WPEN; \ +} + +/** + * @brief Disable write protection on TC registers block. + * + * @param[in] tcp pointer to a TC register block + * + * @notapi + */ +#define tcDisableWP(tcp) { \ + tcp->TC_WPMR = TC_WPMR_WPKEY_PASSWD; \ +} + +/*===========================================================================*/ +/* Driver exported variables. */ +/*===========================================================================*/ + +/** + * @brief TCD0 driver identifier. + * @note The driver TCD0 allocates the timer TC0 when enabled. + */ +#if SAMA_USE_TC0 || defined(__DOXYGEN__) +TCDriver TCD0; +#endif + +/** + * @brief TCD1 driver identifier. + * @note The driver TCD1 allocates the timer TC1 when enabled. + */ +#if SAMA_USE_TC1 || defined(__DOXYGEN__) +TCDriver TCD1; +#endif + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ +/** + * @brief Common IRQ handler. + * @note It is assumed that the various sources are only activated if the + * associated callback pointer is not equal to @p NULL in order to not + * perform an extra check in a potentially critical interrupt handler. + * + * @param[in] tcp pointer to a @p TCDriver object + * + * @notapi + */ +void tc_lld_serve_interrupt(TCDriver *tcp) { + uint32_t sr, imr, i; + + for (i = 0; i < TC_CHANNELS; i++) { + sr = tcp->tim->TC_CHANNEL[i].TC_SR; + imr = tcp->tim->TC_CHANNEL[i].TC_IMR; + if (((sr & TC_SR_CPCS) != 0) && ((imr & TC_IMR_CPCS) != 0) && + (tcp->config->channels[i].callback != NULL)) { + tcp->config->channels[i].callback(tcp); + } + } +} +/*===========================================================================*/ +/* Driver interrupt handlers. */ +/*===========================================================================*/ + +#if SAMA_USE_TC0 || defined(__DOXYGEN__) +#if !defined(SAMA_TC0_SUPPRESS_ISR) +/** + * @brief TC0 interrupt handler. + * @note It is assumed that this interrupt is only activated if the callback + * pointer is not equal to @p NULL in order to not perform an extra + * check in a potentially critical interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(SAMA_TC0_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + tc_lld_serve_interrupt(&TCD0); + aicAckInt(); + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(SAMA_TC0_SUPPRESS_ISR) */ +#endif /* SAMA_USE_TC0 */ + +#if SAMA_USE_TC1 || defined(__DOXYGEN__) +#if !defined(SAMA_TC1_SUPPRESS_ISR) +/** + * @brief TC1 interrupt handler. + * + * @isr + */ +OSAL_IRQ_HANDLER(SAMA_TC1_HANDLER) { + + OSAL_IRQ_PROLOGUE(); + + tc_lld_serve_interrupt(&TCD1); + aicAckInt(); + OSAL_IRQ_EPILOGUE(); +} +#endif /* !defined(SAMA_TC1_SUPPRESS_ISR) */ +#endif /* SAMA_USE_TC1 */ + +/*===========================================================================*/ +/* Driver exported functions. */ +/*===========================================================================*/ + +/** + * @brief Low level TC driver initialization. + * + * @notapi + */ +void tc_lld_init(void) { + +#if SAMA_USE_TC0 +#if SAMA_HAL_IS_SECURE + mtxConfigPeriphSecurity(MATRIX1, ID_TC0, SECURE_PER); +#endif /* SAMA_HAL_IS_SECURE */ + /* Driver initialization.*/ + tcObjectInit(&TCD0); + TCD0.channels = TC_CHANNELS; + TCD0.tim = TC0; + TCD0.clock = SAMA_TC0CLK; +#endif + +#if SAMA_USE_TC1 +#if SAMA_HAL_IS_SECURE + mtxConfigPeriphSecurity(MATRIX1, ID_TC1, SECURE_PER); +#endif /* SAMA_HAL_IS_SECURE */ + /* Driver initialization.*/ + tcObjectInit(&TCD1); + TCD1.channels = TC_CHANNELS; + TCD1.tim = TC1; + TCD1.clock = SAMA_TC1CLK; +#endif + +} + +/** + * @brief Configures and activates the TC peripheral. + * + * @param[in] tcp pointer to a @p TCDriver object + * + * @notapi + */ +void tc_lld_start(TCDriver *tcp) { + uint32_t rc = 0; + + if (tcp->state == TC_STOP) { + /* Clock activation.*/ +#if SAMA_USE_TC0 + if (&TCD0 == tcp) { + pmcEnableTC0(); +#if !defined(SAMA_TC0_SUPPRESS_ISR) + aicSetSourcePriority(ID_TC0, SAMA_TC0_IRQ_PRIORITY); + aicSetSourceHandler(ID_TC0, SAMA_TC0_HANDLER); + aicEnableInt(ID_TC0); +#endif + } +#endif + +#if SAMA_USE_TC1 + if (&TCD1 == tcp) { + pmcEnableTC1(); +#if !defined(SAMA_TC1_SUPPRESS_ISR) + aicSetSourcePriority(ID_TC1, SAMA_TC1_IRQ_PRIORITY); + aicSetSourceHandler(ID_TC1, SAMA_TC1_HANDLER); + aicEnableInt(ID_TC1); +#endif + } +#endif + } + /* Disable Write Protection */ + tcDisableWP(tcp->tim); + /* Output enables*/ + switch (tcp->config->channels[0].mode & TC_OUTPUT_MASK) { + case TC_OUTPUT_ACTIVE: + rc = (tcp->clock) / (tcp->config->channels[0].frequency); + tcp->tim->TC_CHANNEL[0].TC_EMR = TC_EMR_NODIVCLK; + tcp->tim->TC_CHANNEL[0].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET | + TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC; + + tcp->tim->TC_CHANNEL[0].TC_RC = TC_RC_RC(rc); + tcp->tim->TC_CHANNEL[0].TC_SR; /* Clear pending IRQs. */ + default: + ; + } + switch (tcp->config->channels[1].mode & TC_OUTPUT_MASK) { + case TC_OUTPUT_ACTIVE: + rc = (tcp->clock) / (tcp->config->channels[1].frequency); + tcp->tim->TC_CHANNEL[1].TC_EMR = TC_EMR_NODIVCLK; + tcp->tim->TC_CHANNEL[1].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET | + TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC; + + tcp->tim->TC_CHANNEL[1].TC_RC = TC_RC_RC(rc); + tcp->tim->TC_CHANNEL[1].TC_SR; /* Clear pending IRQs. */ + default: + ; + } + switch (tcp->config->channels[2].mode & TC_OUTPUT_MASK) { + case TC_OUTPUT_ACTIVE: + rc = (tcp->clock) / (tcp->config->channels[2].frequency); + tcp->tim->TC_CHANNEL[2].TC_EMR = TC_EMR_NODIVCLK; + tcp->tim->TC_CHANNEL[2].TC_CMR = TC_CMR_WAVE | TC_CMR_ACPA_SET | + TC_CMR_ACPC_CLEAR | TC_CMR_WAVSEL_UP_RC; + + tcp->tim->TC_CHANNEL[2].TC_RC = TC_RC_RC(rc); + tcp->tim->TC_CHANNEL[2].TC_SR; /* Clear pending IRQs. */ + default: + ; + } + /* Enable Write Protection */ + tcEnableWP(tcp->tim); +} + +/** + * @brief Deactivates the TC peripheral. + * + * @param[in] tcp pointer to a @p TCDriver object + * + * @notapi + */ +void tc_lld_stop(TCDriver *tcp) { + + /* If in ready state then disables the TC clock.*/ + if (tcp->state == TC_READY) { +#if SAMA_USE_TC0 + if (&TCD0 == tcp) { + aicDisableInt(ID_TC0); + pmcDisableTC0(); + } +#endif + +#if SAMA_USE_TC1 + if (&TCD1 == tcp) { + aicDisableInt(ID_TC1); + pmcDisableTC1(); + } +#endif + } +} + +/** + * @brief Enables a TC channel. + * @pre The TC unit must have been activated using @p tcStart(). + * @post The channel is active using the specified configuration. + * @note The function has effect at the next cycle start. + * @note Channel notification is not enabled. + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * @param[in] width TC pulse width as clock pulses number + * + * @notapi + */ +void tc_lld_enable_channel(TCDriver *tcp, + tcchannel_t channel, + tccnt_t width) { + /* Disable Write Protection */ + tcDisableWP(tcp->tim); + + /* Changing channel duty cycle on the fly.*/ + uint32_t rc = tcp->tim->TC_CHANNEL[channel].TC_RC; + tcp->tim->TC_CHANNEL[channel].TC_RA = TC_RA_RA((100 - width) * rc / 100); + tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_CLKEN; + tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_SWTRG; + + /* Enable Write Protection */ + tcEnableWP(tcp->tim); +} + +/** + * @brief Disables a TC channel and its notification. + * @pre The TC unit must have been activated using @p tcStart(). + * @post The channel is disabled and its output line returned to the + * idle state. + * @note The function has effect at the next cycle start. + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @notapi + */ +void tc_lld_disable_channel(TCDriver *tcp, tcchannel_t channel) { + + tcp->tim->TC_CHANNEL[channel].TC_CCR = TC_CCR_CLKDIS; +} + +/** + * @brief Enables a channel de-activation edge notification. + * @pre The TC unit must have been activated using @p tcStart(). + * @pre The channel must have been activated using @p tcEnableChannel(). + * @note If the notification is already enabled then the call has no effect. + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @notapi + */ +void tc_lld_enable_channel_notification(TCDriver *tcp, + tcchannel_t channel) { + tcp->tim->TC_CHANNEL[channel].TC_IER |= TC_IER_CPCS; +} + +/** + * @brief Disables a channel de-activation edge notification. + * @pre The TC unit must have been activated using @p tcStart(). + * @pre The channel must have been activated using @p tcEnableChannel(). + * @note If the notification is already disabled then the call has no effect. + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @notapi + */ +void tc_lld_disable_channel_notification(TCDriver *tcp, + tcchannel_t channel) { + + tcp->tim->TC_CHANNEL[channel].TC_IDR |= TC_IDR_CPCS; +} + +/** + * @brief Changes TC channel's frequency. + * @pre The TC unit must have been activated using @p tcStart(). + * @post The channel must be enabled using @p tcEnableChannel(). + * @note Depending on the hardware implementation this function has + * effect starting on the next cycle (recommended implementation) + * or immediately (fallback implementation). + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + */ + +void tcChangeChannelFrequency(TCDriver *tcp, + tcchannel_t channel,uint32_t frequency) { + tcDisableWP(tcp->tim); + uint32_t rc =(tcp->clock) / (frequency); + tcp->tim->TC_CHANNEL[channel].TC_RC = TC_RC_RC(rc); + tcEnableWP(tcp->tim); +} +/** + * @brief TC Driver initialization. + * + * @init + */ +void tcInit(void) { + + tc_lld_init(); +} + +/** + * @brief Initializes the standard part of a @p TCDriver structure. + * + * @param[out] tcp pointer to a @p TCDriver object + * + * @init + */ +void tcObjectInit(TCDriver *tcp) { + + tcp->state = TC_STOP; + tcp->config = NULL; + tcp->enabled = 0; + tcp->channels = 0; +} + + +/** + * @brief Configures and activates the TC peripheral. + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] config pointer to a @p TCConfig object + * + * @api + */ +void tcStart(TCDriver *tcp, const TCConfig *config) { + + osalDbgCheck((tcp != NULL) && (config != NULL)); + + osalSysLock(); + osalDbgAssert((tcp->state == TC_STOP) || (tcp->state == TC_READY), + "invalid state"); + tcp->config = config; + tc_lld_start(tcp); + tcp->enabled = 0; + tcp->state = TC_READY; + osalSysUnlock(); +} + +/** + * @brief Deactivates the TC peripheral. + * + * @param[in] tcp pointer to a @p TCDriver object + * + * @api + */ +void tcStop(TCDriver *tcp) { + + osalDbgCheck(tcp != NULL); + + osalSysLock(); + + osalDbgAssert((tcp->state == TC_STOP) || (tcp->state == TC_READY), + "invalid state"); + + tc_lld_stop(tcp); + tcp->enabled = 0; + tcp->config = NULL; + tcp->state = TC_STOP; + + osalSysUnlock(); +} + +/** + * @brief Enables a TC channel. + * @pre The TC unit must have been activated using @p tcStart(). + * @post The channel is active using the specified configuration. + * @note Depending on the hardware implementation this function has + * effect starting on the next cycle (recommended implementation) + * or immediately (fallback implementation). + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * @param[in] width TC pulse width as clock pulses number + * + * @api + */ +void tcEnableChannel(TCDriver *tcp, + tcchannel_t channel, + tccnt_t width) { + + osalDbgCheck((tcp != NULL) && (channel < tcp->channels)); + + osalSysLock(); + + osalDbgAssert(tcp->state == TC_READY, "not ready"); + + tcEnableChannelI(tcp, channel, width); + + osalSysUnlock(); +} + +/** + * @brief Disables a TC channel and its notification. + * @pre The TC unit must have been activated using @p tcStart(). + * @post The channel is disabled and its output line returned to the + * idle state. + * @note Depending on the hardware implementation this function has + * effect starting on the next cycle (recommended implementation) + * or immediately (fallback implementation). + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @api + */ +void tcDisableChannel(TCDriver *tcp, tcchannel_t channel) { + + osalDbgCheck((tcp != NULL) && (channel < tcp->channels)); + + osalSysLock(); + + osalDbgAssert(tcp->state == TC_READY, "not ready"); + + tcDisableChannelI(tcp, channel); + + osalSysUnlock(); +} + +/** + * @brief Enables a channel de-activation edge notification. + * @pre The TC unit must have been activated using @p tcStart(). + * @pre The channel must have been activated using @p tcEnableChannel(). + * @note If the notification is already enabled then the call has no effect. + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @api + */ +void tcEnableChannelNotification(TCDriver *tcp, tcchannel_t channel) { + + osalDbgCheck((tcp != NULL) && (channel < tcp->channels)); + + osalSysLock(); + + osalDbgAssert(tcp->state == TC_READY, "not ready"); + osalDbgAssert((tcp->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)channel)) != 0U, + "channel not enabled"); + osalDbgAssert(tcp->config->channels[channel].callback != NULL, + "undefined channel callback"); + + tcEnableChannelNotificationI(tcp, channel); + + osalSysUnlock(); +} + +/** + * @brief Disables a channel de-activation edge notification. + * @pre The TC unit must have been activated using @p tcStart(). + * @pre The channel must have been activated using @p tcEnableChannel(). + * @note If the notification is already disabled then the call has no effect. + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @api + */ +void tcDisableChannelNotification(TCDriver *tcp, tcchannel_t channel) { + + osalDbgCheck((tcp != NULL) && (channel < tcp->channels)); + + osalSysLock(); + + osalDbgAssert(tcp->state == TC_READY, "not ready"); + osalDbgAssert((tcp->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)channel)) != 0U, + "channel not enabled"); + osalDbgAssert(tcp->config->channels[channel].callback != NULL, + "undefined channel callback"); + + tcDisableChannelNotificationI(tcp, channel); + + osalSysUnlock(); +} + +#endif /* SAMA_USE_TC */ + +/** @} */ + + + + diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.h b/os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.h new file mode 100644 index 000000000..8cf1a8e1a --- /dev/null +++ b/os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.h @@ -0,0 +1,364 @@ +/* + ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio + + 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 SAMA5D2x/sama_tc_lld.h + * @brief SAMA TC subsystem low level driver header. + * + * @addtogroup TC + * @{ + */ + +#ifndef SAMA_TC_LLD_H +#define SAMA_TC_LLD_H + +/** + * @brief Using the TC driver. + */ +#if !defined(SAMA_USE_TC) || defined(__DOXYGEN__) +#define SAMA_USE_TC FALSE +#endif + +#if SAMA_USE_TC || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @brief Number of TC channels per TC driver. + */ +#define TC_CHANNELS TCCHANNEL_NUMBER + +/** + * @name TC output mode macros + * @{ + */ +/** + * @brief Standard output modes mask. + */ +#define TC_OUTPUT_MASK 0x0FU + +/** + * @brief Output not driven, callback only. + */ +#define TC_OUTPUT_DISABLED 0x00U + +/** + * @brief Output active. + */ +#define TC_OUTPUT_ACTIVE 0x01U + +/** @} */ + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Driver state machine possible states. + */ +typedef enum { + TC_UNINIT = 0, /**< Not initialized. */ + TC_STOP = 1, /**< Stopped. */ + TC_READY = 2 /**< Ready. */ +} tcstate_t; + +/** + * @brief Type of a structure representing a TC driver. + */ +typedef struct TCDriver TCDriver; + +/** + * @brief Type of a TC notification callback. + * + * @param[in] tcp pointer to a @p TCDriver object + */ +typedef void (*tccallback_t)(TCDriver *tcp); + + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief TCD0 driver enable switch. + * @details If set to @p TRUE the support for TCD0 is included. + * @note The default is @p TRUE. + */ +#if !defined(SAMA_USE_TC0) || defined(__DOXYGEN__) +#define SAMA_USE_TC0 FALSE +#endif + +/** + * @brief TCD1 driver enable switch. + * @details If set to @p TRUE the support for TCD1 is included. + * @note The default is @p TRUE. + */ +#if !defined(SAMA_USE_TC1) || defined(__DOXYGEN__) +#define SAMA_USE_TC1 FALSE +#endif + +/** + * @brief TCD0 interrupt priority level setting. + */ +#if !defined(SAMA_TC0_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define SAMA_TC0_IRQ_PRIORITY 2 +#endif + +/** + * @brief TCD1 interrupt priority level setting. + */ +#if !defined(SAMA_TC1_IRQ_PRIORITY) || defined(__DOXYGEN__) +#define SAMA_TC1_IRQ_PRIORITY 2 +#endif + +/** @} */ + +/*===========================================================================*/ +/* Configuration checks. */ +/*===========================================================================*/ + +#if !SAMA_USE_TC0 && !SAMA_USE_TC1 +#error "TC driver activated but no TC peripheral assigned" +#endif + +/* Checks on allocation of TCx units.*/ +#if SAMA_USE_TC0 +#if defined(SAMA_TC0_IS_USED) +#error "TC0 is already used" +#else +#define SAMA_TC0_IS_USED +#endif +#endif + +/* Checks on allocation of TCx units.*/ +#if SAMA_USE_TC1 +#if defined(SAMA_TC1_IS_USED) +#error "TC1 is already used" +#else +#define SAMA_TC1_IS_USED +#endif +#endif +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a TC mode. + */ +typedef uint32_t tcmode_t; + +/** + * @brief Type of a TC channel. + */ +typedef uint8_t tcchannel_t; + +/** + * @brief Type of a channels mask. + */ +typedef uint32_t tcchnmsk_t; + +/** + * @brief Type of a TC counter. + */ +typedef uint32_t tccnt_t; + +/** + * @brief Type of a TC driver channel configuration structure. + */ +typedef struct { + /** + * @brief Channel active logic level. + */ + tcmode_t mode; + /** + * @brief Timer clock in Hz. + * @note The low level can use assertions in order to catch invalid + * frequency specifications. + */ + uint32_t frequency; + /** + * @brief Channel callback pointer. + * @note This callback is invoked on the channel compare event. If set to + * @p NULL then the callback is disabled. + */ + tccallback_t callback; + /* End of the mandatory fields.*/ +} TCChannelConfig; + +/** + * @brief Type of a TC driver configuration structure. + */ +typedef struct { + /** + * @brief Channels configurations. + */ + TCChannelConfig channels[TC_CHANNELS]; + /* End of the mandatory fields.*/ +} TCConfig; + +/** + * @brief Structure representing a TC driver. + */ +struct TCDriver { + /** + * @brief Driver state. + */ + tcstate_t state; + /** + * @brief Current driver configuration data. + */ + const TCConfig *config; + /** + * @brief Mask of the enabled channels. + */ + tcchnmsk_t enabled; + /** + * @brief Number of channels in this instance. + */ + tcchannel_t channels; + /* End of the mandatory fields.*/ + /** + * @brief Timer base clock. + */ + uint32_t clock; + /** + * @brief Pointer to the TCx registers block. + */ + Tc *tim; +}; + +/*===========================================================================*/ +/* Driver macros. */ +/*===========================================================================*/ +/** + * @brief Enables a TC channel. + * @pre The TC unit must have been activated using @p tcStart(). + * @post The channel is active using the specified configuration. + * @note Depending on the hardware implementation this function has + * effect starting on the next cycle (recommended implementation) + * or immediately (fallback implementation). + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * @param[in] width TC pulse width as clock pulses number + * + * @iclass + */ +#define tcEnableChannelI(tcp, channel, width) do { \ + (tcp)->enabled |= ((tcchnmsk_t)1U << (tcchnmsk_t)(channel)); \ + tc_lld_enable_channel(tcp, channel, width); \ +} while (false) + +/** + * @brief Disables a TC channel. + * @pre The TC unit must have been activated using @p tcStart(). + * @post The channel is disabled and its output line returned to the + * idle state. + * @note Depending on the hardware implementation this function has + * effect starting on the next cycle (recommended implementation) + * or immediately (fallback implementation). + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @iclass + */ +#define tcDisableChannelI(tcp, channel) do { \ + (tcp)->enabled &= ~((tcchnmsk_t)1U << (tcchnmsk_t)(channel)); \ + tc_lld_disable_channel(tcp, channel); \ +} while (false) + +/** + * @brief Returns a TC channel status. + * @pre The TC unit must have been activated using @p tcStart(). + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @iclass + */ +#define tcIsChannelEnabledI(tcp, channel) \ + (((tcp)->enabled & ((tcchnmsk_t)1U << (tcchnmsk_t)(channel))) != 0U) + +/** + * @brief Enables a channel de-activation edge notification. + * @pre The TC unit must have been activated using @p tcStart(). + * @pre The channel must have been activated using @p tcEnableChannel(). + * @note If the notification is already enabled then the call has no effect. + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @iclass + */ +#define tcEnableChannelNotificationI(tcp, channel) \ + tc_lld_enable_channel_notification(tcp, channel) + +/** + * @brief Disables a channel de-activation edge notification. + * @pre The TC unit must have been activated using @p tcStart(). + * @pre The channel must have been activated using @p tcEnableChannel(). + * @note If the notification is already disabled then the call has no effect. + * + * @param[in] tcp pointer to a @p TCDriver object + * @param[in] channel TC channel identifier (0...channels-1) + * + * @iclass + */ +#define tcDisableChannelNotificationI(tcp, channel) \ + tc_lld_disable_channel_notification(tcp, channel) + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#if SAMA_USE_TC0 && !defined(__DOXYGEN__) +extern TCDriver TCD0; +#endif + +#if SAMA_USE_TC1 && !defined(__DOXYGEN__) +extern TCDriver TCD1; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + void tcInit(void); + void tcObjectInit(TCDriver *tcp); + void tcStart(TCDriver *tcp, const TCConfig *config); + void tcStop(TCDriver *tcp); + void tcEnableChannel(TCDriver *tcp, + tcchannel_t channel, + tccnt_t width); + void tcDisableChannel(TCDriver *tcp, tcchannel_t channel); + void tcEnableChannelNotification(TCDriver *tcp, tcchannel_t channel); + void tcDisableChannelNotification(TCDriver *tcp, tcchannel_t channel); + void tcChangeChannelFrequency(TCDriver *tcp, tcchannel_t channel, uint32_t frequency); +#ifdef __cplusplus +} +#endif + +#endif /* SAMA_USE_TC */ + +#endif /* SAMA_TC_LLD_H */ + +/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_trng.c b/os/hal/ports/SAMA/SAMA5D2x/sama_trng.c deleted file mode 100644 index 287d37403..000000000 --- a/os/hal/ports/SAMA/SAMA5D2x/sama_trng.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio - - 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 SAMA5D2x/sama_trng.c - * @brief SAMA TRNG support code. - * - * @addtogroup SAMA5D2x_TRNG - * @{ - */ - -#include "hal.h" - -#if (HAL_USE_TRNG) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver local definitions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported variables. */ -/*===========================================================================*/ -TRNGDriver TRNGD0; - -/*===========================================================================*/ -/* Driver local variables. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver local functions. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver interrupt handlers. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver exported functions. */ -/*===========================================================================*/ - -/** - * @brief Low level TRNG driver initialization. - * - * @notapi - */ -void trng_lld_init(void) { -#if SAMA_HAL_IS_SECURE - mtxConfigPeriphSecurity(MATRIX1, ID_TRNG, SECURE_PER); -#endif /* SAMA_HAL_IS_SECURE */ - /* Driver initialization.*/ - TRNGD0.state = TRNG_STOP; - TRNGD0.trng = TRNG; -} - -/** - * @brief Configures and activates the TRNG peripheral. - * - * @param[in] trngp pointer to the @p TRNGDriver object - * - * @notapi - */ -void trng_lld_start(TRNGDriver *trngp) { - - /* Configures the peripheral. */ - if (trngp->state == TRNG_STOP) { - - /* Enable the TRNG peripheral clock. */ - pmcEnableTRNG0(); - - /* Enable the TRNG. */ - trngp->trng->TRNG_CR = TRNG_CR_ENABLE | TRNG_CR_KEY_PASSWD; - } -} - -/** - * @brief Deactivates the TRNG peripheral. - * - * @param[in] trngp pointer to the @p TRNGDriver object - * - * @notapi - */ -void trng_lld_stop(TRNGDriver *trngp) { - - if (trngp->state == TRNG_READY) { - /* Disable the TRNG. */ - trngp->trng->TRNG_CR = TRNG_CR_KEY_PASSWD; - /* Disable the TRNG clock. */ - pmcDisableTRNG0(); - } -} - -/** - * @brief Get random number from TRNG. - * - * @param[in] trngp pointer to the @p TRNGDriver object - * @return TRNG_ODATA content of the TRNG_ODATA register - * - * @notapi - */ -uint32_t trng_lld_get_random_number(TRNGDriver *trngp) { - - while (!(trngp->trng->TRNG_ISR & TRNG_ISR_DATRDY)); - return trngp->trng->TRNG_ODATA; -} - -/** - * @brief TRNG driver initialization. - * - * @notapi - */ -void trngInit(void) { - - trng_lld_init(); -} - -/** - * @brief Configures and activates the TRNG peripheral. - * - * @param[in] trngp pointer to the @p TRNGDriver object - * - * @api - */ -void trngStart(TRNGDriver *trngp) { - - osalDbgCheck(trngp != NULL); - - osalSysLock(); - osalDbgAssert((trngp->state == TRNG_STOP) || - (trngp->state == TRNG_READY), "invalid state"); - trng_lld_start(trngp); - trngp->state = TRNG_READY; - osalSysUnlock(); -} - -/** - * @brief Deactivates the TRNG peripheral. - * - * @param[in] trngp pointer to the @p TRNGDriver object - * - * @api - */ -void trngStop(TRNGDriver *trngp) { - - osalDbgCheck(trngp != NULL); - - osalSysLock(); - osalDbgAssert((trngp->state == TRNG_STOP) || - (trngp->state == TRNG_READY), "invalid state"); - - trng_lld_stop(trngp); - trngp->state = TRNG_STOP; - osalSysUnlock(); -} - -/** - * @brief Get random number from TRNG. - * - * @param[in] trngp pointer to the @p CLASSDDriver object - * @return num random number generated - * - * @api - */ -uint32_t trngGetRandomNumber(TRNGDriver *trngp) { - - osalDbgCheck(trngp != NULL); - - uint32_t num = trng_lld_get_random_number(trngp); - return num; -} - -#endif /* HAL_USE_TRNG == TRUE */ - -/** @} */ diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_trng.h b/os/hal/ports/SAMA/SAMA5D2x/sama_trng.h deleted file mode 100644 index ba9ab34a9..000000000 --- a/os/hal/ports/SAMA/SAMA5D2x/sama_trng.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio - - 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 SAMA5D2x/sama_trng.h - * @brief SAMA TRNG support macros and structures. - * - * @addtogroup SAMA5D2x_TRNG - * @{ - */ - -#ifndef SAMA_TRNG_LLD_H -#define SAMA_TRNG_LLD_H - -/** - * @brief Using the TRNG driver. - */ -#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__) -#define HAL_USE_TRNG FALSE -#endif - -#if (HAL_USE_TRNG) || defined(__DOXYGEN__) - -/*===========================================================================*/ -/* Driver constants. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver pre-compile time settings. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Derived constants and error checks. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* Driver data structures and types. */ -/*===========================================================================*/ - -/** - * @brief Driver state machine possible states. - */ -typedef enum { - TRNG_UNINIT = 0, /**< Not initialized. */ - TRNG_STOP = 1, /**< Stopped. */ - TRNG_READY = 2 /**< Ready. */ -} trngstate_t; - -/** - * @brief Type of a structure representing an CLASSD driver. - */ -typedef struct TRNGDriver TRNGDriver; - -/** - * @brief Structure representing an TRNG driver. - */ -struct TRNGDriver { - /** - * @brief Driver state. - */ - trngstate_t state; - /** - * @brief Pointer to the WDT registers block. - */ - Trng *trng; -}; - -/*===========================================================================*/ -/* Driver macros. */ -/*===========================================================================*/ - -/*===========================================================================*/ -/* External declarations. */ -/*===========================================================================*/ - -extern TRNGDriver TRNGD0; - -#ifdef __cplusplus -extern "C" { -#endif - void trngInit(void); - void trngStart(TRNGDriver *trngp); - void trngStop(TRNGDriver *trngp); - uint32_t trngGetRandomNumber(TRNGDriver *trngp); -#ifdef __cplusplus -} -#endif - -#endif /* HAL_USE_TRNG */ - -#endif /* SAMA_TRNG_LLD_H */ - -/** @} */ -- cgit v1.2.3