spi_flash.c 8.75 KB
Newer Older
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
1
2
3
4
/*
 * SPI flash interface
 *
 * Copyright (C) 2008 Atmel Corporation
5
6
 * Copyright (C) 2010 Reinhard Meyer, EMK Elektronik
 *
Mike Frysinger's avatar
Mike Frysinger committed
7
 * Licensed under the GPL-2 or later.
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
8
 */
Mike Frysinger's avatar
Mike Frysinger committed
9

Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
10
11
12
13
#include <common.h>
#include <malloc.h>
#include <spi.h>
#include <spi_flash.h>
14
#include <watchdog.h>
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
15
16
17

#include "spi_flash_internal.h"

Mike Frysinger's avatar
Mike Frysinger committed
18
19
20
21
22
23
24
25
static void spi_flash_addr(u32 addr, u8 *cmd)
{
	/* cmd[0] is actual command */
	cmd[1] = addr >> 16;
	cmd[2] = addr >> 8;
	cmd[3] = addr >> 0;
}

Mike Frysinger's avatar
Mike Frysinger committed
26
27
28
29
static int spi_flash_read_write(struct spi_slave *spi,
				const u8 *cmd, size_t cmd_len,
				const u8 *data_out, u8 *data_in,
				size_t data_len)
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
30
31
32
33
34
35
36
37
38
{
	unsigned long flags = SPI_XFER_BEGIN;
	int ret;

	if (data_len == 0)
		flags |= SPI_XFER_END;

	ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags);
	if (ret) {
Mike Frysinger's avatar
Mike Frysinger committed
39
		debug("SF: Failed to send command (%zu bytes): %d\n",
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
40
41
				cmd_len, ret);
	} else if (data_len != 0) {
Mike Frysinger's avatar
Mike Frysinger committed
42
		ret = spi_xfer(spi, data_len * 8, data_out, data_in, SPI_XFER_END);
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
43
		if (ret)
Mike Frysinger's avatar
Mike Frysinger committed
44
			debug("SF: Failed to transfer %zu bytes of data: %d\n",
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
45
46
47
48
49
50
					data_len, ret);
	}

	return ret;
}

Mike Frysinger's avatar
Mike Frysinger committed
51
int spi_flash_cmd(struct spi_slave *spi, u8 cmd, void *response, size_t len)
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
52
{
Mike Frysinger's avatar
Mike Frysinger committed
53
54
	return spi_flash_cmd_read(spi, &cmd, 1, response, len);
}
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
55

Mike Frysinger's avatar
Mike Frysinger committed
56
57
58
59
int spi_flash_cmd_read(struct spi_slave *spi, const u8 *cmd,
		size_t cmd_len, void *data, size_t data_len)
{
	return spi_flash_read_write(spi, cmd, cmd_len, NULL, data, data_len);
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
60
61
}

Mike Frysinger's avatar
Mike Frysinger committed
62
63
64
65
66
int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
		const void *data, size_t data_len)
{
	return spi_flash_read_write(spi, cmd, cmd_len, data, NULL, data_len);
}
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
67

Mike Frysinger's avatar
Mike Frysinger committed
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
int spi_flash_cmd_write_multi(struct spi_flash *flash, u32 offset,
		size_t len, const void *buf)
{
	unsigned long page_addr, byte_addr, page_size;
	size_t chunk_len, actual;
	int ret;
	u8 cmd[4];

	page_size = flash->page_size;
	page_addr = offset / page_size;
	byte_addr = offset % page_size;

	ret = spi_claim_bus(flash->spi);
	if (ret) {
		debug("SF: unable to claim SPI bus\n");
		return ret;
	}

	cmd[0] = CMD_PAGE_PROGRAM;
	for (actual = 0; actual < len; actual += chunk_len) {
		chunk_len = min(len - actual, page_size - byte_addr);

		cmd[1] = page_addr >> 8;
		cmd[2] = page_addr;
		cmd[3] = byte_addr;

		debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);

		ret = spi_flash_cmd_write_enable(flash);
		if (ret < 0) {
			debug("SF: enabling write failed\n");
			break;
		}

		ret = spi_flash_cmd_write(flash->spi, cmd, 4,
					  buf + actual, chunk_len);
		if (ret < 0) {
			debug("SF: write failed\n");
			break;
		}

		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PROG_TIMEOUT);
		if (ret)
			break;

		page_addr++;
		byte_addr = 0;
	}

	debug("SF: program %s %zu bytes @ %#x\n",
	      ret ? "failure" : "success", len, offset);

	spi_release_bus(flash->spi);
	return ret;
}

Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
125
126
127
128
129
130
131
132
133
134
135
136
137
int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd,
		size_t cmd_len, void *data, size_t data_len)
{
	struct spi_slave *spi = flash->spi;
	int ret;

	spi_claim_bus(spi);
	ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
	spi_release_bus(spi);

	return ret;
}

