pico.c (3927B)
1 // agents/pico.c 2 // 3 // Copyright 2020 Brian Swetland <swetland@frotz.net> 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #define LOADADDR 0x20000400 18 19 #define FLASH_BASE 0x00000000 20 21 #include <stdint.h> 22 #include <agent/flash.h> 23 #include <fw/io.h> 24 25 static unsigned FLASH_BLOCK_SIZE = 256; 26 static unsigned FLASH_PAGE_SIZE = 4096; 27 static unsigned FLASH_SIZE = 4 * 1024 * 1024; 28 29 #define FLASH_XIP_BASE 0x10000000 30 31 #define CODE(c1, c2) (((c2) << 8) | (c1)) 32 33 #define ROM_LOOKUP_FN_PTR 0x18 34 #define ROM_FN_TABLE_PTR 0x14 35 36 // lookup fn for code using ROM lookup helper and ROM fn table 37 void* lookup_fn(uint32_t code) { 38 void* (*lookup)(uint32_t table, uint32_t code) = 39 (void*) (uintptr_t) *((uint16_t*) ROM_LOOKUP_FN_PTR); 40 41 return lookup(*((uint16_t*)ROM_FN_TABLE_PTR), code); 42 } 43 44 static void (*_flash_connect)(void); 45 static void (*_flash_exit_xip)(void); 46 static void (*_flash_erase)(uint32_t addr, uint32_t len, 47 uint32_t block_size, uint32_t block_cmd); 48 static void (*_flash_write)(uint32_t addr, const void* data, uint32_t len); 49 static void (*_flash_flush_cache)(void); 50 static void (*_flash_enter_xip)(void); 51 52 // erase: addr and count must be 4096 aligned 53 // write: addr and len must be 256 aligned 54 55 int flash_agent_setup(flash_agent *agent) { 56 // TODO - validate part ID 57 if (0) { 58 // unknown part 59 return ERR_INVALID; 60 } 61 62 _flash_connect = lookup_fn(CODE('I','F')); 63 _flash_exit_xip = lookup_fn(CODE('E','X')); 64 _flash_erase = lookup_fn(CODE('R','E')); 65 _flash_write = lookup_fn(CODE('R','P')); 66 _flash_flush_cache = lookup_fn(CODE('F','C')); 67 _flash_enter_xip = lookup_fn(CODE('C','X')); 68 69 // TODO: obtain from spi flash 70 agent->flash_size = FLASH_SIZE; 71 72 return ERR_NONE; 73 } 74 75 int flash_agent_erase(uint32_t flash_addr, uint32_t length) { 76 if (flash_addr > FLASH_SIZE) { 77 return ERR_INVALID; 78 } 79 if (flash_addr & (FLASH_PAGE_SIZE - 1)) { 80 return ERR_ALIGNMENT; 81 } 82 if (length & (FLASH_PAGE_SIZE-1)) { 83 length = (length & (~(FLASH_PAGE_SIZE-1))) + FLASH_PAGE_SIZE; 84 } 85 86 _flash_connect(); 87 _flash_exit_xip(); 88 _flash_erase(flash_addr, length, 65536, 0xD8); 89 _flash_flush_cache(); 90 _flash_enter_xip(); 91 92 uint32_t* flash = (void*) (flash_addr + FLASH_XIP_BASE); 93 for (uint32_t n = 0; n < length; n+= 4) { 94 if (*flash++ != 0xFFFFFFFF) { 95 return ERR_FAIL; 96 } 97 } 98 99 return ERR_NONE; 100 } 101 102 int flash_agent_write(uint32_t flash_addr, const void *data, uint32_t length) { 103 if (flash_addr > FLASH_SIZE) { 104 return ERR_INVALID; 105 } 106 if (flash_addr & (FLASH_BLOCK_SIZE - 1)) { 107 return ERR_ALIGNMENT; 108 } 109 if (length & (FLASH_BLOCK_SIZE-1)) { 110 length = (length & (~(FLASH_BLOCK_SIZE-1))) + FLASH_BLOCK_SIZE; 111 } 112 113 _flash_connect(); 114 _flash_exit_xip(); 115 _flash_write(flash_addr, data, length); 116 _flash_flush_cache(); 117 _flash_enter_xip(); 118 119 uint32_t* flash = (void*) (flash_addr + FLASH_XIP_BASE); 120 const uint32_t* xdata = data; 121 for (uint32_t n = 0; n < length; n += 4) { 122 if (*flash++ != *xdata++) { 123 return ERR_FAIL; 124 } 125 } 126 127 return ERR_NONE; 128 } 129 130 int flash_agent_ioctl(uint32_t op, void *ptr, uint32_t arg0, uint32_t arg1) { 131 return ERR_INVALID; 132 } 133 134 const flash_agent __attribute((section(".vectors"))) FlashAgent = { 135 .magic = AGENT_MAGIC, 136 .version = AGENT_VERSION, 137 .flags = 0, 138 .load_addr = LOADADDR, 139 .data_addr = LOADADDR + 0x400, 140 .data_size = 0x4000, 141 .flash_addr = FLASH_BASE, 142 .flash_size = 0, 143 .setup = flash_agent_setup, 144 .erase = flash_agent_erase, 145 .write = flash_agent_write, 146 .ioctl = flash_agent_ioctl, 147 };