blob: db2cbfbac101ca0a59fe5947556d0ea8dc22650a [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2/* This file is part of the coreboot project. */
Elyes HAOUAS400f9ca2019-06-23 07:01:22 +02003
Kyösti Mälkki13f66502019-03-03 08:01:05 +02004#include <device/mmio.h>
Kyösti Mälkki9f0a2be2014-06-30 07:34:36 +03005#include <console/console.h>
Furquan Shaikhc28984d2016-11-20 21:04:00 -08006#include <spi_flash.h>
Zheng Bao600784e2013-02-07 17:30:23 +08007#include <spi-generic.h>
zbao01bd79f2012-03-23 11:36:08 +08008#include <device/device.h>
Zheng Bao7bcffa52012-11-28 11:36:52 +08009#include <device/pci.h>
10#include <device/pci_ops.h>
Elyes HAOUAS400f9ca2019-06-23 07:01:22 +020011#include <types.h>
zbao01bd79f2012-03-23 11:36:08 +080012
Martin Roth3316cf22012-12-05 16:22:54 -070013#include "SBPLATFORM.h"
14#include <vendorcode/amd/cimx/sb800/ECfan.h>
15
Kyösti Mälkki11104952014-06-29 16:17:33 +030016#define AMD_SB_SPI_TX_LEN 8
17
Stefan Reinauer12bce3f2015-06-18 01:17:38 -070018static uintptr_t spibar;
zbao01bd79f2012-03-23 11:36:08 +080019
Zheng Bao7bcffa52012-11-28 11:36:52 +080020static void reset_internal_fifo_pointer(void)
zbao01bd79f2012-03-23 11:36:08 +080021{
zbao01bd79f2012-03-23 11:36:08 +080022 do {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080023 write8((void *)(spibar + 2),
24 read8((void *)(spibar + 2)) | 0x10);
25 } while (read8((void *)(spibar + 0xD)) & 0x7);
zbao01bd79f2012-03-23 11:36:08 +080026}
27
Zheng Bao7bcffa52012-11-28 11:36:52 +080028static void execute_command(void)
zbao01bd79f2012-03-23 11:36:08 +080029{
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080030 write8((void *)(spibar + 2), read8((void *)(spibar + 2)) | 1);
Zheng Bao7bcffa52012-11-28 11:36:52 +080031
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080032 while ((read8((void *)(spibar + 2)) & 1) &&
33 (read8((void *)(spibar+3)) & 0x80));
zbao01bd79f2012-03-23 11:36:08 +080034}
35
Zheng Bao7bcffa52012-11-28 11:36:52 +080036void spi_init()
zbao01bd79f2012-03-23 11:36:08 +080037{
Elyes HAOUAS1a4abb72018-05-19 16:49:20 +020038 struct device *dev;
Zheng Bao7bcffa52012-11-28 11:36:52 +080039
Kyösti Mälkkic70eed12018-05-22 02:18:00 +030040 dev = pcidev_on_root(0x14, 3);
Zheng Bao7bcffa52012-11-28 11:36:52 +080041 spibar = pci_read_config32(dev, 0xA0) & ~0x1F;
zbao01bd79f2012-03-23 11:36:08 +080042}
43
Furquan Shaikh94f86992016-12-01 07:12:32 -080044static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
Furquan Shaikh0dba0252016-11-30 04:34:22 -080045 size_t bytesout, void *din, size_t bytesin)
zbao01bd79f2012-03-23 11:36:08 +080046{
Paul Menzeldee0f882018-11-10 11:24:38 +010047 /* First byte is cmd which can not be sent through FIFO. */
Zheng Bao7bcffa52012-11-28 11:36:52 +080048 u8 cmd = *(u8 *)dout++;
49 u8 readoffby1;
50 u8 readwrite;
Furquan Shaikh0dba0252016-11-30 04:34:22 -080051 size_t count;
zbao01bd79f2012-03-23 11:36:08 +080052
Gabe Black93d9f922014-03-27 21:52:43 -070053 bytesout--;
zbao01bd79f2012-03-23 11:36:08 +080054
Kyösti Mälkki9f0a2be2014-06-30 07:34:36 +030055 /*
56 * Check if this is a write command attempting to transfer more bytes
57 * than the controller can handle. Iterations for writes are not
58 * supported here because each SPI write command needs to be preceded
59 * and followed by other SPI commands, and this sequence is controlled
60 * by the SPI chip driver.
61 */
62 if (bytesout > AMD_SB_SPI_TX_LEN) {
63 printk(BIOS_DEBUG, "FCH SPI: Too much to write. Does your SPI chip driver use"
64 " spi_crop_chunk()?\n");
65 return -1;
66 }
67
Zheng Bao7bcffa52012-11-28 11:36:52 +080068 readoffby1 = bytesout ? 0 : 1;
zbao01bd79f2012-03-23 11:36:08 +080069
Zheng Bao7bcffa52012-11-28 11:36:52 +080070 readwrite = (bytesin + readoffby1) << 4 | bytesout;
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080071 write8((void *)(spibar + 1), readwrite);
72 write8((void *)(spibar + 0), cmd);
zbao01bd79f2012-03-23 11:36:08 +080073
Zheng Bao7bcffa52012-11-28 11:36:52 +080074 reset_internal_fifo_pointer();
75 for (count = 0; count < bytesout; count++, dout++) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080076 write8((void *)(spibar + 0x0C), *(u8 *)dout);
zbao01bd79f2012-03-23 11:36:08 +080077 }
Zheng Bao7bcffa52012-11-28 11:36:52 +080078
79 reset_internal_fifo_pointer();
80 execute_command();
81
82 reset_internal_fifo_pointer();
83 /* Skip the bytes we sent. */
84 for (count = 0; count < bytesout; count++) {
Paul Menzel9eb4d0a2018-11-10 11:27:02 +010085 read8((void *)(spibar + 0x0C));
Zheng Bao7bcffa52012-11-28 11:36:52 +080086 }
87
88 reset_internal_fifo_pointer();
89 for (count = 0; count < bytesin; count++, din++) {
Kevin Paul Herbertbde6d302014-12-24 18:43:20 -080090 *(u8 *)din = read8((void *)(spibar + 0x0C));
Zheng Bao7bcffa52012-11-28 11:36:52 +080091 }
92
93 return 0;
94}
Martin Roth3316cf22012-12-05 16:22:54 -070095
Martin Roth3316cf22012-12-05 16:22:54 -070096static void ImcSleep(void)
97{
98 u8 cmd_val = 0x96; /* Kick off IMC Mailbox command 96 */
99 u8 reg0_val = 0; /* clear response register */
100 u8 reg1_val = 0xB4; /* request ownership flag */
101
102 WriteECmsg (MSG_REG0, AccWidthUint8, &reg0_val);
103 WriteECmsg (MSG_REG1, AccWidthUint8, &reg1_val);
104 WriteECmsg (MSG_SYS_TO_IMC, AccWidthUint8, &cmd_val);
105
106 WaitForEcLDN9MailboxCmdAck();
107}
108
109
110static void ImcWakeup(void)
111{
112 u8 cmd_val = 0x96; /* Kick off IMC Mailbox command 96 */
Idwer Volleringd26da9c2013-12-22 21:38:18 +0000113 u8 reg0_val = 0; /* clear response register */
Martin Roth3316cf22012-12-05 16:22:54 -0700114 u8 reg1_val = 0xB5; /* release ownership flag */
115
116 WriteECmsg (MSG_REG0, AccWidthUint8, &reg0_val);
117 WriteECmsg (MSG_REG1, AccWidthUint8, &reg1_val);
118 WriteECmsg (MSG_SYS_TO_IMC, AccWidthUint8, &cmd_val);
119
120 WaitForEcLDN9MailboxCmdAck();
121}
Martin Roth3316cf22012-12-05 16:22:54 -0700122
Furquan Shaikhc28984d2016-11-20 21:04:00 -0800123int chipset_volatile_group_begin(const struct spi_flash *flash)
124{
Julius Wernercd49cce2019-03-05 16:53:33 -0800125 if (!CONFIG(SB800_IMC_FWM))
Furquan Shaikhc28984d2016-11-20 21:04:00 -0800126 return 0;
127
128 ImcSleep();
129 return 0;
130}
131
132int chipset_volatile_group_end(const struct spi_flash *flash)
133{
Julius Wernercd49cce2019-03-05 16:53:33 -0800134 if (!CONFIG(SB800_IMC_FWM))
Furquan Shaikhc28984d2016-11-20 21:04:00 -0800135 return 0;
136
137 ImcWakeup();
138 return 0;
zbao01bd79f2012-03-23 11:36:08 +0800139}
140
Aaron Durbin851dde82018-04-19 21:15:25 -0600141static int xfer_vectors(const struct spi_slave *slave,
142 struct spi_op vectors[], size_t count)
143{
144 return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer);
145}
146
Furquan Shaikh94f86992016-12-01 07:12:32 -0800147static const struct spi_ctrlr spi_ctrlr = {
Aaron Durbin851dde82018-04-19 21:15:25 -0600148 .xfer_vector = xfer_vectors,
Furquan Shaikhde705fa2017-04-19 19:27:28 -0700149 .max_xfer_size = AMD_SB_SPI_TX_LEN,
Aaron Durbin1fcc9f32018-01-29 11:30:17 -0700150 .flags = SPI_CNTRLR_DEDUCT_CMD_LEN,
Furquan Shaikh94f86992016-12-01 07:12:32 -0800151};
152
Furquan Shaikh12eca762017-05-18 14:58:49 -0700153const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
154 {
155 .ctrlr = &spi_ctrlr,
156 .bus_start = 0,
157 .bus_end = 0,
158 },
159};
160
161const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);