sb/amd: Fix grammar in comment
[coreboot.git] / src / southbridge / amd / cimx / sb800 / spi.c
blobec18454cc7d570e2f2afdd35b8556ae50a392905
1 /*
2 * This file is part of the coreboot project.
4 * Copyright (C) 2012 Advanced Micro Devices, Inc.
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.
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.
15 #include <stdint.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <arch/io.h>
19 #include <console/console.h>
20 #include <spi_flash.h>
21 #include <spi-generic.h>
22 #include <device/device.h>
23 #include <device/pci.h>
24 #include <device/pci_ops.h>
26 #include "SBPLATFORM.h"
27 #include <vendorcode/amd/cimx/sb800/ECfan.h>
29 #define AMD_SB_SPI_TX_LEN 8
31 static uintptr_t spibar;
33 static void reset_internal_fifo_pointer(void)
35 do {
36 write8((void *)(spibar + 2),
37 read8((void *)(spibar + 2)) | 0x10);
38 } while (read8((void *)(spibar + 0xD)) & 0x7);
41 static void execute_command(void)
43 write8((void *)(spibar + 2), read8((void *)(spibar + 2)) | 1);
45 while ((read8((void *)(spibar + 2)) & 1) &&
46 (read8((void *)(spibar+3)) & 0x80));
49 void spi_init()
51 struct device *dev;
53 dev = dev_find_slot(0, PCI_DEVFN(0x14, 3));
54 spibar = pci_read_config32(dev, 0xA0) & ~0x1F;
57 static int spi_ctrlr_xfer(const struct spi_slave *slave, const void *dout,
58 size_t bytesout, void *din, size_t bytesin)
60 /* First byte is cmd which can not be sent through FIFO. */
61 u8 cmd = *(u8 *)dout++;
62 u8 readoffby1;
63 u8 readwrite;
64 size_t count;
66 bytesout--;
69 * Check if this is a write command attempting to transfer more bytes
70 * than the controller can handle. Iterations for writes are not
71 * supported here because each SPI write command needs to be preceded
72 * and followed by other SPI commands, and this sequence is controlled
73 * by the SPI chip driver.
75 if (bytesout > AMD_SB_SPI_TX_LEN) {
76 printk(BIOS_DEBUG, "FCH SPI: Too much to write. Does your SPI chip driver use"
77 " spi_crop_chunk()?\n");
78 return -1;
81 readoffby1 = bytesout ? 0 : 1;
83 readwrite = (bytesin + readoffby1) << 4 | bytesout;
84 write8((void *)(spibar + 1), readwrite);
85 write8((void *)(spibar + 0), cmd);
87 reset_internal_fifo_pointer();
88 for (count = 0; count < bytesout; count++, dout++) {
89 write8((void *)(spibar + 0x0C), *(u8 *)dout);
92 reset_internal_fifo_pointer();
93 execute_command();
95 reset_internal_fifo_pointer();
96 /* Skip the bytes we sent. */
97 for (count = 0; count < bytesout; count++) {
98 cmd = read8((void *)(spibar + 0x0C));
101 reset_internal_fifo_pointer();
102 for (count = 0; count < bytesin; count++, din++) {
103 *(u8 *)din = read8((void *)(spibar + 0x0C));
106 return 0;
109 static void ImcSleep(void)
111 u8 cmd_val = 0x96; /* Kick off IMC Mailbox command 96 */
112 u8 reg0_val = 0; /* clear response register */
113 u8 reg1_val = 0xB4; /* request ownership flag */
115 WriteECmsg (MSG_REG0, AccWidthUint8, &reg0_val);
116 WriteECmsg (MSG_REG1, AccWidthUint8, &reg1_val);
117 WriteECmsg (MSG_SYS_TO_IMC, AccWidthUint8, &cmd_val);
119 WaitForEcLDN9MailboxCmdAck();
123 static void ImcWakeup(void)
125 u8 cmd_val = 0x96; /* Kick off IMC Mailbox command 96 */
126 u8 reg0_val = 0; /* clear response register */
127 u8 reg1_val = 0xB5; /* release ownership flag */
129 WriteECmsg (MSG_REG0, AccWidthUint8, &reg0_val);
130 WriteECmsg (MSG_REG1, AccWidthUint8, &reg1_val);
131 WriteECmsg (MSG_SYS_TO_IMC, AccWidthUint8, &cmd_val);
133 WaitForEcLDN9MailboxCmdAck();
136 int chipset_volatile_group_begin(const struct spi_flash *flash)
138 if (!IS_ENABLED(CONFIG_SB800_IMC_FWM))
139 return 0;
141 ImcSleep();
142 return 0;
145 int chipset_volatile_group_end(const struct spi_flash *flash)
147 if (!IS_ENABLED(CONFIG_SB800_IMC_FWM))
148 return 0;
150 ImcWakeup();
151 return 0;
154 static int xfer_vectors(const struct spi_slave *slave,
155 struct spi_op vectors[], size_t count)
157 return spi_flash_vector_helper(slave, vectors, count, spi_ctrlr_xfer);
160 static const struct spi_ctrlr spi_ctrlr = {
161 .xfer_vector = xfer_vectors,
162 .max_xfer_size = AMD_SB_SPI_TX_LEN,
163 .flags = SPI_CNTRLR_DEDUCT_CMD_LEN,
166 const struct spi_ctrlr_buses spi_ctrlr_bus_map[] = {
168 .ctrlr = &spi_ctrlr,
169 .bus_start = 0,
170 .bus_end = 0,
174 const size_t spi_ctrlr_bus_map_count = ARRAY_SIZE(spi_ctrlr_bus_map);