blob: c4b25e527a03ceafec371df597ae735ada59bf36 [file] [log] [blame]
Jason Wanga3f04be2008-11-28 21:36:51 +00001/*
2 * This file is part of the flashrom project.
3 *
Jason Wang13f98ce2008-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>
Uwe Hermann97e8f222009-04-13 21:35:49 +00006 * Copyright (C) 2008 Advanced Micro Devices, Inc.
Wei Hu31402ee2014-05-16 21:39:33 +00007 * Copyright (C) 2009, 2010, 2013 Carl-Daniel Hailfinger
8 * Copyright (C) 2013 Stefan Tauner
Jason Wanga3f04be2008-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.
Jason Wanga3f04be2008-11-28 21:36:51 +000019 */
20
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +000021#if defined(__i386__) || defined(__x86_64__)
22
Rudolf Marek70e14592013-07-25 22:58:56 +000023#include <string.h>
24#include <stdlib.h>
Jason Wanga3f04be2008-11-28 21:36:51 +000025#include "flash.h"
Carl-Daniel Hailfinger5b997c32010-07-27 22:41:39 +000026#include "programmer.h"
Patrick Georgi32508eb2012-07-20 20:35:14 +000027#include "hwaccess.h"
Jason Wanga3f04be2008-11-28 21:36:51 +000028#include "spi.h"
29
Carl-Daniel Hailfinger2c7ba8c2009-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 */
Jason Wanga3f04be2008-11-28 21:36:51 +000042
Stefan Tauner463dd692013-08-08 12:00:19 +000043enum amd_chipset {
44 CHIPSET_AMD_UNKNOWN,
45 CHIPSET_SB6XX,
46 CHIPSET_SB7XX, /* SP5100 too */
47 CHIPSET_SB89XX, /* Hudson-1 too */
48 CHIPSET_HUDSON234,
Martin Roth82b6ec12014-07-15 13:50:58 +000049 CHIPSET_BOLTON,
Stefan Tauner463dd692013-08-08 12:00:19 +000050 CHIPSET_YANGTZE,
Edward O'Callaghan93737bc2019-10-29 18:30:01 +110051 CHIPSET_PROMONTORY,
Stefan Tauner463dd692013-08-08 12:00:19 +000052};
Stefan Tauner463dd692013-08-08 12:00:19 +000053
Stefan Taunerd5b2aef2014-05-16 21:39:28 +000054#define FIFO_SIZE_OLD 8
Wei Hu31402ee2014-05-16 21:39:33 +000055#define FIFO_SIZE_YANGTZE 71
Stefan Taunerd5b2aef2014-05-16 21:39:28 +000056
Edward O'Callaghan855d6b62020-07-31 12:21:02 +100057struct sb600spi_data {
58 struct flashctx *flash;
Anastasia Klimchukd6d8c142021-05-20 11:43:06 +100059 uint8_t *spibar;
Edward O'Callaghan855d6b62020-07-31 12:21:02 +100060};
61
Edward O'Callaghanc0a27e12019-10-29 17:05:39 +110062static int find_smbus_dev_rev(uint16_t vendor, uint16_t device)
63{
64 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);
71}
72
Edward O'Callaghan9355e6f2019-10-29 18:18:18 +110073/* Determine the chipset's version and identify the respective SMBUS device. */
Edward O'Callaghan0386aa12019-10-30 00:38:16 +110074static enum amd_chipset determine_generation(struct pci_dev *dev)
Stefan Tauner463dd692013-08-08 12:00:19 +000075{
Stefan Tauner4442b812013-09-12 15:48:35 +000076 msg_pdbg2("Trying to determine the generation of the SPI interface... ");
77 if (dev->device_id == 0x438d) {
Stefan Tauner4442b812013-09-12 15:48:35 +000078 msg_pdbg("SB6xx detected.\n");
Edward O'Callaghan0386aa12019-10-30 00:38:16 +110079 return CHIPSET_SB6XX;
Stefan Tauner4442b812013-09-12 15:48:35 +000080 } else if (dev->device_id == 0x439d) {
Edward O'Callaghanc0a27e12019-10-29 17:05:39 +110081 int rev = find_smbus_dev_rev(0x1002, 0x4385);
82 if (rev < 0)
Edward O'Callaghan0386aa12019-10-30 00:38:16 +110083 return CHIPSET_AMD_UNKNOWN;
Stefan Tauner4442b812013-09-12 15:48:35 +000084 if (rev >= 0x39 && rev <= 0x3D) {
Stefan Tauner4442b812013-09-12 15:48:35 +000085 msg_pdbg("SB7xx/SP5100 detected.\n");
Edward O'Callaghan0386aa12019-10-30 00:38:16 +110086 return CHIPSET_SB7XX;
Stefan Tauner4442b812013-09-12 15:48:35 +000087 } else if (rev >= 0x40 && rev <= 0x42) {
Stefan Tauner4442b812013-09-12 15:48:35 +000088 msg_pdbg("SB8xx/SB9xx/Hudson-1 detected.\n");
Edward O'Callaghan0386aa12019-10-30 00:38:16 +110089 return CHIPSET_SB89XX;
Stefan Tauner4442b812013-09-12 15:48:35 +000090 } 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'Callaghan0386aa12019-10-30 00:38:16 +110094 return CHIPSET_SB89XX;
Stefan Tauner4442b812013-09-12 15:48:35 +000095 }
96 } else if (dev->device_id == 0x780e) {
Stefan Tauner463dd692013-08-08 12:00:19 +000097 /* 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'Callaghanc0a27e12019-10-29 17:05:39 +110099 int rev = find_smbus_dev_rev(0x1022, 0x780B);
100 if (rev < 0)
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100101 return CHIPSET_AMD_UNKNOWN;
Stefan Tauner463dd692013-08-08 12:00:19 +0000102 if (rev >= 0x11 && rev <= 0x15) {
Stefan Tauner463dd692013-08-08 12:00:19 +0000103 msg_pdbg("Hudson-2/3/4 detected.\n");
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100104 return CHIPSET_HUDSON234;
Martin Roth82b6ec12014-07-15 13:50:58 +0000105 } else if (rev == 0x16) {
Martin Roth82b6ec12014-07-15 13:50:58 +0000106 msg_pdbg("Bolton detected.\n");
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100107 return CHIPSET_BOLTON;
Stefan Tauner5c316f92015-02-08 21:57:52 +0000108 } else if ((rev >= 0x39 && rev <= 0x3A) || rev == 0x42) {
Stefan Tauner463dd692013-08-08 12:00:19 +0000109 msg_pdbg("Yangtze detected.\n");
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100110 return CHIPSET_YANGTZE;
Stefan Tauner463dd692013-08-08 12:00:19 +0000111 } 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 }
Ricardo Ribalda Delgado7b629bc2017-03-22 14:08:31 +0100116 } else if (dev->device_id == 0x790e) {
Edward O'Callaghanc0a27e12019-10-29 17:05:39 +1100117 int rev = find_smbus_dev_rev(0x1022, 0x790B);
118 if (rev < 0)
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100119 return CHIPSET_AMD_UNKNOWN;
Ricardo Ribalda Delgado7b629bc2017-03-22 14:08:31 +0100120 if (rev == 0x4a) {
Ricardo Ribalda Delgado7b629bc2017-03-22 14:08:31 +0100121 msg_pdbg("Yangtze detected.\n");
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100122 return CHIPSET_YANGTZE;
Edward O'Callaghan855d6b62020-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'Callaghan55583c02020-12-21 12:29:44 +1100132 } else if (rev == 0x4b || rev == 0x51 || rev == 0x59 || rev == 0x61) {
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000133 msg_pdbg("Promontory (rev 0x%02x) detected.\n", rev);
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100134 return CHIPSET_PROMONTORY;
Ricardo Ribalda Delgado7b629bc2017-03-22 14:08:31 +0100135 } 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
Stefan Tauner4442b812013-09-12 15:48:35 +0000142 } else
143 msg_pwarn("%s: Unknown LPC device %" PRIx16 ":%" PRIx16 ".\n"
144 "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'Callaghan0386aa12019-10-30 00:38:16 +1100147
148 msg_perr("Could not determine chipset generation.");
149 return CHIPSET_AMD_UNKNOWN;
Stefan Tauner463dd692013-08-08 12:00:19 +0000150}
Jason Wanga3f04be2008-11-28 21:36:51 +0000151
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000152static void reset_internal_fifo_pointer(uint8_t *sb600_spibar)
Jason Wanga3f04be2008-11-28 21:36:51 +0000153{
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000154 mmio_writeb(mmio_readb(sb600_spibar + 2) | 0x10, sb600_spibar + 2);
Jason Wanga3f04be2008-11-28 21:36:51 +0000155
Rudolf Marek70e14592013-07-25 22:58:56 +0000156 /* FIXME: This loop needs a timeout and a clearer message. */
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000157 while (mmio_readb(sb600_spibar + 0xD) & 0x7)
Carl-Daniel Hailfinger643415b2010-01-10 01:59:50 +0000158 msg_pspew("reset\n");
Jason Wanga3f04be2008-11-28 21:36:51 +0000159}
160
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000161static int compare_internal_fifo_pointer(uint8_t want, uint8_t *sb600_spibar)
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000162{
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000163 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");
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000169 return 1;
170 } else {
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000171 msg_pspew("AMD SPI FIFO pointer is %d, wanted %d\n", have, want);
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000172 return 0;
173 }
174}
175
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000176/* Check the number of bytes to be transmitted and extract opcode. */
Edward O'Callaghane4ddc362020-04-12 17:27:53 +1000177static int check_readwritecnt(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt)
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000178{
Carl-Daniel Hailfingera5bcbce2014-07-19 22:03:29 +0000179 unsigned int maxwritecnt = flash->mst->spi.max_data_write + 3;
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000180 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 }
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000185
Stefan Tauner6697f712014-08-06 15:09:15 +0000186 unsigned int maxreadcnt = flash->mst->spi.max_data_read;
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000187 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;
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000193}
194
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000195static void execute_command(uint8_t *sb600_spibar)
Jason Wanga3f04be2008-11-28 21:36:51 +0000196{
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000197 msg_pspew("Executing... ");
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000198 mmio_writeb(mmio_readb(sb600_spibar + 2) | 1, sb600_spibar + 2);
Carl-Daniel Hailfinger78185dc2009-05-17 15:49:24 +0000199 while (mmio_readb(sb600_spibar + 2) & 1)
Jason Wanga3f04be2008-11-28 21:36:51 +0000200 ;
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000201 msg_pspew("done\n");
Jason Wanga3f04be2008-11-28 21:36:51 +0000202}
203
Edward O'Callaghane4ddc362020-04-12 17:27:53 +1000204static int sb600_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
Carl-Daniel Hailfinger8a3c60c2011-12-18 15:01:24 +0000205 unsigned int readcnt,
206 const unsigned char *writearr,
207 unsigned char *readarr)
Jason Wanga3f04be2008-11-28 21:36:51 +0000208{
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000209 struct sb600spi_data *sb600_data = flash->mst->spi.data;
Anastasia Klimchukd6d8c142021-05-20 11:43:06 +1000210 uint8_t *sb600_spibar = sb600_data->spibar;
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000211 /* First byte is cmd which can not be sent through the FIFO. */
Jason Wanga3f04be2008-11-28 21:36:51 +0000212 unsigned char cmd = *writearr++;
Jason Wanga3f04be2008-11-28 21:36:51 +0000213 writecnt--;
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000214 msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, cmd, writecnt, readcnt);
215 mmio_writeb(cmd, sb600_spibar + 0);
Jason Wanga3f04be2008-11-28 21:36:51 +0000216
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000217 int ret = check_readwritecnt(flash, writecnt, readcnt);
218 if (ret != 0)
219 return ret;
Jason Wanga3f04be2008-11-28 21:36:51 +0000220
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000221 /* This is a workaround for a bug in SPI controller. If we only send
Carl-Daniel Hailfingerf8555e22009-07-23 01:36:08 +0000222 * an opcode and no additional data/address, the SPI controller will
223 * read one byte too few from the chip. Basically, the last byte of
224 * the chip response is discarded and will not end up in the FIFO.
225 * It is unclear if the CS# line is set high too early as well.
226 */
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000227 unsigned int readoffby1 = (writecnt > 0) ? 0 : 1;
228 uint8_t readwrite = (readcnt + readoffby1) << 4 | (writecnt);
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000229 mmio_writeb(readwrite, sb600_spibar + 1);
Jason Wanga3f04be2008-11-28 21:36:51 +0000230
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000231 reset_internal_fifo_pointer(sb600_spibar);
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000232 msg_pspew("Filling FIFO: ");
Nico Huber519be662018-12-23 20:03:35 +0100233 unsigned int count;
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000234 for (count = 0; count < writecnt; count++) {
235 msg_pspew("[%02x]", writearr[count]);
236 mmio_writeb(writearr[count], sb600_spibar + 0xC);
Jason Wanga3f04be2008-11-28 21:36:51 +0000237 }
Carl-Daniel Hailfinger643415b2010-01-10 01:59:50 +0000238 msg_pspew("\n");
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000239 if (compare_internal_fifo_pointer(writecnt, sb600_spibar))
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000240 return SPI_PROGRAMMER_ERROR;
Jason Wanga3f04be2008-11-28 21:36:51 +0000241
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000242 /*
243 * We should send the data in sequence, which means we need to reset
244 * the FIFO pointer to the first byte we want to send.
245 */
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000246 reset_internal_fifo_pointer(sb600_spibar);
247 execute_command(sb600_spibar);
248 if (compare_internal_fifo_pointer(writecnt + readcnt, sb600_spibar))
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000249 return SPI_PROGRAMMER_ERROR;
Jason Wanga3f04be2008-11-28 21:36:51 +0000250
251 /*
252 * After the command executed, we should find out the index of the
Carl-Daniel Hailfingerf8555e22009-07-23 01:36:08 +0000253 * received byte. Here we just reset the FIFO pointer and skip the
254 * writecnt.
255 * It would be possible to increase the FIFO pointer by one instead
256 * of reading and discarding one byte from the FIFO.
257 * The FIFO is implemented on top of an 8 byte ring buffer and the
258 * buffer is never cleared. For every byte that is shifted out after
259 * the opcode, the FIFO already stores the response from the chip.
260 * Usually, the chip will respond with 0x00 or 0xff.
Jason Wanga3f04be2008-11-28 21:36:51 +0000261 */
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000262 reset_internal_fifo_pointer(sb600_spibar);
Jason Wanga3f04be2008-11-28 21:36:51 +0000263
Carl-Daniel Hailfingerf8555e22009-07-23 01:36:08 +0000264 /* Skip the bytes we sent. */
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000265 msg_pspew("Skipping: ");
Jason Wanga3f04be2008-11-28 21:36:51 +0000266 for (count = 0; count < writecnt; count++) {
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000267 msg_pspew("[%02x]", mmio_readb(sb600_spibar + 0xC));
Jason Wanga3f04be2008-11-28 21:36:51 +0000268 }
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000269 msg_pspew("\n");
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000270 if (compare_internal_fifo_pointer(writecnt, sb600_spibar))
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000271 return SPI_PROGRAMMER_ERROR;
Jason Wanga3f04be2008-11-28 21:36:51 +0000272
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000273 msg_pspew("Reading FIFO: ");
274 for (count = 0; count < readcnt; count++) {
275 readarr[count] = mmio_readb(sb600_spibar + 0xC);
276 msg_pspew("[%02x]", readarr[count]);
Jason Wanga3f04be2008-11-28 21:36:51 +0000277 }
Carl-Daniel Hailfinger643415b2010-01-10 01:59:50 +0000278 msg_pspew("\n");
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000279 if (compare_internal_fifo_pointer(writecnt+readcnt, sb600_spibar))
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000280 return SPI_PROGRAMMER_ERROR;
281
282 if (mmio_readb(sb600_spibar + 1) != readwrite) {
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000283 msg_perr("Unexpected change in AMD SPI read/write count!\n");
284 msg_perr("Something else is accessing the flash chip and causes random corruption.\n"
285 "Please stop all applications and drivers and IPMI which access the flash chip.\n");
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000286 return SPI_PROGRAMMER_ERROR;
287 }
Jason Wanga3f04be2008-11-28 21:36:51 +0000288
289 return 0;
290}
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +0000291
Edward O'Callaghane4ddc362020-04-12 17:27:53 +1000292static int spi100_spi_send_command(const struct flashctx *flash, unsigned int writecnt,
Wei Hu31402ee2014-05-16 21:39:33 +0000293 unsigned int readcnt,
294 const unsigned char *writearr,
295 unsigned char *readarr)
296{
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000297 struct sb600spi_data *sb600_data = flash->mst->spi.data;
Anastasia Klimchukd6d8c142021-05-20 11:43:06 +1000298 uint8_t *sb600_spibar = sb600_data->spibar;
Wei Hu31402ee2014-05-16 21:39:33 +0000299 /* First byte is cmd which can not be sent through the buffer. */
300 unsigned char cmd = *writearr++;
301 writecnt--;
302 msg_pspew("%s, cmd=0x%02x, writecnt=%d, readcnt=%d\n", __func__, cmd, writecnt, readcnt);
303 mmio_writeb(cmd, sb600_spibar + 0);
304
305 int ret = check_readwritecnt(flash, writecnt, readcnt);
306 if (ret != 0)
307 return ret;
308
309 /* Use the extended TxByteCount and RxByteCount registers. */
310 mmio_writeb(writecnt, sb600_spibar + 0x48);
311 mmio_writeb(readcnt, sb600_spibar + 0x4b);
312
313 msg_pspew("Filling buffer: ");
Nico Huber519be662018-12-23 20:03:35 +0100314 unsigned int count;
Wei Hu31402ee2014-05-16 21:39:33 +0000315 for (count = 0; count < writecnt; count++) {
316 msg_pspew("[%02x]", writearr[count]);
317 mmio_writeb(writearr[count], sb600_spibar + 0x80 + count);
318 }
319 msg_pspew("\n");
320
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000321 execute_command(sb600_spibar);
Wei Hu31402ee2014-05-16 21:39:33 +0000322
323 msg_pspew("Reading buffer: ");
324 for (count = 0; count < readcnt; count++) {
325 readarr[count] = mmio_readb(sb600_spibar + 0x80 + (writecnt + count) % FIFO_SIZE_YANGTZE);
326 msg_pspew("[%02x]", readarr[count]);
327 }
328 msg_pspew("\n");
329
330 return 0;
331}
332
Stefan Taunera6a0d202013-09-15 14:17:39 +0000333struct spispeed {
334 const char *const name;
335 const uint8_t speed;
336};
337
Rob Barnes703de982020-01-21 09:10:51 -0700338static const char* spispeeds[] = {
339 "66 MHz",
340 "33 MHz",
341 "22 MHz",
342 "16.5 MHz",
343 "100 MHz",
344 "Reserved",
345 "Reserved",
346 "800 kHz",
Stefan Taunera6a0d202013-09-15 14:17:39 +0000347};
348
Rob Barnes703de982020-01-21 09:10:51 -0700349static const char* spireadmodes[] = {
350 "Normal (up to 33 MHz)",
351 "Reserved",
352 "Dual IO (1-1-2)",
353 "Quad IO (1-1-4)",
354 "Dual IO (1-2-2)",
355 "Quad IO (1-4-4)",
356 "Normal (up to 66 MHz)",
357 "Fast Read",
358};
359
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000360static int set_speed(struct pci_dev *dev, enum amd_chipset amd_gen, uint8_t speed, uint8_t *sb600_spibar)
Stefan Taunera6a0d202013-09-15 14:17:39 +0000361{
362 bool success = false;
Stefan Taunera6a0d202013-09-15 14:17:39 +0000363
Rob Barnes703de982020-01-21 09:10:51 -0700364 msg_pdbg("Setting SPI clock to %s (%i)... ", spispeeds[speed], speed);
Wei Hu31402ee2014-05-16 21:39:33 +0000365 if (amd_gen >= CHIPSET_YANGTZE) {
366 rmmio_writew((speed << 12) | (speed << 8) | (speed << 4) | speed, sb600_spibar + 0x22);
367 uint16_t tmp = mmio_readw(sb600_spibar + 0x22);
368 success = (((tmp >> 12) & 0xf) == speed && ((tmp >> 8) & 0xf) == speed &&
369 ((tmp >> 4) & 0xf) == speed && ((tmp >> 0) & 0xf) == speed);
370 } else {
Stefan Taunera6a0d202013-09-15 14:17:39 +0000371 rmmio_writeb((mmio_readb(sb600_spibar + 0xd) & ~(0x3 << 4)) | (speed << 4), sb600_spibar + 0xd);
372 success = (speed == ((mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3));
373 }
374
375 if (!success) {
Rob Barnes703de982020-01-21 09:10:51 -0700376 msg_perr("FAILED!\n");
Stefan Taunera6a0d202013-09-15 14:17:39 +0000377 return 1;
378 }
Rob Barnes703de982020-01-21 09:10:51 -0700379 msg_pdbg("succeeded.\n");
Stefan Taunera6a0d202013-09-15 14:17:39 +0000380 return 0;
381}
382
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000383static int set_mode(struct pci_dev *dev, uint8_t mode, uint8_t *sb600_spibar)
Wei Hu31402ee2014-05-16 21:39:33 +0000384{
Rob Barnes703de982020-01-21 09:10:51 -0700385 msg_pdbg("Setting SPI read mode to %s (%i)... ", spireadmodes[mode], mode);
Wei Hu31402ee2014-05-16 21:39:33 +0000386 uint32_t tmp = mmio_readl(sb600_spibar + 0x00);
387 tmp &= ~(0x6 << 28 | 0x1 << 18); /* Clear mode bits */
Rob Barnes703de982020-01-21 09:10:51 -0700388 tmp |= ((mode & 0x6) << 28) | ((mode & 0x1) << 18);
Wei Hu31402ee2014-05-16 21:39:33 +0000389 rmmio_writel(tmp, sb600_spibar + 0x00);
Rob Barnes703de982020-01-21 09:10:51 -0700390 if (tmp != mmio_readl(sb600_spibar + 0x00)) {
391 msg_perr("FAILED!\n");
Wei Hu31402ee2014-05-16 21:39:33 +0000392 return 1;
Rob Barnes703de982020-01-21 09:10:51 -0700393 }
394 msg_pdbg("succeeded.\n");
Wei Hu31402ee2014-05-16 21:39:33 +0000395 return 0;
396}
397
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000398static int handle_speed(struct pci_dev *dev, enum amd_chipset amd_gen, uint8_t *sb600_spibar)
Stefan Taunera6a0d202013-09-15 14:17:39 +0000399{
400 uint32_t tmp;
Rob Barnes703de982020-01-21 09:10:51 -0700401 int16_t spispeed_idx = -1;
402 int16_t spireadmode_idx = -1;
403 char *spispeed;
404 char *spireadmode;
Stefan Taunera6a0d202013-09-15 14:17:39 +0000405
Rob Barnes703de982020-01-21 09:10:51 -0700406 spispeed = extract_programmer_param("spispeed");
Stefan Tauner21071b02014-05-16 21:39:48 +0000407 if (spispeed != NULL) {
Carl-Daniel Hailfinger57cdd6b2016-03-12 19:49:14 +0000408 unsigned int i;
409 for (i = 0; i < ARRAY_SIZE(spispeeds); i++) {
Rob Barnes703de982020-01-21 09:10:51 -0700410 if (strcasecmp(spispeeds[i], spispeed) == 0) {
Carl-Daniel Hailfinger57cdd6b2016-03-12 19:49:14 +0000411 spispeed_idx = i;
412 break;
Stefan Tauner21071b02014-05-16 21:39:48 +0000413 }
Stefan Tauner21071b02014-05-16 21:39:48 +0000414 }
Carl-Daniel Hailfinger57cdd6b2016-03-12 19:49:14 +0000415 /* "reserved" is not a valid speed.
416 * Error out on speeds not present in the spispeeds array.
417 * Only Yangtze supports the second half of indices.
418 * No 66 MHz before SB8xx. */
419 if ((strcasecmp(spispeed, "reserved") == 0) ||
420 (i == ARRAY_SIZE(spispeeds)) ||
421 (amd_gen < CHIPSET_YANGTZE && spispeed_idx > 3) ||
422 (amd_gen < CHIPSET_SB89XX && spispeed_idx == 0)) {
Stefan Tauner21071b02014-05-16 21:39:48 +0000423 msg_perr("Error: Invalid spispeed value: '%s'.\n", spispeed);
424 free(spispeed);
425 return 1;
426 }
427 free(spispeed);
428 }
429
Rob Barnes703de982020-01-21 09:10:51 -0700430 spireadmode = extract_programmer_param("spireadmode");
431 if (spireadmode != NULL) {
432 unsigned int i;
433 for (i = 0; i < ARRAY_SIZE(spireadmodes); i++) {
434 if (strcasecmp(spireadmodes[i], spireadmode) == 0) {
435 spireadmode_idx = i;
436 break;
437 }
438 }
439 if ((strcasecmp(spireadmode, "reserved") == 0) ||
440 (i == ARRAY_SIZE(spireadmodes))) {
441 msg_perr("Error: Invalid spireadmode value: '%s'.\n", spireadmode);
442 free(spireadmode);
443 return 1;
444 }
445 if (amd_gen < CHIPSET_BOLTON) {
446 msg_perr("Warning: spireadmode not supported for this chipset.");
447 }
448 free(spireadmode);
449 }
450
Stefan Taunera6a0d202013-09-15 14:17:39 +0000451 /* See the chipset support matrix for SPI Base_Addr below for an explanation of the symbols used.
Martin Roth82b6ec12014-07-15 13:50:58 +0000452 * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson234 bolton/yangtze
Stefan Taunera6a0d202013-09-15 14:17:39 +0000453 * 18 rsvd <- fastReadEnable ? <- ? SpiReadMode[0]
454 * 29:30 rsvd <- <- ? <- ? SpiReadMode[2:1]
455 */
Martin Roth82b6ec12014-07-15 13:50:58 +0000456 if (amd_gen >= CHIPSET_BOLTON) {
Rob Barnes703de982020-01-21 09:10:51 -0700457
Wei Hu31402ee2014-05-16 21:39:33 +0000458 tmp = mmio_readl(sb600_spibar + 0x00);
459 uint8_t read_mode = ((tmp >> 28) & 0x6) | ((tmp >> 18) & 0x1);
Rob Barnes703de982020-01-21 09:10:51 -0700460 msg_pdbg("SPI read mode is %s (%i)\n",
461 spireadmodes[read_mode], read_mode);
462 if (spireadmode_idx < 0) {
463 msg_perr("Warning: spireadmode not set, "
464 "leaving spireadmode unchanged.");
465 }
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000466 else if (set_mode(dev, spireadmode_idx, sb600_spibar) != 0) {
Rob Barnes703de982020-01-21 09:10:51 -0700467 return 1;
Wei Hu31402ee2014-05-16 21:39:33 +0000468 }
469
Martin Roth82b6ec12014-07-15 13:50:58 +0000470 if (amd_gen >= CHIPSET_YANGTZE) {
471 tmp = mmio_readb(sb600_spibar + 0x20);
472 msg_pdbg("UseSpi100 is %sabled\n", (tmp & 0x1) ? "en" : "dis");
473 if ((tmp & 0x1) == 0) {
474 rmmio_writeb(tmp | 0x1, sb600_spibar + 0x20);
475 tmp = mmio_readb(sb600_spibar + 0x20) & 0x1;
476 if (tmp == 0) {
477 msg_perr("Enabling Spi100 failed.\n");
478 return 1;
479 }
480 msg_pdbg("Enabling Spi100 succeeded.\n");
481 }
482
483 tmp = mmio_readw(sb600_spibar + 0x22); /* SPI 100 Speed Config */
Rob Barnes703de982020-01-21 09:10:51 -0700484 msg_pdbg("NormSpeedNew is %s\n", spispeeds[(tmp >> 12) & 0xf]);
485 msg_pdbg("FastSpeedNew is %s\n", spispeeds[(tmp >> 8) & 0xf]);
486 msg_pdbg("AltSpeedNew is %s\n", spispeeds[(tmp >> 4) & 0xf]);
487 msg_pdbg("TpmSpeedNew is %s\n", spispeeds[(tmp >> 0) & 0xf]);
Martin Roth82b6ec12014-07-15 13:50:58 +0000488 }
Wei Hu31402ee2014-05-16 21:39:33 +0000489 } else {
Stefan Taunera6a0d202013-09-15 14:17:39 +0000490 if (amd_gen >= CHIPSET_SB89XX && amd_gen <= CHIPSET_HUDSON234) {
491 bool fast_read = (mmio_readl(sb600_spibar + 0x00) >> 18) & 0x1;
492 msg_pdbg("Fast Reads are %sabled\n", fast_read ? "en" : "dis");
493 if (fast_read) {
494 msg_pdbg("Disabling them temporarily.\n");
495 rmmio_writel(mmio_readl(sb600_spibar + 0x00) & ~(0x1 << 18),
496 sb600_spibar + 0x00);
497 }
498 }
499 tmp = (mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3;
Rob Barnes703de982020-01-21 09:10:51 -0700500 msg_pdbg("NormSpeed is %s\n", spispeeds[tmp]);
501 if (spispeed_idx < 0) {
502 spispeed_idx = 3; /* Default to 16.5 MHz */
503 }
Stefan Taunera6a0d202013-09-15 14:17:39 +0000504 }
Rob Barnes703de982020-01-21 09:10:51 -0700505 if (spispeed_idx < 0) {
506 msg_perr("Warning: spispeed not set, leaving spispeed unchanged.");
507 return 0;
508 }
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000509 return set_speed(dev, amd_gen, spispeed_idx, sb600_spibar);
Stefan Taunera6a0d202013-09-15 14:17:39 +0000510}
511
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100512static int handle_imc(struct pci_dev *dev, enum amd_chipset amd_gen)
Rudolf Marek70e14592013-07-25 22:58:56 +0000513{
514 /* Handle IMC everywhere but sb600 which does not have one. */
Stefan Tauner4442b812013-09-12 15:48:35 +0000515 if (amd_gen == CHIPSET_SB6XX)
Rudolf Marek70e14592013-07-25 22:58:56 +0000516 return 0;
517
Stefan Taunerd5b2aef2014-05-16 21:39:28 +0000518 bool amd_imc_force = false;
519 char *arg = extract_programmer_param("amd_imc_force");
520 if (arg && !strcmp(arg, "yes")) {
521 amd_imc_force = true;
522 msg_pspew("amd_imc_force enabled.\n");
523 } else if (arg && !strlen(arg)) {
524 msg_perr("Missing argument for amd_imc_force.\n");
525 free(arg);
526 return 1;
527 } else if (arg) {
528 msg_perr("Unknown argument for amd_imc_force: \"%s\" (not \"yes\").\n", arg);
529 free(arg);
530 return 1;
531 }
532 free(arg);
533
Rudolf Marek70e14592013-07-25 22:58:56 +0000534 /* TODO: we should not only look at IntegratedImcPresent (LPC Dev 20, Func 3, 40h) but also at
Stefan Tauner5c316f92015-02-08 21:57:52 +0000535 * IMCEnable(Strap) and Override EcEnable(Strap) (sb8xx, sb9xx?, a50, Bolton: Misc_Reg: 80h-87h;
Rudolf Marek70e14592013-07-25 22:58:56 +0000536 * sb7xx, sp5100: PM_Reg: B0h-B1h) etc. */
537 uint8_t reg = pci_read_byte(dev, 0x40);
538 if ((reg & (1 << 7)) == 0) {
539 msg_pdbg("IMC is not active.\n");
540 return 0;
541 }
542
543 if (!amd_imc_force)
544 programmer_may_write = 0;
Stefan Tauner463dd692013-08-08 12:00:19 +0000545 msg_pinfo("Writes have been disabled for safety reasons because the presence of the IMC\n"
546 "was detected and it could interfere with accessing flash memory. Flashrom will\n"
547 "try to disable it temporarily but even then this might not be safe:\n"
Stefan Tauner0be072c2016-03-13 15:16:30 +0000548 "when it is re-enabled and after a reboot it expects to find working code\n"
Rudolf Marek70e14592013-07-25 22:58:56 +0000549 "in the flash and it is unpredictable what happens if there is none.\n"
550 "\n"
551 "To be safe make sure that there is a working IMC firmware at the right\n"
552 "location in the image you intend to write and do not attempt to erase.\n"
553 "\n"
554 "You can enforce write support with the amd_imc_force programmer option.\n");
555 if (amd_imc_force)
556 msg_pinfo("Continuing with write support because the user forced us to!\n");
557
558 return amd_imc_shutdown(dev);
559}
560
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000561static int promontory_read_memmapped(struct flashctx *flash, uint8_t *buf,
562 unsigned int start, unsigned int len)
563{
564 struct sb600spi_data * data = (struct sb600spi_data *)flash->mst->spi.data;
565 if (!data->flash) {
566 map_flash(flash);
567 data->flash = flash; /* keep a copy of flashctx for unmap() on tear-down. */
568 }
569 mmio_readn((void *)(flash->virtual_memory + start), buf, len);
570 return 0;
571}
572
Anastasia Klimchukefab1102021-05-20 10:25:57 +1000573static const struct spi_master spi_master_sb600 = {
Edward O'Callaghan97dcc972020-11-17 19:27:13 +1100574 .max_data_read = FIFO_SIZE_OLD,
575 .max_data_write = FIFO_SIZE_OLD - 3,
576 .command = sb600_spi_send_command,
577 .multicommand = default_spi_send_multicommand,
578 .read = default_spi_read,
579 .write_256 = default_spi_write_256,
580 .write_aai = default_spi_write_aai,
581};
582
Anastasia Klimchukefab1102021-05-20 10:25:57 +1000583static const struct spi_master spi_master_yangtze = {
Edward O'Callaghan97dcc972020-11-17 19:27:13 +1100584 .max_data_read = FIFO_SIZE_YANGTZE - 3, /* Apparently the big SPI 100 buffer is not a ring buffer. */
585 .max_data_write = FIFO_SIZE_YANGTZE - 3,
586 .command = spi100_spi_send_command,
587 .multicommand = default_spi_send_multicommand,
588 .read = default_spi_read,
589 .write_256 = default_spi_write_256,
590 .write_aai = default_spi_write_aai,
591};
592
Anastasia Klimchukefab1102021-05-20 10:25:57 +1000593static const struct spi_master spi_master_promontory = {
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000594 .max_data_read = MAX_DATA_READ_UNLIMITED,
595 .max_data_write = FIFO_SIZE_YANGTZE - 3,
596 .command = spi100_spi_send_command,
597 .multicommand = default_spi_send_multicommand,
598 .read = promontory_read_memmapped,
599 .write_256 = default_spi_write_256,
600 .write_aai = default_spi_write_aai,
601};
602
603static int sb600spi_shutdown(void *data)
604{
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000605 struct sb600spi_data *sb600_data = data;
606 struct flashctx *flash = sb600_data->flash;
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000607 if (flash)
608 finalize_flash_access(flash);
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000609
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000610 free(data);
611 return 0;
612}
613
Michael Karcherb05b9e12010-07-22 18:04:19 +0000614int sb600_probe_spi(struct pci_dev *dev)
615{
616 struct pci_dev *smbus_dev;
617 uint32_t tmp;
618 uint8_t reg;
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000619 uint8_t *sb600_spibar = NULL;
Rudolf Marek70e14592013-07-25 22:58:56 +0000620
Michael Karcherb05b9e12010-07-22 18:04:19 +0000621 /* Read SPI_BaseAddr */
622 tmp = pci_read_long(dev, 0xa0);
623 tmp &= 0xffffffe0; /* remove bits 4-0 (reserved) */
624 msg_pdbg("SPI base address is at 0x%x\n", tmp);
625
626 /* If the BAR has address 0, it is unlikely SPI is used. */
627 if (!tmp)
628 return 0;
629
630 /* Physical memory has to be mapped at page (4k) boundaries. */
Stefan Tauner7fb5aa02013-08-14 15:48:44 +0000631 sb600_spibar = rphysmap("SB600 SPI registers", tmp & 0xfffff000, 0x1000);
632 if (sb600_spibar == ERROR_PTR)
Niklas Söderlund5d307202013-09-14 09:02:27 +0000633 return ERROR_FATAL;
Stefan Tauner7fb5aa02013-08-14 15:48:44 +0000634
Michael Karcherb05b9e12010-07-22 18:04:19 +0000635 /* The low bits of the SPI base address are used as offset into
636 * the mapped page.
637 */
638 sb600_spibar += tmp & 0xfff;
639
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100640 enum amd_chipset amd_gen = determine_generation(dev);
641 if (amd_gen == CHIPSET_AMD_UNKNOWN)
Stefan Tauner4442b812013-09-12 15:48:35 +0000642 return ERROR_NONFATAL;
Stefan Tauner463dd692013-08-08 12:00:19 +0000643
Stefan Tauner4442b812013-09-12 15:48:35 +0000644 /* How to read the following table and similar ones in this file:
645 * "?" means we have no datasheet for this chipset generation or it doesn't have any relevant info.
646 * "<-" means the bit/register meaning is identical to the next non-"?" chipset to the left. "<-" thus
647 * never refers to another "?".
648 * If a "?" chipset is between two chipsets with identical meaning, we assume the meaning didn't change
649 * twice in between, i.e. the meaning is unchanged for the "?" chipset. Usually we assume that
650 * succeeding hardware supports the same functionality as its predecessor unless proven different by
651 * tests or documentation, hence "?" will often be implemented equally to "<-".
652 *
653 * Chipset support matrix for SPI Base_Addr (LPC PCI reg 0xa0)
654 * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson2+ yangtze
655 * 3 rsvd <- <- ? <- ? RouteTpm2Spi
656 * 2 rsvd AbortEnable rsvd ? <- ? <-
657 * 1 rsvd SpiRomEnable <- ? <- ? <-
658 * 0 rsvd AltSpiCSEnable rsvd ? <- ? <-
659 */
660 if (amd_gen >= CHIPSET_SB7XX) {
661 tmp = pci_read_long(dev, 0xa0);
662 msg_pdbg("SpiRomEnable=%i", (tmp >> 1) & 0x1);
663 if (amd_gen == CHIPSET_SB7XX)
664 msg_pdbg(", AltSpiCSEnable=%i, AbortEnable=%i", tmp & 0x1, (tmp >> 2) & 0x1);
Edward O'Callaghan93737bc2019-10-29 18:30:01 +1100665 else if (amd_gen >= CHIPSET_YANGTZE)
Wei Hu31402ee2014-05-16 21:39:33 +0000666 msg_pdbg(", RouteTpm2Sp=%i", (tmp >> 3) & 0x1);
Michael Karcherb05b9e12010-07-22 18:04:19 +0000667
Stefan Tauner4442b812013-09-12 15:48:35 +0000668 tmp = pci_read_byte(dev, 0xba);
669 msg_pdbg(", PrefetchEnSPIFromIMC=%i", (tmp & 0x4) >> 2);
670
671 tmp = pci_read_byte(dev, 0xbb);
672 /* FIXME: Set bit 3,6,7 if not already set.
673 * Set bit 5, otherwise SPI accesses are pointless in LPC mode.
674 * See doc 42413 AMD SB700/710/750 RPR.
675 */
676 if (amd_gen == CHIPSET_SB7XX)
677 msg_pdbg(", SpiOpEnInLpcMode=%i", (tmp >> 5) & 0x1);
678 msg_pdbg(", PrefetchEnSPIFromHost=%i\n", tmp & 0x1);
679 }
680
681 /* Chipset support matrix for SPI_Cntrl0 (spibar + 0x0)
682 * See the chipset support matrix for SPI Base_Addr above for an explanation of the symbols used.
683 * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson2+ yangtze
684 * 17 rsvd <- <- ? <- ? <-
Stefan Taunera6a0d202013-09-15 14:17:39 +0000685 * 18 rsvd <- fastReadEnable<1> ? <- ? SpiReadMode[0]<1>
Stefan Tauner4442b812013-09-12 15:48:35 +0000686 * 19 SpiArbEnable <- <- ? <- ? <-
687 * 20 (FifoPtrClr) <- <- ? <- ? <-
688 * 21 (FifoPtrInc) <- <- ? <- ? IllegalAccess
689 * 22 SpiAccessMacRomEn <- <- ? <- ? <-
690 * 23 SpiHostAccessRomEn <- <- ? <- ? <-
691 * 24:26 ArbWaitCount <- <- ? <- ? <-
692 * 27 SpiBridgeDisable <- <- ? <- ? rsvd
693 * 28 rsvd DropOneClkOnRd = SPIClkGate ? <- ? <-
Stefan Taunera6a0d202013-09-15 14:17:39 +0000694 * 29:30 rsvd <- <- ? <- ? SpiReadMode[2:1]<1>
Stefan Tauner4442b812013-09-12 15:48:35 +0000695 * 31 rsvd <- SpiBusy ? <- ? <-
Stefan Taunera6a0d202013-09-15 14:17:39 +0000696 *
697 * <1> see handle_speed
Carl-Daniel Hailfingereb0e7fc2010-08-18 15:12:43 +0000698 */
Stefan Tauner4442b812013-09-12 15:48:35 +0000699 tmp = mmio_readl(sb600_spibar + 0x00);
700 msg_pdbg("(0x%08" PRIx32 ") SpiArbEnable=%i", tmp, (tmp >> 19) & 0x1);
Edward O'Callaghan93737bc2019-10-29 18:30:01 +1100701 if (amd_gen >= CHIPSET_YANGTZE)
Wei Hu31402ee2014-05-16 21:39:33 +0000702 msg_pdbg(", IllegalAccess=%i", (tmp >> 21) & 0x1);
Stefan Tauner4442b812013-09-12 15:48:35 +0000703
704 msg_pdbg(", SpiAccessMacRomEn=%i, SpiHostAccessRomEn=%i, ArbWaitCount=%i",
705 (tmp >> 22) & 0x1, (tmp >> 23) & 0x1, (tmp >> 24) & 0x7);
706
Edward O'Callaghan93737bc2019-10-29 18:30:01 +1100707 if (amd_gen < CHIPSET_YANGTZE)
Stefan Tauner4442b812013-09-12 15:48:35 +0000708 msg_pdbg(", SpiBridgeDisable=%i", (tmp >> 27) & 0x1);
709
710 switch (amd_gen) {
711 case CHIPSET_SB7XX:
712 msg_pdbg(", DropOneClkOnRd/SpiClkGate=%i", (tmp >> 28) & 0x1);
Richard Hughesdb7482b2018-12-19 12:04:30 +0000713 /* Fall through. */
Stefan Tauner4442b812013-09-12 15:48:35 +0000714 case CHIPSET_SB89XX:
715 case CHIPSET_HUDSON234:
Wei Hu31402ee2014-05-16 21:39:33 +0000716 case CHIPSET_YANGTZE:
Edward O'Callaghan93737bc2019-10-29 18:30:01 +1100717 case CHIPSET_PROMONTORY:
Stefan Tauner4442b812013-09-12 15:48:35 +0000718 msg_pdbg(", SpiBusy=%i", (tmp >> 31) & 0x1);
719 default: break;
720 }
721 msg_pdbg("\n");
722
723 if (((tmp >> 22) & 0x1) == 0 || ((tmp >> 23) & 0x1) == 0) {
724 msg_perr("ERROR: State of SpiAccessMacRomEn or SpiHostAccessRomEn prohibits full access.\n");
725 return ERROR_NONFATAL;
726 }
727
Stefan Tauner4442b812013-09-12 15:48:35 +0000728 if (amd_gen >= CHIPSET_SB89XX) {
729 tmp = mmio_readb(sb600_spibar + 0x1D);
730 msg_pdbg("Using SPI_CS%d\n", tmp & 0x3);
Wei Hu31402ee2014-05-16 21:39:33 +0000731 /* FIXME: Handle SpiProtect* configuration on Yangtze. */
Stefan Tauner4442b812013-09-12 15:48:35 +0000732 }
733
Michael Karcherb05b9e12010-07-22 18:04:19 +0000734 /* Look for the SMBus device. */
735 smbus_dev = pci_dev_find(0x1002, 0x4385);
Ricardo Ribalda Delgado7b629bc2017-03-22 14:08:31 +0100736 if (!smbus_dev)
Stefan Tauner463dd692013-08-08 12:00:19 +0000737 smbus_dev = pci_dev_find(0x1022, 0x780b); /* AMD FCH */
Ricardo Ribalda Delgado7b629bc2017-03-22 14:08:31 +0100738 if (!smbus_dev)
739 smbus_dev = pci_dev_find(0x1022, 0x790b); /* AMD FP4 */
740 if (!smbus_dev) {
741 msg_perr("ERROR: SMBus device not found. Not enabling SPI.\n");
742 return ERROR_NONFATAL;
Michael Karcherb05b9e12010-07-22 18:04:19 +0000743 }
744
745 /* Note about the bit tests below: If a bit is zero, the GPIO is SPI. */
746 /* GPIO11/SPI_DO and GPIO12/SPI_DI status */
747 reg = pci_read_byte(smbus_dev, 0xAB);
748 reg &= 0xC0;
749 msg_pdbg("GPIO11 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_DO");
750 msg_pdbg("GPIO12 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_DI");
751 if (reg != 0x00) {
752 msg_pdbg("Not enabling SPI");
753 return 0;
754 }
755 /* GPIO31/SPI_HOLD and GPIO32/SPI_CS status */
756 reg = pci_read_byte(smbus_dev, 0x83);
757 reg &= 0xC0;
758 msg_pdbg("GPIO31 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_HOLD");
759 msg_pdbg("GPIO32 used for %s\n", (reg & (1 << 7)) ? "GPIO" : "SPI_CS");
760 /* SPI_HOLD is not used on all boards, filter it out. */
761 if ((reg & 0x80) != 0x00) {
762 msg_pdbg("Not enabling SPI");
763 return 0;
764 }
765 /* GPIO47/SPI_CLK status */
766 reg = pci_read_byte(smbus_dev, 0xA7);
767 reg &= 0x40;
768 msg_pdbg("GPIO47 used for %s\n", (reg & (1 << 6)) ? "GPIO" : "SPI_CLK");
769 if (reg != 0x00) {
770 msg_pdbg("Not enabling SPI");
771 return 0;
772 }
773
Anastasia Klimchuk59237a32021-05-20 10:18:52 +1000774 if (handle_speed(dev, amd_gen, sb600_spibar) != 0)
Stefan Taunera6a0d202013-09-15 14:17:39 +0000775 return ERROR_FATAL;
776
Edward O'Callaghan0386aa12019-10-30 00:38:16 +1100777 if (handle_imc(dev, amd_gen) != 0)
Rudolf Marek70e14592013-07-25 22:58:56 +0000778 return ERROR_FATAL;
Carl-Daniel Hailfinger39446e32010-09-15 12:02:07 +0000779
Angel Pons3bd47522021-06-07 12:33:53 +0200780 struct sb600spi_data *data = calloc(1, sizeof(*data));
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000781 if (!data) {
782 msg_perr("Unable to allocate space for extra SPI master data.\n");
783 return SPI_GENERIC_ERROR;
784 }
785
786 data->flash = NULL;
Anastasia Klimchukd6d8c142021-05-20 11:43:06 +1000787 data->spibar = sb600_spibar;
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000788
789 register_shutdown(sb600spi_shutdown, data);
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000790
Wei Hu31402ee2014-05-16 21:39:33 +0000791 /* Starting with Yangtze the SPI controller got a different interface with a much bigger buffer. */
Edward O'Callaghan93737bc2019-10-29 18:30:01 +1100792 if (amd_gen < CHIPSET_YANGTZE)
Anastasia Klimchukefab1102021-05-20 10:25:57 +1000793 register_spi_master(&spi_master_sb600, data);
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000794 else if (amd_gen == CHIPSET_YANGTZE)
Anastasia Klimchukefab1102021-05-20 10:25:57 +1000795 register_spi_master(&spi_master_yangtze, data);
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000796 else
Anastasia Klimchukefab1102021-05-20 10:25:57 +1000797 register_spi_master(&spi_master_promontory, data);
Edward O'Callaghan855d6b62020-07-31 12:21:02 +1000798
Michael Karcherb05b9e12010-07-22 18:04:19 +0000799 return 0;
800}
801
Carl-Daniel Hailfingercceafa22010-05-26 01:45:41 +0000802#endif