blob: dfcda20dc7cdf89e9031ff2fae388ec96d7f8dc2 [file] [log] [blame]
Norman James6a58a272015-10-07 14:34:16 -05001#include <stdint.h>
2#include <stdbool.h>
3#include <stdlib.h>
4#include <errno.h>
5#include <stdio.h>
6#include <string.h>
7
8#include <libflash/libflash.h>
9#include <libflash/libflash-priv.h>
10
11#include "io.h"
12
13/* Offset of SFC registers in FW space */
14#define SFC_CMDREG_OFFSET 0x00000c00
15/* Offset of SFC command buffer in FW space */
16#define SFC_CMDBUF_OFFSET 0x00000d00
17/* Offset of flash MMIO mapping in FW space */
18#define SFC_MMIO_OFFSET 0x0c000000
19
20
21/*
22 * Register definitions
23 */
24#define SFC_REG_CONF 0x10 /* CONF: Direct Access Configuration */
25#define SFC_REG_CONF_FRZE (1 << 3)
26#define SFC_REG_CONF_ECCEN (1 << 2)
27#define SFC_REG_CONF_DRCD (1 << 1)
28#define SFC_REG_CONF_FLRLD (1 << 0)
29
30#define SFC_REG_STATUS 0x0C /* STATUS : Status Reg */
31#define SFC_REG_STATUS_NX_ON_SHFT 28
32#define SFC_REG_STATUS_RWP (1 << 27)
33#define SFC_REG_STATUS_FOURBYTEAD (1 << 26)
34#define SFC_REG_STATUS_ILLEGAL (1 << 4)
35#define SFC_REG_STATUS_ECCERRCNTN (1 << 3)
36#define SFC_REG_STATUS_ECCUEN (1 << 2)
37#define SFC_REG_STATUS_DONE (1 << 0)
38
39#define SFC_REG_CMD 0x40 /* CMD : Command */
40#define SFC_REG_CMD_OPCODE_SHFT 9
41#define SFC_REG_CMD_LENGTH_SHFT 0
42
43#define SFC_REG_SPICLK 0x3C /* SPICLK: SPI clock rate config */
44#define SFC_REG_SPICLK_OUTDLY_SHFT 24
45#define SFC_REG_SPICLK_INSAMPDLY_SHFT 16
46#define SFC_REG_SPICLK_CLKHI_SHFT 8
47#define SFC_REG_SPICLK_CLKLO_SHFT 0
48
49#define SFC_REG_ADR 0x44 /* ADR : Address */
50#define SFC_REG_ERASMS 0x48 /* ERASMS : Small Erase Block Size */
51#define SFC_REG_ERASLGS 0x4C /* ERALGS : Large Erase Block Size */
52#define SFC_REG_CONF4 0x54 /* CONF4 : SPI Op Code for Small Erase */
53#define SFC_REG_CONF5 0x58 /* CONF5 : Small Erase Size config reg */
54
55#define SFC_REG_CONF8 0x64 /* CONF8 : Read Command */
56#define SFC_REG_CONF8_CSINACTIVERD_SHFT 18
57#define SFC_REG_CONF8_DUMMY_SHFT 8
58#define SFC_REG_CONF8_READOP_SHFT 0
59
60#define SFC_REG_ADRCBF 0x80 /* ADRCBF : First Intf NOR Addr Offset */
61#define SFC_REG_ADRCMF 0x84 /* ADRCMF : First Intf NOR Allocation */
62#define SFC_REG_ADRCBS 0x88 /* ADRCBS : Second Intf NOR Addr Offset */
63#define SFC_REG_ADRCMS 0x8C /* ADRCMS : Second Intf NOR Allocation */
64#define SFC_REG_OADRNB 0x90 /* OADRNB : Direct Access OBP Window Base Address */
65#define SFC_REG_OADRNS 0x94 /* OADRNS : DIrect Access OPB Window Size */
66
67#define SFC_REG_CHIPIDCONF 0x9C /* CHIPIDCONF : config ChipId CMD */
68#define SFC_REG_CHIPIDCONF_OPCODE_SHFT 24
69#define SFC_REG_CHIPIDCONF_READ (1 << 23)
70#define SFC_REG_CHIPIDCONF_WRITE (1 << 22)
71#define SFC_REG_CHIPIDCONF_USE_ADDR (1 << 21)
72#define SFC_REG_CHIPIDCONF_DUMMY_SHFT 16
73#define SFC_REG_CHIPIDCONF_LEN_SHFT 0
74
75/*
76 * SFC Opcodes
77 */
78#define SFC_OP_READRAW 0x03 /* Read Raw */
79#define SFC_OP_WRITERAW 0x02 /* Write Raw */
80#define SFC_OP_ERASM 0x32 /* Erase Small */
81#define SFC_OP_ERALG 0x34 /* Erase Large */
82#define SFC_OP_ENWRITPROT 0x53 /* Enable WRite Protect */
83#define SFC_OP_CHIPID 0x1F /* Get Chip ID */
84#define SFC_OP_STATUS 0x05 /* Get Status */
85#define SFC_OP_TURNOFF 0x5E /* Turn Off */
86#define SFC_OP_TURNON 0x50 /* Turn On */
87#define SFC_OP_ABORT 0x6F /* Super-Abort */
88#define SFC_OP_START4BA 0x37 /* Start 4BA */
89#define SFC_OP_END4BA 0x69 /* End 4BA */
90
91/* Command buffer size */
92#define SFC_CMDBUF_SIZE 256
93
94struct sfc_ctrl {
95 /* Erase sizes */
96 uint32_t small_er_size;
97 uint32_t large_er_size;
98
99 /* Current 4b mode */
100 bool mode_4b;
101
102 /* Callbacks */
103 struct spi_flash_ctrl ops;
104};
105
106/* Command register support */
107static inline int sfc_reg_read(uint8_t reg, uint32_t *val)
108{
109 uint32_t tmp;
110 int rc;
111
112 *val = 0xffffffff;
113 rc = lpc_fw_read32(&tmp, SFC_CMDREG_OFFSET + reg);
114 if (rc)
115 return rc;
116 *val = be32_to_cpu(tmp);
117 return 0;
118}
119
120static inline int sfc_reg_write(uint8_t reg, uint32_t val)
121{
122 return lpc_fw_write32(cpu_to_be32(val), SFC_CMDREG_OFFSET + reg);
123}
124
125static int sfc_buf_write(uint32_t len, const void *data)
126{
127 uint32_t tmp, off = 0;
128 int rc;
129
130 if (len > SFC_CMDBUF_SIZE)
131 return FLASH_ERR_PARM_ERROR;
132
133 while (len >= 4) {
134 tmp = *(const uint32_t *)data;
135 rc = lpc_fw_write32(tmp, SFC_CMDBUF_OFFSET + off);
136 if (rc)
137 return rc;
138 off += 4;
139 len -= 4;
140 data += 4;
141 }
142 if (!len)
143 return 0;
144
145 /* lpc_fw_write operates on BE values so that's what we layout
146 * in memory with memcpy. The swap in the register on LE doesn't
147 * matter, the result in memory will be in the right order.
148 */
149 tmp = -1;
150 memcpy(&tmp, data, len);
151 return lpc_fw_write32(tmp, SFC_CMDBUF_OFFSET + off);
152}
153
154static int sfc_buf_read(uint32_t len, void *data)
155{
156 uint32_t tmp, off = 0;
157 int rc;
158
159 if (len > SFC_CMDBUF_SIZE)
160 return FLASH_ERR_PARM_ERROR;
161
162 while (len >= 4) {
163 rc = lpc_fw_read32(data, SFC_CMDBUF_OFFSET + off);
164 if (rc)
165 return rc;
166 off += 4;
167 len -= 4;
168 data += 4;
169 }
170 if (!len)
171 return 0;
172
173 rc = lpc_fw_read32(&tmp, SFC_CMDBUF_OFFSET + off);
174 if (rc)
175 return rc;
176 /* We know tmp contains a big endian value, so memcpy is
177 * our friend here
178 */
179 memcpy(data, &tmp, len);
180 return 0;
181}
182
183/* Polls until SFC indicates command is complete */
184static int sfc_poll_complete(void)
185{
186 uint32_t status;
187
188 /* XXX Add timeout */
189 do {
190 int rc;
191
192 rc = sfc_reg_read(SFC_REG_STATUS, &status);
193 if (rc)
194 return rc;
195 if (status & SFC_REG_STATUS_DONE)
196 break;
197
198 } while (true);
199
200 return 0;
201}
202
203static int sfc_exec_command(uint8_t opcode, uint32_t length)
204{
205 int rc = 0;
206 uint32_t cmd_reg = 0;
207
208 if (opcode > 0x7f || length > 0x1ff)
209 return FLASH_ERR_PARM_ERROR;
210
211 /* Write command register to start execution */
212 cmd_reg |= (opcode << SFC_REG_CMD_OPCODE_SHFT);
213 cmd_reg |= (length << SFC_REG_CMD_LENGTH_SHFT);
214 rc = sfc_reg_write(SFC_REG_CMD, cmd_reg);
215 if (rc)
216 return rc;
217
218 /* Wait for command to complete */
219 return sfc_poll_complete();
220}
221
222static int sfc_chip_id(struct spi_flash_ctrl *ctrl, uint8_t *id_buf,
223 uint32_t *id_size)
224{
225 uint32_t idconf;
226 int rc;
227
228 if ((*id_size) < 3)
229 return FLASH_ERR_PARM_ERROR;
230
231 /*
232 * XXX This will not work in locked down mode but we assume that
233 * in this case, the chip ID command is already properly programmed
234 * and the SFC will ignore this. However I haven't verified...
235 */
236 idconf = ((uint64_t)CMD_RDID) << SFC_REG_CHIPIDCONF_OPCODE_SHFT;
237 idconf |= SFC_REG_CHIPIDCONF_READ;
238 idconf |= (3ul << SFC_REG_CHIPIDCONF_LEN_SHFT);
239 (void)sfc_reg_write(SFC_REG_CHIPIDCONF, idconf);
240
241 /* Perform command */
242 rc = sfc_exec_command(SFC_OP_CHIPID, 0);
243 if (rc)
244 return rc;
245
246 /* Read chip ID */
247 rc = sfc_buf_read(3, id_buf);
248 if (rc)
249 return rc;
250 *id_size = 3;
251
252 return 0;
253}
254
255
256static int sfc_read(struct spi_flash_ctrl *ctrl, uint32_t pos,
257 void *buf, uint32_t len)
258{
259 while(len) {
260 uint32_t chunk = len;
261 int rc;
262
263 if (chunk > SFC_CMDBUF_SIZE)
264 chunk = SFC_CMDBUF_SIZE;
265 rc = sfc_reg_write(SFC_REG_ADR, pos);
266 if (rc)
267 return rc;
268 rc = sfc_exec_command(SFC_OP_READRAW, chunk);
269 if (rc)
270 return rc;
271 rc = sfc_buf_read(chunk, buf);
272 if (rc)
273 return rc;
274 len -= chunk;
275 pos += chunk;
276 buf += chunk;
277 }
278 return 0;
279}
280
281static int sfc_write(struct spi_flash_ctrl *ctrl, uint32_t addr,
282 const void *buf, uint32_t size)
283{
284 uint32_t chunk;
285 int rc;
286
287 while(size) {
288 /* We shall not cross a page boundary */
289 chunk = 0x100 - (addr & 0xff);
290 if (chunk > size)
291 chunk = size;
292
293 /* Write to SFC write buffer */
294 rc = sfc_buf_write(chunk, buf);
295 if (rc)
296 return rc;
297
298 /* Program address */
299 rc = sfc_reg_write(SFC_REG_ADR, addr);
300 if (rc)
301 return rc;
302
303 /* Send command */
304 rc = sfc_exec_command(SFC_OP_WRITERAW, chunk);
305 if (rc)
306 return rc;
307
308 addr += chunk;
309 buf += chunk;
310 size -= chunk;
311 }
312 return 0;
313}
314
315static int sfc_erase(struct spi_flash_ctrl *ctrl, uint32_t addr,
316 uint32_t size)
317{
318 struct sfc_ctrl *ct = container_of(ctrl, struct sfc_ctrl, ops);
319 uint32_t sm_mask = ct->small_er_size - 1;
320 uint32_t lg_mask = ct->large_er_size - 1;
321 uint32_t chunk;
322 uint8_t cmd;
323 int rc;
324
325 while(size) {
326 /* Choose erase size for this chunk */
327 if (((addr | size) & lg_mask) == 0) {
328 chunk = ct->large_er_size;
329 cmd = SFC_OP_ERALG;
330 } else if (((addr | size) & sm_mask) == 0) {
331 chunk = ct->small_er_size;
332 cmd = SFC_OP_ERASM;
333 } else
334 return FLASH_ERR_ERASE_BOUNDARY;
335
336 rc = sfc_reg_write(SFC_REG_ADR, addr);
337 if (rc)
338 return rc;
339 rc = sfc_exec_command(cmd, 0);
340 if (rc)
341 return rc;
342 addr += chunk;
343 size -= chunk;
344 }
345 return 0;
346}
347
348static int sfc_setup(struct spi_flash_ctrl *ctrl, uint32_t *tsize)
349{
350 struct sfc_ctrl *ct = container_of(ctrl, struct sfc_ctrl, ops);
351 struct flash_info *info = ctrl->finfo;
352 uint32_t er_flags;
353
354 /* Keep non-erase related flags */
355 er_flags = ~FL_ERASE_ALL;
356
357 /* Add supported erase sizes */
358 if (ct->small_er_size == 0x1000 || ct->large_er_size == 0x1000)
359 er_flags |= FL_ERASE_4K;
360 if (ct->small_er_size == 0x8000 || ct->large_er_size == 0x8000)
361 er_flags |= FL_ERASE_32K;
362 if (ct->small_er_size == 0x10000 || ct->large_er_size == 0x10000)
363 er_flags |= FL_ERASE_64K;
364
365 /* Mask the flags out */
366 info->flags &= er_flags;
367
368 return 0;
369}
370
371static int sfc_set_4b(struct spi_flash_ctrl *ctrl, bool enable)
372{
373 struct sfc_ctrl *ct = container_of(ctrl, struct sfc_ctrl, ops);
374 int rc;
375
376 rc = sfc_exec_command(enable ? SFC_OP_START4BA : SFC_OP_END4BA, 0);
377 if (rc)
378 return rc;
379 ct->mode_4b = enable;
380 return 0;
381}
382
383static void sfc_validate_er_size(uint32_t *size)
384{
385 if (*size == 0)
386 return;
387
388 /* We only support 4k, 32k and 64k */
389 if (*size != 0x1000 && *size != 0x8000 && *size != 0x10000) {
390 FL_ERR("SFC: Erase size %d bytes unsupported\n", *size);
391 *size = 0;
392 }
393}
394
395static int sfc_init(struct sfc_ctrl *ct)
396{
397 int rc;
398 uint32_t status;
399
400 /*
401 * Assumptions: The controller has been fully initialized
402 * by an earlier FW layer setting the chip ID command, the
403 * erase sizes, and configuring the timings for reads and
404 * writes.
405 *
406 * This driver is meant to be usable if the configuration
407 * is in lock down.
408 *
409 * If that wasn't the case, we could configure some sane
410 * defaults here and tuned values in setup() after the
411 * chip has been identified.
412 */
413
414 /* Read erase sizes from flash */
415 rc = sfc_reg_read(SFC_REG_ERASMS, &ct->small_er_size);
416 if (rc)
417 return rc;
418 sfc_validate_er_size(&ct->small_er_size);
419 rc = sfc_reg_read(SFC_REG_ERASLGS, &ct->large_er_size);
420 if (rc)
421 return rc;
422 sfc_validate_er_size(&ct->large_er_size);
423
424 /* No erase sizes we can cope with ? Ouch... */
425 if ((ct->small_er_size == 0 && ct->large_er_size == 0) ||
426 (ct->large_er_size && (ct->small_er_size > ct->large_er_size))) {
427 FL_ERR("SFC: No supported erase sizes !\n");
428 return FLASH_ERR_CTRL_CONFIG_MISMATCH;
429 }
430
431 FL_INF("SFC: Suppored erase sizes:");
432 if (ct->small_er_size)
433 FL_INF(" %dKB", ct->small_er_size >> 10);
434 if (ct->large_er_size)
435 FL_INF(" %dKB", ct->large_er_size >> 10);
436 FL_INF("\n");
437
438 /* Read current state of 4 byte addressing */
439 rc = sfc_reg_read(SFC_REG_STATUS, &status);
440 if (rc)
441 return rc;
442 ct->mode_4b = !!(status & SFC_REG_STATUS_FOURBYTEAD);
443
444 return 0;
445}
446
447int sfc_open(struct spi_flash_ctrl **ctrl)
448{
449 struct sfc_ctrl *ct;
450 int rc;
451
452 *ctrl = NULL;
453 ct = malloc(sizeof(*ct));
454 if (!ct) {
455 FL_ERR("SFC: Failed to allocate\n");
456 return FLASH_ERR_MALLOC_FAILED;
457 }
458 memset(ct, 0, sizeof(*ct));
459 ct->ops.chip_id = sfc_chip_id;
460 ct->ops.setup = sfc_setup;
461 ct->ops.set_4b = sfc_set_4b;
462 ct->ops.read = sfc_read;
463 ct->ops.write = sfc_write;
464 ct->ops.erase = sfc_erase;
465
466 rc = sfc_init(ct);
467 if (rc)
468 goto fail;
469 *ctrl = &ct->ops;
470 return 0;
471 fail:
472 free(ct);
473 return rc;
474}
475
476void sfc_close(struct spi_flash_ctrl *ctrl)
477{
478 struct sfc_ctrl *ct = container_of(ctrl, struct sfc_ctrl, ops);
479
480 /* Free the whole lot */
481 free(ct);
482}
483