blob: b0ef753e109e28687514528d5e50ddbac98051e7 [file] [log] [blame]
zbao01bd79f2012-03-23 11:36:08 +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 "SBPLATFORM.h"
23
24
25void execute_command(volatile u8 * spi_address)
26{
27 *(spi_address + 2) |= 1;
28}
29
30void wait4command_complete(volatile u8 * spi_address)
31{
32 while (*(spi_address + 2) & 1)
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) = 0x11;
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 return val;
60}
61
62void wait4flashpart_ready(volatile u8 * spi_address)
63{
64 while (read_spi_status(spi_address) & 1) ;
65}
66
67void write_spi_status(volatile u8 * spi_address, u8 status)
68{
69 *spi_address = 0x50; /* EWSR */
70 *(spi_address + 1) = 0; /* RxByte=TxByte=0 */
71 execute_command(spi_address);
72 wait4command_complete(spi_address);
73
74 *spi_address = 0x01; /* WRSR */
75 *(spi_address + 1) = 0x01;
76 reset_internal_fifo_pointer(spi_address);
77 *(spi_address + 0xC) = status;
78 reset_internal_fifo_pointer(spi_address);
79 execute_command(spi_address);
80 wait4command_complete(spi_address);
81 wait4flashpart_ready(spi_address);
82
83 read_spi_status(spi_address);
84}
85
86void read_spi_id(volatile u8 * spi_address)
87{
88 u8 mid = 0, did = 0;
89 *spi_address = 0x90;
90 *(spi_address + 1) = 0x23; /* RxByte=2, TxByte=3 */
91 reset_internal_fifo_pointer(spi_address);
92 *(spi_address + 0xC) = 0;
93 *(spi_address + 0xC) = 0;
94 *(spi_address + 0xC) = 0;
95 reset_internal_fifo_pointer(spi_address);
96 execute_command(spi_address);
97 wait4command_complete(spi_address);
98 reset_internal_fifo_pointer(spi_address);
99 mid = *(spi_address + 0xC);
100 printk(BIOS_DEBUG, "mid=%x, did=%x\n", mid, did);
101 mid = *(spi_address + 0xC);
102 printk(BIOS_DEBUG, "mid=%x, did=%x\n", mid, did);
103 mid = *(spi_address + 0xC);
104 printk(BIOS_DEBUG, "mid=%x, did=%x\n", mid, did);
105
106 mid = *(spi_address + 0xC);
107 did = *(spi_address + 0xC);
108 printk(BIOS_DEBUG, "mid=%x, did=%x\n", mid, did);
109}
110
111void spi_write_enable(volatile u8 * spi_address)
112{
113 *spi_address = 0x06; /* Write Enable */
114 *(spi_address + 1) = 0x0; /* RxByte=0, TxByte=0 */
115 execute_command(spi_address);
116 wait4command_complete(spi_address);
117}
118
119void sector_erase_spi(volatile u8 * spi_address, u32 address)
120{
121 spi_write_enable(spi_address);
122 *spi_address = 0x20;
123 *(spi_address + 1) = 0x03; /* RxByte=0, TxByte=3 */
124
125 reset_internal_fifo_pointer(spi_address);
126 *(spi_address + 0xC) = (address >> 16) & 0xFF;
127 *(spi_address + 0xC) = (address >> 8) & 0xFF;
128 *(spi_address + 0xC) = (address >> 0) & 0xFF;
129 reset_internal_fifo_pointer(spi_address);
130 execute_command(spi_address);
131 wait4command_complete(spi_address);
132 wait4flashpart_ready(spi_address);
133}
134
135void chip_erase_spi(volatile u8 * spi_address)
136{
137 spi_write_enable(spi_address);
138 *spi_address = 0xC7;
139 *(spi_address + 1) = 0x00;
140 execute_command(spi_address);
141 wait4command_complete(spi_address);
142 wait4flashpart_ready(spi_address);
143}
144
145void byte_program(volatile u8 * spi_address, u32 address, u32 data)
146{
147 spi_write_enable(spi_address);
148 *spi_address = 0x02;
149 *(spi_address + 1) = 0x0 << 4 | 4;
150 reset_internal_fifo_pointer(spi_address);
151 *(spi_address + 0xC) = (address >> 16) & 0xFF;
152 *(spi_address + 0xC) = (address >> 8) & 0xFF;
153 *(spi_address + 0xC) = (address >> 0) & 0xFF;
154 *(spi_address + 0xC) = data & 0xFF;
155 reset_internal_fifo_pointer(spi_address);
156 execute_command(spi_address);
157 wait4command_complete(spi_address);
158 wait4flashpart_ready(spi_address);
159}
160
161void dword_noneAAI_program(volatile u8 * spi_address, u32 address, u32 data)
162{
163 u8 i;
164 /*
165 * printk(BIOS_SPEW, "%s: addr=%x, data=%x\n", __func__, address, data);
166 */
167 for (i = 0; i < 4; i++) {
168 spi_write_enable(spi_address);
169 *spi_address = 0x02;
170 *(spi_address + 1) = 0x0 << 4 | 4;
171 reset_internal_fifo_pointer(spi_address);
172 *(spi_address + 0xC) = (address >> 16) & 0xFF;
173 *(spi_address + 0xC) = (address >> 8) & 0xFF;
174 *(spi_address + 0xC) = (address >> 0) & 0xFF;
175 *(spi_address + 0xC) = data & 0xFF;
176 data >>= 8;
177 address++;
178 reset_internal_fifo_pointer(spi_address);
179 execute_command(spi_address);
180 wait4command_complete(spi_address);
181 wait4flashpart_ready(spi_address);
182 }
183}
184
185void dword_program(volatile u8 * spi_address, u32 address, u32 data)
186{
187 spi_write_enable(spi_address);
188 *spi_address = 0x02;
189 *(spi_address + 1) = 0x0 << 4 | 7;
190 reset_internal_fifo_pointer(spi_address);
191 *(spi_address + 0xC) = (address >> 16) & 0xFF;
192 *(spi_address + 0xC) = (address >> 8) & 0xFF;
193 *(spi_address + 0xC) = (address >> 0) & 0xFF;
194 *(spi_address + 0xC) = data & 0xFF;
195 *(spi_address + 0xC) = (data >> 8) & 0xFF;
196 *(spi_address + 0xC) = (data >> 16) & 0xFF;
197 *(spi_address + 0xC) = (data >> 24) & 0xFF;
198 reset_internal_fifo_pointer(spi_address);
199 execute_command(spi_address);
200 wait4command_complete(spi_address);
201 wait4flashpart_ready(spi_address);
202}
203
204void direct_byte_program(volatile u8 * spi_address, volatile u32 * address, u32 data)
205{
206 spi_write_enable(spi_address);
207 *address = data;
208 wait4flashpart_ready(spi_address);
209}