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