blob: ade7a02376ff8645948e9dc201aeb2b7440375d6 [file] [log] [blame]
zbao246e84b2012-07-13 18:47:03 +08001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2012 Advanced Micro Devices, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
zbao246e84b2012-07-13 18:47:03 +080014 */
Zheng Bao7bcffa52012-11-28 11:36:52 +080015#include <stdint.h>
16#include <stdlib.h>
17#include <string.h>
zbao246e84b2012-07-13 18:47:03 +080018#include <arch/io.h>
Kyösti Mälkki9f0a2be2014-06-30 07:34:36 +030019#include <console/console.h>
Furquan Shaikhc28984d2016-11-20 21:04:00 -080020#include <spi_flash.h>
Zheng Bao600784e2013-02-07 17:30:23 +080021#include <spi-generic.h>
zbao246e84b2012-07-13 18:47:03 +080022#include <device/device.h>
Zheng Bao7bcffa52012-11-28 11:36:52 +080023#include <device/pci.h>
24#include <device/pci_ops.h>
zbao246e84b2012-07-13 18:47:03 +080025
Alexandru Gagniuc01e0adf2014-03-29 17:07:26 -050026#include <Proc/Fch/FchPlatform.h>
Martin Roth3316cf22012-12-05 16:22:54 -070027
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050028#define SPI_REG_OPCODE 0x0
29#define SPI_REG_CNTRL01 0x1
30#define SPI_REG_CNTRL02 0x2
31 #define CNTRL02_FIFO_RESET (1 << 4)
32 #define CNTRL02_EXEC_OPCODE (1 << 0)
33#define SPI_REG_CNTRL03 0x3
34 #define CNTRL03_SPIBUSY (1 << 7)
35#define SPI_REG_FIFO 0xc
36#define SPI_REG_CNTRL11 0xd
37 #define CNTRL11_FIFOPTR_MASK 0x07
38
Kyösti Mälkki2fa8cc32014-07-15 02:30:49 +030039#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_AGESA_YANGTZE)
Kyösti Mälkki11104952014-06-29 16:17:33 +030040#define AMD_SB_SPI_TX_LEN 64
Kyösti Mälkki2fa8cc32014-07-15 02:30:49 +030041#else
42#define AMD_SB_SPI_TX_LEN 8
43#endif
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050044
Stefan Reinauerfce128c2015-07-21 12:52:34 -070045static uintptr_t spibar;
Zheng Bao7bcffa52012-11-28 11:36:52 +080046
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050047static inline uint8_t spi_read(uint8_t reg)
48{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080049 return read8((void *)(spibar + reg));
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050050}
51
52static inline void spi_write(uint8_t reg, uint8_t val)
53{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080054 write8((void *)(spibar + reg), val);
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050055}
56
Zheng Bao7bcffa52012-11-28 11:36:52 +080057static void reset_internal_fifo_pointer(void)
zbao246e84b2012-07-13 18:47:03 +080058{
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050059 uint8_t reg8;
60
zbao246e84b2012-07-13 18:47:03 +080061 do {
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050062 reg8 = spi_read(SPI_REG_CNTRL02);
63 reg8 |= CNTRL02_FIFO_RESET;
64 spi_write(SPI_REG_CNTRL02, reg8);
65 } while (spi_read(SPI_REG_CNTRL11) & CNTRL11_FIFOPTR_MASK);
zbao246e84b2012-07-13 18:47:03 +080066}
67
Zheng Bao7bcffa52012-11-28 11:36:52 +080068static void execute_command(void)
zbao246e84b2012-07-13 18:47:03 +080069{
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050070 uint8_t reg8;
Zheng Bao7bcffa52012-11-28 11:36:52 +080071
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050072 reg8 = spi_read(SPI_REG_CNTRL02);
73 reg8 |= CNTRL02_EXEC_OPCODE;
74 spi_write(SPI_REG_CNTRL02, reg8);
75
76 while ((spi_read(SPI_REG_CNTRL02) & CNTRL02_EXEC_OPCODE) &&
77 (spi_read(SPI_REG_CNTRL03) & CNTRL03_SPIBUSY));
zbao246e84b2012-07-13 18:47:03 +080078}
79
Alexandru Gagniuc991e9512014-04-19 22:21:27 -050080void spi_init(void)
zbao246e84b2012-07-13 18:47:03 +080081{
Elyes HAOUASa93e7542018-05-19 14:30:47 +020082 struct device *dev;
Zheng Bao7bcffa52012-11-28 11:36:52 +080083
Kyösti Mälkki4ad7f5b2018-05-22 01:15:17 +030084 dev = pcidev_on_root(0x14, 3);
Zheng Bao7bcffa52012-11-28 11:36:52 +080085 spibar = pci_read_config32(dev, 0xA0) & ~0x1F;
zbao246e84b2012-07-13 18:47:03 +080086}
87
Furquan Shaikh94f86992016-12-01 07:12:32 -080088static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
Furquan Shaikh0dba0252016-11-30 04:34:22 -080089 size_t bytesout, void *din, size_t bytesin)
zbao246e84b2012-07-13 18:47:03 +080090{
Paul Menzeldee0f882018-11-10 11:24:38 +010091 /* First byte is cmd which can not be sent through FIFO. */
Gabe Black93d9f922014-03-27 21:52:43 -070092 u8 cmd = *(u8 *)dout++;
93 u8 readoffby1;
Furquan Shaikh0dba0252016-11-30 04:34:22 -080094 size_t count;
zbao246e84b2012-07-13 18:47:03 +080095
Gabe Black93d9f922014-03-27 21:52:43 -070096 bytesout--;
Kyösti Mälkki9f0a2be2014-06-30 07:34:36 +030097
98 /*
99 * Check if this is a write command attempting to transfer more bytes
100 * than the controller can handle. Iterations for writes are not
101 * supported here because each SPI write command needs to be preceded
102 * and followed by other SPI commands, and this sequence is controlled
103 * by the SPI chip driver.
104 */
105 if (bytesout > AMD_SB_SPI_TX_LEN) {
106 printk(BIOS_DEBUG, "FCH SPI: Too much to write. Does your SPI chip driver use"
107 " spi_crop_chunk()?\n");
108 return -1;
109 }
110
Zheng Bao7bcffa52012-11-28 11:36:52 +0800111 readoffby1 = bytesout ? 0 : 1;
zbao246e84b2012-07-13 18:47:03 +0800112
Martin Roth083504b2017-06-24 21:30:14 -0600113#if IS_ENABLED(CONFIG_SOUTHBRIDGE_AMD_AGESA_YANGTZE)
Alexandru Gagniuc991e9512014-04-19 22:21:27 -0500114 spi_write(0x1E, 5);
115 spi_write(0x1F, bytesout); /* SpiExtRegIndx [5] - TxByteCount */
116 spi_write(0x1E, 6);
117 spi_write(0x1F, bytesin); /* SpiExtRegIndx [6] - RxByteCount */
Siyuan Wang91571452013-07-09 17:32:42 +0800118#else
Gabe Black93d9f922014-03-27 21:52:43 -0700119 u8 readwrite = (bytesin + readoffby1) << 4 | bytesout;
Alexandru Gagniuc991e9512014-04-19 22:21:27 -0500120 spi_write(SPI_REG_CNTRL01, readwrite);
Siyuan Wang91571452013-07-09 17:32:42 +0800121#endif
Alexandru Gagniuc991e9512014-04-19 22:21:27 -0500122 spi_write(SPI_REG_OPCODE, cmd);
zbao246e84b2012-07-13 18:47:03 +0800123
Zheng Bao7bcffa52012-11-28 11:36:52 +0800124 reset_internal_fifo_pointer();
125 for (count = 0; count < bytesout; count++, dout++) {
Alexandru Gagniuc991e9512014-04-19 22:21:27 -0500126 spi_write(SPI_REG_FIFO, *(uint8_t *)dout);
zbao246e84b2012-07-13 18:47:03 +0800127 }
Zheng Bao7bcffa52012-11-28 11:36:52 +0800128
129 reset_internal_fifo_pointer();
130 execute_command();
131
132 reset_internal_fifo_pointer();
133 /* Skip the bytes we sent. */
134 for (count = 0; count < bytesout; count++) {
Paul Menzel9eb4d0a2018-11-10 11:27:02 +0100135 spi_read(SPI_REG_FIFO);
Zheng Bao7bcffa52012-11-28 11:36:52 +0800136 }
137
Zheng Bao7bcffa52012-11-28 11:36:52 +0800138 for (count = 0; count < bytesin; count++, din++) {
Alexandru Gagniuc991e9512014-04-19 22:21:27 -0500139 *(uint8_t *)din = spi_read(SPI_REG_FIFO);
Zheng Bao7bcffa52012-11-28 11:36:52 +0800140 }
141
142 return 0;
143}
Furquan Shaikhc28984d2016-11-20 21:04:00 -0800144
Furquan Shaikhc28984d2016-11-20 21:04:00 -0800145int chipset_volatile_group_begin(const struct spi_flash *flash)
146{
147 if (!IS_ENABLED (CONFIG_HUDSON_IMC_FWM))
148 return 0;
149
150 ImcSleep(NULL);
151 return 0;
152}
153
154int chipset_volatile_group_end(const struct spi_flash *flash)
155{
156 if (!IS_ENABLED (CONFIG_HUDSON_IMC_FWM))
157 return 0;
158
159 ImcWakeup(NULL);
160 return 0;
zbao246e84b2012-07-13 18:47:03 +0800161}
162
Aaron Durbin851dde82018-04-19 21:15:25 -0600163static int xfer_vectors(const struct spi_slave *slave,
164 struct spi_op vectors[], size_t count)
165{
166 return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer);
167}
168
Furquan Shaikh94f86992016-12-01 07:12:32 -0800169static const struct spi_ctrlr spi_ctrlr = {
Aaron Durbin851dde82018-04-19 21:15:25 -0600170 .xfer_vector = xfer_vectors,
Furquan Shaikhde705fa2017-04-19 19:27:28 -0700171 .max_xfer_size = AMD_SB_SPI_TX_LEN,
Aaron Durbin1fcc9f32018-01-29 11:30:17 -0700172 .flags = SPI_CNTRLR_DEDUCT_CMD_LEN,
Furquan Shaikh94f86992016-12-01 07:12:32 -0800173};
174
Furquan Shaikh12eca762017-05-18 14:58:49 -0700175const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
176 {
177 .ctrlr = &spi_ctrlr,
178 .bus_start = 0,
179 .bus_end = 0,
180 },
181};
182
183const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);