ich.c 18.1 KB
Newer Older
S
Simon Glass 已提交
1 2 3
/*
 * Copyright (c) 2011-12 The Chromium OS Authors.
 *
4
 * SPDX-License-Identifier:	GPL-2.0+
S
Simon Glass 已提交
5 6 7
 *
 * This file is derived from the flashrom project.
 */
B
Bin Meng 已提交
8

S
Simon Glass 已提交
9
#include <common.h>
10
#include <dm.h>
11
#include <errno.h>
S
Simon Glass 已提交
12
#include <malloc.h>
13
#include <pch.h>
S
Simon Glass 已提交
14 15
#include <pci.h>
#include <pci_ids.h>
16
#include <spi.h>
S
Simon Glass 已提交
17 18 19 20
#include <asm/io.h>

#include "ich.h"

21 22 23 24 25 26
#ifdef DEBUG_TRACE
#define debug_trace(fmt, args...) debug(fmt, ##args)
#else
#define debug_trace(x, args...)
#endif

27
static u8 ich_readb(struct ich_spi_priv *priv, int reg)
S
Simon Glass 已提交
28
{
29
	u8 value = readb(priv->base + reg);
S
Simon Glass 已提交
30

31
	debug_trace("read %2.2x from %4.4x\n", value, reg);
S
Simon Glass 已提交
32 33 34 35

	return value;
}

36
static u16 ich_readw(struct ich_spi_priv *priv, int reg)
S
Simon Glass 已提交
37
{
38
	u16 value = readw(priv->base + reg);
S
Simon Glass 已提交
39

40
	debug_trace("read %4.4x from %4.4x\n", value, reg);
S
Simon Glass 已提交
41 42 43 44

	return value;
}

45
static u32 ich_readl(struct ich_spi_priv *priv, int reg)
S
Simon Glass 已提交
46
{
47
	u32 value = readl(priv->base + reg);
S
Simon Glass 已提交
48

49
	debug_trace("read %8.8x from %4.4x\n", value, reg);
S
Simon Glass 已提交
50 51 52 53

	return value;
}

54
static void ich_writeb(struct ich_spi_priv *priv, u8 value, int reg)
S
Simon Glass 已提交
55
{
56
	writeb(value, priv->base + reg);
57
	debug_trace("wrote %2.2x to %4.4x\n", value, reg);
S
Simon Glass 已提交
58 59
}

60
static void ich_writew(struct ich_spi_priv *priv, u16 value, int reg)
S
Simon Glass 已提交
61
{
62
	writew(value, priv->base + reg);
63
	debug_trace("wrote %4.4x to %4.4x\n", value, reg);
S
Simon Glass 已提交
64 65
}

66
static void ich_writel(struct ich_spi_priv *priv, u32 value, int reg)
S
Simon Glass 已提交
67
{
68
	writel(value, priv->base + reg);
69
	debug_trace("wrote %8.8x to %4.4x\n", value, reg);
S
Simon Glass 已提交
70 71
}

72 73
static void write_reg(struct ich_spi_priv *priv, const void *value,
		      int dest_reg, uint32_t size)
S
Simon Glass 已提交
74
{
75
	memcpy_toio(priv->base + dest_reg, value, size);
S
Simon Glass 已提交
76 77
}

78 79
static void read_reg(struct ich_spi_priv *priv, int src_reg, void *value,
		     uint32_t size)
S
Simon Glass 已提交
80
{
81
	memcpy_fromio(value, priv->base + src_reg, size);
S
Simon Glass 已提交
82 83
}

84
static void ich_set_bbar(struct ich_spi_priv *ctlr, uint32_t minaddr)
S
Simon Glass 已提交
85 86 87 88 89
{
	const uint32_t bbar_mask = 0x00ffff00;
	uint32_t ichspi_bbar;

	minaddr &= bbar_mask;
90
	ichspi_bbar = ich_readl(ctlr, ctlr->bbar) & ~bbar_mask;
S
Simon Glass 已提交
91
	ichspi_bbar |= minaddr;
92
	ich_writel(ctlr, ichspi_bbar, ctlr->bbar);
S
Simon Glass 已提交
93 94 95
}

