source: trunk/sb600spi.c @ 1474

Revision 1474, 10.1 KB checked in by hailfinger, 5 months ago (diff)

Add struct flashctx * parameter to all functions accessing flash chips.

All programmer access function prototypes except init have been made
static and moved to the respective file.

A few internal functions in flash chip drivers had chipaddr parameters
which are no longer needed.

The lines touched by flashctx changes have been adjusted to 80 columns
except in header files.

Signed-off-by: Carl-Daniel Hailfinger <c-d.hailfinger.devel.2006@…>
Acked-by: Michael Karcher <flashrom@…>

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