aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal
diff options
context:
space:
mode:
authoredolomb <none@example.com>2019-01-17 15:19:20 +0000
committeredolomb <none@example.com>2019-01-17 15:19:20 +0000
commit29309f101a4828842c377ff11a3a59908aab05f2 (patch)
treef75aef8484bc3522621b128eb6bfeacd55ad0e47 /os/hal
parent696701cd6fe254a4cb2e3f748cacabe853d42a9e (diff)
downloadChibiOS-29309f101a4828842c377ff11a3a59908aab05f2.tar.gz
ChibiOS-29309f101a4828842c377ff11a3a59908aab05f2.tar.bz2
ChibiOS-29309f101a4828842c377ff11a3a59908aab05f2.zip
Updated SAMA drivers (still incomplete)
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@12543 110e8d01-0319-4d1e-a829-52ad28d1bb01
Diffstat (limited to 'os/hal')
-rw-r--r--os/hal/boards/ATSAMA5D27_SOM1/board.c289
-rw-r--r--os/hal/boards/ATSAMA5D27_SOM1/board.h238
-rw-r--r--os/hal/boards/ATSAMA5D27_SOM1/board.mk9
-rw-r--r--os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.c165
-rw-r--r--os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.h232
-rw-r--r--os/hal/boards/ATSAMA5D27_SOM1_NSEC/board.mk9
-rw-r--r--os/hal/boards/ATSAMA5D27_SOM1_SEC/board.c229
-rw-r--r--os/hal/boards/ATSAMA5D27_SOM1_SEC/board.h236
-rw-r--r--os/hal/boards/ATSAMA5D27_SOM1_SEC/board.mk9
-rw-r--r--os/hal/ports/SAMA/LLD/CRYPTOv1/sama_aes_lld.c20
-rw-r--r--os/hal/ports/SAMA/LLD/CRYPTOv1/sama_crypto_lld.c7
-rw-r--r--os/hal/ports/SAMA/LLD/CRYPTOv1/sama_gcm_lld.c19
-rw-r--r--os/hal/ports/SAMA/LLD/CRYPTOv1/sama_sha_lld.c16
-rw-r--r--os/hal/ports/SAMA/LLD/CRYPTOv1/sama_tdes_lld.c21
-rw-r--r--os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.c26
-rw-r--r--os/hal/ports/SAMA/LLD/DMAv1/sama_xdmac.h12
-rw-r--r--os/hal/ports/SAMA/LLD/I2Cv1/driver.mk21
-rw-r--r--os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.c963
-rw-r--r--os/hal/ports/SAMA/LLD/I2Cv1/hal_i2c_lld.h277
-rw-r--r--os/hal/ports/SAMA/LLD/MACv1/hal_mac_lld.c25
-rw-r--r--os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.c301
-rw-r--r--os/hal/ports/SAMA/LLD/PIOv1/hal_pal_lld.h49
-rw-r--r--os/hal/ports/SAMA/LLD/RNGv1/driver.mk9
-rw-r--r--os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c (renamed from os/hal/ports/SAMA/SAMA5D2x/sama_trng.c)175
-rw-r--r--os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.h (renamed from os/hal/ports/SAMA/SAMA5D2x/sama_trng.h)95
-rw-r--r--os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.c31
-rw-r--r--os/hal/ports/SAMA/LLD/RTCv1/hal_rtc_lld.h55
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.c2
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc.h2
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_cmds.c4
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_device.c60
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_macros.h11
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_mmc.c2
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sama5d2.h18
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sd.c2
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/ch_sdmmc_sdio.c2
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/driver.mk10
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.c4
-rw-r--r--os/hal/ports/SAMA/LLD/SDMMCv1/sama_sdmmc_lld.h8
-rw-r--r--os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.c205
-rw-r--r--os/hal/ports/SAMA/LLD/SPIv1/hal_spi_lld.h300
-rw-r--r--os/hal/ports/SAMA/LLD/USARTv1/hal_serial_lld.h2
-rw-r--r--os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.c66
-rw-r--r--os/hal/ports/SAMA/LLD/USARTv1/hal_uart_lld.h20
-rw-r--r--os/hal/ports/SAMA/LLD/xWDGv1/driver.mk9
-rw-r--r--os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.c165
-rw-r--r--os/hal/ports/SAMA/LLD/xWDGv1/hal_wdg_lld.h141
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.c12
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/hal_crypto_lld.h20
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/hal_lld.c10
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/hal_lld.h30
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/platform.mk12
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_aic.c (renamed from os/hal/ports/SAMA/SAMA5D2x/aic.c)4
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_aic.h (renamed from os/hal/ports/SAMA/SAMA5D2x/aic.h)0
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_cache.c34
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_cache.h5
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_classd.c526
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_classd.h301
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.c955
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_lcdc.h280
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_onewire.c548
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_onewire.h127
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_pmc.h480
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_rstc.h179
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_secumod.c6
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_secumod.h11
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.c575
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_tc_lld.h364
68 files changed, 8615 insertions, 435 deletions
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. <b>After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state</b>.
+ *
+ * @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. <b>After a
+ * timeout the driver must be stopped and restarted
+ * because the bus is in an uncertain state</b>.
+ *
+ * @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/SAMA5D2x/sama_trng.c b/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c
index 287d37403..6d8fde7d6 100644
--- a/os/hal/ports/SAMA/SAMA5D2x/sama_trng.c
+++ b/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.c
@@ -15,34 +15,38 @@
*/
/**
- * @file SAMA5D2x/sama_trng.c
- * @brief SAMA TRNG support code.
+ * @file hal_trng_lld.c
+ * @brief STM32 TRNG subsystem low level driver source.
*
- * @addtogroup SAMA5D2x_TRNG
+ * @addtogroup TRNG
* @{
*/
#include "hal.h"
-#if (HAL_USE_TRNG) || defined(__DOXYGEN__)
+#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
-/* Driver local macros. */
-/*===========================================================================*/
-
-/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
+
+/**
+ * @brief TRNGD0 driver identifier.
+ */
+#if (SAMA_TRNG_USE_TRNG0 == TRUE) || defined(__DOXYGEN__)
TRNGDriver TRNGD0;
+#endif
/*===========================================================================*/
-/* Driver local variables. */
+/* Driver local variables and types. */
/*===========================================================================*/
+static const TRNGConfig default_cfg = {0};
+
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
@@ -61,128 +65,109 @@ TRNGDriver TRNGD0;
* @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.*/
- TRNGD0.state = TRNG_STOP;
- TRNGD0.trng = TRNG;
+ trngObjectInit(&TRNGD0);
+ TRNGD0.trng = TRNG;
+#endif
}
/**
* @brief Configures and activates the TRNG peripheral.
*
- * @param[in] trngp pointer to the @p TRNGDriver object
+ * @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();
+ /* There is no real configuration but setting up a valid pointer anyway.*/
+ if (trngp->config == NULL) {
+ trngp->config = &default_cfg;
+ }
- /* Enable the TRNG. */
- trngp->trng->TRNG_CR = TRNG_CR_ENABLE | TRNG_CR_KEY_PASSWD;
+ 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
+ * @param[in] trngp pointer to the @p TRNGDriver object
*
* @notapi
*/
void trng_lld_stop(TRNGDriver *trngp) {
if (trngp->state == TRNG_READY) {
- /* Disable the TRNG. */
+ /* Resets the peripheral.*/
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();
+ /* Disables the peripheral.*/
+#if SAMA_TRNG_USE_TRNG0 == TRUE
+ if (&TRNGD0 == trngp) {
+ pmcDisableTRNG0();
+ }
+#endif
+ }
}
/**
- * @brief Get random number from TRNG.
+ * @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 CLASSDDriver object
- * @return num random number generated
+ * @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
*/
-uint32_t trngGetRandomNumber(TRNGDriver *trngp) {
-
- osalDbgCheck(trngp != NULL);
-
- uint32_t num = trng_lld_get_random_number(trngp);
- return num;
+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/SAMA5D2x/sama_trng.h b/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.h
index ba9ab34a9..146635db4 100644
--- a/os/hal/ports/SAMA/SAMA5D2x/sama_trng.h
+++ b/os/hal/ports/SAMA/LLD/RNGv1/hal_trng_lld.h
@@ -15,24 +15,17 @@
*/
/**
- * @file SAMA5D2x/sama_trng.h
- * @brief SAMA TRNG support macros and structures.
+ * @file hal_trng_lld.h
+ * @brief SAMA TRNG subsystem low level driver header.
*
- * @addtogroup SAMA5D2x_TRNG
+ * @addtogroup TRNG
* @{
*/
-#ifndef SAMA_TRNG_LLD_H
-#define SAMA_TRNG_LLD_H
+#ifndef HAL_TRNG_LLD_H
+#define HAL_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__)
+#if (HAL_USE_TRNG == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
@@ -42,65 +35,79 @@
/* 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. */
/*===========================================================================*/
-/**
- * @brief Driver state machine possible states.
- */
-typedef enum {
- TRNG_UNINIT = 0, /**< Not initialized. */
- TRNG_STOP = 1, /**< Stopped. */
- TRNG_READY = 2 /**< Ready. */
-} trngstate_t;
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
/**
- * @brief Type of a structure representing an CLASSD driver.
+ * @brief Low level fields of the TRNG configuration structure.
*/
-typedef struct TRNGDriver TRNGDriver;
+#define trng_lld_config_fields \
+ /* Dummy configuration, it is not needed.*/ \
+ uint32_t dummy
/**
- * @brief Structure representing an TRNG driver.
+ * @brief Low level fields of the TRNG driver structure.
*/
-struct TRNGDriver {
- /**
- * @brief Driver state.
- */
- trngstate_t state;
- /**
- * @brief Pointer to the WDT registers block.
- */
- Trng *trng;
-};
-
-/*===========================================================================*/
-/* Driver macros. */
-/*===========================================================================*/
+#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 trngInit(void);
- void trngStart(TRNGDriver *trngp);
- void trngStop(TRNGDriver *trngp);
- uint32_t trngGetRandomNumber(TRNGDriver *trngp);
+ 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 */
+#endif /* HAL_USE_TRNG == TRUE */
-#endif /* SAMA_TRNG_LLD_H */
+#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
@@ -80,17 +80,6 @@
/*===========================================================================*/
/**
- * @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.
*/
typedef enum {
@@ -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 <string.h>
#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 <string.h>
#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 <string.h>
#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 <string.h>
#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 <string.h>
#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 <string.h>
#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. */
@@ -53,15 +53,58 @@
#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.
*/
@@ -70,6 +113,28 @@
#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.
*/
@@ -78,6 +143,28 @@
#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.
*/
@@ -86,6 +173,28 @@
#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.
*/
@@ -94,6 +203,28 @@
#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.
*/
@@ -102,6 +233,28 @@
#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.
*/
#if !defined(SAMA_SPI_SPI0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
@@ -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/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/aic.c b/os/hal/ports/SAMA/SAMA5D2x/sama_aic.c
index d961c58fd..e47336bb5 100644
--- a/os/hal/ports/SAMA/SAMA5D2x/aic.c
+++ b/os/hal/ports/SAMA/SAMA5D2x/sama_aic.c
@@ -161,7 +161,7 @@ void aicSetSourcePriority(uint32_t source, uint8_t priority) {
/* Disable the interrupt first */
aic->AIC_IDCR = AIC_IDCR_INTD;
/* Configure priority */
- aic->AIC_SMR = AIC_SMR_PRIOR(priority);
+ aic->AIC_SMR |= AIC_SMR_PRIOR(priority);
/* Clear interrupt */
aic->AIC_ICCR = AIC_ICCR_INTCLR;
/* Enable write protection */
@@ -188,7 +188,7 @@ void aicSetIntSourceType(uint32_t source, uint8_t type) {
/* Disable the interrupt first */
aic->AIC_IDCR = AIC_IDCR_INTD;
/* Configure priority */
- aic->AIC_SMR = AIC_SMR_SRCTYPE(type);
+ aic->AIC_SMR |= AIC_SMR_SRCTYPE(type);
/* Clear interrupt */
aic->AIC_ICCR = AIC_ICCR_INTCLR;
/* Enable write protection */
diff --git a/os/hal/ports/SAMA/SAMA5D2x/aic.h b/os/hal/ports/SAMA/SAMA5D2x/sama_aic.h
index a4f220754..a4f220754 100644
--- a/os/hal/ports/SAMA/SAMA5D2x/aic.h
+++ b/os/hal/ports/SAMA/SAMA5D2x/sama_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
+
/** @} */
/**
@@ -519,6 +901,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.
*
* @api
@@ -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 <string.h>
/*===========================================================================*/
@@ -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 */
+
+/** @} */