/* @return 1 if the SPI flash supports the 33MHz speed */
96
static int ich9_can_do_33mhz(struct udevice *dev)
S
Simon Glass 已提交
97 98 99 100
{
	u32 fdod, speed;

	/* Observe SPI Descriptor Component Section 0 */
101
	dm_pci_write_config32(dev->parent, 0xb0, 0x1000);
S
Simon Glass 已提交
102 103

	/* Extract the Write/Erase SPI Frequency from descriptor */
104
	dm_pci_read_config32(dev->parent, 0xb4, &fdod);
S
Simon Glass 已提交
105 106 107 108 109 110 111

	/* Bits 23:21 have the fast read clock frequency, 0=20MHz, 1=33MHz */
	speed = (fdod >> 21) & 7;

	return speed == 1;
}

112 113
static int ich_init_controller(struct udevice *dev,
			       struct ich_spi_platdata *plat,
114
			       struct ich_spi_priv *ctlr)
S
Simon Glass 已提交
115
{
116 117
	ulong sbase_addr;
	void *sbase;
118 119

	/* SBASE is similar */
120 121 122
	pch_get_sbase(dev->parent, &sbase_addr);
	sbase = (void *)sbase_addr;
	debug("%s: sbase=%p\n", __func__, sbase);
123

124 125
	if (plat->ich_version == PCHV_7) {
		struct ich7_spi_regs *ich7_spi = sbase;
S
Simon Glass 已提交
126

127
		ich7_spi = (struct ich7_spi_regs *)sbase;
128 129
		ctlr->ichspi_lock = readw(&ich7_spi->spis) & SPIS_LOCK;
		ctlr->opmenu = offsetof(struct ich7_spi_regs, opmenu);
S
Simon Glass 已提交
130
		ctlr->menubytes = sizeof(ich7_spi->opmenu);
131 132 133
		ctlr->optype = offsetof(struct ich7_spi_regs, optype);
		ctlr->addr = offsetof(struct ich7_spi_regs, spia);
		ctlr->data = offsetof(struct ich7_spi_regs, spid);
S
Simon Glass 已提交
134
		ctlr->databytes = sizeof(ich7_spi->spid);
135 136 137 138
		ctlr->status = offsetof(struct ich7_spi_regs, spis);
		ctlr->control = offsetof(struct ich7_spi_regs, spic);
		ctlr->bbar = offsetof(struct ich7_spi_regs, bbar);
		ctlr->preop = offsetof(struct ich7_spi_regs, preop);
S
Simon Glass 已提交
139
		ctlr->base = ich7_spi;
140 141
	} else if (plat->ich_version == PCHV_9) {
		struct ich9_spi_regs *ich9_spi = sbase;
S
Simon Glass 已提交
142

143 144
		ctlr->ichspi_lock = readw(&ich9_spi->hsfs) & HSFS_FLOCKDN;
		ctlr->opmenu = offsetof(struct ich9_spi_regs, opmenu);
S
Simon Glass 已提交
145
		ctlr->menubytes = sizeof(ich9_spi->opmenu);
146 147 148
		ctlr->optype = offsetof(struct ich9_spi_regs, optype);
		ctlr->addr = offsetof(struct ich9_spi_regs, faddr);
		ctlr->data = offsetof(struct ich9_spi_regs, fdata);
S
Simon Glass 已提交
149
		ctlr->databytes = sizeof(ich9_spi->fdata);
150 151 152 153 154
		ctlr->status = offsetof(struct ich9_spi_regs, ssfs);
		ctlr->control = offsetof(struct ich9_spi_regs, ssfc);
		ctlr->speed = ctlr->control + 2;
		ctlr->bbar = offsetof(struct ich9_spi_regs, bbar);
		ctlr->preop = offsetof(struct ich9_spi_regs, preop);
155
		ctlr->bcr = offsetof(struct ich9_spi_regs, bcr);
S
Simon Glass 已提交
156 157 158
		ctlr->pr = &ich9_spi->pr[0];
		ctlr->base = ich9_spi;
	} else {
159 160 161
		debug("ICH SPI: Unrecognised ICH version %d\n",
		      plat->ich_version);
		return -EINVAL;
S
Simon Glass 已提交
162 163 164 165
	}

	/* Work out the maximum speed we can support */
	ctlr->max_speed = 20000000;
166
	if (plat->ich_version == PCHV_9 && ich9_can_do_33mhz(dev))
S
Simon Glass 已提交
167
		ctlr->max_speed = 33000000;
168
	debug("ICH SPI: Version ID %d detected at %p, speed %ld\n",
169
	      plat->ich_version, ctlr->base, ctlr->max_speed);
S
Simon Glass 已提交
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

	ich_set_bbar(ctlr, 0);

	return 0;
}

