blob: fbb58c783ec06f23a4567bbb9a928a050295977c [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass18530302013-03-19 04:58:56 +00002/*
3 * Copyright (c) 2011-12 The Chromium OS Authors.
4 *
Simon Glass18530302013-03-19 04:58:56 +00005 * This file is derived from the flashrom project.
6 */
Bin Meng9eb43392016-02-01 01:40:36 -08007
Simon Glass18530302013-03-19 04:58:56 +00008#include <common.h>
Simon Glassba457562015-03-26 09:29:26 -06009#include <dm.h>
Simon Glass5093bad2015-01-27 22:13:43 -070010#include <errno.h>
Simon Glass18530302013-03-19 04:58:56 +000011#include <malloc.h>
Simon Glassf2b85ab2016-01-18 20:19:21 -070012#include <pch.h>
Simon Glass18530302013-03-19 04:58:56 +000013#include <pci.h>
14#include <pci_ids.h>
Simon Glassf2b85ab2016-01-18 20:19:21 -070015#include <spi.h>
Simon Glass18530302013-03-19 04:58:56 +000016#include <asm/io.h>
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +020017#include <spi-mem.h>
18#include <div64.h>
Simon Glass18530302013-03-19 04:58:56 +000019
20#include "ich.h"
21
Bin Meng1f9eb592016-02-01 01:40:37 -080022DECLARE_GLOBAL_DATA_PTR;
23
Simon Glassfffe25d2016-01-18 20:19:20 -070024#ifdef DEBUG_TRACE
25#define debug_trace(fmt, args...) debug(fmt, ##args)
26#else
27#define debug_trace(x, args...)
28#endif
29
Simon Glassba457562015-03-26 09:29:26 -060030static u8 ich_readb(struct ich_spi_priv *priv, int reg)
Simon Glass18530302013-03-19 04:58:56 +000031{
Simon Glassba457562015-03-26 09:29:26 -060032 u8 value = readb(priv->base + reg);
Simon Glass18530302013-03-19 04:58:56 +000033
Simon Glassfffe25d2016-01-18 20:19:20 -070034 debug_trace("read %2.2x from %4.4x\n", value, reg);
Simon Glass18530302013-03-19 04:58:56 +000035
36 return value;
37}
38
Simon Glassba457562015-03-26 09:29:26 -060039static u16 ich_readw(struct ich_spi_priv *priv, int reg)
Simon Glass18530302013-03-19 04:58:56 +000040{
Simon Glassba457562015-03-26 09:29:26 -060041 u16 value = readw(priv->base + reg);
Simon Glass18530302013-03-19 04:58:56 +000042
Simon Glassfffe25d2016-01-18 20:19:20 -070043 debug_trace("read %4.4x from %4.4x\n", value, reg);
Simon Glass18530302013-03-19 04:58:56 +000044
45 return value;
46}
47
Simon Glassba457562015-03-26 09:29:26 -060048static u32 ich_readl(struct ich_spi_priv *priv, int reg)
Simon Glass18530302013-03-19 04:58:56 +000049{
Simon Glassba457562015-03-26 09:29:26 -060050 u32 value = readl(priv->base + reg);
Simon Glass18530302013-03-19 04:58:56 +000051
Simon Glassfffe25d2016-01-18 20:19:20 -070052 debug_trace("read %8.8x from %4.4x\n", value, reg);
Simon Glass18530302013-03-19 04:58:56 +000053
54 return value;
55}
56
Simon Glassba457562015-03-26 09:29:26 -060057static void ich_writeb(struct ich_spi_priv *priv, u8 value, int reg)
Simon Glass18530302013-03-19 04:58:56 +000058{
Simon Glassba457562015-03-26 09:29:26 -060059 writeb(value, priv->base + reg);
Simon Glassfffe25d2016-01-18 20:19:20 -070060 debug_trace("wrote %2.2x to %4.4x\n", value, reg);
Simon Glass18530302013-03-19 04:58:56 +000061}
62
Simon Glassba457562015-03-26 09:29:26 -060063static void ich_writew(struct ich_spi_priv *priv, u16 value, int reg)
Simon Glass18530302013-03-19 04:58:56 +000064{
Simon Glassba457562015-03-26 09:29:26 -060065 writew(value, priv->base + reg);
Simon Glassfffe25d2016-01-18 20:19:20 -070066 debug_trace("wrote %4.4x to %4.4x\n", value, reg);
Simon Glass18530302013-03-19 04:58:56 +000067}
68
Simon Glassba457562015-03-26 09:29:26 -060069static void ich_writel(struct ich_spi_priv *priv, u32 value, int reg)
Simon Glass18530302013-03-19 04:58:56 +000070{
Simon Glassba457562015-03-26 09:29:26 -060071 writel(value, priv->base + reg);
Simon Glassfffe25d2016-01-18 20:19:20 -070072 debug_trace("wrote %8.8x to %4.4x\n", value, reg);
Simon Glass18530302013-03-19 04:58:56 +000073}
74
Simon Glassba457562015-03-26 09:29:26 -060075static void write_reg(struct ich_spi_priv *priv, const void *value,
76 int dest_reg, uint32_t size)
Simon Glass18530302013-03-19 04:58:56 +000077{
Simon Glassba457562015-03-26 09:29:26 -060078 memcpy_toio(priv->base + dest_reg, value, size);
Simon Glass18530302013-03-19 04:58:56 +000079}
80
Simon Glassba457562015-03-26 09:29:26 -060081static void read_reg(struct ich_spi_priv *priv, int src_reg, void *value,
82 uint32_t size)
Simon Glass18530302013-03-19 04:58:56 +000083{
Simon Glassba457562015-03-26 09:29:26 -060084 memcpy_fromio(value, priv->base + src_reg, size);
Simon Glass18530302013-03-19 04:58:56 +000085}
86
Simon Glassba457562015-03-26 09:29:26 -060087static void ich_set_bbar(struct ich_spi_priv *ctlr, uint32_t minaddr)
Simon Glass18530302013-03-19 04:58:56 +000088{
89 const uint32_t bbar_mask = 0x00ffff00;
90 uint32_t ichspi_bbar;
91
92 minaddr &= bbar_mask;
Simon Glassba457562015-03-26 09:29:26 -060093 ichspi_bbar = ich_readl(ctlr, ctlr->bbar) & ~bbar_mask;
Simon Glass18530302013-03-19 04:58:56 +000094 ichspi_bbar |= minaddr;
Simon Glassba457562015-03-26 09:29:26 -060095 ich_writel(ctlr, ichspi_bbar, ctlr->bbar);
Simon Glass18530302013-03-19 04:58:56 +000096}
97
Simon Glass18530302013-03-19 04:58:56 +000098/* @return 1 if the SPI flash supports the 33MHz speed */
Simon Glassf2b85ab2016-01-18 20:19:21 -070099static int ich9_can_do_33mhz(struct udevice *dev)
Simon Glass18530302013-03-19 04:58:56 +0000100{
101 u32 fdod, speed;
102
103 /* Observe SPI Descriptor Component Section 0 */
Simon Glassf2b85ab2016-01-18 20:19:21 -0700104 dm_pci_write_config32(dev->parent, 0xb0, 0x1000);
Simon Glass18530302013-03-19 04:58:56 +0000105
106 /* Extract the Write/Erase SPI Frequency from descriptor */
Simon Glassf2b85ab2016-01-18 20:19:21 -0700107 dm_pci_read_config32(dev->parent, 0xb4, &fdod);
Simon Glass18530302013-03-19 04:58:56 +0000108
109 /* Bits 23:21 have the fast read clock frequency, 0=20MHz, 1=33MHz */
110 speed = (fdod >> 21) & 7;
111
112 return speed == 1;
113}
114
Simon Glassf2b85ab2016-01-18 20:19:21 -0700115static int ich_init_controller(struct udevice *dev,
116 struct ich_spi_platdata *plat,
Simon Glassba457562015-03-26 09:29:26 -0600117 struct ich_spi_priv *ctlr)
Simon Glass18530302013-03-19 04:58:56 +0000118{
Simon Glassf2b85ab2016-01-18 20:19:21 -0700119 ulong sbase_addr;
120 void *sbase;
Simon Glass5093bad2015-01-27 22:13:43 -0700121
122 /* SBASE is similar */
Bin Meng3e389d82016-02-01 01:40:42 -0800123 pch_get_spi_base(dev->parent, &sbase_addr);
Simon Glassf2b85ab2016-01-18 20:19:21 -0700124 sbase = (void *)sbase_addr;
125 debug("%s: sbase=%p\n", __func__, sbase);
Simon Glass5093bad2015-01-27 22:13:43 -0700126
Bin Meng6e670b52016-02-01 01:40:38 -0800127 if (plat->ich_version == ICHV_7) {
Simon Glassf2b85ab2016-01-18 20:19:21 -0700128 struct ich7_spi_regs *ich7_spi = sbase;
Simon Glass18530302013-03-19 04:58:56 +0000129
Simon Glassba457562015-03-26 09:29:26 -0600130 ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu);
Simon Glass18530302013-03-19 04:58:56 +0000131 ctlr->menubytes = sizeof(ich7_spi->opmenu);
Simon Glassba457562015-03-26 09:29:26 -0600132 ctlr->optype = offsetof(struct ich7_spi_regs, optype);
133 ctlr->addr = offsetof(struct ich7_spi_regs, spia);
134 ctlr->data = offsetof(struct ich7_spi_regs, spid);
Simon Glass18530302013-03-19 04:58:56 +0000135 ctlr->databytes = sizeof(ich7_spi->spid);
Simon Glassba457562015-03-26 09:29:26 -0600136 ctlr->status = offsetof(struct ich7_spi_regs, spis);
137 ctlr->control = offsetof(struct ich7_spi_regs, spic);
138 ctlr->bbar = offsetof(struct ich7_spi_regs, bbar);
139 ctlr->preop = offsetof(struct ich7_spi_regs, preop);
Simon Glass18530302013-03-19 04:58:56 +0000140 ctlr->base = ich7_spi;
Bin Meng6e670b52016-02-01 01:40:38 -0800141 } else if (plat->ich_version == ICHV_9) {
Simon Glassf2b85ab2016-01-18 20:19:21 -0700142 struct ich9_spi_regs *ich9_spi = sbase;
Simon Glass18530302013-03-19 04:58:56 +0000143
Simon Glassba457562015-03-26 09:29:26 -0600144 ctlr->opmenu = offsetof(struct ich9_spi_regs, opmenu);
Simon Glass18530302013-03-19 04:58:56 +0000145 ctlr->menubytes = sizeof(ich9_spi->opmenu);
Simon Glassba457562015-03-26 09:29:26 -0600146 ctlr->optype = offsetof(struct ich9_spi_regs, optype);
147 ctlr->addr = offsetof(struct ich9_spi_regs, faddr);
148 ctlr->data = offsetof(struct ich9_spi_regs, fdata);
Simon Glass18530302013-03-19 04:58:56 +0000149 ctlr->databytes = sizeof(ich9_spi->fdata);
Simon Glassba457562015-03-26 09:29:26 -0600150 ctlr->status = offsetof(struct ich9_spi_regs, ssfs);
151 ctlr->control = offsetof(struct ich9_spi_regs, ssfc);
152 ctlr->speed = ctlr->control + 2;
153 ctlr->bbar = offsetof(struct ich9_spi_regs, bbar);
154 ctlr->preop = offsetof(struct ich9_spi_regs, preop);
Simon Glass50787922015-07-03 18:28:22 -0600155 ctlr->bcr = offsetof(struct ich9_spi_regs, bcr);
Simon Glass18530302013-03-19 04:58:56 +0000156 ctlr->pr = &ich9_spi->pr[0];
157 ctlr->base = ich9_spi;
158 } else {
Simon Glassba457562015-03-26 09:29:26 -0600159 debug("ICH SPI: Unrecognised ICH version %d\n",
160 plat->ich_version);
161 return -EINVAL;
Simon Glass18530302013-03-19 04:58:56 +0000162 }
Simon Glass18530302013-03-19 04:58:56 +0000163
164 /* Work out the maximum speed we can support */
165 ctlr->max_speed = 20000000;
Bin Meng6e670b52016-02-01 01:40:38 -0800166 if (plat->ich_version == ICHV_9 && ich9_can_do_33mhz(dev))
Simon Glass18530302013-03-19 04:58:56 +0000167 ctlr->max_speed = 33000000;
Simon Glassf2b85ab2016-01-18 20:19:21 -0700168 debug("ICH SPI: Version ID %d detected at %p, speed %ld\n",
Simon Glassba457562015-03-26 09:29:26 -0600169 plat->ich_version, ctlr->base, ctlr->max_speed);
Simon Glass18530302013-03-19 04:58:56 +0000170
171 ich_set_bbar(ctlr, 0);
172
173 return 0;
174}
175
Bin Mengab201072017-10-18 18:20:57 -0700176static void spi_lock_down(struct ich_spi_platdata *plat, void *sbase)
177{
178 if (plat->ich_version == ICHV_7) {
179 struct ich7_spi_regs *ich7_spi = sbase;
180
181 setbits_le16(&ich7_spi->spis, SPIS_LOCK);
182 } else if (plat->ich_version == ICHV_9) {
183 struct ich9_spi_regs *ich9_spi = sbase;
184
185 setbits_le16(&ich9_spi->hsfs, HSFS_FLOCKDN);
186 }
187}
188
Bin Meng3e791412017-08-15 22:38:29 -0700189static bool spi_lock_status(struct ich_spi_platdata *plat, void *sbase)
190{
191 int lock = 0;
192
193 if (plat->ich_version == ICHV_7) {
194 struct ich7_spi_regs *ich7_spi = sbase;
195
196 lock = readw(&ich7_spi->spis) & SPIS_LOCK;
197 } else if (plat->ich_version == ICHV_9) {
198 struct ich9_spi_regs *ich9_spi = sbase;
199
200 lock = readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
201 }
202
203 return lock != 0;
204}
205
Bin Meng3e791412017-08-15 22:38:29 -0700206static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans,
207 bool lock)
Simon Glass18530302013-03-19 04:58:56 +0000208{
209 uint16_t optypes;
Simon Glassba457562015-03-26 09:29:26 -0600210 uint8_t opmenu[ctlr->menubytes];
Simon Glass18530302013-03-19 04:58:56 +0000211
Bin Meng3e791412017-08-15 22:38:29 -0700212 if (!lock) {
Simon Glass18530302013-03-19 04:58:56 +0000213 /* The lock is off, so just use index 0. */
Simon Glassba457562015-03-26 09:29:26 -0600214 ich_writeb(ctlr, trans->opcode, ctlr->opmenu);
215 optypes = ich_readw(ctlr, ctlr->optype);
Simon Glass18530302013-03-19 04:58:56 +0000216 optypes = (optypes & 0xfffc) | (trans->type & 0x3);
Simon Glassba457562015-03-26 09:29:26 -0600217 ich_writew(ctlr, optypes, ctlr->optype);
Simon Glass18530302013-03-19 04:58:56 +0000218 return 0;
219 } else {
220 /* The lock is on. See if what we need is on the menu. */
221 uint8_t optype;
222 uint16_t opcode_index;
223
224 /* Write Enable is handled as atomic prefix */
225 if (trans->opcode == SPI_OPCODE_WREN)
226 return 0;
227
Simon Glassba457562015-03-26 09:29:26 -0600228 read_reg(ctlr, ctlr->opmenu, opmenu, sizeof(opmenu));
229 for (opcode_index = 0; opcode_index < ctlr->menubytes;
Simon Glass18530302013-03-19 04:58:56 +0000230 opcode_index++) {
231 if (opmenu[opcode_index] == trans->opcode)
232 break;
233 }
234
Simon Glassba457562015-03-26 09:29:26 -0600235 if (opcode_index == ctlr->menubytes) {
Simon Glass18530302013-03-19 04:58:56 +0000236 printf("ICH SPI: Opcode %x not found\n",
237 trans->opcode);
Simon Glassba457562015-03-26 09:29:26 -0600238 return -EINVAL;
Simon Glass18530302013-03-19 04:58:56 +0000239 }
240
Simon Glassba457562015-03-26 09:29:26 -0600241 optypes = ich_readw(ctlr, ctlr->optype);
Simon Glass18530302013-03-19 04:58:56 +0000242 optype = (optypes >> (opcode_index * 2)) & 0x3;
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200243
Simon Glass18530302013-03-19 04:58:56 +0000244 if (optype != trans->type) {
245 printf("ICH SPI: Transaction doesn't fit type %d\n",
246 optype);
Simon Glassba457562015-03-26 09:29:26 -0600247 return -ENOSPC;
Simon Glass18530302013-03-19 04:58:56 +0000248 }
249 return opcode_index;
250 }
251}
252
Simon Glass18530302013-03-19 04:58:56 +0000253/*
254 * Wait for up to 6s til status register bit(s) turn 1 (in case wait_til_set
York Sun472d5462013-04-01 11:29:11 -0700255 * below is true) or 0. In case the wait was for the bit(s) to set - write
Simon Glass18530302013-03-19 04:58:56 +0000256 * those bits back, which would cause resetting them.
257 *
258 * Return the last read status value on success or -1 on failure.
259 */
Simon Glassba457562015-03-26 09:29:26 -0600260static int ich_status_poll(struct ich_spi_priv *ctlr, u16 bitmask,
261 int wait_til_set)
Simon Glass18530302013-03-19 04:58:56 +0000262{
263 int timeout = 600000; /* This will result in 6s */
264 u16 status = 0;
265
266 while (timeout--) {
Simon Glassba457562015-03-26 09:29:26 -0600267 status = ich_readw(ctlr, ctlr->status);
Simon Glass18530302013-03-19 04:58:56 +0000268 if (wait_til_set ^ ((status & bitmask) == 0)) {
Simon Glassba457562015-03-26 09:29:26 -0600269 if (wait_til_set) {
270 ich_writew(ctlr, status & bitmask,
271 ctlr->status);
272 }
Simon Glass18530302013-03-19 04:58:56 +0000273 return status;
274 }
275 udelay(10);
276 }
277
278 printf("ICH SPI: SCIP timeout, read %x, expected %x\n",
279 status, bitmask);
Simon Glassba457562015-03-26 09:29:26 -0600280 return -ETIMEDOUT;
Simon Glass18530302013-03-19 04:58:56 +0000281}
282
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200283static void ich_spi_config_opcode(struct udevice *dev)
Bin Mengb42711f2017-08-15 22:38:30 -0700284{
285 struct ich_spi_priv *ctlr = dev_get_priv(dev);
286
287 /*
288 * PREOP, OPTYPE, OPMENU1/OPMENU2 registers can be locked down
289 * to prevent accidental or intentional writes. Before they get
290 * locked down, these registers should be initialized properly.
291 */
292 ich_writew(ctlr, SPI_OPPREFIX, ctlr->preop);
293 ich_writew(ctlr, SPI_OPTYPE, ctlr->optype);
294 ich_writel(ctlr, SPI_OPMENU_LOWER, ctlr->opmenu);
295 ich_writel(ctlr, SPI_OPMENU_UPPER, ctlr->opmenu + sizeof(u32));
296}
297
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200298static int ich_spi_exec_op(struct spi_slave *slave, const struct spi_mem_op *op)
Simon Glass18530302013-03-19 04:58:56 +0000299{
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200300 struct udevice *bus = dev_get_parent(slave->dev);
Simon Glasse1e332c2015-07-03 18:28:21 -0600301 struct ich_spi_platdata *plat = dev_get_platdata(bus);
Simon Glassba457562015-03-26 09:29:26 -0600302 struct ich_spi_priv *ctlr = dev_get_priv(bus);
Simon Glass18530302013-03-19 04:58:56 +0000303 uint16_t control;
304 int16_t opcode_index;
305 int with_address;
306 int status;
Simon Glassba457562015-03-26 09:29:26 -0600307 struct spi_trans *trans = &ctlr->trans;
Bin Meng3e791412017-08-15 22:38:29 -0700308 bool lock = spi_lock_status(plat, ctlr->base);
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200309 int ret = 0;
Simon Glass18530302013-03-19 04:58:56 +0000310
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200311 trans->in = NULL;
312 trans->out = NULL;
313 trans->type = 0xFF;
Simon Glass18530302013-03-19 04:58:56 +0000314
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200315 if (op->data.nbytes) {
316 if (op->data.dir == SPI_MEM_DATA_IN) {
317 trans->in = op->data.buf.in;
318 trans->bytesin = op->data.nbytes;
319 } else {
320 trans->out = op->data.buf.out;
321 trans->bytesout = op->data.nbytes;
Simon Glass18530302013-03-19 04:58:56 +0000322 }
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200323 }
324
325 if (trans->opcode != op->cmd.opcode)
326 trans->opcode = op->cmd.opcode;
327
328 if (lock && trans->opcode == SPI_OPCODE_WRDIS)
Simon Glass18530302013-03-19 04:58:56 +0000329 return 0;
Simon Glass18530302013-03-19 04:58:56 +0000330
331 if (trans->opcode == SPI_OPCODE_WREN) {
332 /*
333 * Treat Write Enable as Atomic Pre-Op if possible
334 * in order to prevent the Management Engine from
335 * issuing a transaction between WREN and DATA.
336 */
Bin Meng3e791412017-08-15 22:38:29 -0700337 if (!lock)
Simon Glassba457562015-03-26 09:29:26 -0600338 ich_writew(ctlr, trans->opcode, ctlr->preop);
Simon Glass18530302013-03-19 04:58:56 +0000339 return 0;
340 }
341
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200342 ret = ich_status_poll(ctlr, SPIS_SCIP, 0);
343 if (ret < 0)
344 return ret;
345
346 if (plat->ich_version == ICHV_7)
347 ich_writew(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
348 else
349 ich_writeb(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
350
351 /* Try to guess spi transaction type */
352 if (op->data.dir == SPI_MEM_DATA_OUT) {
353 if (op->addr.nbytes)
354 trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS;
355 else
356 trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
357 } else {
358 if (op->addr.nbytes)
359 trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
360 else
361 trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
362 }
363 /* Special erase case handling */
364 if (op->addr.nbytes && !op->data.buswidth)
365 trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS;
366
367 opcode_index = spi_setup_opcode(ctlr, trans, lock);
368 if (opcode_index < 0)
369 return -EINVAL;
370
371 if (op->addr.nbytes) {
372 trans->offset = op->addr.val;
373 with_address = 1;
374 }
375
Simon Glassba457562015-03-26 09:29:26 -0600376 if (ctlr->speed && ctlr->max_speed >= 33000000) {
Simon Glass18530302013-03-19 04:58:56 +0000377 int byte;
378
Simon Glassba457562015-03-26 09:29:26 -0600379 byte = ich_readb(ctlr, ctlr->speed);
380 if (ctlr->cur_speed >= 33000000)
Simon Glass18530302013-03-19 04:58:56 +0000381 byte |= SSFC_SCF_33MHZ;
382 else
383 byte &= ~SSFC_SCF_33MHZ;
Simon Glassba457562015-03-26 09:29:26 -0600384 ich_writeb(ctlr, byte, ctlr->speed);
Simon Glass18530302013-03-19 04:58:56 +0000385 }
386
Simon Glass18530302013-03-19 04:58:56 +0000387 /* Preset control fields */
Simon Glass18530302013-03-19 04:58:56 +0000388 control = SPIC_SCGO | ((opcode_index & 0x07) << 4);
389
390 /* Issue atomic preop cycle if needed */
Simon Glassba457562015-03-26 09:29:26 -0600391 if (ich_readw(ctlr, ctlr->preop))
Simon Glass18530302013-03-19 04:58:56 +0000392 control |= SPIC_ACS;
393
394 if (!trans->bytesout && !trans->bytesin) {
395 /* SPI addresses are 24 bit only */
Simon Glassba457562015-03-26 09:29:26 -0600396 if (with_address) {
397 ich_writel(ctlr, trans->offset & 0x00FFFFFF,
398 ctlr->addr);
399 }
Simon Glass18530302013-03-19 04:58:56 +0000400 /*
401 * This is a 'no data' command (like Write Enable), its
402 * bitesout size was 1, decremented to zero while executing
403 * spi_setup_opcode() above. Tell the chip to send the
404 * command.
405 */
Simon Glassba457562015-03-26 09:29:26 -0600406 ich_writew(ctlr, control, ctlr->control);
Simon Glass18530302013-03-19 04:58:56 +0000407
408 /* wait for the result */
Simon Glassba457562015-03-26 09:29:26 -0600409 status = ich_status_poll(ctlr, SPIS_CDS | SPIS_FCERR, 1);
410 if (status < 0)
411 return status;
Simon Glass18530302013-03-19 04:58:56 +0000412
413 if (status & SPIS_FCERR) {
414 debug("ICH SPI: Command transaction error\n");
Simon Glassba457562015-03-26 09:29:26 -0600415 return -EIO;
Simon Glass18530302013-03-19 04:58:56 +0000416 }
417
418 return 0;
419 }
420
Simon Glass18530302013-03-19 04:58:56 +0000421 while (trans->bytesout || trans->bytesin) {
422 uint32_t data_length;
Simon Glass18530302013-03-19 04:58:56 +0000423
424 /* SPI addresses are 24 bit only */
Simon Glassba457562015-03-26 09:29:26 -0600425 ich_writel(ctlr, trans->offset & 0x00FFFFFF, ctlr->addr);
Simon Glass18530302013-03-19 04:58:56 +0000426
427 if (trans->bytesout)
Simon Glassba457562015-03-26 09:29:26 -0600428 data_length = min(trans->bytesout, ctlr->databytes);
Simon Glass18530302013-03-19 04:58:56 +0000429 else
Simon Glassba457562015-03-26 09:29:26 -0600430 data_length = min(trans->bytesin, ctlr->databytes);
Simon Glass18530302013-03-19 04:58:56 +0000431
432 /* Program data into FDATA0 to N */
433 if (trans->bytesout) {
Simon Glassba457562015-03-26 09:29:26 -0600434 write_reg(ctlr, trans->out, ctlr->data, data_length);
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200435 trans->bytesout -= data_length;
Simon Glass18530302013-03-19 04:58:56 +0000436 }
437
438 /* Add proper control fields' values */
Simon Glassba457562015-03-26 09:29:26 -0600439 control &= ~((ctlr->databytes - 1) << 8);
Simon Glass18530302013-03-19 04:58:56 +0000440 control |= SPIC_DS;
441 control |= (data_length - 1) << 8;
442
443 /* write it */
Simon Glassba457562015-03-26 09:29:26 -0600444 ich_writew(ctlr, control, ctlr->control);
Simon Glass18530302013-03-19 04:58:56 +0000445
Bin Meng9eb43392016-02-01 01:40:36 -0800446 /* Wait for Cycle Done Status or Flash Cycle Error */
Simon Glassba457562015-03-26 09:29:26 -0600447 status = ich_status_poll(ctlr, SPIS_CDS | SPIS_FCERR, 1);
448 if (status < 0)
449 return status;
Simon Glass18530302013-03-19 04:58:56 +0000450
451 if (status & SPIS_FCERR) {
Simon Glass5d4a7572015-06-07 08:50:33 -0600452 debug("ICH SPI: Data transaction error %x\n", status);
Simon Glassba457562015-03-26 09:29:26 -0600453 return -EIO;
Simon Glass18530302013-03-19 04:58:56 +0000454 }
455
456 if (trans->bytesin) {
Simon Glassba457562015-03-26 09:29:26 -0600457 read_reg(ctlr, ctlr->data, trans->in, data_length);
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200458 trans->bytesin -= data_length;
Simon Glass18530302013-03-19 04:58:56 +0000459 }
460 }
461
462 /* Clear atomic preop now that xfer is done */
Bin Mengd2ca80c2017-08-26 19:22:59 -0700463 if (!lock)
464 ich_writew(ctlr, 0, ctlr->preop);
Simon Glass18530302013-03-19 04:58:56 +0000465
466 return 0;
467}
468
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200469static int ich_spi_adjust_size(struct spi_slave *slave, struct spi_mem_op *op)
470{
471 unsigned int page_offset;
472 int addr = op->addr.val;
473 unsigned int byte_count = op->data.nbytes;
474
475 if (hweight32(ICH_BOUNDARY) == 1) {
476 page_offset = addr & (ICH_BOUNDARY - 1);
477 } else {
478 u64 aux = addr;
479
480 page_offset = do_div(aux, ICH_BOUNDARY);
481 }
482
483 if (op->data.dir == SPI_MEM_DATA_IN && slave->max_read_size) {
484 op->data.nbytes = min(ICH_BOUNDARY - page_offset,
485 slave->max_read_size);
486 } else if (slave->max_write_size) {
487 op->data.nbytes = min(ICH_BOUNDARY - page_offset,
488 slave->max_write_size);
489 }
490
491 op->data.nbytes = min(op->data.nbytes, byte_count);
492
493 return 0;
494}
495
496static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
497 const void *dout, void *din, unsigned long flags)
498{
499 printf("ICH SPI: Only supports memory operations\n");
500 return -1;
501}
502
Simon Glassf2b85ab2016-01-18 20:19:21 -0700503static int ich_spi_probe(struct udevice *dev)
Simon Glassba457562015-03-26 09:29:26 -0600504{
Simon Glassf2b85ab2016-01-18 20:19:21 -0700505 struct ich_spi_platdata *plat = dev_get_platdata(dev);
506 struct ich_spi_priv *priv = dev_get_priv(dev);
Simon Glassba457562015-03-26 09:29:26 -0600507 uint8_t bios_cntl;
508 int ret;
509
Simon Glassf2b85ab2016-01-18 20:19:21 -0700510 ret = ich_init_controller(dev, plat, priv);
Simon Glassba457562015-03-26 09:29:26 -0600511 if (ret)
512 return ret;
Simon Glassf2b85ab2016-01-18 20:19:21 -0700513 /* Disable the BIOS write protect so write commands are allowed */
514 ret = pch_set_spi_protect(dev->parent, false);
515 if (ret == -ENOSYS) {
Simon Glass50787922015-07-03 18:28:22 -0600516 bios_cntl = ich_readb(priv, priv->bcr);
Jagan Teki69fd4c32015-10-23 01:37:56 +0530517 bios_cntl &= ~BIT(5); /* clear Enable InSMM_STS (EISS) */
Simon Glassba457562015-03-26 09:29:26 -0600518 bios_cntl |= 1; /* Write Protect Disable (WPD) */
Simon Glass50787922015-07-03 18:28:22 -0600519 ich_writeb(priv, bios_cntl, priv->bcr);
Simon Glassf2b85ab2016-01-18 20:19:21 -0700520 } else if (ret) {
521 debug("%s: Failed to disable write-protect: err=%d\n",
522 __func__, ret);
523 return ret;
Simon Glassba457562015-03-26 09:29:26 -0600524 }
525
Bin Mengab201072017-10-18 18:20:57 -0700526 /* Lock down SPI controller settings if required */
527 if (plat->lockdown) {
528 ich_spi_config_opcode(dev);
529 spi_lock_down(plat, priv->base);
530 }
531
Simon Glassba457562015-03-26 09:29:26 -0600532 priv->cur_speed = priv->max_speed;
533
534 return 0;
535}
536
Stefan Roese4759dff2017-04-24 09:48:04 +0200537static int ich_spi_remove(struct udevice *bus)
538{
Stefan Roese4759dff2017-04-24 09:48:04 +0200539 /*
540 * Configure SPI controller so that the Linux MTD driver can fully
541 * access the SPI NOR chip
542 */
Bin Mengb42711f2017-08-15 22:38:30 -0700543 ich_spi_config_opcode(bus);
Stefan Roese4759dff2017-04-24 09:48:04 +0200544
545 return 0;
546}
547
Simon Glassba457562015-03-26 09:29:26 -0600548static int ich_spi_set_speed(struct udevice *bus, uint speed)
549{
550 struct ich_spi_priv *priv = dev_get_priv(bus);
551
552 priv->cur_speed = speed;
553
554 return 0;
555}
556
557static int ich_spi_set_mode(struct udevice *bus, uint mode)
558{
559 debug("%s: mode=%d\n", __func__, mode);
560
561 return 0;
562}
563
564static int ich_spi_child_pre_probe(struct udevice *dev)
565{
566 struct udevice *bus = dev_get_parent(dev);
567 struct ich_spi_platdata *plat = dev_get_platdata(bus);
568 struct ich_spi_priv *priv = dev_get_priv(bus);
Simon Glassbcbe3d12015-09-28 23:32:01 -0600569 struct spi_slave *slave = dev_get_parent_priv(dev);
Simon Glassba457562015-03-26 09:29:26 -0600570
571 /*
572 * Yes this controller can only write a small number of bytes at
573 * once! The limit is typically 64 bytes.
574 */
575 slave->max_write_size = priv->databytes;
576 /*
577 * ICH 7 SPI controller only supports array read command
578 * and byte program command for SST flash
579 */
Jagan Teki08fe9c22016-08-08 17:12:12 +0530580 if (plat->ich_version == ICHV_7)
581 slave->mode = SPI_RX_SLOW | SPI_TX_BYTE;
Simon Glassba457562015-03-26 09:29:26 -0600582
583 return 0;
584}
585
Bin Meng1f9eb592016-02-01 01:40:37 -0800586static int ich_spi_ofdata_to_platdata(struct udevice *dev)
587{
588 struct ich_spi_platdata *plat = dev_get_platdata(dev);
Simon Glasse160f7d2017-01-17 16:52:55 -0700589 int node = dev_of_offset(dev);
Bin Meng1f9eb592016-02-01 01:40:37 -0800590 int ret;
591
Simon Glasse160f7d2017-01-17 16:52:55 -0700592 ret = fdt_node_check_compatible(gd->fdt_blob, node, "intel,ich7-spi");
Bin Meng1f9eb592016-02-01 01:40:37 -0800593 if (ret == 0) {
Bin Meng6e670b52016-02-01 01:40:38 -0800594 plat->ich_version = ICHV_7;
Bin Meng1f9eb592016-02-01 01:40:37 -0800595 } else {
Simon Glasse160f7d2017-01-17 16:52:55 -0700596 ret = fdt_node_check_compatible(gd->fdt_blob, node,
Bin Meng1f9eb592016-02-01 01:40:37 -0800597 "intel,ich9-spi");
598 if (ret == 0)
Bin Meng6e670b52016-02-01 01:40:38 -0800599 plat->ich_version = ICHV_9;
Bin Meng1f9eb592016-02-01 01:40:37 -0800600 }
601
Bin Mengab201072017-10-18 18:20:57 -0700602 plat->lockdown = fdtdec_get_bool(gd->fdt_blob, node,
603 "intel,spi-lock-down");
604
Bin Meng1f9eb592016-02-01 01:40:37 -0800605 return ret;
606}
607
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200608static const struct spi_controller_mem_ops ich_controller_mem_ops = {
609 .adjust_op_size = ich_spi_adjust_size,
610 .supports_op = NULL,
611 .exec_op = ich_spi_exec_op,
612};
613
Simon Glassba457562015-03-26 09:29:26 -0600614static const struct dm_spi_ops ich_spi_ops = {
615 .xfer = ich_spi_xfer,
616 .set_speed = ich_spi_set_speed,
617 .set_mode = ich_spi_set_mode,
Bernhard Messerklinger0709ddb2019-08-02 08:38:34 +0200618 .mem_ops = &ich_controller_mem_ops,
Simon Glassba457562015-03-26 09:29:26 -0600619 /*
620 * cs_info is not needed, since we require all chip selects to be
621 * in the device tree explicitly
622 */
623};
624
625static const struct udevice_id ich_spi_ids[] = {
Bin Meng1f9eb592016-02-01 01:40:37 -0800626 { .compatible = "intel,ich7-spi" },
627 { .compatible = "intel,ich9-spi" },
Simon Glassba457562015-03-26 09:29:26 -0600628 { }
629};
630
631U_BOOT_DRIVER(ich_spi) = {
632 .name = "ich_spi",
633 .id = UCLASS_SPI,
634 .of_match = ich_spi_ids,
635 .ops = &ich_spi_ops,
Bin Meng1f9eb592016-02-01 01:40:37 -0800636 .ofdata_to_platdata = ich_spi_ofdata_to_platdata,
Simon Glassba457562015-03-26 09:29:26 -0600637 .platdata_auto_alloc_size = sizeof(struct ich_spi_platdata),
638 .priv_auto_alloc_size = sizeof(struct ich_spi_priv),
639 .child_pre_probe = ich_spi_child_pre_probe,
640 .probe = ich_spi_probe,
Stefan Roese4759dff2017-04-24 09:48:04 +0200641 .remove = ich_spi_remove,
642 .flags = DM_FLAG_OS_PREPARE,
Simon Glassba457562015-03-26 09:29:26 -0600643};