aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/ports/SAMA/SAMA5D2x
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/ports/SAMA/SAMA5D2x
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/ports/SAMA/SAMA5D2x')
-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.h (renamed from os/hal/ports/SAMA/SAMA5D2x/sama_trng.h)79
-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
-rw-r--r--os/hal/ports/SAMA/SAMA5D2x/sama_trng.c190
22 files changed, 4373 insertions, 248 deletions
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_trng.h b/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.h
index ba9ab34a9..b8edb1185 100644
--- a/os/hal/ports/SAMA/SAMA5D2x/sama_trng.h
+++ b/os/hal/ports/SAMA/SAMA5D2x/sama_onewire.h
@@ -15,24 +15,24 @@
*/
/**
- * @file SAMA5D2x/sama_trng.h
- * @brief SAMA TRNG support macros and structures.
+ * @file SAMA5D2x/sama_onewire.h
+ * @brief SAMA ONEWIRE support macros and structures.
*
- * @addtogroup SAMA5D2x_TRNG
+ * @addtogroup SAMA5D2x_ONEWIRE
* @{
*/
-#ifndef SAMA_TRNG_LLD_H
-#define SAMA_TRNG_LLD_H
+#ifndef SAMA_ONEWIRE_LLD_H
+#define SAMA_ONEWIRE_LLD_H
/**
- * @brief Using the TRNG driver.
+ * @brief Using the ONEWIRE driver.
*/
-#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__)
-#define HAL_USE_TRNG FALSE
+#if !defined(SAMA_USE_ONEWIRE) || defined(__DOXYGEN__)
+#define SAMA_USE_ONEWIRE FALSE
#endif
-#if (HAL_USE_TRNG) || defined(__DOXYGEN__)
+#if (SAMA_USE_ONEWIRE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
@@ -49,33 +49,48 @@
/*===========================================================================*/
/* 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;
+ 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 an CLASSD driver.
+ * @brief Type of a structure representing a ONEWIRE driver.
*/
-typedef struct TRNGDriver TRNGDriver;
+typedef struct ONEWIREDriver ONEWIREDriver;
/**
- * @brief Structure representing an TRNG driver.
+ * @brief Driver configuration structure.
*/
-struct TRNGDriver {
+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 Driver state.
+ * @brief Current configuration data.
*/
- trngstate_t state;
+ const ONEWIREConfig *config;
/**
- * @brief Pointer to the WDT registers block.
+ * @brief Mutex protecting the bus.
*/
- Trng *trng;
+ mutex_t mutex;
};
/*===========================================================================*/
@@ -86,21 +101,27 @@ struct TRNGDriver {
/* External declarations. */
/*===========================================================================*/
-extern TRNGDriver TRNGD0;
+extern ONEWIREDriver ONEWD0;
#ifdef __cplusplus
extern "C" {
#endif
- void trngInit(void);
- void trngStart(TRNGDriver *trngp);
- void trngStop(TRNGDriver *trngp);
- uint32_t trngGetRandomNumber(TRNGDriver *trngp);
+ 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 /* HAL_USE_TRNG */
+#endif /* SAMA_USE_ONEWIRE */
-#endif /* SAMA_TRNG_LLD_H */
+#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 */
+
+/** @} */
diff --git a/os/hal/ports/SAMA/SAMA5D2x/sama_trng.c b/os/hal/ports/SAMA/SAMA5D2x/sama_trng.c
deleted file mode 100644
index 287d37403..000000000
--- a/os/hal/ports/SAMA/SAMA5D2x/sama_trng.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-/**
- * @file SAMA5D2x/sama_trng.c
- * @brief SAMA TRNG support code.
- *
- * @addtogroup SAMA5D2x_TRNG
- * @{
- */
-
-#include "hal.h"
-
-#if (HAL_USE_TRNG) || defined(__DOXYGEN__)
-
-/*===========================================================================*/
-/* Driver local definitions. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local macros. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported variables. */
-/*===========================================================================*/
-TRNGDriver TRNGD0;
-
-/*===========================================================================*/
-/* Driver local variables. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver local functions. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
-/*===========================================================================*/
-/* Driver exported functions. */
-/*===========================================================================*/
-
-/**
- * @brief Low level TRNG driver initialization.
- *
- * @notapi
- */
-void trng_lld_init(void) {
-#if SAMA_HAL_IS_SECURE
- mtxConfigPeriphSecurity(MATRIX1, ID_TRNG, SECURE_PER);
-#endif /* SAMA_HAL_IS_SECURE */
- /* Driver initialization.*/
- TRNGD0.state = TRNG_STOP;
- TRNGD0.trng = TRNG;
-}
-
-/**
- * @brief Configures and activates the TRNG peripheral.
- *
- * @param[in] trngp pointer to the @p TRNGDriver object
- *
- * @notapi
- */
-void trng_lld_start(TRNGDriver *trngp) {
-
- /* Configures the peripheral. */
- if (trngp->state == TRNG_STOP) {
-
- /* Enable the TRNG peripheral clock. */
- pmcEnableTRNG0();
-
- /* Enable the TRNG. */
- trngp->trng->TRNG_CR = TRNG_CR_ENABLE | TRNG_CR_KEY_PASSWD;
- }
-}
-
-/**
- * @brief Deactivates the TRNG peripheral.
- *
- * @param[in] trngp pointer to the @p TRNGDriver object
- *
- * @notapi
- */
-void trng_lld_stop(TRNGDriver *trngp) {
-
- if (trngp->state == TRNG_READY) {
- /* Disable the TRNG. */
- trngp->trng->TRNG_CR = TRNG_CR_KEY_PASSWD;
- /* Disable the TRNG clock. */
- pmcDisableTRNG0();
- }
-}
-
-/**
- * @brief Get random number from TRNG.
- *
- * @param[in] trngp pointer to the @p TRNGDriver object
- * @return TRNG_ODATA content of the TRNG_ODATA register
- *
- * @notapi
- */
-uint32_t trng_lld_get_random_number(TRNGDriver *trngp) {
-
- while (!(trngp->trng->TRNG_ISR & TRNG_ISR_DATRDY));
- return trngp->trng->TRNG_ODATA;
-}
-
-/**
- * @brief TRNG driver initialization.
- *
- * @notapi
- */
-void trngInit(void) {
-
- trng_lld_init();
-}
-
-/**
- * @brief Configures and activates the TRNG peripheral.
- *
- * @param[in] trngp pointer to the @p TRNGDriver object
- *
- * @api
- */
-void trngStart(TRNGDriver *trngp) {
-
- osalDbgCheck(trngp != NULL);
-
- osalSysLock();
- osalDbgAssert((trngp->state == TRNG_STOP) ||
- (trngp->state == TRNG_READY), "invalid state");
- trng_lld_start(trngp);
- trngp->state = TRNG_READY;
- osalSysUnlock();
-}
-
-/**
- * @brief Deactivates the TRNG peripheral.
- *
- * @param[in] trngp pointer to the @p TRNGDriver object
- *
- * @api
- */
-void trngStop(TRNGDriver *trngp) {
-
- osalDbgCheck(trngp != NULL);
-
- osalSysLock();
- osalDbgAssert((trngp->state == TRNG_STOP) ||
- (trngp->state == TRNG_READY), "invalid state");
-
- trng_lld_stop(trngp);
- trngp->state = TRNG_STOP;
- osalSysUnlock();
-}
-
-/**
- * @brief Get random number from TRNG.
- *
- * @param[in] trngp pointer to the @p CLASSDDriver object
- * @return num random number generated
- *
- * @api
- */
-uint32_t trngGetRandomNumber(TRNGDriver *trngp) {
-
- osalDbgCheck(trngp != NULL);
-
- uint32_t num = trng_lld_get_random_number(trngp);
- return num;
-}
-
-#endif /* HAL_USE_TRNG == TRUE */
-
-/** @} */