efr32bg2x.c (4309B)
1 // agents/efr32bg2x.c 2 // 3 // Copyright 2022 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 <agent/flash.h> 22 #include <fw/io.h> 23 24 #define CMU_CLKEN1_SET 0x40009068 25 #define CMU_CLKEN1_MSC (1U<<17) 26 27 #define MSC_WRITECTRL 0x4003000C 28 #define MSC_WRITECTRL_SET 0x4003100C 29 #define MSC_WRITECTRL_CLR 0x4003200C 30 #define MSC_WRITECMD 0x40030010 31 #define MSC_WRITECMD_SET 0x40031010 32 #define MSC_WRITECMD_CLR 0x40032010 33 #define MSC_ADDRB 0x40030014 34 #define MSC_WDATA 0x40030018 35 #define MSC_STATUS 0x4003001C 36 37 #define MSC_WRITECTRL_WREN 1 38 39 #define MSC_WRITECMD_WRITEND (1U<<2) 40 #define MSC_WRITECMD_ERASEPAGE (1U<<1) 41 42 #define MSC_STATUS_WREADY (1U<<27) 43 #define MSC_STATUS_PWRON (1U<<24) 44 #define MSC_STATUS_REGLOCK (1U<<16) 45 #define MSC_STATUS_TIMEOUT (1U<<6) 46 #define MSC_STATUS_PENDING (1U<<5) 47 #define MSC_STATUS_ERASEABORTYED (1U<<4) 48 #define MSC_STATUS_WDATAREADY (1U<<3) 49 #define MSC_STATUS_INVADDR (1U<<2) 50 #define MSC_STATUS_LOCKED (1U<<1) 51 #define MSC_STATUS_BUSY (1U<<0) 52 53 static unsigned FLASH_PAGE_SIZE = 8192; 54 static unsigned FLASH_SIZE = 352 * 1024; 55 56 int flash_agent_setup(flash_agent *agent) { 57 // TODO - validate part ID 58 if (0) { 59 // unknown part 60 return ERR_INVALID; 61 } 62 63 // TODO: read from userdata 64 agent->flash_size = FLASH_SIZE; 65 66 return ERR_NONE; 67 } 68 69 int flash_agent_erase(u32 flash_addr, u32 length) { 70 unsigned v; 71 int status = ERR_NONE; 72 if (flash_addr > FLASH_SIZE) { 73 return ERR_INVALID; 74 } 75 if (flash_addr & (FLASH_PAGE_SIZE - 1)) { 76 return ERR_ALIGNMENT; 77 } 78 79 writel(CMU_CLKEN1_MSC, CMU_CLKEN1_SET); 80 writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_SET); 81 while (length > 0) { 82 writel(flash_addr, MSC_ADDRB); 83 v = readl(MSC_STATUS); 84 if (v & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) { 85 status = ERR_INVALID; 86 break; 87 } 88 if (!(v & MSC_STATUS_WREADY)) { 89 status = ERR_FAIL; 90 break; 91 } 92 if (length > FLASH_PAGE_SIZE) { 93 length -= FLASH_PAGE_SIZE; 94 } else { 95 length = 0; 96 } 97 writel(MSC_WRITECMD_ERASEPAGE, MSC_WRITECMD_SET); 98 while (readl(MSC_STATUS) & MSC_STATUS_BUSY) ; 99 for (unsigned n = 0; n < FLASH_PAGE_SIZE; n += 4) { 100 if (readl(flash_addr + n) != 0xFFFFFFFF) { 101 status = ERR_FAIL; 102 goto done; 103 } 104 } 105 flash_addr += FLASH_PAGE_SIZE; 106 } 107 done: 108 writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_CLR); 109 return status; 110 } 111 112 int flash_agent_write(u32 flash_addr, const void *_data, u32 length) { 113 int status = ERR_NONE; 114 const unsigned *data = _data; 115 unsigned v; 116 if (flash_addr > FLASH_SIZE) { 117 return ERR_INVALID; 118 } 119 if ((flash_addr & 3) || (length & 3)) { 120 return ERR_ALIGNMENT; 121 } 122 writel(CMU_CLKEN1_MSC, CMU_CLKEN1_SET); 123 writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_SET); 124 while (length > 0) { 125 writel(flash_addr, MSC_ADDRB); 126 v = readl(MSC_STATUS); 127 if (v & (MSC_STATUS_INVADDR | MSC_STATUS_LOCKED)) { 128 status = ERR_INVALID; 129 break; 130 } 131 if (!(v & MSC_STATUS_WREADY)) { 132 status = ERR_FAIL; 133 break; 134 } 135 writel(*data, MSC_WDATA); 136 while (readl(MSC_STATUS) & MSC_STATUS_BUSY) ; 137 if (readl(flash_addr) != *data) { 138 status = ERR_FAIL; 139 goto done; 140 } 141 data++; 142 length -= 4; 143 flash_addr += 4; 144 } 145 done: 146 writel(MSC_WRITECTRL_WREN, MSC_WRITECTRL_CLR); 147 return status; 148 } 149 150 int flash_agent_ioctl(u32 op, void *ptr, u32 arg0, u32 arg1) { 151 return ERR_INVALID; 152 } 153 154 const flash_agent __attribute((section(".vectors"))) FlashAgent = { 155 .magic = AGENT_MAGIC, 156 .version = AGENT_VERSION, 157 .flags = 0, 158 .load_addr = LOADADDR, 159 .data_addr = LOADADDR + 0x400, 160 .data_size = 0x4000, 161 .flash_addr = FLASH_BASE, 162 .flash_size = 0, 163 .setup = flash_agent_setup, 164 .erase = flash_agent_erase, 165 .write = flash_agent_write, 166 .ioctl = flash_agent_ioctl, 167 };