lpc43xx-spifi.c (7721B)
1 // agent-lpc15xx/main.c 2 // 3 // Copyright 2015 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 #include <agent/flash.h> 18 #include <fw/io.h> 19 20 // ---- pinmux 21 22 #define PIN_CFG(m,n) (0x40086000 + ((m) * 0x80) + ((n) * 4)) 23 #define PIN_MODE(n) ((n) & 3) 24 #define PIN_PULLUP (0 << 3) // pull-up, no pull-down 25 #define PIN_REPEATER (1 << 3) // repeater mode 26 #define PIN_PLAIN (2 << 3) // no pull-up, no pull-down 27 #define PIN_PULLDOWN (3 << 3) // pull-down, no pull-up 28 #define PIN_SLOW (0 << 5) // slow slew rate (low noise, medium speed) 29 #define PIN_FAST (1 << 5) // fast slew rate (medium noise, fast speed) 30 #define PIN_INPUT (1 << 6) // enable input buffer, required for inputs 31 #define PIN_FILTER (1 << 7) // enable glitch filter, not for >30MHz signals 32 33 // ---- spifi serial flash controller 34 35 #define SPIFI_CTRL 0x40003000 // Control 36 #define SPIFI_CMD 0x40003004 // Command 37 #define SPIFI_ADDR 0x40003008 // Address 38 #define SPIFI_IDATA 0x4000300C // Intermediate Data 39 #define SPIFI_CLIMIT 0x40003010 // Cache Limit 40 #define SPIFI_DATA 0x40003014 // Data 41 #define SPIFI_MCMD 0x40003018 // Memory Command 42 #define SPIFI_STAT 0x4000301C // Status 43 44 #define CTRL_TIMEOUT(n) ((n) & 0xFFFF) 45 #define CTRL_CSHIGH(n) (((n) & 0xF) << 16) // Minimum /CS high time (serclks - 1) 46 #define CTRL_D_PRFTCH_DIS (1 << 21) // Disable Prefetch of Data 47 #define CTRL_INTEN (1 << 22) // Enable IRQ on end of command 48 #define CTRL_MODE3 (1 << 23) // 0=SCK low after +edge of last bit, 1=high 49 #define CTRL_PRFTCH_DIS (1 << 27) // Disable Prefetch 50 #define CTRL_DUAL (1 << 28) // 0=Quad 1=Dual (bits in "wide" ops) 51 #define CTRL_QUAD (0 << 28) 52 #define CTRL_RFCLK (1 << 29) // 1=sample read data on -edge clock 53 #define CTRL_FBCLK (1 << 30) // use feedback clock from SCK pin for sampling 54 #define CTRL_DMAEN (1 << 31) // enable DMA request output 55 56 #define CMD_DATALEN(n) ((n) & 0x3FFF) 57 #define CMD_POLL (1 << 14) // if set, read byte repeatedly until condition 58 #define CMD_POLLBIT(n) ((n) & 7) // which bit# to check 59 #define CMD_POLLSET (1 << 3) // condition is bit# set 60 #define CMD_POLLCLR (0 << 3) // condition is bit# clear 61 #define CMD_DOUT (1 << 15) // 1=data phase output, 0=data phase input 62 #define CMD_DIN (0 << 15) 63 #define CMD_INTLEN(n) (((n) & 7) << 16) // count of intermediate bytes 64 #define CMD_FF_SERIAL (0 << 19) // all command fields serial 65 #define CMD_FF_WIDE_DATA (1 << 19) // data is wide, all other fields serial 66 #define CMD_FF_SERIAL_OPCODE (2 << 19) // opcode is serial, all other fields wide 67 #define CMD_FF_WIDE (3 << 19) // all command fields wide 68 #define CMD_FR_OP (1 << 21) // frame format: opcode only 69 #define CMD_FR_OP_1B (2 << 21) // opcode, lsb addr 70 #define CMD_FR_OP_2B (3 << 21) // opcode, 2 lsb addr 71 #define CMD_FR_OP_3B (4 << 21) // opcode, 3 lsb addr 72 #define CMD_FR_OP_4B (5 << 21) // opcode, 4b address 73 #define CMD_FR_3B (6 << 21) // 3 lsb addr 74 #define CMD_FR_4B (7 << 21) // 4 lsb addr 75 #define CMD_OPCODE(n) ((n) << 24) 76 77 #define STAT_MCINIT (1 << 0) // set on sw write to MCMD, clear on RST, wr(0) 78 #define STAT_CMD (1 << 1) // set when CMD written, clear on CS, RST 79 #define STAT_RESET (1 << 4) // write 1 to abort current txn or memory mode 80 #define STAT_INTRQ (1 << 5) // read IRQ status, wr(1) to clear 81 82 #define CMD_PAGE_PROGRAM 0x02 83 #define CMD_READ_DATA 0x03 84 #define CMD_READ_STATUS 0x05 85 #define CMD_WRITE_ENABLE 0x06 86 #define CMD_SECTOR_ERASE 0x20 87 88 static void spifi_write_enable(void) { 89 writel(CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_WRITE_ENABLE), 90 SPIFI_CMD); 91 while (readl(SPIFI_STAT) & STAT_CMD) ; 92 } 93 94 static void spifi_wait_busy(void) { 95 while (readl(SPIFI_STAT) & STAT_CMD) ; 96 writel(CMD_POLLBIT(0) | CMD_POLLCLR | CMD_POLL | 97 CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_READ_STATUS), 98 SPIFI_CMD); 99 while (readl(SPIFI_STAT) & STAT_CMD) ; 100 // discard matching status byte from fifo 101 readb(SPIFI_DATA); 102 } 103 104 static void spifi_page_program(u32 addr, u32 *ptr, u32 count) { 105 spifi_write_enable(); 106 writel(addr, SPIFI_ADDR); 107 writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B | 108 CMD_DOUT | CMD_OPCODE(CMD_PAGE_PROGRAM), SPIFI_CMD); 109 while (count-- > 0) { 110 writel(*ptr++, SPIFI_DATA); 111 } 112 spifi_wait_busy(); 113 } 114 115 static void spifi_sector_erase(u32 addr) { 116 spifi_write_enable(); 117 writel(addr, SPIFI_ADDR); 118 writel(CMD_FF_SERIAL | CMD_FR_OP_3B | CMD_OPCODE(CMD_SECTOR_ERASE), 119 SPIFI_CMD); 120 spifi_wait_busy(); 121 } 122 123 static int verify_erased(u32 addr, u32 count) { 124 int err = 0; 125 writel(addr, SPIFI_ADDR); 126 writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B | 127 CMD_OPCODE(CMD_READ_DATA), SPIFI_CMD); 128 while (count-- > 0) { 129 if (readl(SPIFI_DATA) != 0xFFFFFFFF) err = -1; 130 } 131 while (readl(SPIFI_STAT) & STAT_CMD) ; 132 return err; 133 } 134 135 static int verify_page(u32 addr, u32 *ptr) { 136 int count = 256 / 4; 137 int err = 0; 138 writel(addr, SPIFI_ADDR); 139 writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B | 140 CMD_OPCODE(CMD_READ_DATA), SPIFI_CMD); 141 while (count-- > 0) { 142 if (readl(SPIFI_DATA) != *ptr++) err = -1; 143 } 144 while (readl(SPIFI_STAT) & STAT_CMD) ; 145 return err; 146 } 147 148 // at reset-stop, all clocks are running from 12MHz internal osc 149 // todo: run SPIFI_CLK at a much higher rate 150 // todo: use 4bit modes 151 int flash_agent_setup(flash_agent *agent) { 152 // configure pinmux 153 writel(PIN_MODE(3) | PIN_PLAIN, PIN_CFG(3,3)); // SPIFI_SCK 154 writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 4)); // SPIFI_SIO3 155 writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 5)); // SPIFI_SIO2 156 writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 6)); // SPIFI_MISO 157 writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 7)); // SPIFI_MOSI 158 writel(PIN_MODE(3) | PIN_PLAIN, PIN_CFG(3, 8)); // SPIFI_CS 159 160 // reset spifi controller 161 writel(STAT_RESET, SPIFI_STAT); 162 while (readl(SPIFI_STAT) & STAT_RESET) ; 163 writel(0xFFFFF, SPIFI_CTRL); 164 165 return ERR_NONE; 166 } 167 168 int flash_agent_erase(u32 flash_addr, u32 length) { 169 if (flash_addr & 0xFFF) { 170 return ERR_ALIGNMENT; 171 } 172 while (length != 0) { 173 spifi_sector_erase(flash_addr); 174 if (verify_erased(flash_addr, 0x1000/4)) { 175 return ERR_FAIL; 176 } 177 if (length < 0x1000) break; 178 length -= 0x1000; 179 flash_addr += 0x1000; 180 } 181 return ERR_NONE; 182 } 183 184 int flash_agent_write(u32 flash_addr, const void *data, u32 length) { 185 char *x = (void*) data; 186 if (flash_addr & 0xFFF) { 187 return ERR_ALIGNMENT; 188 } 189 while (length != 0) { 190 if (length < 256) { 191 int n; 192 for (n = length; n < 256; n++) { 193 x[n] = 0; 194 } 195 } 196 spifi_page_program(flash_addr, (void*) x, 256 / 4); 197 if (verify_page(flash_addr, (void*) x)) { 198 return ERR_FAIL; 199 } 200 if (length < 256) break; 201 length -= 256; 202 flash_addr += 256; 203 x += 256; 204 } 205 writel(CMD_FF_SERIAL | CMD_FR_OP_3B | CMD_OPCODE(CMD_READ_DATA), SPIFI_MCMD); 206 return ERR_NONE; 207 } 208 209 int flash_agent_ioctl(u32 op, void *ptr, u32 arg0, u32 arg1) { 210 return ERR_INVALID; 211 } 212 213 const flash_agent __attribute((section(".vectors"))) FlashAgent = { 214 .magic = AGENT_MAGIC, 215 .version = AGENT_VERSION, 216 .flags = 0, 217 .load_addr = LOADADDR, 218 .data_addr = LOADADDR + 0x400, 219 .data_size = 0x8000, 220 .flash_addr = FLASH_BASE, 221 .flash_size = FLASH_SIZE, 222 .setup = flash_agent_setup, 223 .erase = flash_agent_erase, 224 .write = flash_agent_write, 225 .ioctl = flash_agent_ioctl, 226 };