diff --git a/arch/arm/src/Makefile b/arch/arm/src/Makefile index 5cb4485b54d..eddbc70ee9c 100644 --- a/arch/arm/src/Makefile +++ b/arch/arm/src/Makefile @@ -170,7 +170,7 @@ $(COBJS) $(UCOBJS): %$(OBJEXT): %.c $(call COMPILE, $<, $@) $(STARTUP_OBJS): %$(OBJEXT): %.c - $(Q) $(CC) $(CELFFLAGS) -c common$(DELIM)crt0.c -o crt0$(OBJEXT) + $(Q) $(CC) $(CELFFLAGS) $(CFLAGS) -c common$(DELIM)crt0.c -o crt0$(OBJEXT) ifeq ($(CONFIG_BUILD_FLAT),y) $(BIN): $(STARTUP_OBJS) $(OBJS) diff --git a/arch/arm/src/common/Make.defs b/arch/arm/src/common/Make.defs index c0722eb1f51..0615bcee580 100644 --- a/arch/arm/src/common/Make.defs +++ b/arch/arm/src/common/Make.defs @@ -20,6 +20,8 @@ # ############################################################################ +#include $(TOPDIR)/tools/Config.mk + STARTUP_OBJS = crt0$(OBJEXT) # Common ARM files diff --git a/arch/arm/src/rp23xx/Kconfig b/arch/arm/src/rp23xx/Kconfig index e53f6a54553..0bf2d40eed0 100644 --- a/arch/arm/src/rp23xx/Kconfig +++ b/arch/arm/src/rp23xx/Kconfig @@ -1059,3 +1059,46 @@ config RP23XX_BOARD_HAS_WS2812 ---help--- See the Board Selection menu to configure the pins used by ws2812. + + + +##################################################################### +# Flash File System Configuration +##################################################################### + +config RP23XX_FLASH_FILE_SYSTEM + bool "Configure a read/write filesystem on unused flash memory" + default n + select MTD + select MTD_SMART + select FS_SMARTFS + ---help--- + See the Board Selection menu to configure the size of the + flash chip for a particular board. + +if RP23XX_FLASH_FILE_SYSTEM + +config RP23XX_FLASH_MOUNT_POINT + string "mount point for flash file system" + default "/flash" + ---help--- + This is the mount point where the flash file system will + be mounted. Leave this string empty to prevent automatic + mounting of the filesystem. + +endif # RP23XX_FLASH_FILE_SYSTEM + + +##################################################################### +# FLASH File System Configuration +##################################################################### + +if RP23XX_FLASH_FILE_SYSTEM + +config RP23XX_FLASH_LENGTH + int "Size of flash memory in bytes." + default 2097152 + ---help--- + This is the overall amount of flash memory on the board. + +endif # RP23XX_FLASH_FILE_SYSTEM diff --git a/arch/arm/src/rp23xx/Make.defs b/arch/arm/src/rp23xx/Make.defs index 9a94796a0d9..d110212b247 100644 --- a/arch/arm/src/rp23xx/Make.defs +++ b/arch/arm/src/rp23xx/Make.defs @@ -88,3 +88,8 @@ endif ifeq ($(CONFIG_WATCHDOG),y) CHIP_CSRCS += rp23xx_wdt.c endif + +ifeq ($(CONFIG_RP23XX_FLASH_FILE_SYSTEM),y) +CHIP_CSRCS += rp23xx_flash_mtd.c +CHIP_ASRCS += rp23xx_flash_initialize.S +endif diff --git a/arch/arm/src/rp23xx/rp23xx_cpupause.c b/arch/arm/src/rp23xx/rp23xx_cpupause.c new file mode 100644 index 00000000000..bb451e05166 --- /dev/null +++ b/arch/arm/src/rp23xx/rp23xx_cpupause.c @@ -0,0 +1,438 @@ +/**************************************************************************** + * arch/arm/src/rp2040/rp2040_cpupause.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 + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sched/sched.h" +#include "arm_internal.h" +#include "hardware/rp23xx_sio.h" + +#ifdef CONFIG_SMP + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#if 0 +#define DPRINTF(fmt, args...) llinfo(fmt, ##args) +#else +#define DPRINTF(fmt, args...) do {} while (0) +#endif + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* These spinlocks are used in the SMP configuration in order to implement + * up_cpu_pause(). The protocol for CPUn to pause CPUm is as follows + * + * 1. The up_cpu_pause() implementation on CPUn locks both g_cpu_wait[m] + * and g_cpu_paused[m]. CPUn then waits spinning on g_cpu_paused[m]. + * 2. CPUm receives the interrupt it (1) unlocks g_cpu_paused[m] and + * (2) locks g_cpu_wait[m]. The first unblocks CPUn and the second + * blocks CPUm in the interrupt handler. + * + * When CPUm resumes, CPUn unlocks g_cpu_wait[m] and the interrupt handler + * on CPUm continues. CPUm must, of course, also then unlock g_cpu_wait[m] + * so that it will be ready for the next pause operation. + */ + +static volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS]; +static volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS]; + +/**************************************************************************** + * Name: rp23xx_handle_irqreq + * + * Description: + * If an irq handling request is found on cpu, call up_enable_irq() or + * up_disable_irq(). + * + * Input Parameters: + * irqreq - The IRQ number to be handled (>0 : enable / <0 : disable) + * + ****************************************************************************/ + +static void rp23xx_handle_irqreq(int irqreq) +{ + DEBUGASSERT(up_cpu_index() == 0); + + /* Unlock the spinlock first */ + + spin_unlock(&g_cpu_paused[0]); + + /* Then wait for the spinlock to be released */ + + spin_lock(&g_cpu_wait[0]); + + if (irqreq > 0) + { + up_enable_irq(irqreq); + } + else + { + up_disable_irq(-irqreq); + } + + /* Finally unlock the spinlock */ + + spin_unlock(&g_cpu_wait[0]); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_cpu_pausereq + * + * Description: + * Return true if a pause request is pending for this CPU. + * + * Input Parameters: + * cpu - The index of the CPU to be queried + * + * Returned Value: + * true = a pause request is pending. + * false = no pasue request is pending. + * + ****************************************************************************/ + +bool up_cpu_pausereq(int cpu) +{ + return spin_islocked(&g_cpu_paused[cpu]); +} + +/**************************************************************************** + * Name: up_cpu_paused + * + * Description: + * Handle a pause request from another CPU. Normally, this logic is + * executed from interrupt handling logic within the architecture-specific + * However, it is sometimes necessary necessary to perform the pending + * pause operation in other contexts where the interrupt cannot be taken + * in order to avoid deadlocks. + * + * This function performs the following operations: + * + * 1. It saves the current task state at the head of the current assigned + * task list. + * 2. It waits on a spinlock, then + * 3. Returns from interrupt, restoring the state of the new task at the + * head of the ready to run list. + * + * Input Parameters: + * cpu - The index of the CPU to be paused + * + * Returned Value: + * On success, OK is returned. Otherwise, a negated errno value indicating + * the nature of the failure is returned. + * + ****************************************************************************/ + +int up_cpu_paused(int cpu) +{ + struct tcb_s *tcb = this_task(); + + /* Update scheduler parameters */ + + nxsched_suspend_scheduler(tcb); + +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify that we are paused */ + + sched_note_cpu_paused(tcb); +#endif + + /* Save the current context at CURRENT_REGS into the TCB at the head + * of the assigned task list for this CPU. + */ + + arm_savestate(tcb->xcp.regs); + + /* Wait for the spinlock to be released */ + + spin_unlock(&g_cpu_paused[cpu]); + spin_lock(&g_cpu_wait[cpu]); + + /* Restore the exception context of the tcb at the (new) head of the + * assigned task list. + */ + + tcb = this_task(); + +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify that we have resumed */ + + sched_note_cpu_resumed(tcb); +#endif + + /* Reset scheduler parameters */ + + nxsched_resume_scheduler(tcb); + + /* Then switch contexts. Any necessary address environment changes + * will be made when the interrupt returns. + */ + + arm_restorestate(tcb->xcp.regs); + spin_unlock(&g_cpu_wait[cpu]); + + return OK; +} + +/**************************************************************************** + * Name: arm_pause_handler + * + * Description: + * Inter-CPU interrupt handler + * + * Input Parameters: + * Standard interrupt handler inputs + * + * Returned Value: + * Should always return OK + * + ****************************************************************************/ + +int arm_pause_handler(int irq, void *c, void *arg) +{ + int cpu = up_cpu_index(); + int irqreq; + uint32_t stat; + + stat = getreg32(RP23XX_SIO_FIFO_ST); + if (stat & (RP23XX_SIO_FIFO_ST_ROE | RP23XX_SIO_FIFO_ST_WOF)) + { + /* Clear sticky flag */ + + putreg32(0, RP23XX_SIO_FIFO_ST); + } + + if (!(stat & RP23XX_SIO_FIFO_ST_VLD)) + { + /* No data received */ + + return OK; + } + + irqreq = getreg32(RP23XX_SIO_FIFO_RD); + + if (irqreq != 0) + { + /* Handle IRQ enable/disable request */ + + rp23xx_handle_irqreq(irqreq); + return OK; + } + + DPRINTF("cpu%d will be paused\n", cpu); + + /* Check for false alarms. Such false could occur as a consequence of + * some deadlock breaking logic that might have already serviced the SG2 + * interrupt by calling up_cpu_paused. + */ + + if (up_cpu_pausereq(cpu)) + { + /* NOTE: The following enter_critical_section() will call + * up_cpu_paused() to process a pause request to break a deadlock + * because the caller held a critical section. Once up_cpu_paused() + * finished, the caller will proceed and release the g_cpu_irqlock. + * Then this CPU will acquire g_cpu_irqlock in the function. + */ + + irqstate_t flags = enter_critical_section(); + + /* NOTE: the pause request should not exist here */ + + DEBUGVERIFY(!up_cpu_pausereq(cpu)); + + leave_critical_section(flags); + } + + return OK; +} + +/**************************************************************************** + * Name: up_cpu_pause + * + * Description: + * Save the state of the current task at the head of the + * g_assignedtasks[cpu] task list and then pause task execution on the + * CPU. + * + * This function is called by the OS when the logic executing on one CPU + * needs to modify the state of the g_assignedtasks[cpu] list for another + * CPU. + * + * Input Parameters: + * cpu - The index of the CPU to be stopped/ + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int up_cpu_pause(int cpu) +{ + DPRINTF("cpu=%d\n", cpu); + + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu()); + +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify of the pause event */ + + sched_note_cpu_pause(this_task(), cpu); +#endif + + /* Take the both spinlocks. The g_cpu_wait spinlock will prevent the SGI2 + * handler from returning until up_cpu_resume() is called; g_cpu_paused + * is a handshake that will prefent this function from returning until + * the CPU is actually paused. + * Note that we might spin before getting g_cpu_wait, this just means that + * the other CPU still hasn't finished responding to the previous resume + * request. + */ + + DEBUGASSERT(!spin_islocked(&g_cpu_paused[cpu])); + + spin_lock(&g_cpu_wait[cpu]); + spin_lock(&g_cpu_paused[cpu]); + + DEBUGASSERT(cpu != up_cpu_index()); + + /* Generate IRQ for CPU(cpu) */ + + while (!(getreg32(RP23XX_SIO_FIFO_ST) & RP23XX_SIO_FIFO_ST_RDY)) + ; + putreg32(0, RP23XX_SIO_FIFO_WR); + + /* Wait for the other CPU to unlock g_cpu_paused meaning that + * it is fully paused and ready for up_cpu_resume(); + */ + + spin_lock(&g_cpu_paused[cpu]); + spin_unlock(&g_cpu_paused[cpu]); + + /* On successful return g_cpu_wait will be locked, the other CPU will be + * spinning on g_cpu_wait and will not continue until g_cpu_resume() is + * called. g_cpu_paused will be unlocked in any case. + */ + + return 0; +} + +/**************************************************************************** + * Name: up_cpu_resume + * + * Description: + * Restart the cpu after it was paused via up_cpu_pause(), restoring the + * state of the task at the head of the g_assignedtasks[cpu] list, and + * resume normal tasking. + * + * This function is called after up_cpu_pause in order resume operation of + * the CPU after modifying its g_assignedtasks[cpu] list. + * + * Input Parameters: + * cpu - The index of the CPU being re-started. + * + * Returned Value: + * Zero on success; a negated errno value on failure. + * + ****************************************************************************/ + +int up_cpu_resume(int cpu) +{ + DPRINTF("cpu=%d\n", cpu); + + DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu()); + +#ifdef CONFIG_SCHED_INSTRUMENTATION + /* Notify of the resume event */ + + sched_note_cpu_resume(this_task(), cpu); +#endif + + /* Release the spinlock. Releasing the spinlock will cause the SGI2 + * handler on 'cpu' to continue and return from interrupt to the newly + * established thread. + */ + + DEBUGASSERT(spin_islocked(&g_cpu_wait[cpu]) && + !spin_islocked(&g_cpu_paused[cpu])); + + spin_unlock(&g_cpu_wait[cpu]); + return 0; +} + +/**************************************************************************** + * Name: rp23xx_send_irqreq() + * + * Description: + * Send up_enable_irq() / up_disable_irq() request to the Core #0 + * + * This function is called from up_enable_irq() or up_disable_irq() + * to be handled on specified CPU. Locking protocol in the sequence is + * the same as up_pause_cpu() plus up_resume_cpu(). + * + * Input Parameters: + * irqreq - The IRQ number to be handled (>0 : enable / <0 : disable) + * + ****************************************************************************/ + +void rp23xx_send_irqreq(int irqreq) +{ + /* Wait for the spinlocks to be released */ + + spin_lock(&g_cpu_wait[0]); + spin_lock(&g_cpu_paused[0]); + + /* Send IRQ number to Core #0 */ + + while (!(getreg32(RP23XX_SIO_FIFO_ST) & RP23XX_SIO_FIFO_ST_RDY)) + ; + putreg32(irqreq, RP23XX_SIO_FIFO_WR); + + /* Wait for the handler is executed on cpu */ + + spin_lock(&g_cpu_paused[0]); + spin_unlock(&g_cpu_paused[0]); + + /* Finally unlock the spinlock to proceed the handler */ + + spin_unlock(&g_cpu_wait[0]); + return; +} + +#endif /* CONFIG_SMP */ diff --git a/arch/arm/src/rp23xx/rp23xx_flash_initialize.S b/arch/arm/src/rp23xx/rp23xx_flash_initialize.S new file mode 100644 index 00000000000..d551e34d633 --- /dev/null +++ b/arch/arm/src/rp23xx/rp23xx_flash_initialize.S @@ -0,0 +1,197 @@ +/**************************************************************************** + * arch/arm/src/rp2040/rp2040_flash_initialize.S + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Description: + * The low-level format of the smart filesystem for the rp2040 consists of + * a series of 4096-byte blocks each of which contain four 1024 byte + * logical sectors. Due to the way flash works the filesystem can only + * erase (set to all 1 bits) a whole block. It can however, write smaller + * amounts. On the rp2040 the smallest write is 256 bytes. The write can + * only flip 1 bits to 0 -- it cannot change a 0 bit to 1. + * + * Each logical sector starts with a five byte sector header. Most sectors + * follow this with a five byte filesystem header. Sector zero does not + * follow this rule; it contains the volume label. + * + * The volume will have root directory located in logical sector three. It + * may have additional root directories (indicated by a count in the volume + * label). This will be in sequential sectors starting with sector four. + * + * Actual files and other subdirectories start in logical sector twelve. + * + * == SECTOR HEADER == + * + * Logical sector number: 2 bytes + * Sequence number: 2 bytes + * Flags: 1 byte + * + * Flag bits are: C R X S S S V V + * C - Set to zero if block committed 0 + * R - Set to zero if block erased 1 + * X - CRC status 1 + * S - Size Code 010 + * V - Version code 01 + * + * The logical sector number does not have to match the actual position + * of a sector. The volume in scanned when mounted and the mapping of + * sector number to position in volume is maintained in ram. If a sector + * is written to it will be re-written to a new location. + * + * == VOLUME LABEL == + * + * Sector zero is the volume label. It currently consists of the + * following fields. + * + * Smart Volume ID: 4 bytes "SMRT" + * Smart version: 1 byte 0x01 + * Sector size flag: 1 byte 0x10 + * Extra Root Directories: 1 byte 0x00 + * + * == FILE SYSTEM HEADER == + * + * File and directory sectors have a filesystem header directly following + * the sector header. This filesystem header consists of: + * + * Entry type: 1 byte 0x01 = Directory, 0x02 = File. + * Next logical sector: 2 bytes 0xff no more sectors + * Number of bytes used 2 bytes 0xff empty sector + * + * == DIRECTORY ENTRIES == + * + * Directory Flags: 2 bytes + * + * == FILE ENTRIES == + * + * File data starts following the filesystem header and extends + * for a number of bytes as specified in the filesystem header. + * + * Files with a length of greater that 1019 bytes will span multiple + * sectors, linked with the next logical sector flag. + ****************************************************************************/ + +dir= 1 +file= 2 +name_length= 16 + +/**************************************************************************** + * Name: sector + * + * Description: + * This macro defines a sector header. It actually sets both the actual + * sector header and the filesystem header values. + * + * Parameters: + * num - The logical sector number. Each sector must be unique. + * type - The sector type. Should be 'dir' or 'file' + * used - The length of the data in this sector. + * next - The logical sector number of the next sector in a chain. + ****************************************************************************/ + + .macro sector num, type, used=0xffff, next=0xffff + .balign 1024, 0xff + .hword \num, 0 + .byte 0b01101001, \type + .hword \next, \used + .endm + +/**************************************************************************** + * Name: dir_entry + * + * Description: + * This macro defines a directory entry. + * + * Parameters: + * perm - Permission bits for this directory entry + * addr - Logical sector number of named entry + * time - entry creation time stamp + * name - name of this entry + ****************************************************************************/ + + .macro dir_entry perm, addr, time, name + .hword \perm | 0x7e00, \addr + .word \time +0: + .ascii "\name" +.= 0b + name_length + .endm + +/**************************************************************************** + * Name: file_entry + * + * Description: + * This macro defines a directory entry. + * + * Parameters: + * perm - Permission bits for this directory entry + * addr - Logical sector number of named entry + * time - entry creation time stamp + * name - name of this entry + ****************************************************************************/ + + .macro file_entry perm, addr, time, name + .hword \perm | 0x5e00, \addr + .word \time +0: + .ascii "\name" +.= 0b + name_length + .endm + +/**************************************************************************** + * Global name of the initial filesystem data + ****************************************************************************/ + + .cpu cortex-m33 + .thumb + + .section .flash.init, "ax" + .balign 4096 + .global rp2040_smart_flash_start +rp2040_smart_flash_start: + +/**************************************************************************** + * Volume Label + ****************************************************************************/ + + .ascii "2040" /* magic tag for flash initialization */ + .byte 0b01101001 + .ascii "SMRT" + .byte 0x01, 0x10, 0 + + .balign 4096, 0xff + +/**************************************************************************** + * Root directory and initial files in the filesystem + ****************************************************************************/ + + sector 3, dir + file_entry 0777, 4, 0, "test" + + sector 4, file, used=14 + .ascii "Hello, world!\n" + + + .balign 4096, 0xff + .global rp2040_smart_flash_end +rp2040_smart_flash_end: + + .end diff --git a/arch/arm/src/rp23xx/rp23xx_flash_mtd.c b/arch/arm/src/rp23xx/rp23xx_flash_mtd.c new file mode 100644 index 00000000000..de7ac9d07c9 --- /dev/null +++ b/arch/arm/src/rp23xx/rp23xx_flash_mtd.c @@ -0,0 +1,615 @@ +/**************************************************************************** + * arch/arm/src/rp2040/rp2040_flash_mtd.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * This code implements a Sector Mapped Allocation for Really Tiny (SMART) + * filesystem in the RP2040 flash memory chip. It uses the space not + * otherwise used by the NuttX binary and supports both read and write + * access. + * + * There initial contents of this filesystem may be configured when a NuttX + * binary is built (using tools/rp2040/make_flash_fs.c), but any changes + * subsequently written to the filesystem will persist over re-boots of the + * RP2040. + * + * Note: Although read access to any data stored in this filesystem is very + * rapid; because of how the RP2040's flash access routines work with + * the normal execute-in-place (XIP) access to that chip, no code can + * access flash in the normal manner when this filesystem is erasing + * or writing blocks. This means that interrupts must be disabled + * during any such access. The main issue with this is that any + * application which requires precise timing or rapid response may + * be negatively impacted by such operations. + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include "rp23xx_flash_mtd.h" +#include "rp23xx_rom.h" + +#include +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +// https://github.com/raspberrypi/pico-sdk/blob/ee68c78d0afae2b69c03ae1a72bf5cc267a2d94c/src/rp2350/hardware_regs/include/hardware/regs/addressmap.h#L27 +#define XIP_BASE 0x10000000 +#define XIP_NOCACHE_NOALLOC_BASE 0x14000000 +#define FLASH_BLOCK_ERASE_CMD 0x20 +// FIXME: Boot ROM: +// Each RP2350 device contains 32 kB of mask ROM: a physically immutable memory resource +// Unlike RP2040, there is no requirement for flash binaries to have a checksummed "boot2" flash setup function at flash +// address 0. + +// FIXME: Boot RAM +// is a 1 kB (256 × 32-bit) SRAM dedicated for use by the bootrom. It is *slower than main SRAM*, as it is +// accessed over APB, taking three cycles for a read and four cycles for a write. +// contains: +// - a copy of the flash XIP setup function (formerly known as boot2) to +// quickly reinitialise flash XIP modes following serial programming operations. +// It is physically impossible to execute code from boot RAM, +#define BOOT_2_SIZE 256 +// flash_initialize.S +#define FLASH_START_OFFSET (rp2040_smart_flash_start - (uint8_t *)XIP_BASE) +#define FLASH_END_OFFSET (rp2040_smart_flash_end - (uint8_t *)XIP_BASE) +// within XIP_NOCACHE_NOALLOC_BASE to disable cache +#define FLASH_START_READ (rp2040_smart_flash_start + 0x04000000) // RP2350 has different address than RP2040 ! + +// FIXME cleanup +#define CONFIG_RP2040_FLASH_LENGTH ( CONFIG_RP23XX_FLASH_LENGTH ) + +/* Note: There is some ambiguity in terminology when it comes to flash. + * Some call the chunk that can be erased a sector where others + * call that a block. + * + * Some call the chunk that can be written a sector where others + * call that a page. + */ + +/* Blocks are the smallest unit that can be erased */ +// FIXME: bigger is faster? 64K ? + +#define FLASH_BLOCK_SIZE (4 * 1024) +#define FLASH_BLOCK_COUNT (CONFIG_RP2040_FLASH_LENGTH - FLASH_START_OFFSET)\ + / FLASH_BLOCK_SIZE + +/* Sectors are the smallest unit that can be written */ + +#define FLASH_SECTOR_SIZE 256 +#define FLASH_SECTOR_COUNT (CONFIG_RP2040_FLASH_LENGTH - FLASH_START_OFFSET)\ + / FLASH_SECTOR_SIZE + +#ifdef CONFIG_SMP +# define OTHER_CPU (this_cpu() == 0 ? 1 : 0) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef struct rp2040_flash_dev_s +{ + struct mtd_dev_s mtd_dev; /* Embedded mdt_dev structure */ + mutex_t lock; /* file access serialization */ + uint32_t boot_2[BOOT_2_SIZE / 4]; /* RAM copy of boot_2 : FIXME - or this is bootrom !!! */ +} rp2040_flash_dev_t; + +typedef void (*connect_internal_flash_f)(void); +typedef void (*flash_exit_xip_f)(void); +typedef void (*flash_range_erase_f)(uint32_t, size_t, uint32_t, uint8_t); +typedef void (*flash_range_program_f)(uint32_t, const uint8_t *, size_t); +typedef void (*flash_flush_cache_f)(void); +typedef void (*flash_enable_xip_f)(void); + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int rp2040_flash_erase (struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks); + +static ssize_t rp2040_flash_block_read (struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + uint8_t *buffer); + +static ssize_t rp2040_flash_block_write(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + const uint8_t *buffer); + +static ssize_t rp2040_flash_byte_read (struct mtd_dev_s *dev, + off_t offset, + size_t nbytes, + uint8_t *buffer); + +static int rp2040_flash_ioctl (struct mtd_dev_s *dev, + int cmd, + unsigned long arg); + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +extern const uint8_t rp2040_smart_flash_start[256]; +extern const uint8_t rp2040_smart_flash_end[0]; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct rp2040_flash_dev_s my_dev = +{ + .mtd_dev = + { + rp2040_flash_erase, + rp2040_flash_block_read, + rp2040_flash_block_write, + rp2040_flash_byte_read, +#ifdef CONFIG_MTD_BYTE_WRITE + NULL, +#endif + rp2040_flash_ioctl, + NULL, + NULL, + "rp_flash" + }, + .lock = NXMUTEX_INITIALIZER, +}; + +static bool initialized = false; + +static struct +{ + connect_internal_flash_f connect_internal_flash; + flash_exit_xip_f flash_exit_xip; + flash_range_erase_f flash_range_erase; + flash_range_program_f flash_range_program; + flash_flush_cache_f flash_flush_cache; + flash_enable_xip_f flash_enable_xip; +} rom_functions; + +void *boot_2_copy = NULL; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: do_erase + ****************************************************************************/ + +void RAM_CODE(do_erase)(uint32_t addr, size_t count) +{ + /* Note: While we would prefer not to flush the cache, the + * flash_flush_cache call is needed to remove CSn IO force. + */ + + __asm__ volatile ("" : : : "memory"); + + rom_functions.connect_internal_flash(); + + rom_functions.flash_exit_xip(); + + /* The range erase will try to erase 65536-byte blocks with the 0xd8 flash + * command. If it cannot, because either the addr or count are not + * multiple of 65536, it will fall back to erasing 4096-byte blocks as + * needed. + */ + + rom_functions.flash_range_erase(addr, count, 65536, 0xd8); + + rom_functions.flash_flush_cache(); + + rom_functions.flash_enable_xip(); +} + +/**************************************************************************** + * Name: do_write + ****************************************************************************/ + +void RAM_CODE(do_write)(uint32_t addr, const uint8_t *data, size_t count) +{ + /* Note: While we would prefer not to flush the cache, the + * flash_flush_cache call is needed to remove CSn IO force. + */ + + __asm__ volatile ("" : : : "memory"); + + rom_functions.connect_internal_flash(); + + rom_functions.flash_exit_xip(); + + rom_functions.flash_range_program(addr, (uint8_t *)data, count); + + rom_functions.flash_flush_cache(); + + rom_functions.flash_enable_xip(); +} + +/**************************************************************************** + * Name: rp2040_flash_erase + ****************************************************************************/ + +static int rp2040_flash_erase(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks) +{ + rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *)dev; + irqstate_t flags; + int ret = OK; + + finfo("FLASH: erase block: %8u (0x%08x) count:%5u (0x%08X)\n", + (unsigned)(startblock), + (unsigned)(FLASH_BLOCK_SIZE * startblock + FLASH_START_OFFSET), + nblocks, + FLASH_BLOCK_SIZE * nblocks); + + ret = nxmutex_lock(&rp_dev->lock); + if (ret < 0) + { + return ret; + } + + flags = enter_critical_section(); + +#ifdef CONFIG_SMP + up_cpu_pause(OTHER_CPU); +#endif + + do_erase(FLASH_BLOCK_SIZE * startblock + FLASH_START_OFFSET, + FLASH_BLOCK_SIZE * nblocks); + +#ifdef CONFIG_SMP + up_cpu_resume(OTHER_CPU); +#endif + + leave_critical_section(flags); + + ret = nblocks; + + nxmutex_unlock(&rp_dev->lock); + return ret; +} + +/**************************************************************************** + * Name: rp2040_flash_block_read + ****************************************************************************/ + +static ssize_t rp2040_flash_block_read(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + uint8_t *buffer) +{ + rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *)dev; + int start; + int length; + int ret = OK; + + ret = nxmutex_lock(&rp_dev->lock); + if (ret < 0) + { + return ret; + } + + finfo("FLASH: read sector: %8u (0x%08x) count:%5u\n", + (unsigned)(startblock), + (unsigned)(FLASH_SECTOR_SIZE * startblock + FLASH_START_OFFSET), + nblocks); + + start = FLASH_SECTOR_SIZE * startblock; + length = FLASH_SECTOR_SIZE * nblocks; + + /* This reads starting at XIP_NOCACHE_NOALLOC_BASE to bypass the + * XIP cache. This is done because flash programming does not update + * the cache and we don't want to read stale data. Since we expect + * access to the flash filesystem to be rather infrequent this isn't + * really much of a burden. + */ + + memcpy(buffer, FLASH_START_READ + start, length); + + /* Update the file position */ + + nxmutex_unlock(&rp_dev->lock); + return nblocks; +} + +/**************************************************************************** + * Name: rp2040_flash_write + ****************************************************************************/ + +static ssize_t rp2040_flash_block_write(struct mtd_dev_s *dev, + off_t startblock, + size_t nblocks, + const uint8_t *buffer) +{ + rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *)dev; + irqstate_t flags; + int ret; + + ret = nxmutex_lock(&rp_dev->lock); + if (ret < 0) + { + return ret; + } + + flags = enter_critical_section(); + +#ifdef CONFIG_SMP + up_cpu_pause(OTHER_CPU); +#endif + + do_write(FLASH_SECTOR_SIZE * startblock + FLASH_START_OFFSET, + buffer, + FLASH_SECTOR_SIZE * nblocks); + +#ifdef CONFIG_SMP + up_cpu_resume(OTHER_CPU); +#endif + + leave_critical_section(flags); + + finfo("FLASH: write sector: %8u (0x%08x) count:%5u\n", + (unsigned)(startblock), + (unsigned)(FLASH_SECTOR_SIZE * startblock + FLASH_START_OFFSET), + nblocks); + +#ifdef CONFIG_DEBUG_FS_INFO + for (int i = 0; i < FLASH_SECTOR_SIZE * nblocks; i += 16) + { + for (int j = 0; j < 16; ++j) + { + printf("%02x, ", buffer[i + j]); + } + + printf("\n"); + } +#endif + + ret = nblocks; + + nxmutex_unlock(&rp_dev->lock); + return ret; +} + +/**************************************************************************** + * Name: rp2040_flash_byte_read + ****************************************************************************/ + +static ssize_t rp2040_flash_byte_read(struct mtd_dev_s *dev, + off_t offset, + size_t nbytes, + uint8_t *buffer) +{ + rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *)dev; + int length; + int ret = OK; + + ret = nxmutex_lock(&rp_dev->lock); + if (ret < 0) + { + return ret; + } + + length = nbytes; + + finfo("FLASH: read bytes: %8u (0x%08x) count:%5u\n", + (unsigned)(offset), + (unsigned)(offset + FLASH_START_OFFSET), + nbytes); + + /* This reads starting at XIP_NOCACHE_NOALLOC_BASE to bypass the + * XIP cache. This is done because flash programming does not update + * the cache and we don't want to read stale data. Since we expect + * access to the flash filesystem to be rather infrequent this isn't + * really much of a burden. + */ + + memcpy(buffer, FLASH_START_READ + offset, length); + +#ifdef CONFIG_DEBUG_FS_INFO + for (int j = 0; j < 16 && j < nbytes; ++j) + { + printf("%02x, ", buffer[j]); + } + + printf("\n"); +#endif + + /* Update the file position */ + + nxmutex_unlock(&rp_dev->lock); + return length; +} + +/**************************************************************************** + * Name: rp2040_flash_ioctl + ****************************************************************************/ + +static int rp2040_flash_ioctl(struct mtd_dev_s *dev, + int cmd, + unsigned long arg) +{ + rp2040_flash_dev_t *rp_dev = (rp2040_flash_dev_t *)dev; + int ret = OK; + + UNUSED(rp_dev); + + switch (cmd) + { + case MTDIOC_GEOMETRY: + { + struct mtd_geometry_s *geo = (struct mtd_geometry_s *)arg; + + if (geo != NULL) + { + memset(geo, 0, sizeof(*geo)); + + geo->blocksize = FLASH_SECTOR_SIZE; + geo->erasesize = FLASH_BLOCK_SIZE; + geo->neraseblocks = FLASH_BLOCK_COUNT; + } + + break; + } + + case MTDIOC_BULKERASE: + { + /* Erase all the filesystem blocks for the device. Remember that + * we share this device with XIP memory so we cannot erase entire + * device. + */ + + ret = rp2040_flash_erase(dev, 0, FLASH_BLOCK_COUNT); + + break; + } + + default: + ret = -ENOTTY; + } + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: rp2040_flash_initialize + * + * Description: Bind a block mode driver that uses the built-in rp2040 + * flash programming commands for read/write access to unused flash. + ****************************************************************************/ + +struct mtd_dev_s *rp23xx_flash_mtd_initialize(void) +{ + if (initialized) + { + errno = EBUSY; + return NULL; + } + + initialized = true; + + if (FLASH_BLOCK_COUNT < 4) + { + errno = ENOMEM; + return NULL; + } + + rom_functions.connect_internal_flash = ROM_LOOKUP(ROM_FUNC_CONNECT_INTERNAL_FLASH); + rom_functions.flash_exit_xip = ROM_LOOKUP(ROM_FUNC_FLASH_EXIT_XIP); + rom_functions.flash_range_erase = ROM_LOOKUP(ROM_FUNC_FLASH_RANGE_ERASE); + rom_functions.flash_range_program = ROM_LOOKUP(ROM_FUNC_FLASH_RANGE_PROGRAM); + rom_functions.flash_flush_cache = ROM_LOOKUP(ROM_FUNC_FLASH_FLUSH_CACHE); + // FIXME: for now using impl from ROM, is there a better one? no boot2 @ RP2350 inst there? + rom_functions.flash_enable_xip = ROM_LOOKUP(ROM_FUNC_FLASH_ENTER_CMD_XIP); + + /* Instead of using the rom_function for flash_enable_xip, we use the one + * from boot stage 2 loaded at the beginning of the XIP rom. We do this + * because the boot_rom version can result in slower access to the the + * XIP memory. + * + * We need to make our own copy of this code in ram since we cannot use + * the rom until after this call completes. + */ + + // FIXME: RP2350 would need a change here?!!! + //memcpy(my_dev.boot_2, (void *)XIP_BASE, BOOT_2_SIZE); + // rom_functions.flash_enable_xip = (flash_enable_xip_f)my_dev.boot_2 + 1; + + /* RP2350 Manual: + *Boot RAM*: + is used for myriad purposes during boot, including the initial pre-boot stack. After the bootrom enters the + user application, boot RAM contains state for the user-facing ROM APIs, such as the resident partition table used for + flash programming protection, + and a copy of the flash XIP setup function (formerly known as boot2) to quickly reinitialise flash XIP modes + following serial programming operations. + + Boot RAM is hardwired to permit Secure access only (Arm) or Machine-mode access only (RISC-V). + *It is physically impossible to execute code from boot RAM*, + regardless of MPU configuration, as it is on the APB peripheral bus + segment, which is not wired to the processor instruction fetch ports. + + above the boot RAM base address of 0x400e0000 (defined as BOOTRAM_BASE in the SDK). + --- + You should save your XIP setup function in the first 256 bytes of boot RAM to make it easily locatable when the XIP + mode is re-initialised following a serial flash programming operation which had to drop out of XIP mode. The bootrom + writes a default XIP setup function to this address before entering the flash image, which restores the mode the + bootrom discovered during flash programming. + -- + You cannot execute an XIP setup function directly from boot RAM, because boot RAM is never executable. You must + copy it into SRAM before execution. + + 5.4. Bootrom APIs (p. 376, 379) + + + • Using the QSPI direct-mode interface to program the flash causes XIP access to return a bus fault. + + + */ + + /* Do we need to initialize the flash? */ + // FIXME: rom_functions are NULL now - this fails, w/o init ok, /flash exists (empty), and /dev/smart0 too, but not writeable + if (true && memcmp(rp2040_smart_flash_start, "2040", 4) == 0) + { + uint8_t buffer[FLASH_SECTOR_SIZE]; + irqstate_t flags = enter_critical_section(); + + /* OK, we found the "magic" tag... */ + + /* Erase all flash beyond what was loaded from NuttX binary. */ + + do_erase(FLASH_END_OFFSET, + CONFIG_RP2040_FLASH_LENGTH - FLASH_END_OFFSET); + + /* Erase the "magic" flag, setting the first two bytes to zero. */ + + memcpy(buffer, rp2040_smart_flash_start, FLASH_SECTOR_SIZE); + + buffer[0] = 0; + buffer[1] = 0; + + do_write(FLASH_START_OFFSET, buffer, FLASH_SECTOR_SIZE); + + leave_critical_section(flags); + } + + return &(my_dev.mtd_dev); +} diff --git a/arch/arm/src/rp23xx/rp23xx_flash_mtd.h b/arch/arm/src/rp23xx/rp23xx_flash_mtd.h new file mode 100644 index 00000000000..f2371d1ebdb --- /dev/null +++ b/arch/arm/src/rp23xx/rp23xx_flash_mtd.h @@ -0,0 +1,37 @@ +/**************************************************************************** + * arch/arm/src/rp2040/rp2040_flash_mtd.h + * + * SPDX-License-Identifier: Apache-2.0 + * + * 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 + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Name: rp2040_flash_mtd_initialize + ****************************************************************************/ + +struct mtd_dev_s *rp23xx_flash_mtd_initialize(void); diff --git a/arch/arm/src/rp23xx/rp23xx_gpio.c b/arch/arm/src/rp23xx/rp23xx_gpio.c index 64b9e554bff..7dd02fd8af4 100644 --- a/arch/arm/src/rp23xx/rp23xx_gpio.c +++ b/arch/arm/src/rp23xx/rp23xx_gpio.c @@ -291,17 +291,28 @@ int rp23xx_gpio_get_function_pin(uint32_t func, uint32_t port) void rp23xx_gpio_set_function(uint32_t gpio, uint32_t func) { + // logic now matches pico-sdk: + // https://github.com/raspberrypi/pico-sdk/blob/9a4113fbbae65ee82d8cd6537963bc3d3b14bcca/src/rp2_common/hardware_gpio/gpio.c#L38-L54 DEBUGASSERT(gpio < RP23XX_GPIO_NUM); modbits_reg32(RP23XX_PADS_BANK0_GPIO_IE, - RP23XX_PADS_BANK0_GPIO_ISO | + // FIXME: is this needed here? SDK do not include this bitmask here, but only at very end (see below) + // RP23XX_PADS_BANK0_GPIO_ISO | RP23XX_PADS_BANK0_GPIO_IE | RP23XX_PADS_BANK0_GPIO_OD, RP23XX_PADS_BANK0_GPIO(gpio)); + // pico-sdk: Zero all fields apart from fsel; we want this IO to do what the peripheral tells it. + // pico-sdk: This doesn't affect e.g. pullup/pulldown, as these are in pad controls. + // pico-sdk: io_bank0_hw->io[gpio].ctrl = fn << IO_BANK0_GPIO0_CTRL_FUNCSEL_LSB; + // pico-sdk: #define RP23XX_IO_BANK0_GPIO_CTRL(n) (RP23XX_IO_BANK0_BASE + RP23XX_IO_BANK0_GPIO_CTRL_OFFSET(n)) putreg32(func & RP23XX_IO_BANK0_GPIO_CTRL_FUNCSEL_MASK, RP23XX_IO_BANK0_GPIO_CTRL(gpio)); + // pico-sdk: [rp2350]: Remove pad isolation now that the correct peripheral is in control of the pad + // pico-sdk: [rp2350] hw_clear_bits(&pads_bank0_hw->io[gpio], PADS_BANK0_GPIO0_ISO_BITS); + clrbits_reg32(RP23XX_PADS_BANK0_GPIO_ISO, RP23XX_PADS_BANK0_GPIO(gpio)); + g_gpio_function[gpio] = func; } @@ -394,6 +405,8 @@ void rp23xx_gpio_enable_irq(uint32_t gpio) { /* Set interrupt enable bit */ + // FIXME - isn't this separate per core like in pico-sdk (different IRQ control base)?! + // https://github.com/raspberrypi/pico-sdk/blob/9a4113fbbae65ee82d8cd6537963bc3d3b14bcca/src/rp2_common/hardware_gpio/gpio.c#L173-L196 reg = RP23XX_IO_BANK0_PROC_INTE(gpio, 0); clrbits_reg32(0xf << ((gpio % 8) * 4), reg); setbits_reg32(0x1 << ((gpio % 8) * 4 + g_gpio_irq_modes[gpio]), reg); @@ -417,7 +430,8 @@ void rp23xx_gpio_disable_irq(uint32_t gpio) if (g_gpio_irq_handlers[gpio] != NULL) { /* Clear interrupt enable bit */ - + // FIXME - isn't this separate per core like in pico-sdk (different IRQ control base)?! + // https://github.com/raspberrypi/pico-sdk/blob/9a4113fbbae65ee82d8cd6537963bc3d3b14bcca/src/rp2_common/hardware_gpio/gpio.c#L173-L196 reg = RP23XX_IO_BANK0_PROC_INTE(gpio, 0); clrbits_reg32(0xf << ((gpio % 8) * 4), reg); } diff --git a/arch/arm/src/rp23xx/rp23xx_gpio.h b/arch/arm/src/rp23xx/rp23xx_gpio.h index 5eaa6d0b266..735af00ea43 100644 --- a/arch/arm/src/rp23xx/rp23xx_gpio.h +++ b/arch/arm/src/rp23xx/rp23xx_gpio.h @@ -110,11 +110,11 @@ static inline void rp23xx_gpio_put(uint32_t gpio, int set) if (set) { - putreg32(value, RP23XX_SIO_GPIO_OUT_SET); + putreg32(value, reg_set); } else { - putreg32(value, RP23XX_SIO_GPIO_OUT_CLR); + putreg32(value, reg_clr); } #else uint32_t mask = 1ul << (gpio & 0x1fu); diff --git a/arch/arm/src/rp23xx/rp23xx_i2c.c b/arch/arm/src/rp23xx/rp23xx_i2c.c index 65573624ca8..22c133e4a52 100644 --- a/arch/arm/src/rp23xx/rp23xx_i2c.c +++ b/arch/arm/src/rp23xx/rp23xx_i2c.c @@ -821,11 +821,6 @@ static void rp23xx_i2c_init(struct rp23xx_i2cdev_s *priv) i2c_reg_write(priv, RP23XX_I2C_IC_INTR_MASK_OFFSET, 0x00); i2c_reg_read(priv, RP23XX_I2C_IC_CLR_INTR_OFFSET); - /* set threshold level of the Rx/Tx FIFO */ - - i2c_reg_write(priv, RP23XX_I2C_IC_RX_TL_OFFSET, 0xff); - i2c_reg_write(priv, RP23XX_I2C_IC_TX_TL_OFFSET, 0); - /* set hold time for margin */ i2c_reg_write(priv, RP23XX_I2C_IC_SDA_HOLD_OFFSET, 1); @@ -835,6 +830,16 @@ static void rp23xx_i2c_init(struct rp23xx_i2cdev_s *priv) RP23XX_I2C_IC_CON_IC_SLAVE_DISABLE | RP23XX_I2C_IC_CON_MASTER_MODE | RP23XX_I2C_IC_CON_TX_EMPTY_CTRL)); + + /* set threshold level of the Rx/Tx FIFO */ + + // in the pico-sdk, these are written after the RP23XX_I2C_IC_CON_OFFSET write + + i2c_reg_write(priv, RP23XX_I2C_IC_RX_TL_OFFSET, 0); // nuttx: 0xff -> pico-sdk: i2c->hw->tx_tl = 0; ? + i2c_reg_write(priv, RP23XX_I2C_IC_TX_TL_OFFSET, 0); + + // sdk: Always enable the DREQ signalling -- harmless if DMA isn't listening + // sdk: i2c->hw->dma_cr = I2C_IC_DMA_CR_TDMAE_BITS | I2C_IC_DMA_CR_RDMAE_BITS; } static void rp23xx_i2c_enable(struct rp23xx_i2cdev_s *priv) diff --git a/arch/arm/src/rp23xx/rp23xx_rom.h b/arch/arm/src/rp23xx/rp23xx_rom.h index 27eb739c077..2bdefc4ca2e 100644 --- a/arch/arm/src/rp23xx/rp23xx_rom.h +++ b/arch/arm/src/rp23xx/rp23xx_rom.h @@ -78,6 +78,7 @@ /* reserved for 32-bit pointer: 0x0008 */ #define RT_FLAG_FUNC_ARM_NONSEC 0x0010 +// 0x00000014 16-bit pointer Pointer to ROM entry table (BOOTROM_ROMTABLE_START) #define BOOTROM_FUNC_TABLE_OFFSET 0x14 #define BOOTROM_IS_A2() ((*(volatile uint8_t *)0x13) == 2) @@ -94,6 +95,48 @@ #define ROM_TABLE_CODE(c1, c2) ((c1) | ((c2) << 8)) +#define STR(s) #s +#define RAM_CODE_ATTR(f) __attribute__((noinline, section(".ram_code." f))) +#define RAM_CODE(f) RAM_CODE_ATTR(STR(f)) f + + +#define ROM_HWORD_AS_PTR(a) ((void *)(uintptr_t) (*(uint16_t *)(uintptr_t)a)) + +// 0x00000018 16-bit pointer Pointer to a helper function (rom_table_lookup_entry()) +#define ROM_LOOKUP(x) rom_func_lookup(x) + //((rom_table_lookup_fn)ROM_HWORD_AS_PTR(0x18)) \ + //(ROM_HWORD_AS_PTR(BOOTROM_FUNC_TABLE_OFFSET),x) + + + +/*! \brief Return true if executing in the NonSecure state (Arm-only) + * \ingroup pico_platform + * + * \return True if currently executing in the NonSecure state on an Arm processor + */ +#define pico_default_asm_volatile(...) __asm volatile (".syntax unified\n" __VA_ARGS__) + +static __inline bool pico_processor_state_is_nonsecure(void) { +#ifndef __riscv + // todo add a define to disable NS checking at all? + // IDAU-Exempt addresses return S=1 when tested in the Secure state, + // whereas executing a tt in the NonSecure state will always return S=0. + uint32_t tt; + pico_default_asm_volatile ( + "movs %0, #0\n" + "tt %0, %0\n" + : "=r" (tt) : : "cc" + ); + return !(tt & (1u << 22)); +#else + // NonSecure is an Arm concept, there is nothing meaningful to return + // here. Note it's not possible in general to detect whether you are + // executing in U-mode as, for example, M-mode is classically + // virtualisable in U-mode. + return false; +#endif +} + /**************************************************************************** * Public Type Definitions ****************************************************************************/ diff --git a/arch/arm/src/rp23xx/rp23xx_serial.c b/arch/arm/src/rp23xx/rp23xx_serial.c index de0da1ebb58..073861ebdc0 100644 --- a/arch/arm/src/rp23xx/rp23xx_serial.c +++ b/arch/arm/src/rp23xx/rp23xx_serial.c @@ -167,6 +167,11 @@ static struct up_dev_s g_uart0priv = static uart_dev_t g_uart0port = { +#ifdef CONFIG_UART0_SERIAL_CONSOLE + .isconsole = true, +#else + .isconsole = false, +#endif .recv = { .size = CONFIG_UART0_RXBUFSIZE, @@ -206,6 +211,11 @@ static struct up_dev_s g_uart1priv = static uart_dev_t g_uart1port = { +#ifdef CONFIG_UART1_SERIAL_CONSOLE + .isconsole = true, +#else + .isconsole = false, +#endif .recv = { .size = CONFIG_UART1_RXBUFSIZE, @@ -776,7 +786,10 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg) /* Configure the UART line format and speed. */ +#ifndef CONFIG_SUPPRESS_UART_CONFIG up_set_format(dev); +#endif + } break; #endif diff --git a/arch/arm/src/rp23xx/rp23xx_uart.c b/arch/arm/src/rp23xx/rp23xx_uart.c index 1a36e354ed3..b899d08a26d 100644 --- a/arch/arm/src/rp23xx/rp23xx_uart.c +++ b/arch/arm/src/rp23xx/rp23xx_uart.c @@ -140,8 +140,9 @@ void arm_lowputc(char ch) /* Wait for the transmitter to be available */ while ((getreg32(CONSOLE_BASE + RP23XX_UART_UARTFR_OFFSET) & - RP23XX_UART_UARTFR_TXFF)) - ; + RP23XX_UART_UARTFR_TXFF)){ + up_udelay(10); // Small delay to allow hardware to catch up + } /* Send the character */ diff --git a/arch/arm/src/rp23xx/rp23xx_xosc.c b/arch/arm/src/rp23xx/rp23xx_xosc.c index 27f4cf15767..eba14db205a 100644 --- a/arch/arm/src/rp23xx/rp23xx_xosc.c +++ b/arch/arm/src/rp23xx/rp23xx_xosc.c @@ -57,7 +57,7 @@ * Pre-processor Definitions ****************************************************************************/ -#define XOSC_STARTUPDELAY_MULT 6 +#define XOSC_STARTUPDELAY_MULT 2 #define XOSC_STARTUPDELAY (BOARD_XOSC_STARTUPDELAY * XOSC_STARTUPDELAY_MULT) /**************************************************************************** @@ -87,6 +87,7 @@ void rp23xx_xosc_init(void) uint32_t startup_delay = (((BOARD_XOSC_FREQ / 1000) + 128) / 256) * XOSC_STARTUPDELAY; + // FIXME: either the assert is incorrect or the XOSC_STARTUPDELAY_MULT 6 is too high! ASSERT(startup_delay < 1 << 13); putreg32(startup_delay, RP23XX_XOSC_STARTUP); diff --git a/include/crc32.h b/include/crc32.h new file mode 100644 index 00000000000..c0e4367bbfb --- /dev/null +++ b/include/crc32.h @@ -0,0 +1,26 @@ +/**************************************************************************** + * include/crc32.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 __INCLUDE_CRC32_H +#define __INCLUDE_CRC32_H + +#include + +#endif /* __INCLUDE_CRC32_H */ diff --git a/include/queue.h b/include/queue.h new file mode 100644 index 00000000000..6363cb3b30c --- /dev/null +++ b/include/queue.h @@ -0,0 +1,27 @@ +/**************************************************************************** + * include/queue.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 __INCLUDE_QUEUE_H +#define __INCLUDE_QUEUE_H + +// fixme? only if nuttx !? +#include + +#endif /* __INCLUDE_QUEUE_H_ */