static inline void spi_use_out(struct spi_trans *trans, unsigned bytes)
{
	trans->out += bytes;
	trans->bytesout -= bytes;
}

static inline void spi_use_in(struct spi_trans *trans, unsigned bytes)
{
	trans->in += bytes;
	trans->bytesin -= bytes;
}

static void spi_setup_type(struct spi_trans *trans, int data_bytes)
{
	trans->type = 0xFF;

B
Bin Meng 已提交
192
	/* Try to guess spi type from read/write sizes */
S
Simon Glass 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
	if (trans->bytesin == 0) {
		if (trans->bytesout + data_bytes > 4)
			/*
			 * If bytesin = 0 and bytesout > 4, we presume this is
			 * a write data operation, which is accompanied by an
			 * address.
			 */
			trans->type = SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS;
		else
			trans->type = SPI_OPCODE_TYPE_WRITE_NO_ADDRESS;
		return;
	}

	if (trans->bytesout == 1) {	/* and bytesin is > 0 */
		trans->type = SPI_OPCODE_TYPE_READ_NO_ADDRESS;
		return;
	}

	if (trans->bytesout == 4)	/* and bytesin is > 0 */
		trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;

	/* Fast read command is called with 5 bytes instead of 4 */
	if (trans->out[0] == SPI_OPCODE_FAST_READ && trans->bytesout == 5) {
		trans->type = SPI_OPCODE_TYPE_READ_WITH_ADDRESS;
		--trans->bytesout;
	}
}

221
static int spi_setup_opcode(struct ich_spi_priv *ctlr, struct spi_trans *trans)
S
Simon Glass 已提交
222 223
{
	uint16_t optypes;
224
	uint8_t opmenu[ctlr->menubytes];
S
Simon Glass 已提交
225 226 227

	trans->opcode = trans->out[0];
	spi_use_out(trans, 1);
228
	if (!ctlr->ichspi_lock) {
S
Simon Glass 已提交
229
		/* The lock is off, so just use index 0. */
230 231
		ich_writeb(ctlr, trans->opcode, ctlr->opmenu);
		optypes = ich_readw(ctlr, ctlr->optype);
S
Simon Glass 已提交
232
		optypes = (optypes & 0xfffc) | (trans->type & 0x3);
233
		ich_writew(ctlr, optypes, ctlr->optype);
S
Simon Glass 已提交
234 235 236 237 238 239 240 241 242 243
		return 0;
	} else {
		/* The lock is on. See if what we need is on the menu. */
		uint8_t optype;
		uint16_t opcode_index;

		/* Write Enable is handled as atomic prefix */
		if (trans->opcode == SPI_OPCODE_WREN)
			return 0;

244 245
		read_reg(ctlr, ctlr->opmenu, opmenu, sizeof(opmenu));
		for (opcode_index = 0; opcode_index < ctlr->menubytes;
S
Simon Glass 已提交
246 247 248 249 250
				opcode_index++) {
			if (opmenu[opcode_index] == trans->opcode)
				break;
		}

251
		if (opcode_index == ctlr->menubytes) {
S
Simon Glass 已提交
252 253
			printf("ICH SPI: Opcode %x not found\n",
			       trans->opcode);
254
			return -EINVAL;
S
Simon Glass 已提交
255 256
		}

257
		optypes = ich_readw(ctlr, ctlr->optype);
S
Simon Glass 已提交
258 259 260 261 262 263 264 265 266 267
		optype = (optypes >> (opcode_index * 2)) & 0x3;
		if (trans->type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS &&
		    optype == SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS &&
		    trans->bytesout >= 3) {
			/* We guessed wrong earlier. Fix it up. */
			trans->type = optype;
		}
		if (optype != trans->type) {
			printf("ICH SPI: Transaction doesn't fit type %d\n",
			       optype);
268
			return -ENOSPC;
S
Simon Glass 已提交
269 270 271 272 273 274 275
		}
		return opcode_index;
	}
}

