You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2024/03/17 13:00:30 UTC

(nuttx) branch master updated: RP2040: Implement board_uniqueid()

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new b4407b529a RP2040: Implement board_uniqueid()
b4407b529a is described below

commit b4407b529a82b015afbcfe230cf54bc656da947f
Author: Adam Comley <ad...@novators.net>
AuthorDate: Thu Mar 14 21:55:30 2024 -0500

    RP2040: Implement board_uniqueid()
---
 LICENSE                                            |   1 +
 boards/arm/rp2040/common/include/rp2040_uniqueid.h |  69 +++++
 boards/arm/rp2040/common/src/Make.defs             |   4 +
 .../rp2040/common/src/rp2040_common_initialize.c   |   5 +
 boards/arm/rp2040/common/src/rp2040_uniqueid.c     | 341 +++++++++++++++++++++
 5 files changed, 420 insertions(+)

diff --git a/LICENSE b/LICENSE
index 425c003446..8913ecfb81 100644
--- a/LICENSE
+++ b/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.
diff --git a/boards/arm/rp2040/common/include/rp2040_uniqueid.h b/boards/arm/rp2040/common/include/rp2040_uniqueid.h
new file mode 100644
index 0000000000..46edcec3d8
--- /dev/null
+++ b/boards/arm/rp2040/common/include/rp2040_uniqueid.h
@@ -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 */
\ No newline at end of file
diff --git a/boards/arm/rp2040/common/src/Make.defs b/boards/arm/rp2040/common/src/Make.defs
index f7f13bce68..43c8a11cbc 100644
--- a/boards/arm/rp2040/common/src/Make.defs
+++ b/boards/arm/rp2040/common/src/Make.defs
@@ -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
diff --git a/boards/arm/rp2040/common/src/rp2040_common_initialize.c b/boards/arm/rp2040/common/src/rp2040_common_initialize.c
index 4a9058193f..d5bab584e6 100644
--- a/boards/arm/rp2040/common/src/rp2040_common_initialize.c
+++ b/boards/arm/rp2040/common/src/rp2040_common_initialize.c
@@ -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
diff --git a/boards/arm/rp2040/common/src/rp2040_uniqueid.c b/boards/arm/rp2040/common/src/rp2040_uniqueid.c
new file mode 100644
index 0000000000..653028c2bc
--- /dev/null
+++ b/boards/arm/rp2040/common/src/rp2040_uniqueid.c
@@ -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;
+}