Mike Frysinger's avatar
Mike Frysinger committed
138
139
140
141
142
143
144
145
146
147
148
149
int spi_flash_cmd_read_fast(struct spi_flash *flash, u32 offset,
		size_t len, void *data)
{
	u8 cmd[5];

	cmd[0] = CMD_READ_ARRAY_FAST;
	spi_flash_addr(offset, cmd);
	cmd[4] = 0x00;

	return spi_flash_read_common(flash, cmd, sizeof(cmd), data, len);
}

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
int spi_flash_cmd_poll_bit(struct spi_flash *flash, unsigned long timeout,
			   u8 cmd, u8 poll_bit)
{
	struct spi_slave *spi = flash->spi;
	unsigned long timebase;
	int ret;
	u8 status;

	ret = spi_xfer(spi, 8, &cmd, NULL, SPI_XFER_BEGIN);
	if (ret) {
		debug("SF: Failed to send command %02x: %d\n", cmd, ret);
		return ret;
	}

	timebase = get_timer(0);
	do {
166
167
		WATCHDOG_RESET();

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
		ret = spi_xfer(spi, 8, NULL, &status, 0);
		if (ret)
			return -1;

		if ((status & poll_bit) == 0)
			break;

	} while (get_timer(timebase) < timeout);

	spi_xfer(spi, 0, NULL, NULL, SPI_XFER_END);

	if ((status & poll_bit) == 0)
		return 0;

	/* Timed out */
	debug("SF: time out!\n");
	return -1;
}

int spi_flash_cmd_wait_ready(struct spi_flash *flash, unsigned long timeout)
{
	return spi_flash_cmd_poll_bit(flash, timeout,
		CMD_READ_STATUS, STATUS_WIP);
}

Mike Frysinger's avatar
Mike Frysinger committed
193
int spi_flash_cmd_erase(struct spi_flash *flash, u8 erase_cmd,
194
			u32 offset, size_t len)
Mike Frysinger's avatar
Mike Frysinger committed
195
{
196
	u32 start, end, erase_size;
Mike Frysinger's avatar
Mike Frysinger committed
197
198
199
	int ret;
	u8 cmd[4];

200
	erase_size = flash->sector_size;
Mike Frysinger's avatar
Mike Frysinger committed
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
	if (offset % erase_size || len % erase_size) {
		debug("SF: Erase offset/length not multiple of erase size\n");
		return -1;
	}

	ret = spi_claim_bus(flash->spi);
	if (ret) {
		debug("SF: Unable to claim SPI bus\n");
		return ret;
	}

	cmd[0] = erase_cmd;
	start = offset;
	end = start + len;

	while (offset < end) {
		spi_flash_addr(offset, cmd);
		offset += erase_size;

		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
		      cmd[2], cmd[3], offset);

223
		ret = spi_flash_cmd_write_enable(flash);
Mike Frysinger's avatar
Mike Frysinger committed
224
225
226
227
228
229
230
231
232
233
234
235
		if (ret)
			goto out;

		ret = spi_flash_cmd_write(flash->spi, cmd, sizeof(cmd), NULL, 0);
		if (ret)
			goto out;

		ret = spi_flash_cmd_wait_ready(flash, SPI_FLASH_PAGE_ERASE_TIMEOUT);
		if (ret)
			goto out;
	}

236
	debug("SF: Successfully erased %zu bytes @ %#x\n",
Mike Frysinger's avatar
Mike Frysinger committed
237
238
239
240
241
242
243
	      len * erase_size, start);

 out:
	spi_release_bus(flash->spi);
	return ret;
}

244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
/*
 * The following table holds all device probe functions
 *
 * shift:  number of continuation bytes before the ID
 * idcode: the expected IDCODE or 0xff for non JEDEC devices
 * probe:  the function to call
 *
 * Non JEDEC devices should be ordered in the table such that
 * the probe functions with best detection algorithms come first.
 *
 * Several matching entries are permitted, they will be tried
 * in sequence until a probe function returns non NULL.
 *
 * IDCODE_CONT_LEN may be redefined if a device needs to declare a
 * larger "shift" value.  IDCODE_PART_LEN generally shouldn't be
 * changed.  This is the max number of bytes probe functions may
 * examine when looking up part-specific identification info.
 *
 * Probe functions will be given the idcode buffer starting at their
 * manu id byte (the "idcode" in the table below).  In other words,
 * all of the continuation bytes will be skipped (the "shift" below).
 */