static int spi_setup_offset(struct spi_trans *trans)
{
B
Bin Meng 已提交
276
	/* Separate the SPI address and data */
S
Simon Glass 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289
	switch (trans->type) {
	case SPI_OPCODE_TYPE_READ_NO_ADDRESS:
	case SPI_OPCODE_TYPE_WRITE_NO_ADDRESS:
		return 0;
	case SPI_OPCODE_TYPE_READ_WITH_ADDRESS:
	case SPI_OPCODE_TYPE_WRITE_WITH_ADDRESS:
		trans->offset = ((uint32_t)trans->out[0] << 16) |
				((uint32_t)trans->out[1] << 8) |
				((uint32_t)trans->out[2] << 0);
		spi_use_out(trans, 3);
		return 1;
	default:
		printf("Unrecognized SPI transaction type %#x\n", trans->type);
290
		return -EPROTO;
S
Simon Glass 已提交
291 292 293 294 295
	}
}

/*
 * Wait for up to 6s til status register bit(s) turn 1 (in case wait_til_set
Y
York Sun 已提交
296
 * below is true) or 0. In case the wait was for the bit(s) to set - write
S
Simon Glass 已提交
297 298 299 300
 * those bits back, which would cause resetting them.
 *
 * Return the last read status value on success or -1 on failure.
 */
301 302
static int ich_status_poll(struct ich_spi_priv *ctlr, u16 bitmask,
			   int wait_til_set)
S
Simon Glass 已提交
303 304 305 306 307
{
	int timeout = 600000; /* This will result in 6s */
	u16 status = 0;

	while (timeout--) {
308
		status = ich_readw(ctlr, ctlr->status);
S
Simon Glass 已提交
309
		if (wait_til_set ^ ((status & bitmask) == 0)) {
310 311 312 313
			if (wait_til_set) {
				ich_writew(ctlr, status & bitmask,
					   ctlr->status);
			}
S
Simon Glass 已提交
314 315 316 317 318 319 320
			return status;
		}
		udelay(10);
	}

	printf("ICH SPI: SCIP timeout, read %x, expected %x\n",
	       status, bitmask);
321
	return -ETIMEDOUT;
S
Simon Glass 已提交
322 323
}

324 325
static int ich_spi_xfer(struct udevice *dev, unsigned int bitlen,
			const void *dout, void *din, unsigned long flags)
