blob: 43bf407ad729ab4ba0c6d511cb119e405c8bf956 [file] [log] [blame]
uwe17efbed2008-11-28 21:36:51 +00001/*
2 * This file is part of the flashrom project.
3 *
stepan6c529e62008-11-29 15:07:15 +00004 * Copyright (C) 2008 Wang Qingpei <Qingpei.Wang@amd.com>
5 * Copyright (C) 2008 Joe Bao <Zheng.Bao@amd.com>
uwef5176752009-04-13 21:35:49 +00006 * Copyright (C) 2008 Advanced Micro Devices, Inc.
ivy_jian8e0c4e52017-08-23 09:17:56 +08007 * Copyright (C) 2009, 2010, 2013 Carl-Daniel Hailfinger
8 * Copyright (C) 2013 Stefan Tauner
uwe17efbed2008-11-28 21:36:51 +00009 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
uwe17efbed2008-11-28 21:36:51 +000019 */
20
hailfinger324a9cc2010-05-26 01:45:41 +000021#if defined(__i386__) || defined(__x86_64__)
22
ivy_jian8e0c4e52017-08-23 09:17:56 +080023#include <string.h>
24#include <stdlib.h>
uwe17efbed2008-11-28 21:36:51 +000025#include "flash.h"
hailfinger428f6852010-07-27 22:41:39 +000026#include "programmer.h"
ivy_jian8e0c4e52017-08-23 09:17:56 +080027#include "hwaccess.h"
uwe17efbed2008-11-28 21:36:51 +000028#include "spi.h"
29
hailfinger469ab3b2009-06-23 00:47:26 +000030/* 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 */
uwe17efbed2008-11-28 21:36:51 +000042
mkarcher8b2b7ab2010-07-22 18:04:19 +000043static uint8_t *sb600_spibar = NULL;
ivy_jian8e0c4e52017-08-23 09:17:56 +080044enum amd_chipset {
45 CHIPSET_AMD_UNKNOWN,
46 CHIPSET_SB6XX,
47 CHIPSET_SB7XX, /* SP5100 too */
48 CHIPSET_SB89XX, /* Hudson-1 too */
49 CHIPSET_HUDSON234,
50 CHIPSET_BOLTON,
51 CHIPSET_YANGTZE,
52 CHIPSET_PROMONTORY,
53};
ivy_jian8e0c4e52017-08-23 09:17:56 +080054
55#define FIFO_SIZE_OLD 8
56#define FIFO_SIZE_YANGTZE 71
57
Edward O'Callaghan999593b2020-07-31 12:21:02 +100058struct sb600spi_data {
59 struct flashctx *flash;
60};
Edward O'Callaghana040e622020-11-04 10:32:24 +110061
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +100062static int find_smbus_dev_rev(uint16_t vendor, uint16_t device)
ivy_jian8e0c4e52017-08-23 09:17:56 +080063{
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +100064 struct pci_dev *smbus_dev = pci_dev_find(vendor, device);
65 if (!smbus_dev) {
66 msg_pdbg("No SMBus device with ID %04X:%04X found.\n", vendor, device);
67 msg_perr("ERROR: SMBus device not found. Not enabling SPI.\n");
68 return -1;
69 }
70 return pci_read_byte(smbus_dev, PCI_REVISION_ID);
ivy_jian8e0c4e52017-08-23 09:17:56 +080071}
72
73/* Determine the chipset's version and identify the respective SMBUS device. */
Edward O'Callaghanf77f9432019-10-30 00:38:16 +110074static enum amd_chipset determine_generation(struct pci_dev *dev)
ivy_jian8e0c4e52017-08-23 09:17:56 +080075{
ivy_jian8e0c4e52017-08-23 09:17:56 +080076 msg_pdbg2("Trying to determine the generation of the SPI interface... ");
77 if (dev->device_id == 0x438d) {
ivy_jian8e0c4e52017-08-23 09:17:56 +080078 msg_pdbg("SB6xx detected.\n");
Edward O'Callaghanf77f9432019-10-30 00:38:16 +110079 return CHIPSET_SB6XX;
ivy_jian8e0c4e52017-08-23 09:17:56 +080080 } else if (dev->device_id == 0x439d) {
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +100081 int rev = find_smbus_dev_rev(0x1002, 0x4385);
82 if (rev < 0)
Edward O'Callaghanf77f9432019-10-30 00:38:16 +110083 return CHIPSET_AMD_UNKNOWN;
ivy_jian8e0c4e52017-08-23 09:17:56 +080084 if (rev >= 0x39 && rev <= 0x3D) {
ivy_jian8e0c4e52017-08-23 09:17:56 +080085 msg_pdbg("SB7xx/SP5100 detected.\n");
Edward O'Callaghanf77f9432019-10-30 00:38:16 +110086 return CHIPSET_SB7XX;
ivy_jian8e0c4e52017-08-23 09:17:56 +080087 } else if (rev >= 0x40 && rev <= 0x42) {
ivy_jian8e0c4e52017-08-23 09:17:56 +080088 msg_pdbg("SB8xx/SB9xx/Hudson-1 detected.\n");
Edward O'Callaghanf77f9432019-10-30 00:38:16 +110089 return CHIPSET_SB89XX;
ivy_jian8e0c4e52017-08-23 09:17:56 +080090 } else {
91 msg_pwarn("SB device found but SMBus revision 0x%02x does not match known values.\n"
92 "Assuming SB8xx/SB9xx/Hudson-1. Please send a log to flashrom@flashrom.org\n",
93 rev);
Edward O'Callaghanf77f9432019-10-30 00:38:16 +110094 return CHIPSET_SB89XX;
ivy_jian8e0c4e52017-08-23 09:17:56 +080095 }
96 } else if (dev->device_id == 0x780e) {
97 /* The PCI ID of the LPC bridge doesn't change between Hudson-2/3/4 and Yangtze (Kabini/Temash)
98 * although they use different SPI interfaces. */
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +100099 int rev = find_smbus_dev_rev(0x1022, 0x780B);
100 if (rev < 0)
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100101 return CHIPSET_AMD_UNKNOWN;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800102 if (rev >= 0x11 && rev <= 0x15) {
ivy_jian8e0c4e52017-08-23 09:17:56 +0800103 msg_pdbg("Hudson-2/3/4 detected.\n");
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100104 return CHIPSET_HUDSON234;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800105 } else if (rev == 0x16) {
ivy_jian8e0c4e52017-08-23 09:17:56 +0800106 msg_pdbg("Bolton detected.\n");
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100107 return CHIPSET_BOLTON;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800108 } else if ((rev >= 0x39 && rev <= 0x3A) || rev == 0x42) {
ivy_jian8e0c4e52017-08-23 09:17:56 +0800109 msg_pdbg("Yangtze detected.\n");
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100110 return CHIPSET_YANGTZE;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800111 } else {
112 msg_pwarn("FCH device found but SMBus revision 0x%02x does not match known values.\n"
113 "Please report this to flashrom@flashrom.org and include this log and\n"
114 "the output of lspci -nnvx, thanks!.\n", rev);
115 }
116 } else if (dev->device_id == 0x790e) {
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000117 int rev = find_smbus_dev_rev(0x1022, 0x790B);
118 if (rev < 0)
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100119 return CHIPSET_AMD_UNKNOWN;
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000120 if (rev == 0x4a) {
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000121 msg_pdbg("Yangtze detected.\n");
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100122 return CHIPSET_YANGTZE;
Edward O'Callaghan999593b2020-07-31 12:21:02 +1000123 /**
124 * FCH chipsets called 'Promontory' are one's with the
125 * so-called SPI100 ip core that uses memory mapping and
126 * not a ring buffer for transactions. Typically this is
127 * found on both Stoney Ridge and Zen platforms.
128 *
129 * The revisions I have found by searching various lspci
130 * outputs are as follows: 0x4b, 0x59 & 0x61.
131 */
Edward O'Callaghan7f7a1e92020-12-21 12:29:44 +1100132 } else if (rev == 0x4b || rev == 0x51 || rev == 0x59 || rev == 0x61) {
Edward O'Callaghan999593b2020-07-31 12:21:02 +1000133 msg_pdbg("Promontory (rev 0x%02x) detected.\n", rev);
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100134 return CHIPSET_PROMONTORY;
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000135 } else {
136 msg_pwarn("FCH device found but SMBus revision 0x%02x does not match known values.\n"
137 "Please report this to flashrom@flashrom.org and include this log and\n"
138 "the output of lspci -nnvx, thanks!.\n", rev);
139 }
140
141
ivy_jian8e0c4e52017-08-23 09:17:56 +0800142 } else
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000143 msg_pwarn("%s: Unknown LPC device %" PRIx16 ":%" PRIx16 ".\n"
ivy_jian8e0c4e52017-08-23 09:17:56 +0800144 "Please report this to flashrom@flashrom.org and include this log and\n"
145 "the output of lspci -nnvx, thanks!\n",
146 __func__, dev->vendor_id, dev->device_id);
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100147
148 msg_perr("Could not determine chipset generation.");
149 return CHIPSET_AMD_UNKNOWN;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800150}
uwe17efbed2008-11-28 21:36:51 +0000151
hailfinger469ab3b2009-06-23 00:47:26 +0000152static void reset_internal_fifo_pointer(void)
uwe17efbed2008-11-28 21:36:51 +0000153{
hailfinger38da6812009-05-17 15:49:24 +0000154 mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2);
uwe17efbed2008-11-28 21:36:51 +0000155
ivy_jian8e0c4e52017-08-23 09:17:56 +0800156 /* FIXME: This loop needs a timeout and a clearer message. */
hailfinger38da6812009-05-17 15:49:24 +0000157 while (mmio_readb(sb600_spibar + 0xD) & 0x7)
hailfinger4efe6682010-01-10 01:59:50 +0000158 msg_pspew("reset\n");
uwe17efbed2008-11-28 21:36:51 +0000159}
160
hailfingere30f6d52010-08-18 15:12:43 +0000161static int compare_internal_fifo_pointer(uint8_t want)
162{
ivy_jian8e0c4e52017-08-23 09:17:56 +0800163 uint8_t have = mmio_readb(sb600_spibar + 0xd) & 0x07;
164 want %= FIFO_SIZE_OLD;
165 if (have != want) {
166 msg_perr("AMD SPI FIFO pointer corruption! Pointer is %d, wanted %d\n", have, want);
167 msg_perr("Something else is accessing the flash chip and causes random corruption.\n"
168 "Please stop all applications and drivers and IPMI which access the flash chip.\n");
hailfingere30f6d52010-08-18 15:12:43 +0000169 return 1;
170 } else {
ivy_jian8e0c4e52017-08-23 09:17:56 +0800171 msg_pspew("AMD SPI FIFO pointer is %d, wanted %d\n", have, want);
hailfingere30f6d52010-08-18 15:12:43 +0000172 return 0;
173 }
174}
175
ivy_jian8e0c4e52017-08-23 09:17:56 +0800176/* Check the number of bytes to be transmitted and extract opcode. */
177static int check_readwritecnt(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt)
hailfingere30f6d52010-08-18 15:12:43 +0000178{
Edward O'Callaghan9326c852020-11-23 23:36:14 +1100179 unsigned int maxwritecnt = flash->mst->spi.max_data_write + 3;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800180 if (writecnt > maxwritecnt) {
181 msg_pinfo("%s: SPI controller can not send %d bytes, it is limited to %d bytes\n",
182 __func__, writecnt, maxwritecnt);
183 return SPI_INVALID_LENGTH;
184 }
hailfingere30f6d52010-08-18 15:12:43 +0000185
Edward O'Callaghan9326c852020-11-23 23:36:14 +1100186 unsigned int maxreadcnt = flash->mst->spi.max_data_read;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800187 if (readcnt > maxreadcnt) {
188 msg_pinfo("%s: SPI controller can not receive %d bytes, it is limited to %d bytes\n",
189 __func__, readcnt, maxreadcnt);
190 return SPI_INVALID_LENGTH;
191 }
192 return 0;
hailfingere30f6d52010-08-18 15:12:43 +0000193}
194
hailfinger469ab3b2009-06-23 00:47:26 +0000195static void execute_command(void)
uwe17efbed2008-11-28 21:36:51 +0000196{
ivy_jian8e0c4e52017-08-23 09:17:56 +0800197 msg_pspew("Executing... ");
hailfinger38da6812009-05-17 15:49:24 +0000198 mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2);
hailfinger38da6812009-05-17 15:49:24 +0000199 while (mmio_readb(sb600_spibar + 2) & 1)
uwe17efbed2008-11-28 21:36:51 +0000200 ;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800201 msg_pspew("done\n");
uwe17efbed2008-11-28 21:36:51 +0000202}
203
ivy_jian8e0c4e52017-08-23 09:17:56 +0800204static int sb600_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
205 unsigned int readcnt,
206 const unsigned char *writearr,
207 unsigned char *readarr)
uwe17efbed2008-11-28 21:36:51 +0000208{
ivy_jian8e0c4e52017-08-23 09:17:56 +0800209 /* First byte is cmd which can not be sent through the FIFO. */
uwe17efbed2008-11-28 21:36:51 +0000210 unsigned char cmd = *writearr++;
uwe17efbed2008-11-28 21:36:51 +0000211 writecnt--;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800212 msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, cmd, writecnt, readcnt);
213 mmio_writeb(cmd, sb600_spibar + 0);
uwe17efbed2008-11-28 21:36:51 +0000214
ivy_jian8e0c4e52017-08-23 09:17:56 +0800215 int ret = check_readwritecnt(flash, writecnt, readcnt);
216 if (ret != 0)
217 return ret;
uwe17efbed2008-11-28 21:36:51 +0000218
ivy_jian8e0c4e52017-08-23 09:17:56 +0800219 /* This is a workaround for a bug in SPI controller. If we only send
hailfinger783de7b2009-07-23 01:36:08 +0000220 * an opcode and no additional data/address, the SPI controller will
221 * read one byte too few from the chip. Basically, the last byte of
222 * the chip response is discarded and will not end up in the FIFO.
223 * It is unclear if the CS# line is set high too early as well.
224 */
ivy_jian8e0c4e52017-08-23 09:17:56 +0800225 unsigned int readoffby1 = (writecnt > 0) ? 0 : 1;
226 uint8_t readwrite = (readcnt + readoffby1) << 4 | (writecnt);
hailfingere30f6d52010-08-18 15:12:43 +0000227 mmio_writeb(readwrite, sb600_spibar + 1);
uwe17efbed2008-11-28 21:36:51 +0000228
uwe17efbed2008-11-28 21:36:51 +0000229 reset_internal_fifo_pointer();
ivy_jian8e0c4e52017-08-23 09:17:56 +0800230 msg_pspew("Filling FIFO: ");
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000231 unsigned int count;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800232 for (count = 0; count < writecnt; count++) {
233 msg_pspew("[%02x]", writearr[count]);
234 mmio_writeb(writearr[count], sb600_spibar + 0xC);
uwe17efbed2008-11-28 21:36:51 +0000235 }
hailfinger4efe6682010-01-10 01:59:50 +0000236 msg_pspew("\n");
ivy_jian8e0c4e52017-08-23 09:17:56 +0800237 if (compare_internal_fifo_pointer(writecnt))
hailfingere30f6d52010-08-18 15:12:43 +0000238 return SPI_PROGRAMMER_ERROR;
uwe17efbed2008-11-28 21:36:51 +0000239
ivy_jian8e0c4e52017-08-23 09:17:56 +0800240 /*
241 * We should send the data in sequence, which means we need to reset
242 * the FIFO pointer to the first byte we want to send.
243 */
244 reset_internal_fifo_pointer();
uwe17efbed2008-11-28 21:36:51 +0000245 execute_command();
ivy_jian8e0c4e52017-08-23 09:17:56 +0800246 if (compare_internal_fifo_pointer(writecnt + readcnt))
247 return SPI_PROGRAMMER_ERROR;
uwe17efbed2008-11-28 21:36:51 +0000248
249 /*
250 * After the command executed, we should find out the index of the
hailfinger783de7b2009-07-23 01:36:08 +0000251 * received byte. Here we just reset the FIFO pointer and skip the
252 * writecnt.
253 * It would be possible to increase the FIFO pointer by one instead
254 * of reading and discarding one byte from the FIFO.
255 * The FIFO is implemented on top of an 8 byte ring buffer and the
256 * buffer is never cleared. For every byte that is shifted out after
257 * the opcode, the FIFO already stores the response from the chip.
258 * Usually, the chip will respond with 0x00 or 0xff.
uwe17efbed2008-11-28 21:36:51 +0000259 */
ivy_jian8e0c4e52017-08-23 09:17:56 +0800260 reset_internal_fifo_pointer();
uwe17efbed2008-11-28 21:36:51 +0000261
hailfinger783de7b2009-07-23 01:36:08 +0000262 /* Skip the bytes we sent. */
hailfingere30f6d52010-08-18 15:12:43 +0000263 msg_pspew("Skipping: ");
uwe17efbed2008-11-28 21:36:51 +0000264 for (count = 0; count < writecnt; count++) {
ivy_jian8e0c4e52017-08-23 09:17:56 +0800265 msg_pspew("[%02x]", mmio_readb(sb600_spibar + 0xC));
uwe17efbed2008-11-28 21:36:51 +0000266 }
hailfingere30f6d52010-08-18 15:12:43 +0000267 msg_pspew("\n");
268 if (compare_internal_fifo_pointer(writecnt))
269 return SPI_PROGRAMMER_ERROR;
uwe17efbed2008-11-28 21:36:51 +0000270
ivy_jian8e0c4e52017-08-23 09:17:56 +0800271 msg_pspew("Reading FIFO: ");
272 for (count = 0; count < readcnt; count++) {
273 readarr[count] = mmio_readb(sb600_spibar + 0xC);
274 msg_pspew("[%02x]", readarr[count]);
uwe17efbed2008-11-28 21:36:51 +0000275 }
hailfinger4efe6682010-01-10 01:59:50 +0000276 msg_pspew("\n");
ivy_jian8e0c4e52017-08-23 09:17:56 +0800277 if (compare_internal_fifo_pointer(writecnt+readcnt))
hailfingere30f6d52010-08-18 15:12:43 +0000278 return SPI_PROGRAMMER_ERROR;
279
280 if (mmio_readb(sb600_spibar + 1) != readwrite) {
ivy_jian8e0c4e52017-08-23 09:17:56 +0800281 msg_perr("Unexpected change in AMD SPI read/write count!\n");
282 msg_perr("Something else is accessing the flash chip and causes random corruption.\n"
283 "Please stop all applications and drivers and IPMI which access the flash chip.\n");
hailfingere30f6d52010-08-18 15:12:43 +0000284 return SPI_PROGRAMMER_ERROR;
285 }
uwe17efbed2008-11-28 21:36:51 +0000286
287 return 0;
288}
hailfinger324a9cc2010-05-26 01:45:41 +0000289
ivy_jian8e0c4e52017-08-23 09:17:56 +0800290static int spi100_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
291 unsigned int readcnt,
292 const unsigned char *writearr,
293 unsigned char *readarr)
294{
295 /* First byte is cmd which can not be sent through the buffer. */
296 unsigned char cmd = *writearr++;
297 writecnt--;
298 msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, cmd, writecnt, readcnt);
299 mmio_writeb(cmd, sb600_spibar + 0);
300
301 int ret = check_readwritecnt(flash, writecnt, readcnt);
302 if (ret != 0)
303 return ret;
304
305 /* Use the extended TxByteCount and RxByteCount registers. */
306 mmio_writeb(writecnt, sb600_spibar + 0x48);
307 mmio_writeb(readcnt, sb600_spibar + 0x4b);
308
309 msg_pspew("Filling buffer: ");
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000310 unsigned int count;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800311 for (count = 0; count < writecnt; count++) {
312 msg_pspew("[%02x]", writearr[count]);
313 mmio_writeb(writearr[count], sb600_spibar + 0x80 + count);
314 }
315 msg_pspew("\n");
316
317 execute_command();
318
319 msg_pspew("Reading buffer: ");
320 for (count = 0; count < readcnt; count++) {
321 readarr[count] = mmio_readb(sb600_spibar + 0x80 + (writecnt + count) % FIFO_SIZE_YANGTZE);
322 msg_pspew("[%02x]", readarr[count]);
323 }
324 msg_pspew("\n");
325
326 return 0;
327}
328
329struct spispeed {
330 const char *const name;
331 const uint8_t speed;
mkarcherd264e9e2011-05-11 17:07:07 +0000332};
333
Rob Barnes26567e42020-01-21 09:10:51 -0700334static const char* spispeeds[] = {
335 "66 MHz",
336 "33 MHz",
337 "22 MHz",
338 "16.5 MHz",
339 "100 MHz",
340 "Reserved",
341 "Reserved",
342 "800 kHz",
ivy_jian8e0c4e52017-08-23 09:17:56 +0800343};
344
Rob Barnes26567e42020-01-21 09:10:51 -0700345static const char* spireadmodes[] = {
346 "Normal (up to 33 MHz)",
347 "Reserved",
348 "Dual IO (1-1-2)",
349 "Quad IO (1-1-4)",
350 "Dual IO (1-2-2)",
351 "Quad IO (1-4-4)",
352 "Normal (up to 66 MHz)",
353 "Fast Read",
354};
355
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100356static int set_speed(struct pci_dev *dev, enum amd_chipset amd_gen, uint8_t speed)
ivy_jian8e0c4e52017-08-23 09:17:56 +0800357{
358 bool success = false;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800359
Rob Barnes26567e42020-01-21 09:10:51 -0700360 msg_pdbg("Setting SPI clock to %s (%i)... ", spispeeds[speed], speed);
ivy_jian8e0c4e52017-08-23 09:17:56 +0800361 if (amd_gen >= CHIPSET_YANGTZE) {
362 rmmio_writew((speed << 12) | (speed << 8) | (speed << 4) | speed, sb600_spibar + 0x22);
363 uint16_t tmp = mmio_readw(sb600_spibar + 0x22);
364 success = (((tmp >> 12) & 0xf) == speed && ((tmp >> 8) & 0xf) == speed &&
365 ((tmp >> 4) & 0xf) == speed && ((tmp >> 0) & 0xf) == speed);
366 } else {
367 rmmio_writeb((mmio_readb(sb600_spibar + 0xd) & ~(0x3 << 4)) | (speed << 4), sb600_spibar + 0xd);
368 success = (speed == ((mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3));
369 }
370
371 if (!success) {
Rob Barnes26567e42020-01-21 09:10:51 -0700372 msg_perr("FAILED!\n");
ivy_jian8e0c4e52017-08-23 09:17:56 +0800373 return 1;
374 }
Rob Barnes26567e42020-01-21 09:10:51 -0700375 msg_pdbg("succeeded.\n");
ivy_jian8e0c4e52017-08-23 09:17:56 +0800376 return 0;
377}
378
Rob Barnes26567e42020-01-21 09:10:51 -0700379static int set_mode(struct pci_dev *dev, uint8_t mode)
ivy_jian8e0c4e52017-08-23 09:17:56 +0800380{
Rob Barnes26567e42020-01-21 09:10:51 -0700381 msg_pdbg("Setting SPI read mode to %s (%i)... ", spireadmodes[mode], mode);
ivy_jian8e0c4e52017-08-23 09:17:56 +0800382 uint32_t tmp = mmio_readl(sb600_spibar + 0x00);
383 tmp &= ~(0x6 << 28 | 0x1 << 18); /* Clear mode bits */
Rob Barnes26567e42020-01-21 09:10:51 -0700384 tmp |= ((mode & 0x6) << 28) | ((mode & 0x1) << 18);
ivy_jian8e0c4e52017-08-23 09:17:56 +0800385 rmmio_writel(tmp, sb600_spibar + 0x00);
Rob Barnes26567e42020-01-21 09:10:51 -0700386 if (tmp != mmio_readl(sb600_spibar + 0x00)) {
387 msg_perr("FAILED!\n");
ivy_jian8e0c4e52017-08-23 09:17:56 +0800388 return 1;
Rob Barnes26567e42020-01-21 09:10:51 -0700389 }
390 msg_pdbg("succeeded.\n");
ivy_jian8e0c4e52017-08-23 09:17:56 +0800391 return 0;
392}
393
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100394static int handle_speed(struct pci_dev *dev, enum amd_chipset amd_gen)
ivy_jian8e0c4e52017-08-23 09:17:56 +0800395{
396 uint32_t tmp;
Rob Barnes26567e42020-01-21 09:10:51 -0700397 int16_t spispeed_idx = -1;
398 int16_t spireadmode_idx = -1;
399 char *spispeed;
400 char *spireadmode;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800401
Rob Barnes26567e42020-01-21 09:10:51 -0700402 spispeed = extract_programmer_param("spispeed");
ivy_jian8e0c4e52017-08-23 09:17:56 +0800403 if (spispeed != NULL) {
404 unsigned int i;
405 for (i = 0; i < ARRAY_SIZE(spispeeds); i++) {
Rob Barnes26567e42020-01-21 09:10:51 -0700406 if (strcasecmp(spispeeds[i], spispeed) == 0) {
ivy_jian8e0c4e52017-08-23 09:17:56 +0800407 spispeed_idx = i;
408 break;
409 }
410 }
411 /* "reserved" is not a valid speed.
412 * Error out on speeds not present in the spispeeds array.
413 * Only Yangtze supports the second half of indices.
414 * No 66 MHz before SB8xx. */
415 if ((strcasecmp(spispeed, "reserved") == 0) ||
416 (i == ARRAY_SIZE(spispeeds)) ||
417 (amd_gen < CHIPSET_YANGTZE && spispeed_idx > 3) ||
418 (amd_gen < CHIPSET_SB89XX && spispeed_idx == 0)) {
419 msg_perr("Error: Invalid spispeed value: '%s'.\n", spispeed);
420 free(spispeed);
421 return 1;
422 }
423 free(spispeed);
424 }
425
Rob Barnes26567e42020-01-21 09:10:51 -0700426 spireadmode = extract_programmer_param("spireadmode");
427 if (spireadmode != NULL) {
428 unsigned int i;
429 for (i = 0; i < ARRAY_SIZE(spireadmodes); i++) {
430 if (strcasecmp(spireadmodes[i], spireadmode) == 0) {
431 spireadmode_idx = i;
432 break;
433 }
434 }
435 if ((strcasecmp(spireadmode, "reserved") == 0) ||
436 (i == ARRAY_SIZE(spireadmodes))) {
437 msg_perr("Error: Invalid spireadmode value: '%s'.\n", spireadmode);
438 free(spireadmode);
439 return 1;
440 }
441 if (amd_gen < CHIPSET_BOLTON) {
442 msg_perr("Warning: spireadmode not supported for this chipset.");
443 }
444 free(spireadmode);
445 }
446
ivy_jian8e0c4e52017-08-23 09:17:56 +0800447 /* See the chipset support matrix for SPI Base_Addr below for an explanation of the symbols used.
448 * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson234 bolton/yangtze
449 * 18 rsvd <- fastReadEnable ? <- ? SpiReadMode[0]
450 * 29:30 rsvd <- <- ? <- ? SpiReadMode[2:1]
451 */
452 if (amd_gen >= CHIPSET_BOLTON) {
Rob Barnes26567e42020-01-21 09:10:51 -0700453
ivy_jian8e0c4e52017-08-23 09:17:56 +0800454 tmp = mmio_readl(sb600_spibar + 0x00);
455 uint8_t read_mode = ((tmp >> 28) & 0x6) | ((tmp >> 18) & 0x1);
Rob Barnes26567e42020-01-21 09:10:51 -0700456 msg_pdbg("SPI read mode is %s (%i)\n",
457 spireadmodes[read_mode], read_mode);
458 if (spireadmode_idx < 0) {
459 msg_perr("Warning: spireadmode not set, "
460 "leaving spireadmode unchanged.");
461 }
462 else if (set_mode(dev, spireadmode_idx) != 0) {
463 return 1;
ivy_jian8e0c4e52017-08-23 09:17:56 +0800464 }
465
466 if (amd_gen >= CHIPSET_YANGTZE) {
467 tmp = mmio_readb(sb600_spibar + 0x20);
468 msg_pdbg("UseSpi100 is %sabled\n", (tmp & 0x1) ? "en" : "dis");
469 if ((tmp & 0x1) == 0) {
470 rmmio_writeb(tmp | 0x1, sb600_spibar + 0x20);
471 tmp = mmio_readb(sb600_spibar + 0x20) & 0x1;
472 if (tmp == 0) {
473 msg_perr("Enabling Spi100 failed.\n");
474 return 1;
475 }
476 msg_pdbg("Enabling Spi100 succeeded.\n");
477 }
478
479 tmp = mmio_readw(sb600_spibar + 0x22); /* SPI 100 Speed Config */
Rob Barnes26567e42020-01-21 09:10:51 -0700480 msg_pdbg("NormSpeedNew is %s\n", spispeeds[(tmp >> 12) & 0xf]);
481 msg_pdbg("FastSpeedNew is %s\n", spispeeds[(tmp >> 8) & 0xf]);
482 msg_pdbg("AltSpeedNew is %s\n", spispeeds[(tmp >> 4) & 0xf]);
483 msg_pdbg("TpmSpeedNew is %s\n", spispeeds[(tmp >> 0) & 0xf]);
ivy_jian8e0c4e52017-08-23 09:17:56 +0800484 }
485 } else {
486 if (amd_gen >= CHIPSET_SB89XX && amd_gen <= CHIPSET_HUDSON234) {
487 bool fast_read = (mmio_readl(sb600_spibar + 0x00) >> 18) & 0x1;
488 msg_pdbg("Fast Reads are %sabled\n", fast_read ? "en" : "dis");
489 if (fast_read) {
490 msg_pdbg("Disabling them temporarily.\n");
491 rmmio_writel(mmio_readl(sb600_spibar + 0x00) & ~(0x1 << 18),
492 sb600_spibar + 0x00);
493 }
494 }
495 tmp = (mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3;
Rob Barnes26567e42020-01-21 09:10:51 -0700496 msg_pdbg("NormSpeed is %s\n", spispeeds[tmp]);
497 if (spispeed_idx < 0) {
498 spispeed_idx = 3; /* Default to 16.5 MHz */
499 }
ivy_jian8e0c4e52017-08-23 09:17:56 +0800500 }
Rob Barnes26567e42020-01-21 09:10:51 -0700501 if (spispeed_idx < 0) {
502 msg_perr("Warning: spispeed not set, leaving spispeed unchanged.");
503 return 0;
504 }
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100505 return set_speed(dev, amd_gen, spispeed_idx);
ivy_jian8e0c4e52017-08-23 09:17:56 +0800506}
507
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100508static int handle_imc(struct pci_dev *dev, enum amd_chipset amd_gen)
ivy_jian8e0c4e52017-08-23 09:17:56 +0800509{
510 /* Handle IMC everywhere but sb600 which does not have one. */
511 if (amd_gen == CHIPSET_SB6XX)
512 return 0;
513
514 bool amd_imc_force = false;
515 char *arg = extract_programmer_param("amd_imc_force");
516 if (arg && !strcmp(arg, "yes")) {
517 amd_imc_force = true;
518 msg_pspew("amd_imc_force enabled.\n");
519 } else if (arg && !strlen(arg)) {
520 msg_perr("Missing argument for amd_imc_force.\n");
521 free(arg);
522 return 1;
523 } else if (arg) {
524 msg_perr("Unknown argument for amd_imc_force: \"%s\" (not \"yes\").\n", arg);
525 free(arg);
526 return 1;
527 }
528 free(arg);
529
530 /* TODO: we should not only look at IntegratedImcPresent (LPC Dev 20, Func 3, 40h) but also at
531 * IMCEnable(Strap) and Override EcEnable(Strap) (sb8xx, sb9xx?, a50, Bolton: Misc_Reg: 80h-87h;
532 * sb7xx, sp5100: PM_Reg: B0h-B1h) etc. */
533 uint8_t reg = pci_read_byte(dev, 0x40);
534 if ((reg & (1 << 7)) == 0) {
535 msg_pdbg("IMC is not active.\n");
536 return 0;
537 }
538
ivy_jian8e0c4e52017-08-23 09:17:56 +0800539 if (!amd_imc_force)
540 programmer_may_write = 0;
541 msg_pinfo("Writes have been disabled for safety reasons because the presence of the IMC\n"
542 "was detected and it could interfere with accessing flash memory. Flashrom will\n"
543 "try to disable it temporarily but even then this might not be safe:\n"
544 "when it is re-enabled and after a reboot it expects to find working code\n"
545 "in the flash and it is unpredictable what happens if there is none.\n"
546 "\n"
547 "To be safe make sure that there is a working IMC firmware at the right\n"
548 "location in the image you intend to write and do not attempt to erase.\n"
549 "\n"
550 "You can enforce write support with the amd_imc_force programmer option.\n");
551 if (amd_imc_force)
552 msg_pinfo("Continuing with write support because the user forced us to!\n");
553
554 return amd_imc_shutdown(dev);
555}
556
Edward O'Callaghan999593b2020-07-31 12:21:02 +1000557static int promontory_read_memmapped(struct flashctx *flash, uint8_t *buf,
558 unsigned int start, unsigned int len)
559{
560 struct sb600spi_data * data = (struct sb600spi_data *)flash->mst->spi.data;
561 if (!data->flash) {
562 map_flash(flash);
563 data->flash = flash; /* keep a copy of flashctx for unmap() on tear-down. */
564 }
565 mmio_readn((void *)(flash->virtual_memory + start), buf, len);
566 return 0;
567}
568
Edward O'Callaghan9c71e022020-11-17 19:27:13 +1100569static struct spi_master spi_master_sb600 = {
570 .max_data_read = FIFO_SIZE_OLD,
571 .max_data_write = FIFO_SIZE_OLD - 3,
572 .command = sb600_spi_send_command,
573 .multicommand = default_spi_send_multicommand,
574 .read = default_spi_read,
575 .write_256 = default_spi_write_256,
576 .write_aai = default_spi_write_aai,
577};
578
579static struct spi_master spi_master_yangtze = {
580 .max_data_read = FIFO_SIZE_YANGTZE - 3, /* Apparently the big SPI 100 buffer is not a ring buffer. */
581 .max_data_write = FIFO_SIZE_YANGTZE - 3,
582 .command = spi100_spi_send_command,
583 .multicommand = default_spi_send_multicommand,
Edward O'Callaghan999593b2020-07-31 12:21:02 +1000584 .read = default_spi_read,
Edward O'Callaghan9c71e022020-11-17 19:27:13 +1100585 .write_256 = default_spi_write_256,
586 .write_aai = default_spi_write_aai,
587};
588
Edward O'Callaghan999593b2020-07-31 12:21:02 +1000589static struct spi_master spi_master_promontory = {
590 .max_data_read = MAX_DATA_READ_UNLIMITED,
591 .max_data_write = FIFO_SIZE_YANGTZE - 3,
592 .command = spi100_spi_send_command,
593 .multicommand = default_spi_send_multicommand,
594 .read = promontory_read_memmapped,
595 .write_256 = default_spi_write_256,
596 .write_aai = default_spi_write_aai,
597};
598
599static int sb600spi_shutdown(void *data)
600{
601 struct flashctx *flash = ((struct sb600spi_data *)data)->flash;
602 if (flash)
603 finalize_flash_access(flash);
604 free(data);
605 return 0;
606}
607
mkarcher8b2b7ab2010-07-22 18:04:19 +0000608int sb600_probe_spi(struct pci_dev *dev)
609{
610 struct pci_dev *smbus_dev;
611 uint32_t tmp;
612 uint8_t reg;
hailfingere30f6d52010-08-18 15:12:43 +0000613
mkarcher8b2b7ab2010-07-22 18:04:19 +0000614 /* Read SPI_BaseAddr */
615 tmp = pci_read_long(dev, 0xa0);
616 tmp &= 0xffffffe0; /* remove bits 4-0 (reserved) */
617 msg_pdbg("SPI base address is at 0x%x\n", tmp);
618
619 /* If the BAR has address 0, it is unlikely SPI is used. */
620 if (!tmp)
621 return 0;
622
623 /* Physical memory has to be mapped at page (4k) boundaries. */
ivy_jian8e0c4e52017-08-23 09:17:56 +0800624 sb600_spibar = rphysmap("SB600 SPI registers", tmp & 0xfffff000, 0x1000);
625 if (sb600_spibar == ERROR_PTR)
626 return ERROR_FATAL;
627
mkarcher8b2b7ab2010-07-22 18:04:19 +0000628 /* The low bits of the SPI base address are used as offset into
629 * the mapped page.
630 */
631 sb600_spibar += tmp & 0xfff;
632
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100633 enum amd_chipset amd_gen = determine_generation(dev);
634 if (amd_gen == CHIPSET_AMD_UNKNOWN)
ivy_jian8e0c4e52017-08-23 09:17:56 +0800635 return ERROR_NONFATAL;
mkarcher8b2b7ab2010-07-22 18:04:19 +0000636
ivy_jian8e0c4e52017-08-23 09:17:56 +0800637 /* How to read the following table and similar ones in this file:
638 * "?" means we have no datasheet for this chipset generation or it doesn't have any relevant info.
639 * "<-" means the bit/register meaning is identical to the next non-"?" chipset to the left. "<-" thus
640 * never refers to another "?".
641 * If a "?" chipset is between two chipsets with identical meaning, we assume the meaning didn't change
642 * twice in between, i.e. the meaning is unchanged for the "?" chipset. Usually we assume that
643 * succeeding hardware supports the same functionality as its predecessor unless proven different by
644 * tests or documentation, hence "?" will often be implemented equally to "<-".
645 *
646 * Chipset support matrix for SPI Base_Addr (LPC PCI reg 0xa0)
647 * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson2+ yangtze
648 * 3 rsvd <- <- ? <- ? RouteTpm2Spi
649 * 2 rsvd AbortEnable rsvd ? <- ? <-
650 * 1 rsvd SpiRomEnable <- ? <- ? <-
651 * 0 rsvd AltSpiCSEnable rsvd ? <- ? <-
hailfingere30f6d52010-08-18 15:12:43 +0000652 */
ivy_jian8e0c4e52017-08-23 09:17:56 +0800653 if (amd_gen >= CHIPSET_SB7XX) {
654 tmp = pci_read_long(dev, 0xa0);
655 msg_pdbg("SpiRomEnable=%i", (tmp >> 1) & 0x1);
656 if (amd_gen == CHIPSET_SB7XX)
657 msg_pdbg(", AltSpiCSEnable=%i, AbortEnable=%i", tmp & 0x1, (tmp >> 2) & 0x1);
658 else if (amd_gen >= CHIPSET_YANGTZE)
659 msg_pdbg(", RouteTpm2Sp=%i", (tmp >> 3) & 0x1);
660
661 tmp = pci_read_byte(dev, 0xba);
662 msg_pdbg(", PrefetchEnSPIFromIMC=%i", (tmp & 0x4) >> 2);
663
664 tmp = pci_read_byte(dev, 0xbb);
665 /* FIXME: Set bit 3,6,7 if not already set.
666 * Set bit 5, otherwise SPI accesses are pointless in LPC mode.
667 * See doc 42413 AMD SB700/710/750 RPR.
668 */
669 if (amd_gen == CHIPSET_SB7XX)
670 msg_pdbg(", SpiOpEnInLpcMode=%i", (tmp >> 5) & 0x1);
671 msg_pdbg(", PrefetchEnSPIFromHost=%i\n", tmp & 0x1);
672 }
673
674 /* Chipset support matrix for SPI_Cntrl0 (spibar + 0x0)
675 * See the chipset support matrix for SPI Base_Addr above for an explanation of the symbols used.
676 * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson2+ yangtze
677 * 17 rsvd <- <- ? <- ? <-
678 * 18 rsvd <- fastReadEnable<1> ? <- ? SpiReadMode[0]<1>
679 * 19 SpiArbEnable <- <- ? <- ? <-
680 * 20 (FifoPtrClr) <- <- ? <- ? <-
681 * 21 (FifoPtrInc) <- <- ? <- ? IllegalAccess
682 * 22 SpiAccessMacRomEn <- <- ? <- ? <-
683 * 23 SpiHostAccessRomEn <- <- ? <- ? <-
684 * 24:26 ArbWaitCount <- <- ? <- ? <-
685 * 27 SpiBridgeDisable <- <- ? <- ? rsvd
686 * 28 rsvd DropOneClkOnRd = SPIClkGate ? <- ? <-
687 * 29:30 rsvd <- <- ? <- ? SpiReadMode[2:1]<1>
688 * 31 rsvd <- SpiBusy ? <- ? <-
689 *
690 * <1> see handle_speed
hailfingere30f6d52010-08-18 15:12:43 +0000691 */
ivy_jian8e0c4e52017-08-23 09:17:56 +0800692 tmp = mmio_readl(sb600_spibar + 0x00);
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000693 msg_pdbg("(0x%08" PRIx32 ") SpiArbEnable=%i", tmp, (tmp >> 19) & 0x1);
ivy_jian8e0c4e52017-08-23 09:17:56 +0800694 if (amd_gen >= CHIPSET_YANGTZE)
695 msg_pdbg(", IllegalAccess=%i", (tmp >> 21) & 0x1);
mkarcher8b2b7ab2010-07-22 18:04:19 +0000696
ivy_jian8e0c4e52017-08-23 09:17:56 +0800697 msg_pdbg(", SpiAccessMacRomEn=%i, SpiHostAccessRomEn=%i, ArbWaitCount=%i",
698 (tmp >> 22) & 0x1, (tmp >> 23) & 0x1, (tmp >> 24) & 0x7);
mkarcher8b2b7ab2010-07-22 18:04:19 +0000699
ivy_jian8e0c4e52017-08-23 09:17:56 +0800700 if (amd_gen < CHIPSET_YANGTZE)
701 msg_pdbg(", SpiBridgeDisable=%i", (tmp >> 27) & 0x1);
702
703 switch (amd_gen) {
704 case CHIPSET_SB7XX:
705 msg_pdbg(", DropOneClkOnRd/SpiClkGate=%i", (tmp >> 28) & 0x1);
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000706 /* Fall through. */
ivy_jian8e0c4e52017-08-23 09:17:56 +0800707 case CHIPSET_SB89XX:
708 case CHIPSET_HUDSON234:
709 case CHIPSET_YANGTZE:
710 case CHIPSET_PROMONTORY:
711 msg_pdbg(", SpiBusy=%i", (tmp >> 31) & 0x1);
712 default: break;
713 }
714 msg_pdbg("\n");
715
716 if (((tmp >> 22) & 0x1) == 0 || ((tmp >> 23) & 0x1) == 0) {
717 msg_perr("ERROR: State of SpiAccessMacRomEn or SpiHostAccessRomEn prohibits full access.\n");
718 return ERROR_NONFATAL;
719 }
720
721 if (amd_gen >= CHIPSET_SB89XX) {
722 tmp = mmio_readb(sb600_spibar + 0x1D);
723 msg_pdbg("Using SPI_CS%d\n", tmp & 0x3);
724 /* FIXME: Handle SpiProtect* configuration on Yangtze. */
mkarcher8b2b7ab2010-07-22 18:04:19 +0000725 }
726
Edward O'Callaghan0eee19e2020-07-30 20:26:14 +1000727 /* Look for the SMBus device. */
728 smbus_dev = pci_dev_find(0x1002, 0x4385);
729 if (!smbus_dev)
730 smbus_dev = pci_dev_find(0x1022, 0x780b); /* AMD FCH */
731 if (!smbus_dev)
732 smbus_dev = pci_dev_find(0x1022, 0x790b); /* AMD FP4 */
733 if (!smbus_dev) {
734 msg_perr("ERROR: SMBus device not found. Not enabling SPI.\n");
735 return ERROR_NONFATAL;
736 }
737
mkarcher8b2b7ab2010-07-22 18:04:19 +0000738 /* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */
739 /* GPIO11/SPI_DO and GPIO12/SPI_DI status */
740 reg = pci_read_byte(smbus_dev, 0xAB);
741 reg &= 0xC0;
742 msg_pdbg("GPIO11 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_DO");
743 msg_pdbg("GPIO12 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_DI");
744 if (reg != 0x00) {
745 msg_pdbg("Not enabling SPI");
746 return 0;
747 }
748 /* GPIO31/SPI_HOLD and GPIO32/SPI_CS status */
749 reg = pci_read_byte(smbus_dev, 0x83);
750 reg &= 0xC0;
751 msg_pdbg("GPIO31 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_HOLD");
752 msg_pdbg("GPIO32 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_CS");
753 /* SPI_HOLD is not used on all boards, filter it out. */
754 if ((reg & 0x80) != 0x00) {
755 msg_pdbg("Not enabling SPI");
756 return 0;
757 }
758 /* GPIO47/SPI_CLK status */
759 reg = pci_read_byte(smbus_dev, 0xA7);
760 reg &= 0x40;
761 msg_pdbg("GPIO47 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_CLK");
762 if (reg != 0x00) {
763 msg_pdbg("Not enabling SPI");
764 return 0;
765 }
766
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100767 if (handle_speed(dev, amd_gen) != 0)
ivy_jian8e0c4e52017-08-23 09:17:56 +0800768 return ERROR_FATAL;
hailfinger705832e2010-09-15 12:02:07 +0000769
Edward O'Callaghanf77f9432019-10-30 00:38:16 +1100770 if (handle_imc(dev, amd_gen) != 0)
ivy_jian8e0c4e52017-08-23 09:17:56 +0800771 return ERROR_FATAL;
hailfingere30f6d52010-08-18 15:12:43 +0000772
Edward O'Callaghan999593b2020-07-31 12:21:02 +1000773 struct sb600spi_data *data = calloc(1, sizeof(struct sb600spi_data));
774 if (!data) {
775 msg_perr("Unable to allocate space for extra SPI master data.\n");
776 return SPI_GENERIC_ERROR;
777 }
778
779 data->flash = NULL;
780
781 register_shutdown(sb600spi_shutdown, data);
782 spi_master_sb600.data = data;
783 spi_master_yangtze.data = data;
784 spi_master_promontory.data = data;
785
786
ivy_jian8e0c4e52017-08-23 09:17:56 +0800787 /* Starting with Yangtze the SPI controller got a different interface with a much bigger buffer. */
788 if (amd_gen < CHIPSET_YANGTZE)
Nico Huberf1eeda62021-05-11 17:38:14 +0200789 register_spi_master(&spi_master_sb600, NULL);
Edward O'Callaghan999593b2020-07-31 12:21:02 +1000790 else if (amd_gen == CHIPSET_YANGTZE)
Nico Huberf1eeda62021-05-11 17:38:14 +0200791 register_spi_master(&spi_master_yangtze, NULL);
Edward O'Callaghan999593b2020-07-31 12:21:02 +1000792 else
Nico Huberf1eeda62021-05-11 17:38:14 +0200793 register_spi_master(&spi_master_promontory, NULL);
Edward O'Callaghan999593b2020-07-31 12:21:02 +1000794
mkarcher8b2b7ab2010-07-22 18:04:19 +0000795 return 0;
796}
797
hailfinger324a9cc2010-05-26 01:45:41 +0000798#endif