1 /*
2 * Copyright (c) 2015 Brian Swetland
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9 #include <lk/debug.h>
10 #include <string.h>
11 #include <stdlib.h>
12 #include <printf.h>
13 #include <lk/reg.h>
14
15 #include <platform/lpc43xx-spifi.h>
16
17 #define CMD_PAGE_PROGRAM 0x02
18 #define CMD_READ_DATA 0x03
19 #define CMD_READ_STATUS 0x05
20 #define CMD_WRITE_ENABLE 0x06
21 #define CMD_SECTOR_ERASE 0x20
22
spifi_write_enable(void)23 static void spifi_write_enable(void) {
24 writel(CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_WRITE_ENABLE),
25 SPIFI_CMD);
26 while (readl(SPIFI_STAT) & STAT_CMD) ;
27 }
28
spifi_wait_busy(void)29 static void spifi_wait_busy(void) {
30 while (readl(SPIFI_STAT) & STAT_CMD) ;
31 writel(CMD_POLLBIT(0) | CMD_POLLCLR | CMD_POLL |
32 CMD_FF_SERIAL | CMD_FR_OP | CMD_OPCODE(CMD_READ_STATUS),
33 SPIFI_CMD);
34 while (readl(SPIFI_STAT) & STAT_CMD) ;
35 // discard matching status byte from fifo
36 readb(SPIFI_DATA);
37 }
38
spifi_page_program(u32 addr,u32 * ptr,u32 count)39 void spifi_page_program(u32 addr, u32 *ptr, u32 count) {
40 spifi_write_enable();
41 writel(addr, SPIFI_ADDR);
42 writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B |
43 CMD_DOUT | CMD_OPCODE(CMD_PAGE_PROGRAM), SPIFI_CMD);
44 while (count-- > 0) {
45 writel(*ptr++, SPIFI_DATA);
46 }
47 spifi_wait_busy();
48 }
49
spifi_sector_erase(u32 addr)50 void spifi_sector_erase(u32 addr) {
51 spifi_write_enable();
52 writel(addr, SPIFI_ADDR);
53 writel(CMD_FF_SERIAL | CMD_FR_OP_3B | CMD_OPCODE(CMD_SECTOR_ERASE),
54 SPIFI_CMD);
55 spifi_wait_busy();
56 }
57
spifi_verify_erased(u32 addr,u32 count)58 int spifi_verify_erased(u32 addr, u32 count) {
59 int err = 0;
60 writel(addr, SPIFI_ADDR);
61 writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B |
62 CMD_OPCODE(CMD_READ_DATA), SPIFI_CMD);
63 while (count-- > 0) {
64 if (readl(SPIFI_DATA) != 0xFFFFFFFF) err = -1;
65 }
66 while (readl(SPIFI_STAT) & STAT_CMD) ;
67 return err;
68 }
69
spifi_verify_page(u32 addr,u32 * ptr)70 int spifi_verify_page(u32 addr, u32 *ptr) {
71 int count = 256 / 4;
72 int err = 0;
73 writel(addr, SPIFI_ADDR);
74 writel(CMD_DATALEN(count * 4) | CMD_FF_SERIAL | CMD_FR_OP_3B |
75 CMD_OPCODE(CMD_READ_DATA), SPIFI_CMD);
76 while (count-- > 0) {
77 if (readl(SPIFI_DATA) != *ptr++) err = -1;
78 }
79 while (readl(SPIFI_STAT) & STAT_CMD) ;
80 return err;
81 }
82
83 // at reset-stop, all clocks are running from 12MHz internal osc
84 // todo: run SPIFI_CLK at a much higher rate
85 // todo: use 4bit modes
spifi_init(void)86 void spifi_init(void) {
87 // reset spifi controller
88 writel(STAT_RESET, SPIFI_STAT);
89 while (readl(SPIFI_STAT) & STAT_RESET) ;
90 writel(0xFFFFF, SPIFI_CTRL);
91 }
92
93