blob: a46349e933ea16ca6e2875b869e17bb05573a296 [file] [log] [blame]
zbao01bd79f2012-03-23 11:36:08 +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.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
Paul Menzela46a7122013-02-23 18:37:27 +010017 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
zbao01bd79f2012-03-23 11:36:08 +080018 */
Zheng Bao7bcffa52012-11-28 11:36:52 +080019#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
zbao01bd79f2012-03-23 11:36:08 +080022#include <arch/io.h>
Zheng Bao600784e2013-02-07 17:30:23 +080023#include <spi-generic.h>
zbao01bd79f2012-03-23 11:36:08 +080024#include <device/device.h>
Zheng Bao7bcffa52012-11-28 11:36:52 +080025#include <device/pci.h>
26#include <device/pci_ops.h>
zbao01bd79f2012-03-23 11:36:08 +080027
Dave Frodin9b800ae2014-06-11 13:15:56 -060028#if IS_ENABLED (CONFIG_SB800_IMC_FWM)
Martin Roth3316cf22012-12-05 16:22:54 -070029#include "SBPLATFORM.h"
30#include <vendorcode/amd/cimx/sb800/ECfan.h>
31
32static int bus_claimed = 0;
33#endif
34
Zheng Bao7bcffa52012-11-28 11:36:52 +080035static u32 spibar;
zbao01bd79f2012-03-23 11:36:08 +080036
Zheng Bao7bcffa52012-11-28 11:36:52 +080037static void reset_internal_fifo_pointer(void)
zbao01bd79f2012-03-23 11:36:08 +080038{
zbao01bd79f2012-03-23 11:36:08 +080039 do {
Zheng Bao7bcffa52012-11-28 11:36:52 +080040 write8(spibar + 2, read8(spibar + 2) | 0x10);
41 } while (read8(spibar + 0xD) & 0x7);
zbao01bd79f2012-03-23 11:36:08 +080042}
43
Zheng Bao7bcffa52012-11-28 11:36:52 +080044static void execute_command(void)
zbao01bd79f2012-03-23 11:36:08 +080045{
Zheng Bao7bcffa52012-11-28 11:36:52 +080046 write8(spibar + 2, read8(spibar + 2) | 1);
47
48 while ((read8(spibar + 2) & 1) && (read8(spibar+3) & 0x80));
zbao01bd79f2012-03-23 11:36:08 +080049}
50
Zheng Bao7bcffa52012-11-28 11:36:52 +080051void spi_init()
zbao01bd79f2012-03-23 11:36:08 +080052{
Zheng Bao7bcffa52012-11-28 11:36:52 +080053 device_t dev;
54
55 dev = dev_find_slot(0, PCI_DEVFN(0x14, 3));
56 spibar = pci_read_config32(dev, 0xA0) & ~0x1F;
zbao01bd79f2012-03-23 11:36:08 +080057}
58
Zheng Bao7bcffa52012-11-28 11:36:52 +080059int spi_xfer(struct spi_slave *slave, const void *dout,
Gabe Black93d9f922014-03-27 21:52:43 -070060 unsigned int bytesout, void *din, unsigned int bytesin)
zbao01bd79f2012-03-23 11:36:08 +080061{
Zheng Bao7bcffa52012-11-28 11:36:52 +080062 /* First byte is cmd which can not being sent through FIFO. */
63 u8 cmd = *(u8 *)dout++;
64 u8 readoffby1;
65 u8 readwrite;
Zheng Bao7bcffa52012-11-28 11:36:52 +080066 u8 count;
zbao01bd79f2012-03-23 11:36:08 +080067
Gabe Black93d9f922014-03-27 21:52:43 -070068 bytesout--;
zbao01bd79f2012-03-23 11:36:08 +080069
Zheng Bao7bcffa52012-11-28 11:36:52 +080070 readoffby1 = bytesout ? 0 : 1;
zbao01bd79f2012-03-23 11:36:08 +080071
Zheng Bao7bcffa52012-11-28 11:36:52 +080072 readwrite = (bytesin + readoffby1) << 4 | bytesout;
73 write8(spibar + 1, readwrite);
74 write8(spibar + 0, cmd);
zbao01bd79f2012-03-23 11:36:08 +080075
Zheng Bao7bcffa52012-11-28 11:36:52 +080076 reset_internal_fifo_pointer();
77 for (count = 0; count < bytesout; count++, dout++) {
78 write8(spibar + 0x0C, *(u8 *)dout);
zbao01bd79f2012-03-23 11:36:08 +080079 }
Zheng Bao7bcffa52012-11-28 11:36:52 +080080
81 reset_internal_fifo_pointer();
82 execute_command();
83
84 reset_internal_fifo_pointer();
85 /* Skip the bytes we sent. */
86 for (count = 0; count < bytesout; count++) {
87 cmd = read8(spibar + 0x0C);
88 }
89
90 reset_internal_fifo_pointer();
91 for (count = 0; count < bytesin; count++, din++) {
92 *(u8 *)din = read8(spibar + 0x0C);
93 }
94
95 return 0;
96}
Martin Roth3316cf22012-12-05 16:22:54 -070097
Dave Frodin9b800ae2014-06-11 13:15:56 -060098#if IS_ENABLED (CONFIG_SB800_IMC_FWM)
Martin Roth3316cf22012-12-05 16:22:54 -070099
100static void ImcSleep(void)
101{
102 u8 cmd_val = 0x96; /* Kick off IMC Mailbox command 96 */
103 u8 reg0_val = 0; /* clear response register */
104 u8 reg1_val = 0xB4; /* request ownership flag */
105
106 WriteECmsg (MSG_REG0, AccWidthUint8, &reg0_val);
107 WriteECmsg (MSG_REG1, AccWidthUint8, &reg1_val);
108 WriteECmsg (MSG_SYS_TO_IMC, AccWidthUint8, &cmd_val);
109
110 WaitForEcLDN9MailboxCmdAck();
111}
112
113
114static void ImcWakeup(void)
115{
116 u8 cmd_val = 0x96; /* Kick off IMC Mailbox command 96 */
Idwer Volleringd26da9c2013-12-22 21:38:18 +0000117 u8 reg0_val = 0; /* clear response register */
Martin Roth3316cf22012-12-05 16:22:54 -0700118 u8 reg1_val = 0xB5; /* release ownership flag */
119
120 WriteECmsg (MSG_REG0, AccWidthUint8, &reg0_val);
121 WriteECmsg (MSG_REG1, AccWidthUint8, &reg1_val);
122 WriteECmsg (MSG_SYS_TO_IMC, AccWidthUint8, &cmd_val);
123
124 WaitForEcLDN9MailboxCmdAck();
125}
126#endif
127
Zheng Bao7bcffa52012-11-28 11:36:52 +0800128int spi_claim_bus(struct spi_slave *slave)
129{
Dave Frodin9b800ae2014-06-11 13:15:56 -0600130#if IS_ENABLED (CONFIG_SB800_IMC_FWM)
Martin Roth3316cf22012-12-05 16:22:54 -0700131
132 if (slave->rw == SPI_WRITE_FLAG) {
133 bus_claimed++;
134 if (bus_claimed == 1)
135 ImcSleep();
136 }
137#endif
138
Zheng Bao7bcffa52012-11-28 11:36:52 +0800139 return 0;
zbao01bd79f2012-03-23 11:36:08 +0800140}
141
Zheng Bao7bcffa52012-11-28 11:36:52 +0800142void spi_release_bus(struct spi_slave *slave)
zbao01bd79f2012-03-23 11:36:08 +0800143{
Dave Frodin9b800ae2014-06-11 13:15:56 -0600144#if IS_ENABLED (CONFIG_SB800_IMC_FWM)
Martin Roth3316cf22012-12-05 16:22:54 -0700145
146 if (slave->rw == SPI_WRITE_FLAG) {
147 bus_claimed--;
148 if (bus_claimed <= 0) {
149 bus_claimed = 0;
150 ImcWakeup();
151 }
152 }
153#endif
zbao01bd79f2012-03-23 11:36:08 +0800154}
155
Zheng Bao7bcffa52012-11-28 11:36:52 +0800156void spi_cs_activate(struct spi_slave *slave)
zbao01bd79f2012-03-23 11:36:08 +0800157{
Zheng Bao7bcffa52012-11-28 11:36:52 +0800158}
159
160void spi_cs_deactivate(struct spi_slave *slave)
161{
162}
163
Gabe Black1e187352014-03-27 20:37:03 -0700164struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs)
Zheng Bao7bcffa52012-11-28 11:36:52 +0800165{
166 struct spi_slave *slave = malloc(sizeof(*slave));
167
168 if (!slave) {
169 return NULL;
170 }
171
172 memset(slave, 0, sizeof(*slave));
173
174 return slave;
zbao01bd79f2012-03-23 11:36:08 +0800175}