mdebug

cortex m series debugger
git clone http://frotz.net/git/mdebug.git
Log | Files | Refs | README | LICENSE

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 };