drivers: hwinfo: add driver support for Atmel SAM device ID
Add driver support for Atmel SAM device ID, which is 16-bytes long. On this SoC family, the device ID is part of the flash controller and complex to read. Therefore the driver reads it once at boot time and then just returned the copy saved in RAM. Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
2d8ac0cf5e
commit
bf59fcb78c
3 changed files with 98 additions and 0 deletions
|
@ -5,5 +5,6 @@ zephyr_sources_ifdef(CONFIG_HWINFO_STM32 hwinfo_stm32.c)
|
||||||
zephyr_sources_ifdef(CONFIG_HWINFO_NRF hwinfo_nrf.c)
|
zephyr_sources_ifdef(CONFIG_HWINFO_NRF hwinfo_nrf.c)
|
||||||
zephyr_sources_ifdef(CONFIG_HWINFO_MCUX_SIM hwinfo_mcux_sim.c)
|
zephyr_sources_ifdef(CONFIG_HWINFO_MCUX_SIM hwinfo_mcux_sim.c)
|
||||||
zephyr_sources_ifdef(CONFIG_HWINFO_IMXRT hwinfo_imxrt.c)
|
zephyr_sources_ifdef(CONFIG_HWINFO_IMXRT hwinfo_imxrt.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_HWINFO_SAM hwinfo_sam.c)
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_HWINFO_SHELL hwinfo_shell.c)
|
zephyr_sources_ifdef(CONFIG_HWINFO_SHELL hwinfo_shell.c)
|
||||||
|
|
|
@ -48,4 +48,11 @@ config HWINFO_IMXRT
|
||||||
help
|
help
|
||||||
Enable NXP i.mx RT hwinfo driver.
|
Enable NXP i.mx RT hwinfo driver.
|
||||||
|
|
||||||
|
config HWINFO_SAM
|
||||||
|
bool "Atmel SAM device ID"
|
||||||
|
default y
|
||||||
|
depends on SOC_FAMILY_SAM
|
||||||
|
help
|
||||||
|
Enable Atmel SAM hwinfo driver.
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
90
drivers/hwinfo/hwinfo_sam.c
Normal file
90
drivers/hwinfo/hwinfo_sam.c
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 Aurelien Jarno
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <device.h>
|
||||||
|
#include <hwinfo.h>
|
||||||
|
#include <init.h>
|
||||||
|
#include <soc.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static u8_t sam_uid[16];
|
||||||
|
|
||||||
|
ssize_t z_impl_hwinfo_get_device_id(u8_t *buffer, size_t length)
|
||||||
|
{
|
||||||
|
if (length > sizeof(sam_uid)) {
|
||||||
|
length = sizeof(sam_uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(buffer, sam_uid, length);
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* On the Atmel SAM SoC series, the device id is located in the flash
|
||||||
|
* controller. The controller can either present the flash area containing
|
||||||
|
* the code, the unique identifier or the user signature area at the flash
|
||||||
|
* location. Therefore the function reading the device id must be executed
|
||||||
|
* from RAM with the interrupts disabled. To avoid executing this complex
|
||||||
|
* code each time the device id is requested, we do this at boot time at save
|
||||||
|
* the 128-bit value into RAM.
|
||||||
|
*/
|
||||||
|
__ramfunc static void hwinfo_sam_read_device_id(void)
|
||||||
|
{
|
||||||
|
Efc *efc = (Efc *)DT_FLASH_DEV_BASE_ADDRESS;
|
||||||
|
u8_t *flash = (u8_t *)CONFIG_FLASH_BASE_ADDRESS;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Switch the flash controller to the unique identifier area. The flash
|
||||||
|
* is not available anymore, hence we have to wait for it to be *NOT*
|
||||||
|
* ready.
|
||||||
|
*/
|
||||||
|
efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_STUI;
|
||||||
|
while ((efc->EEFC_FSR & EEFC_FSR_FRDY) == EEFC_FSR_FRDY) {
|
||||||
|
/* Wait */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the 128-bit unique ID. We cannot use memcpy as it would
|
||||||
|
* execute code from flash.
|
||||||
|
*/
|
||||||
|
for (i = 0; i < sizeof(sam_uid); i++) {
|
||||||
|
sam_uid[i] = flash[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Switch back the controller to the flash area and wait for it to
|
||||||
|
* be ready.
|
||||||
|
*/
|
||||||
|
efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FCMD_SPUI;
|
||||||
|
while ((efc->EEFC_FSR & EEFC_FSR_FRDY) != EEFC_FSR_FRDY) {
|
||||||
|
/* Wait */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hwinfo_sam_init(struct device *arg)
|
||||||
|
{
|
||||||
|
Efc *efc = (Efc *)DT_FLASH_DEV_BASE_ADDRESS;
|
||||||
|
u32_t fmr;
|
||||||
|
int key;
|
||||||
|
|
||||||
|
/* Disable interrupts. */
|
||||||
|
key = irq_lock();
|
||||||
|
|
||||||
|
/* Disable code loop optimization and sequential code optimization. */
|
||||||
|
fmr = efc->EEFC_FMR;
|
||||||
|
efc->EEFC_FMR = (fmr & (~EEFC_FMR_CLOE)) | EEFC_FMR_SCOD;
|
||||||
|
|
||||||
|
/* Read the device ID using code in RAM */
|
||||||
|
hwinfo_sam_read_device_id();
|
||||||
|
|
||||||
|
/* Restore code optimization settings. */
|
||||||
|
efc->EEFC_FMR = fmr;
|
||||||
|
|
||||||
|
/* Re-enable interrupts */
|
||||||
|
irq_unlock(key);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYS_INIT(hwinfo_sam_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);
|
Loading…
Add table
Add a link
Reference in a new issue