2019-02-10 13:26:55 +01:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2019 Aurelien Jarno
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2022-05-06 10:25:46 +02:00
|
|
|
#include <zephyr/device.h>
|
|
|
|
#include <zephyr/drivers/hwinfo.h>
|
|
|
|
#include <zephyr/init.h>
|
2019-02-10 13:26:55 +01:00
|
|
|
#include <soc.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
static uint8_t sam_uid[16];
|
2019-02-10 13:26:55 +01:00
|
|
|
|
2020-05-27 18:26:57 +02:00
|
|
|
ssize_t z_impl_hwinfo_get_device_id(uint8_t *buffer, size_t length)
|
2019-02-10 13:26:55 +01:00
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2020-04-08 17:04:14 +02:00
|
|
|
Efc *efc = (Efc *)DT_REG_ADDR(DT_INST(0, atmel_sam_flash_controller));
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t *flash = (uint8_t *)CONFIG_FLASH_BASE_ADDRESS;
|
2019-02-10 13:26:55 +01:00
|
|
|
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 */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
init: remove the need for a dummy device pointer in SYS_INIT functions
The init infrastructure, found in `init.h`, is currently used by:
- `SYS_INIT`: to call functions before `main`
- `DEVICE_*`: to initialize devices
They are all sorted according to an initialization level + a priority.
`SYS_INIT` calls are really orthogonal to devices, however, the required
function signature requires a `const struct device *dev` as a first
argument. The only reason for that is because the same init machinery is
used by devices, so we have something like:
```c
struct init_entry {
int (*init)(const struct device *dev);
/* only set by DEVICE_*, otherwise NULL */
const struct device *dev;
}
```
As a result, we end up with such weird/ugly pattern:
```c
static int my_init(const struct device *dev)
{
/* always NULL! add ARG_UNUSED to avoid compiler warning */
ARG_UNUSED(dev);
...
}
```
This is really a result of poor internals isolation. This patch proposes
a to make init entries more flexible so that they can accept sytem
initialization calls like this:
```c
static int my_init(void)
{
...
}
```
This is achieved using a union:
```c
union init_function {
/* for SYS_INIT, used when init_entry.dev == NULL */
int (*sys)(void);
/* for DEVICE*, used when init_entry.dev != NULL */
int (*dev)(const struct device *dev);
};
struct init_entry {
/* stores init function (either for SYS_INIT or DEVICE*)
union init_function init_fn;
/* stores device pointer for DEVICE*, NULL for SYS_INIT. Allows
* to know which union entry to call.
*/
const struct device *dev;
}
```
This solution **does not increase ROM usage**, and allows to offer clean
public APIs for both SYS_INIT and DEVICE*. Note that however, init
machinery keeps a coupling with devices.
**NOTE**: This is a breaking change! All `SYS_INIT` functions will need
to be converted to the new signature. See the script offered in the
following commit.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
init: convert SYS_INIT functions to the new signature
Conversion scripted using scripts/utils/migrate_sys_init.py.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
manifest: update projects for SYS_INIT changes
Update modules with updated SYS_INIT calls:
- hal_ti
- lvgl
- sof
- TraceRecorderSource
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
tests: devicetree: devices: adjust test
Adjust test according to the recently introduced SYS_INIT
infrastructure.
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
tests: kernel: threads: adjust SYS_INIT call
Adjust to the new signature: int (*init_fn)(void);
Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
2022-10-19 09:33:44 +02:00
|
|
|
static int hwinfo_sam_init(void)
|
2019-02-10 13:26:55 +01:00
|
|
|
{
|
2020-04-08 17:04:14 +02:00
|
|
|
Efc *efc = (Efc *)DT_REG_ADDR(DT_INST(0, atmel_sam_flash_controller));
|
2020-05-27 18:26:57 +02:00
|
|
|
uint32_t fmr;
|
2022-07-13 16:50:25 +02:00
|
|
|
unsigned int key;
|
2019-02-10 13:26:55 +01:00
|
|
|
|
|
|
|
/* Disable interrupts. */
|
|
|
|
key = irq_lock();
|
|
|
|
|
|
|
|
/* Disable code loop optimization and sequential code optimization. */
|
|
|
|
fmr = efc->EEFC_FMR;
|
2020-02-20 13:33:09 +01:00
|
|
|
|
|
|
|
#ifndef CONFIG_SOC_SERIES_SAM3X
|
2019-02-10 13:26:55 +01:00
|
|
|
efc->EEFC_FMR = (fmr & (~EEFC_FMR_CLOE)) | EEFC_FMR_SCOD;
|
2020-02-20 13:33:09 +01:00
|
|
|
#else
|
|
|
|
/* SAM3x does not have loop optimization (EEFC_FMR_CLOE) */
|
|
|
|
efc->EEFC_FMR |= EEFC_FMR_SCOD;
|
|
|
|
#endif
|
2019-02-10 13:26:55 +01:00
|
|
|
|
|
|
|
/* 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);
|