commit e540c7f4fc13d2bee5176443dd4f64c8c95b97df
parent f7344fa2f15e5601d9261e83082f2c1ade329885
Author: Brian Swetland <swetland@frotz.net>
Date:   Tue,  2 Feb 2021 15:10:43 -0800
agents: pico: flash agent for rp2040 family MCUs
Use the ROM helper functions to do all the heavy lifting.
Diffstat:
| M | Makefile |  |  | 1 | + | 
| A | agents/pico.c |  |  | 147 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
2 files changed, 148 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -46,6 +46,7 @@ $(call agent, lpc13xx,   0x10000400, M3)
 $(call agent, lpc15xx,   0x02000400, M3)
 $(call agent, cc13xx,    0x20000400, M3)
 $(call agent, nrf528xx,  0x20000400, M3)
+$(call agent, pico, 0x20000400, M0)
 
 # tool to pack the agents into a source file
 SRCS := tools/mkbuiltins.c
diff --git a/agents/pico.c b/agents/pico.c
@@ -0,0 +1,147 @@
+// agents/pico.c
+//
+// Copyright 2020 Brian Swetland <swetland@frotz.net>
+//
+// Licensed 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.
+
+#define LOADADDR	0x20000400
+
+#define FLASH_BASE	0x00000000
+
+#include <stdint.h>
+#include <agent/flash.h>
+#include <fw/io.h>
+
+static unsigned FLASH_BLOCK_SIZE = 256;
+static unsigned FLASH_PAGE_SIZE = 4096;
+static unsigned FLASH_SIZE = 4 * 1024 * 1024;
+
+#define FLASH_XIP_BASE 0x10000000
+
+#define CODE(c1, c2) (((c2) << 8) | (c1))
+
+#define ROM_LOOKUP_FN_PTR 0x18
+#define ROM_FN_TABLE_PTR 0x14
+
+// lookup fn for code using ROM lookup helper and ROM fn table
+void* lookup_fn(uint32_t code) {
+	void* (*lookup)(uint32_t table, uint32_t code) =
+		(void*) (uintptr_t) *((uint16_t*) ROM_LOOKUP_FN_PTR);
+
+	return lookup(*((uint16_t*)ROM_FN_TABLE_PTR), code);
+}
+
+static void (*_flash_connect)(void);
+static void (*_flash_exit_xip)(void);
+static void (*_flash_erase)(uint32_t addr, uint32_t len,
+		uint32_t block_size, uint32_t block_cmd);
+static void (*_flash_write)(uint32_t addr, const void* data, uint32_t len);
+static void (*_flash_flush_cache)(void);
+static void (*_flash_enter_xip)(void);
+
+// erase: addr and count must be 4096 aligned
+// write: addr and len must be 256 aligned 
+
+int flash_agent_setup(flash_agent *agent) {
+	// TODO - validate part ID
+	if (0) {
+		// unknown part
+		return ERR_INVALID;
+	}
+
+	_flash_connect = lookup_fn(CODE('I','F'));
+	_flash_exit_xip = lookup_fn(CODE('E','X'));
+	_flash_erase = lookup_fn(CODE('R','E'));
+	_flash_write = lookup_fn(CODE('R','P'));
+	_flash_flush_cache = lookup_fn(CODE('F','C'));
+	_flash_enter_xip = lookup_fn(CODE('C','X'));
+
+	// TODO: obtain from spi flash	
+	agent->flash_size = FLASH_SIZE;
+
+	return ERR_NONE;
+}
+
+int flash_agent_erase(u32 flash_addr, u32 length) {
+	if (flash_addr > FLASH_SIZE) {
+		return ERR_INVALID;
+	}
+	if (flash_addr & (FLASH_PAGE_SIZE - 1)) {
+		return ERR_ALIGNMENT;
+	}
+	if (length & (FLASH_PAGE_SIZE-1)) {
+		length = (length & (~(FLASH_PAGE_SIZE-1))) + FLASH_PAGE_SIZE;
+	}
+
+	_flash_connect();
+	_flash_exit_xip();
+	_flash_erase(flash_addr, length, 65536, 0xD8);
+	_flash_flush_cache();
+	_flash_enter_xip();
+
+	uint32_t* flash = (void*) (flash_addr + FLASH_XIP_BASE);
+	for (uint32_t n = 0; n < length; n+= 4) {
+		if (*flash++ != 0xFFFFFFFF) {
+			return ERR_FAIL;
+		}
+	}
+
+	return ERR_NONE;
+}
+
+int flash_agent_write(u32 flash_addr, const void *data, u32 length) {
+	if (flash_addr > FLASH_SIZE) {
+		return ERR_INVALID;
+	}
+	if (flash_addr & (FLASH_BLOCK_SIZE - 1)) {
+		return ERR_ALIGNMENT;
+	}
+	if (length & (FLASH_BLOCK_SIZE-1)) {
+		length = (length & (~(FLASH_BLOCK_SIZE-1))) + FLASH_BLOCK_SIZE;
+	}
+
+	_flash_connect();
+	_flash_exit_xip();
+	_flash_write(flash_addr, data, length);
+	_flash_flush_cache();
+	_flash_enter_xip();
+
+	uint32_t* flash = (void*) (flash_addr + FLASH_XIP_BASE);
+	const uint32_t* xdata = data;
+	for (uint32_t n = 0; n < length; n += 4) {
+		if (*flash++ != *xdata++) {
+			return ERR_FAIL;
+		}
+	}
+
+	return ERR_NONE;
+}
+
+int flash_agent_ioctl(u32 op, void *ptr, u32 arg0, u32 arg1) {
+	return ERR_INVALID;
+}
+
+const flash_agent __attribute((section(".vectors"))) FlashAgent = {
+	.magic =	AGENT_MAGIC,
+	.version =	AGENT_VERSION,
+	.flags =	0,
+	.load_addr =	LOADADDR,
+	.data_addr =	LOADADDR + 0x400,
+	.data_size =	0x4000,
+	.flash_addr =	FLASH_BASE,
+	.flash_size =	0,
+	.setup =	flash_agent_setup,
+	.erase =	flash_agent_erase,
+	.write =	flash_agent_write,
+	.ioctl =	flash_agent_ioctl,
+};