#define IDCODE_CONT_LEN 0
#define IDCODE_PART_LEN 5
static const struct {
	const u8 shift;
	const u8 idcode;
	struct spi_flash *(*probe) (struct spi_slave *spi, u8 *idcode);
} flashes[] = {
	/* Keep it sorted by define name */
#ifdef CONFIG_SPI_FLASH_ATMEL
	{ 0, 0x1f, spi_flash_probe_atmel, },
#endif
Chong Huang's avatar
Chong Huang committed
277
278
279
#ifdef CONFIG_SPI_FLASH_EON
	{ 0, 0x1c, spi_flash_probe_eon, },
#endif
280
281
282
283
284
285
286
287
288
289
290
291
292
293
#ifdef CONFIG_SPI_FLASH_MACRONIX
	{ 0, 0xc2, spi_flash_probe_macronix, },
#endif
#ifdef CONFIG_SPI_FLASH_SPANSION
	{ 0, 0x01, spi_flash_probe_spansion, },
#endif
#ifdef CONFIG_SPI_FLASH_SST
	{ 0, 0xbf, spi_flash_probe_sst, },
#endif
#ifdef CONFIG_SPI_FLASH_STMICRO
	{ 0, 0x20, spi_flash_probe_stmicro, },
#endif
#ifdef CONFIG_SPI_FLASH_WINBOND
	{ 0, 0xef, spi_flash_probe_winbond, },
294
295
296
297
298
#endif
#ifdef CONFIG_SPI_FRAM_RAMTRON
	{ 6, 0xc2, spi_fram_probe_ramtron, },
# undef IDCODE_CONT_LEN
# define IDCODE_CONT_LEN 6
299
300
301
302
303
#endif
	/* Keep it sorted by best detection */
#ifdef CONFIG_SPI_FLASH_STMICRO
	{ 0, 0xff, spi_flash_probe_stmicro, },
#endif
304
305
306
#ifdef CONFIG_SPI_FRAM_RAMTRON_NON_JEDEC
	{ 0, 0xff, spi_fram_probe_ramtron, },
#endif
307
308
309
};
#define IDCODE_LEN (IDCODE_CONT_LEN + IDCODE_PART_LEN)

Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
310
311
312
313
struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs,
		unsigned int max_hz, unsigned int spi_mode)
{
	struct spi_slave *spi;
314
315
316
	struct spi_flash *flash = NULL;
	int ret, i, shift;
	u8 idcode[IDCODE_LEN], *idp;
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
317
318
319

	spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
	if (!spi) {
320
		printf("SF: Failed to set up slave\n");
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
321
322
323
324
325
326
327
328
329
330
		return NULL;
	}

	ret = spi_claim_bus(spi);
	if (ret) {
		debug("SF: Failed to claim SPI bus: %d\n", ret);
		goto err_claim_bus;
	}

	/* Read the ID codes */
331
	ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
332
333
334
	if (ret)
		goto err_read_id;

335
336
337
#ifdef DEBUG
	printf("SF: Got idcodes\n");
	print_buffer(0, idcode, 1, sizeof(idcode), 0);
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
338
339
#endif

340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
	/* count the number of continuation bytes */
	for (shift = 0, idp = idcode;
	     shift < IDCODE_CONT_LEN && *idp == 0x7f;
	     ++shift, ++idp)
		continue;

	/* search the table for matches in shift and id */
	for (i = 0; i < ARRAY_SIZE(flashes); ++i)
		if (flashes[i].shift == shift && flashes[i].idcode == *idp) {
			/* we have a match, call probe */
			flash = flashes[i].probe(spi, idp);
			if (flash)
				break;
		}

	if (!flash) {
		printf("SF: Unsupported manufacturer %02x\n", *idp);
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
357
		goto err_manufacturer_probe;
358
	}
Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
359

360
361
	printf("SF: Detected %s with page size ", flash->name);
	print_size(flash->sector_size, ", total ");
362
363
	print_size(flash->size, "\n");

Haavard Skinnemoen's avatar
Haavard Skinnemoen committed
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
	spi_release_bus(spi);

	return flash;

err_manufacturer_probe:
err_read_id:
	spi_release_bus(spi);
err_claim_bus:
	spi_free_slave(spi);
	return NULL;
}

void spi_flash_free(struct spi_flash *flash)
{
	spi_free_slave(flash->spi);
	free(flash);
}