source: trunk/sb600spi.c

Last change on this file was 1549, checked in by hailfinger, 10 months ago

Hide hwaccess.h from public API.

Move hwaccess.h #include from flash.h to individual drivers.
libflashrom users need flash.h, but they do not care about hwaccess.h
and should not see its definitions because they may conflict with
other hardware access functions and #defines used by the libflashrom
user.

Signed-off-by: Patrick Georgi <patrick.georgi@…>
Acked-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@…>

File size: 10.2 KB
Line 
1/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2008 Wang Qingpei <Qingpei.Wang@amd.com>
5 * Copyright (C) 2008 Joe Bao <Zheng.Bao@amd.com>
6 * Copyright (C) 2008 Advanced Micro Devices, Inc.
7 * Copyright (C) 2009, 2010 Carl-Daniel Hailfinger
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
22 */
23
24#if defined(__i386__) || defined(__x86_64__)
25
26#include "flash.h"
27#include "programmer.h"
28#include "hwaccess.h"
29#include "spi.h"
30
31/* This struct is unused, but helps visualize the SB600 SPI BAR layout.
32 *struct sb600_spi_controller {
33 *      unsigned int spi_cntrl0;        / * 00h * /
34 *      unsigned int restrictedcmd1;    / * 04h * /
35 *      unsigned int restrictedcmd2;    / * 08h * /
36 *      unsigned int spi_cntrl1;        / * 0ch * /
37 *      unsigned int spi_cmdvalue0;     / * 10h * /
38 *      unsigned int spi_cmdvalue1;     / * 14h * /
39 *      unsigned int spi_cmdvalue2;     / * 18h * /
40 *      unsigned int spi_fakeid;        / * 1Ch * /
41 *};
42 */
43
44static uint8_t *sb600_spibar = NULL;
45
46static void reset_internal_fifo_pointer(void)
47{
48        mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2);
49
50        /* FIXME: This loop makes no sense at all. */
51        while (mmio_readb(sb600_spibar + 0xD) & 0x7)
52                msg_pspew("reset\n");
53}
54
55static int compare_internal_fifo_pointer(uint8_t want)
56{
57        uint8_t tmp;
58
59        tmp = mmio_readb(sb600_spibar + 0xd) & 0x07;
60        want &= 0x7;
61        if (want != tmp) {
62                msg_perr("SB600 FIFO pointer corruption! Pointer is %d, wanted "
63                         "%d\n", tmp, want);
64                msg_perr("Something else is accessing the flash chip and "
65                         "causes random corruption.\nPlease stop all "
66                         "applications and drivers and IPMI which access the "
67                         "flash chip.\n");
68                return 1;
69        } else {
70                msg_pspew("SB600 FIFO pointer is %d, wanted %d\n", tmp, want);
71                return 0;
72        }
73}
74
75static int reset_compare_internal_fifo_pointer(uint8_t want)
76{
77        int ret;
78
79        ret = compare_internal_fifo_pointer(want);
80        reset_internal_fifo_pointer();
81        return ret;
82}
83
84static void execute_command(void)
85{
86        mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2);
87
88        while (mmio_readb(sb600_spibar + 2) & 1)
89                ;
90}
91
92static int sb600_spi_send_command(struct flashctx *flash, unsigned int writecnt,
93                                  unsigned int readcnt,
94                                  const unsigned char *writearr,
95                                  unsigned char *readarr)
96{
97        int count;
98        /* First byte is cmd which can not being sent through FIFO. */
99        unsigned char cmd = *writearr++;
100        unsigned int readoffby1;
101        unsigned char readwrite;
102
103        writecnt--;
104
105        msg_pspew("%s, cmd=%x, writecnt=%x, readcnt=%x\n",
106                  __func__, cmd, writecnt, readcnt);
107
108        if (readcnt > 8) {
109                msg_pinfo("%s, SB600 SPI controller can not receive %d bytes, "
110                       "it is limited to 8 bytes\n", __func__, readcnt);
111                return SPI_INVALID_LENGTH;
112        }
113
114        if (writecnt > 8) {
115                msg_pinfo("%s, SB600 SPI controller can not send %d bytes, "
116                       "it is limited to 8 bytes\n", __func__, writecnt);
117                return SPI_INVALID_LENGTH;
118        }
119
120        /* This is a workaround for a bug in SB600 and SB700. If we only send
121         * an opcode and no additional data/address, the SPI controller will
122         * read one byte too few from the chip. Basically, the last byte of
123         * the chip response is discarded and will not end up in the FIFO.
124         * It is unclear if the CS# line is set high too early as well.
125         */
126        readoffby1 = (writecnt) ? 0 : 1;
127        readwrite = (readcnt + readoffby1) << 4 | (writecnt);
128        mmio_writeb(readwrite, sb600_spibar + 1);
129        mmio_writeb(cmd, sb600_spibar + 0);
130
131        /* Before we use the FIFO, reset it first. */
132        reset_internal_fifo_pointer();
133
134        /* Send the write byte to FIFO. */
135        msg_pspew("Writing: ");
136        for (count = 0; count < writecnt; count++, writearr++) {
137                msg_pspew("[%02x]", *writearr);
138                mmio_writeb(*writearr, sb600_spibar + 0xC);
139        }
140        msg_pspew("\n");
141
142        /*
143         * We should send the data by sequence, which means we need to reset
144         * the FIFO pointer to the first byte we want to send.
145         */
146        if (reset_compare_internal_fifo_pointer(writecnt))
147                return SPI_PROGRAMMER_ERROR;
148
149        msg_pspew("Executing: \n");
150        execute_command();
151
152        /*
153         * After the command executed, we should find out the index of the
154         * received byte. Here we just reset the FIFO pointer and skip the
155         * writecnt.
156         * It would be possible to increase the FIFO pointer by one instead
157         * of reading and discarding one byte from the FIFO.
158         * The FIFO is implemented on top of an 8 byte ring buffer and the
159         * buffer is never cleared. For every byte that is shifted out after
160         * the opcode, the FIFO already stores the response from the chip.
161         * Usually, the chip will respond with 0x00 or 0xff.
162         */
163        if (reset_compare_internal_fifo_pointer(writecnt + readcnt))
164                return SPI_PROGRAMMER_ERROR;
165
166        /* Skip the bytes we sent. */
167        msg_pspew("Skipping: ");
168        for (count = 0; count < writecnt; count++) {
169                cmd = mmio_readb(sb600_spibar + 0xC);
170                msg_pspew("[%02x]", cmd);
171        }
172        msg_pspew("\n");
173        if (compare_internal_fifo_pointer(writecnt))
174                return SPI_PROGRAMMER_ERROR;
175
176        msg_pspew("Reading: ");
177        for (count = 0; count < readcnt; count++, readarr++) {
178                *readarr = mmio_readb(sb600_spibar + 0xC);
179                msg_pspew("[%02x]", *readarr);
180        }
181        msg_pspew("\n");
182        if (reset_compare_internal_fifo_pointer(readcnt + writecnt))
183                return SPI_PROGRAMMER_ERROR;
184
185        if (mmio_readb(sb600_spibar + 1) != readwrite) {
186                msg_perr("Unexpected change in SB600 read/write count!\n");
187                msg_perr("Something else is accessing the flash chip and "
188                         "causes random corruption.\nPlease stop all "
189                         "applications and drivers and IPMI which access the "
190                         "flash chip.\n");
191                return SPI_PROGRAMMER_ERROR;
192        }
193
194        return 0;
195}
196
197static const struct spi_programmer spi_programmer_sb600 = {
198        .type = SPI_CONTROLLER_SB600,
199        .max_data_read = 8,
200        .max_data_write = 5,
201        .command = sb600_spi_send_command,
202        .multicommand = default_spi_send_multicommand,
203        .read = default_spi_read,
204        .write_256 = default_spi_write_256,
205        .write_aai = default_spi_write_aai,
206};
207
208int sb600_probe_spi(struct pci_dev *dev)
209{
210        struct pci_dev *smbus_dev;
211        uint32_t tmp;
212        uint8_t reg;
213        static const char *const speed_names[4] = {
214                "Reserved", "33", "22", "16.5"
215        };
216
217        /* Read SPI_BaseAddr */
218        tmp = pci_read_long(dev, 0xa0);
219        tmp &= 0xffffffe0;      /* remove bits 4-0 (reserved) */
220        msg_pdbg("SPI base address is at 0x%x\n", tmp);
221
222        /* If the BAR has address 0, it is unlikely SPI is used. */
223        if (!tmp)
224                return 0;
225
226        /* Physical memory has to be mapped at page (4k) boundaries. */
227        sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000,
228                               0x1000);
229        /* The low bits of the SPI base address are used as offset into
230         * the mapped page.
231         */
232        sb600_spibar += tmp & 0xfff;
233
234        tmp = pci_read_long(dev, 0xa0);
235        msg_pdbg("AltSpiCSEnable=%i, SpiRomEnable=%i, "
236                     "AbortEnable=%i\n", tmp & 0x1, (tmp & 0x2) >> 1,
237                     (tmp & 0x4) >> 2);
238        tmp = (pci_read_byte(dev, 0xba) & 0x4) >> 2;
239        msg_pdbg("PrefetchEnSPIFromIMC=%i, ", tmp);
240
241        tmp = pci_read_byte(dev, 0xbb);
242        /* FIXME: Set bit 3,6,7 if not already set.
243         * Set bit 5, otherwise SPI accesses are pointless in LPC mode.
244         * See doc 42413 AMD SB700/710/750 RPR.
245         */
246        msg_pdbg("PrefetchEnSPIFromHost=%i, SpiOpEnInLpcMode=%i\n",
247                     tmp & 0x1, (tmp & 0x20) >> 5);
248        tmp = mmio_readl(sb600_spibar);
249        /* FIXME: If SpiAccessMacRomEn or SpiHostAccessRomEn are zero on
250         * SB700 or later, reads and writes will be corrupted. Abort in this
251         * case. Make sure to avoid this check on SB600.
252         */
253        msg_pdbg("SpiArbEnable=%i, SpiAccessMacRomEn=%i, "
254                     "SpiHostAccessRomEn=%i, ArbWaitCount=%i, "
255                     "SpiBridgeDisable=%i, DropOneClkOnRd=%i\n",
256                     (tmp >> 19) & 0x1, (tmp >> 22) & 0x1,
257                     (tmp >> 23) & 0x1, (tmp >> 24) & 0x7,
258                     (tmp >> 27) & 0x1, (tmp >> 28) & 0x1);
259        tmp = (mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3;
260        msg_pdbg("NormSpeed is %s MHz\n", speed_names[tmp]);
261
262        /* Look for the SMBus device. */
263        smbus_dev = pci_dev_find(0x1002, 0x4385);
264
265        if (!smbus_dev) {
266                smbus_dev = pci_dev_find(0x1022, 0x780b); /* AMD Hudson */
267                if (!smbus_dev) {
268                        msg_perr("ERROR: SMBus device not found. Not enabling SPI.\n");
269                        return ERROR_NONFATAL;
270                }
271        }
272
273        /* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */
274        /* GPIO11/SPI_DO and GPIO12/SPI_DI status */
275        reg = pci_read_byte(smbus_dev, 0xAB);
276        reg &= 0xC0;
277        msg_pdbg("GPIO11 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_DO");
278        msg_pdbg("GPIO12 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_DI");
279        if (reg != 0x00) {
280                msg_pdbg("Not enabling SPI");
281                return 0;
282        }
283        /* GPIO31/SPI_HOLD and GPIO32/SPI_CS status */
284        reg = pci_read_byte(smbus_dev, 0x83);
285        reg &= 0xC0;
286        msg_pdbg("GPIO31 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_HOLD");
287        msg_pdbg("GPIO32 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_CS");
288        /* SPI_HOLD is not used on all boards, filter it out. */
289        if ((reg & 0x80) != 0x00) {
290                msg_pdbg("Not enabling SPI");
291                return 0;
292        }
293        /* GPIO47/SPI_CLK status */
294        reg = pci_read_byte(smbus_dev, 0xA7);
295        reg &= 0x40;
296        msg_pdbg("GPIO47 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_CLK");
297        if (reg != 0x00) {
298                msg_pdbg("Not enabling SPI");
299                return 0;
300        }
301
302        reg = pci_read_byte(dev, 0x40);
303        msg_pdbg("SB700 IMC is %sactive.\n", (reg & (1 << 7)) ? "" : "not ");
304        if (reg & (1 << 7)) {
305                /* If we touch any region used by the IMC, the IMC and the SPI
306                 * interface will lock up, and the only way to recover is a
307                 * hard reset, but that is a bad choice for a half-erased or
308                 * half-written flash chip.
309                 * There appears to be an undocumented register which can freeze
310                 * or disable the IMC, but for now we want to play it safe.
311                 */
312                msg_perr("The SB700 IMC is active and may interfere with SPI "
313                         "commands. Disabling write.\n");
314                /* FIXME: Should we only disable SPI writes, or will the lockup
315                 * affect LPC/FWH chips as well?
316                 */
317                programmer_may_write = 0;
318        }
319
320        /* Bring the FIFO to a clean state. */
321        reset_internal_fifo_pointer();
322
323        register_spi_programmer(&spi_programmer_sb600);
324        return 0;
325}
326
327#endif
Note: See TracBrowser for help on using the repository browser.