RP2040: Implement board_uniqueid()
This commit is contained in:
parent
7e07d23af1
commit
b4407b529a
1
LICENSE
1
LICENSE
@ -3842,6 +3842,7 @@ arch/arm/src/rp2040/rp2040_pio.h
|
||||
arch/arm/src/rp2040/rp2040_pio_instructions.h
|
||||
arch/arm/src/rp2040/rp2040_pll.c
|
||||
arch/arm/src/rp2040/rp2040_xosc.c
|
||||
boards/arm/rp2040/common/src/rp2040_uniqueid.c
|
||||
==========================================================
|
||||
Based upon the software originally developed by
|
||||
Raspberry Pi (Trading) Ltd.
|
||||
|
69
boards/arm/rp2040/common/include/rp2040_uniqueid.h
Normal file
69
boards/arm/rp2040/common/include/rp2040_uniqueid.h
Normal file
@ -0,0 +1,69 @@
|
||||
/****************************************************************************
|
||||
* boards/arm/rp2040/common/include/rp2040_uniqueid.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef __BOARDS_ARM_RP2040_COMMON_INCLUDE_RP2040_UNIQUEID_H
|
||||
#define __BOARDS_ARM_RP2040_COMMON_INCLUDE_RP2040_UNIQUEID_H
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define RP2040_FLASH_ID_SIZE 8
|
||||
#define RP2040_FLASH_ID_BUFFER_SIZE 13
|
||||
#define RP2040_FLASH_ID_BUFFER_OFFSET 5
|
||||
#define RP2040_FLASH_RUID_CMD 0x4b
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_uniqueid_initialize
|
||||
*
|
||||
* Description:
|
||||
* The RP2040 doesn't have a unique ID, so we load the ID from the
|
||||
* connected flash chip. We use the flash ID to seed a simple xorshift
|
||||
* PRNG. The PRNG then generates CONFIG_BOARDCTL_UNIQUEID_SIZE bytes,
|
||||
* which we will use as the board's unique ID.
|
||||
*
|
||||
* Retrieving the flash id is somewhat slow and complex, so we only do
|
||||
* this during initialization and store the result for later use.
|
||||
*
|
||||
* Assumptions/Limitations:
|
||||
* This uniqueid implementation requires a flash chip. It should not be
|
||||
* used on boards without flash.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_uniqueid_initialize(void);
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BOARDS_ARM_RP2040_COMMON_INCLUDE_RP2040_UNIQUEID_H */
|
@ -91,6 +91,10 @@ ifeq ($(CONFIG_LCD_BACKPACK),y)
|
||||
CSRCS += rp2040_lcd_backpack.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BOARDCTL_UNIQUEID),y)
|
||||
CSRCS += rp2040_uniqueid.c
|
||||
endif
|
||||
|
||||
DEPPATH += --dep-path src
|
||||
VPATH += :src
|
||||
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)arch$(DELIM)$(CONFIG_ARCH)$(DELIM)src$(DELIM)board$(DELIM)src
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "rp2040_gpio.h"
|
||||
#include "rp2040_uniqueid.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
@ -123,6 +124,10 @@ void rp2040_common_earlyinitialize(void)
|
||||
|
||||
void rp2040_common_initialize(void)
|
||||
{
|
||||
#ifdef CONFIG_BOARDCTL_UNIQUEID
|
||||
rp2040_uniqueid_initialize();
|
||||
#endif
|
||||
|
||||
/* Set default I2C pin */
|
||||
|
||||
#ifdef CONFIG_RP2040_I2C0
|
||||
|
341
boards/arm/rp2040/common/src/rp2040_uniqueid.c
Normal file
341
boards/arm/rp2040/common/src/rp2040_uniqueid.c
Normal file
@ -0,0 +1,341 @@
|
||||
/****************************************************************************
|
||||
* boards/arm/rp2040/common/src/rp2040_uniqueid.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "rp2040_uniqueid.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#define ROM_FUNC_CIF ROM_TABLE_CODE('I', 'F')
|
||||
#define ROM_FUNC_FEX ROM_TABLE_CODE('E', 'X')
|
||||
#define ROM_FUNC_FFC ROM_TABLE_CODE('F', 'C')
|
||||
|
||||
#define QSPI_SS_CTRL_OUTOVER_LSB 8
|
||||
#define QSPI_SS_CTRL_OUTOVER_VALUE_LOW 0x2
|
||||
#define QSPI_SS_CTRL_OUTOVER_VALUE_HIGH 0x3
|
||||
#define QSPI_SS_CTRL_OUTOVER_BITS 0x00000300
|
||||
#define QSPI_SS_CTRL 0x4001800c
|
||||
#define XIP_BASE 0x10000000
|
||||
#define XIP_SSI_SR 0x18000028
|
||||
#define XIP_SSI_DR0 0x18000060
|
||||
#define SSI_SR_TFNF_BITS 0x00000002
|
||||
#define SSI_SR_RFNE_BITS 0x00000008
|
||||
#define BOOT2_SIZE_WORDS 64
|
||||
#define REG_ALIAS_XOR_BITS (0x1u << 12u)
|
||||
|
||||
#define ROM_TABLE_CODE(c1, c2) ((c1) | ((c2) << 8))
|
||||
#define hw_alias_check_addr(addr) ((uintptr_t)(addr))
|
||||
#define hw_xor_alias_untyped(addr) ((void *)(REG_ALIAS_XOR_BITS | hw_alias_check_addr(addr)))
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
typedef volatile uint32_t io_rw_32;
|
||||
typedef void (*rom_cif_fn)(void);
|
||||
typedef void (*rom_fex_fn)(void);
|
||||
typedef void (*rom_ffc_fn)(void);
|
||||
typedef void (*rom_flash_enter_cmd_xip_fn)(void);
|
||||
typedef void *(*rom_table_lookup_fn)(uint16_t *table, uint32_t code);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
static inline void __compiler_memory_barrier(void);
|
||||
static inline void *rom_hword_as_ptr(uint16_t rom_address);
|
||||
static inline uint32_t rom_table_code(uint8_t c1, uint8_t c2);
|
||||
static void *rf_lookup(uint32_t code);
|
||||
static void hw_xor_bits(io_rw_32 *addr, uint32_t mask);
|
||||
static void hw_write_masked(io_rw_32 *addr,
|
||||
uint32_t values,
|
||||
uint32_t write_mask);
|
||||
static void flash_cs_force (bool high);
|
||||
void rp2040_flash_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
||||
static uint8_t g_uniqueid[CONFIG_BOARDCTL_UNIQUEID_SIZE];
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: __compiler_memory_barrier
|
||||
*
|
||||
* Description:
|
||||
* Prevent compiler from moving memory access across this barrier.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void __compiler_memory_barrier(void)
|
||||
{
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rom_hword_as_ptr
|
||||
*
|
||||
* Description:
|
||||
* Converts a (well known) address value into a pointer to that address.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline void *rom_hword_as_ptr(uint16_t rom_address)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Warray-bounds"
|
||||
return (void *)(uintptr_t)*(uint16_t *)(uintptr_t)rom_address;
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: <Static function name>
|
||||
*
|
||||
* Description:
|
||||
* Return a bootrom lookup code based on two ASCII characters.
|
||||
*
|
||||
* Input Parameters:
|
||||
* uint8_t c1: first character
|
||||
* uint8_t c2: second character
|
||||
*
|
||||
* Returned Value:
|
||||
* A code to use with rf_lookup
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static inline uint32_t rom_table_code(uint8_t c1, uint8_t c2)
|
||||
{
|
||||
return ROM_TABLE_CODE((uint32_t) c1, (uint32_t) c2);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rf_lookup
|
||||
*
|
||||
* Description:
|
||||
* Lookup a bootrom function by code.
|
||||
*
|
||||
* Input Parameters:
|
||||
* uint32_t code: A code from rom_table_code()
|
||||
*
|
||||
* Returned Value:
|
||||
* a pointer to the function, or NULL if the code does not match any
|
||||
* bootrom function
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
always_inline_function static void *rf_lookup(uint32_t code)
|
||||
{
|
||||
rom_table_lookup_fn rom_table_lookup;
|
||||
rom_table_lookup = (rom_table_lookup_fn) rom_hword_as_ptr(0x18);
|
||||
uint16_t *func_table = (uint16_t *) rom_hword_as_ptr(0x14);
|
||||
return rom_table_lookup(func_table, code);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: hw_xor_bits
|
||||
*
|
||||
* Description:
|
||||
* Helper function for flash_cs_force.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
always_inline_function static void hw_xor_bits(io_rw_32 *addr, uint32_t mask)
|
||||
{
|
||||
*(io_rw_32 *) hw_xor_alias_untyped((volatile void *) addr) = mask;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: hw_write_masked
|
||||
*
|
||||
* Description:
|
||||
* Helper function for flash_cs_force.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
always_inline_function static void hw_write_masked(io_rw_32 *addr,
|
||||
uint32_t values,
|
||||
uint32_t write_mask)
|
||||
{
|
||||
hw_xor_bits(addr, (*addr ^ values) & write_mask);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: flash_cs_force
|
||||
*
|
||||
* Description:
|
||||
* Override the chip select line to flash chip.
|
||||
*
|
||||
* Input Parameters:
|
||||
* bool high: true to force CS high, false to force low
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
noinline_function locate_code(".ram_code.flash_cs_force")
|
||||
static void flash_cs_force (bool high)
|
||||
{
|
||||
uint32_t field_val = high ?
|
||||
QSPI_SS_CTRL_OUTOVER_VALUE_HIGH :
|
||||
QSPI_SS_CTRL_OUTOVER_VALUE_LOW;
|
||||
hw_write_masked((io_rw_32 *)QSPI_SS_CTRL,
|
||||
field_val << QSPI_SS_CTRL_OUTOVER_LSB,
|
||||
QSPI_SS_CTRL_OUTOVER_BITS
|
||||
);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_flash_cmd
|
||||
*
|
||||
* Description:
|
||||
* Send a command to flash chip and receive the result.
|
||||
*
|
||||
* Input Parameters:
|
||||
* uint8_t* txbuf: Pointer to buffer to send
|
||||
* uint8_t* rxbuf: Pointer to buffer to hold received value
|
||||
* size_t count: Number of bytes to send / receive
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
noinline_function locate_code(".ram_code.rp2040_flash_cmd")
|
||||
void rp2040_flash_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count)
|
||||
{
|
||||
rom_cif_fn connect_internal_flash = (rom_cif_fn)rf_lookup(ROM_FUNC_CIF);
|
||||
rom_fex_fn flash_exit_xip = (rom_fex_fn)rf_lookup(ROM_FUNC_FEX);
|
||||
rom_ffc_fn flash_flush_cache = (rom_ffc_fn)rf_lookup(ROM_FUNC_FFC);
|
||||
|
||||
uint32_t boot2_copyout[BOOT2_SIZE_WORDS];
|
||||
for (int i = 0; i < BOOT2_SIZE_WORDS; ++i)
|
||||
boot2_copyout[i] = ((uint32_t *)XIP_BASE)[i];
|
||||
__compiler_memory_barrier();
|
||||
connect_internal_flash();
|
||||
flash_exit_xip();
|
||||
|
||||
flash_cs_force(0);
|
||||
size_t tx_cnt = count;
|
||||
size_t rx_cnt = count;
|
||||
|
||||
const size_t max_in_flight = 16 - 2;
|
||||
while (tx_cnt || rx_cnt)
|
||||
{
|
||||
uint32_t flags = *((uint32_t *)XIP_SSI_SR);
|
||||
|
||||
bool can_put = !!(flags & SSI_SR_TFNF_BITS);
|
||||
bool can_get = !!(flags & SSI_SR_RFNE_BITS);
|
||||
|
||||
if (can_put && tx_cnt && rx_cnt - tx_cnt < max_in_flight)
|
||||
{
|
||||
*((uint8_t *)XIP_SSI_DR0) = *txbuf++;
|
||||
--tx_cnt;
|
||||
}
|
||||
|
||||
if (can_get && rx_cnt)
|
||||
{
|
||||
*rxbuf++ = *((uint8_t *)XIP_SSI_DR0);
|
||||
--rx_cnt;
|
||||
}
|
||||
}
|
||||
|
||||
flash_cs_force(1);
|
||||
flash_flush_cache();
|
||||
((void (*)(void))((intptr_t)boot2_copyout + 1))(); /* re-enable xip */
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: rp2040_uniqueid_initialize
|
||||
*
|
||||
* Description:
|
||||
* The RP2040 doesn't have a unique ID, so we load the ID from the
|
||||
* connected flash chip. We use the flash ID to seed a simple xorshift
|
||||
* PRNG. The PRNG then generates CONFIG_BOARDCTL_UNIQUEID_SIZE bytes,
|
||||
* which we will use as the board's unique ID.
|
||||
*
|
||||
* Retrieving the flash id is somewhat slow and complex, so we only do
|
||||
* this during initialization and store the result for later use.
|
||||
*
|
||||
* Assumptions/Limitations:
|
||||
* This uniqueid implementation requires a flash chip. It should not be
|
||||
* used on boards without flash.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void rp2040_uniqueid_initialize(void)
|
||||
{
|
||||
uint64_t x;
|
||||
uint8_t txbuf[RP2040_FLASH_ID_BUFFER_SIZE];
|
||||
uint8_t rxbuf[RP2040_FLASH_ID_BUFFER_SIZE];
|
||||
|
||||
memset(g_uniqueid, 0xac, CONFIG_BOARDCTL_UNIQUEID_SIZE);
|
||||
memset(txbuf, 0, RP2040_FLASH_ID_BUFFER_SIZE);
|
||||
memset(rxbuf, 0, RP2040_FLASH_ID_BUFFER_SIZE);
|
||||
txbuf[0] = RP2040_FLASH_RUID_CMD;
|
||||
|
||||
rp2040_flash_cmd(txbuf, rxbuf, RP2040_FLASH_ID_BUFFER_SIZE);
|
||||
|
||||
/* xorshift PRNG: */
|
||||
|
||||
x = *(uint64_t *)(rxbuf + RP2040_FLASH_ID_BUFFER_OFFSET);
|
||||
for (int i = 0; i < CONFIG_BOARDCTL_UNIQUEID_SIZE; i++)
|
||||
{
|
||||
x ^= x >> 12;
|
||||
x ^= x << 25;
|
||||
x ^= x >> 27;
|
||||
g_uniqueid[i] = (uint8_t)((x * 0x2545f4914f6cdd1dull) >> 32);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: board_uniqueid
|
||||
*
|
||||
* Description:
|
||||
* Return a unique ID associated with the board.
|
||||
*
|
||||
* Input Parameters:
|
||||
* uniqueid - A reference to a writable memory location provided by the
|
||||
* caller to receive the board unique ID. The memory memory referenced
|
||||
* by this pointer must be at least CONFIG_BOARDCTL_UNIQUEID_SIZE in
|
||||
* length.
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) is returned on success. Otherwize a negated errno value is
|
||||
* returned indicating the nature of the failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int board_uniqueid(FAR uint8_t *uniqueid)
|
||||
{
|
||||
memcpy(uniqueid, g_uniqueid, CONFIG_BOARDCTL_UNIQUEID_SIZE);
|
||||
return OK;
|
||||
}
|
Loading…
Reference in New Issue
Block a user