S
Simon Glass 已提交
326
{
327
	struct udevice *bus = dev_get_parent(dev);
328
	struct ich_spi_platdata *plat = dev_get_platdata(bus);
329
	struct ich_spi_priv *ctlr = dev_get_priv(bus);
S
Simon Glass 已提交
330 331 332 333 334
	uint16_t control;
	int16_t opcode_index;
	int with_address;
	int status;
	int bytes = bitlen / 8;
335
	struct spi_trans *trans = &ctlr->trans;
S
Simon Glass 已提交
336 337
	unsigned type = flags & (SPI_XFER_BEGIN | SPI_XFER_END);
	int using_cmd = 0;
338
	int ret;
S
Simon Glass 已提交
339

340
	/* We don't support writing partial bytes */
S
Simon Glass 已提交
341 342
	if (bitlen % 8) {
		debug("ICH SPI: Accessing partial bytes not supported\n");
343
		return -EPROTONOSUPPORT;
S
Simon Glass 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356
	}

	/* An empty end transaction can be ignored */
	if (type == SPI_XFER_END && !dout && !din)
		return 0;

	if (type & SPI_XFER_BEGIN)
		memset(trans, '\0', sizeof(*trans));

	/* Dp we need to come back later to finish it? */
	if (dout && type == SPI_XFER_BEGIN) {
		if (bytes > ICH_MAX_CMD_LEN) {
			debug("ICH SPI: Command length limit exceeded\n");
357
			return -ENOSPC;
S
Simon Glass 已提交
358 359 360
		}
		memcpy(trans->cmd, dout, bytes);
		trans->cmd_len = bytes;
361
		debug_trace("ICH SPI: Saved %d bytes\n", bytes);
S
Simon Glass 已提交
362 363 364 365 366 367 368 369 370 371 372 373 374 375
		return 0;
	}

	/*
	 * We process a 'middle' spi_xfer() call, which has no
	 * SPI_XFER_BEGIN/END, as an independent transaction as if it had
	 * an end. We therefore repeat the command. This is because ICH
	 * seems to have no support for this, or because interest (in digging
	 * out the details and creating a special case in the code) is low.
	 */
	if (trans->cmd_len) {
		trans->out = trans->cmd;
		trans->bytesout = trans->cmd_len;
		using_cmd = 1;
376
		debug_trace("ICH SPI: Using %d bytes\n", trans->cmd_len);
S
Simon Glass 已提交
377 378 379 380 381 382 383 384
	} else {
		trans->out = dout;
		trans->bytesout = dout ? bytes : 0;
	}

	trans->in = din;
	trans->bytesin = din ? bytes : 0;

B
Bin Meng 已提交
385
	/* There has to always at least be an opcode */
S
Simon Glass 已提交
386 387
	if (!trans->bytesout) {
		debug("ICH SPI: No opcode for transfer\n");
388
		return -EPROTO;
S
Simon Glass 已提交
389 390
	}

391 392 393
	ret = ich_status_poll(ctlr, SPIS_SCIP, 0);
	if (ret < 0)
		return ret;
S
Simon Glass 已提交
394

395
	if (plat->ich_version == PCHV_7)
396 397 398
		ich_writew(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
	else
		ich_writeb(ctlr, SPIS_CDS | SPIS_FCERR, ctlr->status);
S
Simon Glass 已提交
399 400

	spi_setup_type(trans, using_cmd ? bytes : 0);
401
	opcode_index = spi_setup_opcode(ctlr, trans);
S
Simon Glass 已提交
402
	if (opcode_index < 0)
403
		return -EINVAL;
S
Simon Glass 已提交
404 405
	with_address = spi_setup_offset(trans);
	if (with_address < 0)
406
		return -EINVAL;
S
Simon Glass 已提交
407 408 409 410 411 412 413

	if (trans->opcode == SPI_OPCODE_WREN) {
		/*
		 * Treat Write Enable as Atomic Pre-Op if possible
		 * in order to prevent the Management Engine from
		 * issuing a transaction between WREN and DATA.
		 */
414 415
		if (!ctlr->ichspi_lock)
			ich_writew(ctlr, trans->opcode, ctlr->preop);
S
Simon Glass 已提交
416 417 418
		return 0;
	}

419
	if (ctlr->speed && ctlr->max_speed >= 33000000) {
S
Simon Glass 已提交
420 421
		int byte;

422 423
		byte = ich_readb(ctlr, ctlr->speed);
		if (ctlr->cur_speed >= 33000000)
S
Simon Glass 已提交
424 425 426
			byte |= SSFC_SCF_33MHZ;
		else
			byte &= ~SSFC_SCF_33MHZ;
427
		ich_writeb(ctlr, byte, ctlr->speed);
S
Simon Glass 已提交
428 429 430 431 432 433
	}

	/* See if we have used up the command data */
	if (using_cmd && dout && bytes) {
		trans->out = dout;
		trans->bytesout = bytes;
434
		debug_trace("ICH SPI: Moving to data, %d bytes\n", bytes);
S
Simon Glass 已提交
435 436 437
	}

	/* Preset control fields */
438
	control = ich_readw(ctlr, ctlr->control);
S
Simon Glass 已提交
439 440 441 442
	control &= ~SSFC_RESERVED;
	control = SPIC_SCGO | ((opcode_index & 0x07) << 4);

	/* Issue atomic preop cycle if needed */
443
	if (ich_readw(ctlr, ctlr->preop))
S
Simon Glass 已提交
444 445 446 447
		control |= SPIC_ACS;

	if (!trans->bytesout && !trans->bytesin) {
		/* SPI addresses are 24 bit only */
448 449 450 451
		if (with_address) {
			ich_writel(ctlr, trans->offset & 0x00FFFFFF,
				   ctlr->addr);
		}
S
Simon Glass 已提交
452 453 454 455 456 457
		/*
		 * This is a 'no data' command (like Write Enable), its
		 * bitesout size was 1, decremented to zero while executing
		 * spi_setup_opcode() above. Tell the chip to send the
		 * command.
		 */
458
		ich_writew(ctlr, control, ctlr->control);
S
Simon Glass 已提交
459 460

		/* wait for the result */
461 462 463
		status = ich_status_poll(ctlr, SPIS_CDS | SPIS_FCERR, 1);
		if (status < 0)
			return status;
S
Simon Glass 已提交
464 465 466

		if (status & SPIS_FCERR) {
			debug("ICH SPI: Command transaction error\n");
467
			return -EIO;
S
Simon Glass 已提交
468 469 470 471 472 473 474 475 476 477 478 479
		}

		return 0;
	}

	/*
	 * Check if this is a write command atempting to transfer more bytes
	 * than the controller can handle. Iterations for writes are not
	 * supported here because each SPI write command needs to be preceded
	 * and followed by other SPI commands, and this sequence is controlled
	 * by the SPI chip driver.
	 */
480
	if (trans->bytesout > ctlr->databytes) {
S
Simon Glass 已提交
481
		debug("ICH SPI: Too much to write. This should be prevented by the driver's max_write_size?\n");
482
		return -EPROTO;
S
Simon Glass 已提交
483 484 485 486 487 488 489 490 491 492
	}

	/*
	 * Read or write up to databytes bytes at a time until everything has
	 * been sent.
	 */
	while (trans->bytesout || trans->bytesin) {
		uint32_t data_length;

		/* SPI addresses are 24 bit only */
493
		ich_writel(ctlr, trans->offset & 0x00FFFFFF, ctlr->addr);
S
Simon Glass 已提交
494 495

		if (trans->bytesout)
496
			data_length = min(trans->bytesout, ctlr->databytes);
S
Simon Glass 已提交
497
		else
498
			data_length = min(trans->bytesin, ctlr->databytes);
S
Simon Glass 已提交
499 500 501

		/* Program data into FDATA0 to N */
		if (trans->bytesout) {
502
			write_reg(ctlr, trans->out, ctlr->data, data_length);
S
Simon Glass 已提交
503 504 505 506 507 508
			spi_use_out(trans, data_length);
			if (with_address)
				trans->offset += data_length;
		}

		/* Add proper control fields' values */
509
		control &= ~((ctlr->databytes - 1) << 8);
S
Simon Glass 已提交
510 511 512 513
		control |= SPIC_DS;
		control |= (data_length - 1) << 8;

		/* write it */
514
		ich_writew(ctlr, control, ctlr->control);
S
Simon Glass 已提交
515

B
Bin Meng 已提交
516
		/* Wait for Cycle Done Status or Flash Cycle Error */
517 518 519
		status = ich_status_poll(ctlr, SPIS_CDS | SPIS_FCERR, 1);
		if (status < 0)
			return status;
S
Simon Glass 已提交
520 521

		if (status & SPIS_FCERR) {
522
			debug("ICH SPI: Data transaction error %x\n", status);
523
			return -EIO;
S
Simon Glass 已提交
524 525 526
		}

		if (trans->bytesin) {
527
			read_reg(ctlr, ctlr->data, trans->in, data_length);
S
Simon Glass 已提交
528 529 530 531 532 533 534
			spi_use_in(trans, data_length);
			if (with_address)
				trans->offset += data_length;
		}
	}

	/* Clear atomic preop now that xfer is done */
535
	ich_writew(ctlr, 0, ctlr->preop);
S
Simon Glass 已提交
536 537 538 539 540 541 542 543 544 545

	return 0;
}

/*
 * This uses the SPI controller from the Intel Cougar Point and Panther Point
 * PCH to write-protect portions of the SPI flash until reboot. The changes
 * don't actually take effect until the HSFS[FLOCKDN] bit is set, but that's
 * done elsewhere.
 */
546 547
int spi_write_protect_region(struct udevice *dev, uint32_t lower_limit,
			     uint32_t length, int hint)
S
Simon Glass 已提交
548
{
549 550
	struct udevice *bus = dev->parent;
	struct ich_spi_priv *ctlr = dev_get_priv(bus);
S
Simon Glass 已提交
551 552 553
	uint32_t tmplong;
	uint32_t upper_limit;

554
	if (!ctlr->pr) {
S
Simon Glass 已提交
555 556
		printf("%s: operation not supported on this chipset\n",
		       __func__);
557
		return -ENOSYS;
S
Simon Glass 已提交
558 559 560 561 562 563 564
	}

	if (length == 0 ||
	    lower_limit > (0xFFFFFFFFUL - length) + 1 ||
	    hint < 0 || hint > 4) {
		printf("%s(0x%x, 0x%x, %d): invalid args\n", __func__,
		       lower_limit, length, hint);
565
		return -EPERM;
S
Simon Glass 已提交
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
	}

	upper_limit = lower_limit + length - 1;

	/*
	 * Determine bits to write, as follows:
	 *  31     Write-protection enable (includes erase operation)
	 *  30:29  reserved
	 *  28:16  Upper Limit (FLA address bits 24:12, with 11:0 == 0xfff)
	 *  15     Read-protection enable
	 *  14:13  reserved
	 *  12:0   Lower Limit (FLA address bits 24:12, with 11:0 == 0x000)
	 */
	tmplong = 0x80000000 |
		((upper_limit & 0x01fff000) << 4) |
		((lower_limit & 0x01fff000) >> 12);

	printf("%s: writing 0x%08x to %p\n", __func__, tmplong,
584 585 586 587 588 589
	       &ctlr->pr[hint]);
	ctlr->pr[hint] = tmplong;

	return 0;
}

590
static int ich_spi_probe(struct udevice *dev)
591
{
592 593
	struct ich_spi_platdata *plat = dev_get_platdata(dev);
	struct ich_spi_priv *priv = dev_get_priv(dev);
594 595 596
	uint8_t bios_cntl;
	int ret;

597 598 599 600
	/* Check the ICH version */
	plat->ich_version = pch_get_version(dev->parent);

	ret = ich_init_controller(dev, plat, priv);
601 602
	if (ret)
		return ret;
603 604 605
	/* Disable the BIOS write protect so write commands are allowed */
	ret = pch_set_spi_protect(dev->parent, false);
	if (ret == -ENOSYS) {
606
		bios_cntl = ich_readb(priv, priv->bcr);
J
Jagan Teki 已提交
607
		bios_cntl &= ~BIT(5);	/* clear Enable InSMM_STS (EISS) */
608
		bios_cntl |= 1;		/* Write Protect Disable (WPD) */
609
		ich_writeb(priv, bios_cntl, priv->bcr);
610 611 612 613
	} else if (ret) {
		debug("%s: Failed to disable write-protect: err=%d\n",
		      __func__, ret);
		return ret;
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
	}

	priv->cur_speed = priv->max_speed;

	return 0;
}

static int ich_spi_set_speed(struct udevice *bus, uint speed)
{
	struct ich_spi_priv *priv = dev_get_priv(bus);

	priv->cur_speed = speed;

	return 0;
}

static int ich_spi_set_mode(struct udevice *bus, uint mode)
{
	debug("%s: mode=%d\n", __func__, mode);

	return 0;
}

static int ich_spi_child_pre_probe(struct udevice *dev)
{
	struct udevice *bus = dev_get_parent(dev);
	struct ich_spi_platdata *plat = dev_get_platdata(bus);
	struct ich_spi_priv *priv = dev_get_priv(bus);
642
	struct spi_slave *slave = dev_get_parent_priv(dev);
643 644 645 646 647 648 649 650 651 652

	/*
	 * Yes this controller can only write a small number of bytes at
	 * once! The limit is typically 64 bytes.
	 */
	slave->max_write_size = priv->databytes;
	/*
	 * ICH 7 SPI controller only supports array read command
	 * and byte program command for SST flash
	 */
653
	if (plat->ich_version == PCHV_7) {
J
Jagan Teki 已提交
654
		slave->mode_rx = SPI_RX_SLOW;
655
		slave->mode = SPI_TX_BYTE;
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685
	}

	return 0;
}

static const struct dm_spi_ops ich_spi_ops = {
	.xfer		= ich_spi_xfer,
	.set_speed	= ich_spi_set_speed,
	.set_mode	= ich_spi_set_mode,
	/*
	 * cs_info is not needed, since we require all chip selects to be
	 * in the device tree explicitly
	 */
};

static const struct udevice_id ich_spi_ids[] = {
	{ .compatible = "intel,ich-spi" },
	{ }
};

U_BOOT_DRIVER(ich_spi) = {
	.name	= "ich_spi",
	.id	= UCLASS_SPI,
	.of_match = ich_spi_ids,
	.ops	= &ich_spi_ops,
	.platdata_auto_alloc_size = sizeof(struct ich_spi_platdata),
	.priv_auto_alloc_size = sizeof(struct ich_spi_priv),
	.child_pre_probe = ich_spi_child_pre_probe,
	.probe	= ich_spi_probe,
};