blob: ad8b6d4f44f0a5c4e822492559f333012537d5ec [file] [log] [blame]
zbao246e84b2012-07-13 18:47:03 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19#include <console/console.h>
20#include <arch/io.h>
21#include <device/device.h>
22#include "spi.h"
23
24void execute_command(volatile u8 * spi_address)
25{
26 *(spi_address + 2) |= 1;
27}
28
29void wait4command_complete(volatile u8 * spi_address)
30{
31// while (*(spi_address + 2) & 1)
32 while ((*(spi_address + 2) & 1) && (*(spi_address + 3) & 0x80))
33 printk(BIOS_DEBUG, "wait4CommandComplete\n");
34}
35
36void reset_internal_fifo_pointer(volatile u8 * spi_address)
37{
38 u8 val;
39
40 do {
41 *(spi_address + 2) |= 0x10;
42 val = *(spi_address + 0xd);
43 } while (val & 0x7);
44}
45
46u8 read_spi_status(volatile u8 * spi_address)
47{
48 u8 val;
49 *spi_address = 0x05;
50 *(spi_address + 1) = 0x21;
51 reset_internal_fifo_pointer(spi_address);
52 *(spi_address + 0xC) = 0x0; /* dummy */
53 reset_internal_fifo_pointer(spi_address);
54 execute_command(spi_address);
55 wait4command_complete(spi_address);
56 reset_internal_fifo_pointer(spi_address);
57 val = *(spi_address + 0xC);
58 val = *(spi_address + 0xC);
59 val = *(spi_address + 0xC);
60 return val;
61}
62
63void wait4flashpart_ready(volatile u8 * spi_address)
64{
65 while (read_spi_status(spi_address) & 1) ;
66}
67
68void write_spi_status(volatile u8 * spi_address, u8 status)
69{
70 *spi_address = 0x50; /* EWSR */
71 *(spi_address + 1) = 0; /* RxByte=TxByte=0 */
72 execute_command(spi_address);
73 wait4command_complete(spi_address);
74
75 *spi_address = 0x01; /* WRSR */
76 *(spi_address + 1) = 0x01;
77 reset_internal_fifo_pointer(spi_address);
78 *(spi_address + 0xC) = status;
79 reset_internal_fifo_pointer(spi_address);
80 execute_command(spi_address);
81 wait4command_complete(spi_address);
82 wait4flashpart_ready(spi_address);
83
84 read_spi_status(spi_address);
85}
86
87void read_spi_id(volatile u8 * spi_address)
88{
89 u8 mid = 0, did = 0;
90 *spi_address = 0x90;
91 *(spi_address + 1) = 0x23; /* RxByte=2, TxByte=3 */
92 reset_internal_fifo_pointer(spi_address);
93 *(spi_address + 0xC) = 0;
94 *(spi_address + 0xC) = 0;
95 *(spi_address + 0xC) = 0;
96 reset_internal_fifo_pointer(spi_address);
97 execute_command(spi_address);
98 wait4command_complete(spi_address);
99 reset_internal_fifo_pointer(spi_address);
100 mid = *(spi_address + 0xC);
101 printk(BIOS_DEBUG, "mid=%x, did=%x\n", mid, did);
102 mid = *(spi_address + 0xC);
103 printk(BIOS_DEBUG, "mid=%x, did=%x\n", mid, did);
104 mid = *(spi_address + 0xC);
105 printk(BIOS_DEBUG, "mid=%x, did=%x\n", mid, did);
106
107 mid = *(spi_address + 0xC);
108 did = *(spi_address + 0xC);
109 printk(BIOS_DEBUG, "mid=%x, did=%x\n", mid, did);
110}
111
112void spi_write_enable(volatile u8 * spi_address)
113{
114 *spi_address = 0x06; /* Write Enable */
115 *(spi_address + 1) = 0x0; /* RxByte=0, TxByte=0 */
116 execute_command(spi_address);
117 wait4command_complete(spi_address);
118}
119
120void spi_write_disable(volatile u8 * spi_address)
121{
122 *spi_address = 0x04; /* Write Enable */
123 *(spi_address + 1) = 0x0; /* RxByte=0, TxByte=0 */
124 execute_command(spi_address);
125 wait4command_complete(spi_address);
126}
127
128void sector_erase_spi(volatile u8 * spi_address, u32 address)
129{
130 spi_write_enable(spi_address);
131 *spi_address = 0x20;
132 *(spi_address + 1) = 0x03; /* RxByte=0, TxByte=3 */
133
134 reset_internal_fifo_pointer(spi_address);
135 *(spi_address + 0xC) = (address >> 16) & 0xFF;
136 *(spi_address + 0xC) = (address >> 8) & 0xFF;
137 *(spi_address + 0xC) = (address >> 0) & 0xFF;
138 reset_internal_fifo_pointer(spi_address);
139 execute_command(spi_address);
140 wait4command_complete(spi_address);
141 wait4flashpart_ready(spi_address);
142}
143
144void chip_erase_spi(volatile u8 * spi_address)
145{
146 spi_write_enable(spi_address);
147 *spi_address = 0xC7;
148 *(spi_address + 1) = 0x00;
149 execute_command(spi_address);
150 wait4command_complete(spi_address);
151 wait4flashpart_ready(spi_address);
152}
153
154void byte_program(volatile u8 * spi_address, u32 address, u32 data)
155{
156 spi_write_enable(spi_address);
157 *spi_address = 0x02;
158 *(spi_address + 1) = 0x0 << 4 | 4;
159 reset_internal_fifo_pointer(spi_address);
160 *(spi_address + 0xC) = (address >> 16) & 0xFF;
161 *(spi_address + 0xC) = (address >> 8) & 0xFF;
162 *(spi_address + 0xC) = (address >> 0) & 0xFF;
163 *(spi_address + 0xC) = data & 0xFF;
164 reset_internal_fifo_pointer(spi_address);
165 execute_command(spi_address);
166 wait4command_complete(spi_address);
167 wait4flashpart_ready(spi_address);
168}
169
170void dword_noneAAI_program(volatile u8 * spi_address, u32 address, u32 data)
171{
172 u8 i;
173 /*
174 * printk(BIOS_SPEW, "%s: addr=%x, data=%x\n", __func__, address, data);
175 */
176 for (i = 0; i < 4; i++) {
177 spi_write_enable(spi_address);
178 *spi_address = 0x02;
179 *(spi_address + 1) = 0x0 << 4 | 4;
180 reset_internal_fifo_pointer(spi_address);
181 *(spi_address + 0xC) = (address >> 16) & 0xFF;
182 *(spi_address + 0xC) = (address >> 8) & 0xFF;
183 *(spi_address + 0xC) = (address >> 0) & 0xFF;
184 *(spi_address + 0xC) = data & 0xFF;
185 data >>= 8;
186 address++;
187 reset_internal_fifo_pointer(spi_address);
188 execute_command(spi_address);
189 wait4command_complete(spi_address);
190 wait4flashpart_ready(spi_address);
191 }
192}
193
194void dword_program(volatile u8 * spi_address, u32 address, u32 data)
195{
196 spi_write_enable(spi_address);
197 *spi_address = 0x02;
198 *(spi_address + 1) = 0x0 << 4 | 7;
199 reset_internal_fifo_pointer(spi_address);
200 *(spi_address + 0xC) = (address >> 16) & 0xFF;
201 *(spi_address + 0xC) = (address >> 8) & 0xFF;
202 *(spi_address + 0xC) = (address >> 0) & 0xFF;
203 *(spi_address + 0xC) = data & 0xFF;
204 *(spi_address + 0xC) = (data >> 8) & 0xFF;
205 *(spi_address + 0xC) = (data >> 16) & 0xFF;
206 *(spi_address + 0xC) = (data >> 24) & 0xFF;
207 reset_internal_fifo_pointer(spi_address);
208 execute_command(spi_address);
209 wait4command_complete(spi_address);
210 wait4flashpart_ready(spi_address);
211}
212
213void direct_byte_program(volatile u8 * spi_address, volatile u32 * address, u32 data)
214{
215 spi_write_enable(spi_address);
216 *address = data;
217 wait4flashpart_ready(spi_address);
218}