m3dev

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 9a806e19292e0135d23f11874c6d00017fdbf33b
parent 2b0ab579ae6da0a3ae144bd364874ea967279eb8
Author: Brian Swetland <swetland@frotz.net>
Date:   Sun, 12 Jul 2015 05:56:48 -0700

agent: lpc43xx-spifi suitable for flashing lpclink2

Diffstat:
Aagents/lpc43xx-spifi.c | 195+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Magents/module.mk | 7+++++++
2 files changed, 202 insertions(+), 0 deletions(-)

diff --git a/agents/lpc43xx-spifi.c b/agents/lpc43xx-spifi.c @@ -0,0 +1,195 @@ +// agent-lpc15xx/main.c +// +// Copyright 2015 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. + +#include <agent/flash.h> +#include <fw/io.h> + +// ---- pinmux + +#define PIN_CFG(m,n) (0x40086000 + ((m) * 0x80) + ((n) * 4)) +#define PIN_MODE(n) ((n) & 3) +#define PIN_PULLUP (0 << 3) // pull-up, no pull-down +#define PIN_REPEATER (1 << 3) // repeater mode +#define PIN_PLAIN (2 << 3) // no pull-up, no pull-down +#define PIN_PULLDOWN (3 << 3) // pull-down, no pull-up +#define PIN_SLOW (0 << 5) // slow slew rate (low noise, medium speed) +#define PIN_FAST (1 << 5) // fast slew rate (medium noise, fast speed) +#define PIN_INPUT (1 << 6) // enable input buffer, required for inputs +#define PIN_FILTER (1 << 7) // enable glitch filter, not for >30MHz signals + +// ---- spifi serial flash controller + +#define SPIFI_CTRL 0x40003000 // Control +#define SPIFI_CMD 0x40003004 // Command +#define SPIFI_ADDR 0x40003008 // Address +#define SPIFI_IDATA 0x4000300C // Intermediate Data +#define SPIFI_CLIMIT 0x40003010 // Cache Limit +#define SPIFI_DATA 0x40003014 // Data +#define SPIFI_MCMD 0x40003018 // Memory Command +#define SPIFI_STAT 0x4000301C // Status + +#define CTRL_TIMEOUT(n) ((n) & 0xFFFF) +#define CTRL_CSHIGH(n) (((n) & 0xF) << 16) // Minimum /CS high time (serclks - 1) +#define CTRL_D_PRFTCH_DIS (1 << 21) // Disable Prefetch of Data +#define CTRL_INTEN (1 << 22) // Enable IRQ on end of command +#define CTRL_MODE3 (1 << 23) // 0=SCK low after +edge of last bit, 1=high +#define CTRL_PRFTCH_DIS (1 << 27) // Disable Prefetch +#define CTRL_DUAL (1 << 28) // 0=Quad 1=Dual (bits in "wide" ops) +#define CTRL_QUAD (0 << 28) +#define CTRL_RFCLK (1 << 29) // 1=sample read data on -edge clock +#define CTRL_FBCLK (1 << 30) // use feedback clock from SCK pin for sampling +#define CTRL_DMAEN (1 << 31) // enable DMA request output + +#define CMD_DATALEN(n) ((n) & 0x3FFF) +#define CMD_POLL (1 << 14) // if set, read byte repeatedly until condition +#define CMD_POLLBIT(n) ((n) & 7) // which bit# to check +#define CMD_POLLSET (1 << 3) // condition is bit# set +#define CMD_POLLCLR (0 << 3) // condition is bit# clear +#define CMD_DOUT (1 << 15) // 1=data phase output, 0=data phase input +#define CMD_DIN (0 << 15) +#define CMD_INTLEN(n) (((n) & 7) << 16) // count of intermediate bytes +#define CMD_FF_SERIAL (0 << 19) // all command fields serial +#define CMD_FF_WIDE_DATA (1 << 19) // data is wide, all other fields serial +#define CMD_FF_SERIAL_OPCODE (2 << 19) // opcode is serial, all other fields wide +#define CMD_FF_WIDE (3 << 19) // all command fields wide +#define CMD_FR_OP (1 << 21) // frame format: opcode only +#define CMD_FR_OP_1B (2 << 21) // opcode, lsb addr +#define CMD_FR_OP_2B (3 << 21) // opcode, 2 lsb addr +#define CMD_FR_OP_3B (4 << 21) // opcode, 3 lsb addr +#define CMD_FR_OP_4B (5 << 21) // opcode, 4b address +#define CMD_FR_3B (6 << 21) // 3 lsb addr +#define CMD_FR_4B (7 << 21) // 4 lsb addr +#define CMD_OPCODE(n) ((n) << 24) + +#define STAT_MCINIT (1 << 0) // set on sw write to MCMD, clear on RST, wr(0) +#define STAT_CMD (1 << 1) // set when CMD written, clear on CS, RST +#define STAT_RESET (1 << 4) // write 1 to abort current txn or memory mode +#define STAT_INTRQ (1 << 5) // read IRQ status, wr(1) to clear + +#define CMD_PAGE_PROGRAM 0x02 +#define CMD_READ_DATA 0x03 +#define CMD_READ_STATUS 0x05 +#define CMD_WRITE_ENABLE 0x06 +#define CMD_SECTOR_ERASE 0x20 + +static void spifi_write_enable(void) { + writel(CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_WRITE_ENABLE), + SPIFI_CMD); + while (readl(SPIFI_STAT) & STAT_CMD) ; +} + +static void spifi_wait_busy(void) { + while (readl(SPIFI_STAT) & STAT_CMD) ; + writel(CMD_POLLBIT(0) | CMD_POLLCLR | CMD_POLL | + CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_READ_STATUS), + SPIFI_CMD); + while (readl(SPIFI_STAT) & STAT_CMD) ; + // discard matching status byte from fifo + readb(SPIFI_DATA); +} + +static void spifi_page_program(u32 addr, u32 *ptr, u32 count) { + spifi_write_enable(); + writel(addr, SPIFI_ADDR); + writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B | + CMD_DOUT | CMD_OPCODE(CMD_PAGE_PROGRAM), SPIFI_CMD); + while (count-- > 0) { + writel(*ptr++, SPIFI_DATA); + } + spifi_wait_busy(); +} + +static void spifi_sector_erase(u32 addr) { + spifi_write_enable(); + writel(addr, SPIFI_ADDR); + writel(CMD_FF_SERIAL | CMD_FR_OP_3B | CMD_OPCODE(CMD_SECTOR_ERASE), + SPIFI_CMD); + spifi_wait_busy(); +} + +// at reset-stop, all clocks are running from 12MHz internal osc +// todo: run SPIFI_CLK at a much higher rate +// todo: use 4bit modes +int flash_agent_setup(flash_agent *agent) { + // configure pinmux + writel(PIN_MODE(3) | PIN_PLAIN, PIN_CFG(3,3)); // SPIFI_SCK + writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 4)); // SPIFI_SIO3 + writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 5)); // SPIFI_SIO2 + writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 6)); // SPIFI_MISO + writel(PIN_MODE(3) | PIN_PLAIN | PIN_INPUT, PIN_CFG(3, 7)); // SPIFI_MOSI + writel(PIN_MODE(3) | PIN_PLAIN, PIN_CFG(3, 8)); // SPIFI_CS + + // reset spifi controller + writel(STAT_RESET, SPIFI_STAT); + while (readl(SPIFI_STAT) & STAT_RESET) ; + writel(0xFFFFF, SPIFI_CTRL); + + return ERR_NONE; +} + +int flash_agent_erase(u32 flash_addr, u32 length) { + if (flash_addr & 0xFFF) { + return ERR_ALIGNMENT; + } + while (length != 0) { + spifi_sector_erase(flash_addr); + if (length < 0x1000) break; + length -= 0x1000; + flash_addr += 0x1000; + } + return ERR_NONE; +} + +int flash_agent_write(u32 flash_addr, const void *data, u32 length) { + char *x = (void*) data; + if (flash_addr & 0xFFF) { + return ERR_ALIGNMENT; + } + while (length != 0) { + if (length < 256) { + int n; + for (n = length; n < 256; n++) { + x[n] = 0; + } + } + spifi_page_program(flash_addr, (void*) x, 256 / 4); + if (length < 256) break; + length -= 256; + flash_addr += 256; + x += 256; + } + writel(CMD_FF_SERIAL | CMD_FR_OP_3B | CMD_OPCODE(CMD_READ_DATA), SPIFI_MCMD); + 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 = CONFIG_LOADADDR, + .data_addr = CONFIG_LOADADDR + 0x400, + .data_size = 0x8000, + .flash_addr = CONFIG_FLASHADDR, + .flash_size = CONFIG_FLASHSIZE, + .setup = flash_agent_setup, + .erase = flash_agent_erase, + .write = flash_agent_write, + .ioctl = flash_agent_ioctl, +}; diff --git a/agents/module.mk b/agents/module.mk @@ -24,3 +24,10 @@ M_RAMSIZE := 0x00000400 M_OBJS := agents/stm32fxxx.o $(call build-target-agent) +M_NAME := agent-lpclink2 +M_ROMBASE := 0x00000000 +M_ROMSIZE := 0x00100000 +M_RAMBASE := 0x10080400 +M_RAMSIZE := 0x10000400 +M_OBJS := agents/lpc43xx-spifi.o +$(call build-target-agent)