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.
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)
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));
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
++;
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");
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();
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));
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
, ®0_val
);
116 WriteECmsg (MSG_REG1
, AccWidthUint8
, ®1_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
, ®0_val
);
130 WriteECmsg (MSG_REG1
, AccWidthUint8
, ®1_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
))
145 int chipset_volatile_group_end(const struct spi_flash
*flash
)
147 if (!IS_ENABLED(CONFIG_SB800_IMC_FWM
))
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
[] = {
174 const size_t spi_ctrlr_bus_map_count
= ARRAY_SIZE(spi_ctrlr_bus_map
);