| Norman James | 6a58a27 | 2015-10-07 14:34:16 -0500 | [diff] [blame] | 1 | #include <stdlib.h>
 | 
 | 2 | #include <stdio.h>
 | 
 | 3 | #include <string.h>
 | 
 | 4 | 
 | 
 | 5 | #include "libflash.h"
 | 
 | 6 | #include "libflash-priv.h"
 | 
 | 7 | 
 | 
 | 8 | static const struct flash_info flash_info[] = {
 | 
 | 9 | 	{ 0xc22019, 0x02000000, FL_ERASE_ALL | FL_CAN_4B, "Macronix MXxxL25635F"},
 | 
 | 10 | 	{ 0xc2201a, 0x04000000, FL_ERASE_ALL | FL_CAN_4B, "Macronix MXxxL51235F"},
 | 
 | 11 | 	{ 0xef4018, 0x01000000, FL_ERASE_ALL,             "Winbond W25Q128BV"   },
 | 
 | 12 | 	{ 0x20ba20, 0x04000000, FL_ERASE_4K  | FL_ERASE_64K | FL_CAN_4B |
 | 
 | 13 |                                 FL_ERASE_BULK | FL_MICRON_BUGS,
 | 
 | 14 |                                                           "Micron N25Qx512Ax"   },
 | 
 | 15 | 	{ 0x55aa55, 0x00100000, FL_ERASE_ALL | FL_CAN_4B, "TEST_FLASH" },
 | 
 | 16 | };
 | 
 | 17 | 
 | 
 | 18 | struct flash_chip {
 | 
 | 19 | 	struct spi_flash_ctrl	*ctrl;		/* Controller */
 | 
 | 20 | 	struct flash_info	info;		/* Flash info */
 | 
 | 21 | 	uint32_t		tsize;		/* Corrected flash size */
 | 
 | 22 | 	uint32_t		min_erase_mask;	/* Minimum erase size */
 | 
 | 23 | 	bool			mode_4b;	/* Flash currently in 4b mode */
 | 
 | 24 | 	struct flash_req	*cur_req;	/* Current request */
 | 
 | 25 | 	void			*smart_buf;	/* Buffer for smart writes */
 | 
 | 26 | };
 | 
 | 27 | 
 | 
 | 28 | bool libflash_debug;
 | 
 | 29 | 
 | 
 | 30 | int fl_read_stat(struct spi_flash_ctrl *ct, uint8_t *stat)
 | 
 | 31 | {
 | 
 | 32 | 	return ct->cmd_rd(ct, CMD_RDSR, false, 0, stat, 1);
 | 
 | 33 | }
 | 
 | 34 | 
 | 
 | 35 | static void fl_micron_status(struct spi_flash_ctrl *ct)
 | 
 | 36 | {
 | 
 | 37 | 	uint8_t flst;
 | 
 | 38 | 
 | 
 | 39 | 	/*
 | 
 | 40 | 	 * After a success status on a write or erase, we
 | 
 | 41 | 	 * need to do that command or some chip variants will
 | 
 | 42 | 	 * lock
 | 
 | 43 | 	 */
 | 
 | 44 | 	ct->cmd_rd(ct, CMD_MIC_RDFLST, false, 0, &flst, 1);
 | 
 | 45 | }
 | 
 | 46 | 
 | 
 | 47 | /* Synchronous write completion, probably need a yield hook */
 | 
 | 48 | int fl_sync_wait_idle(struct spi_flash_ctrl *ct)
 | 
 | 49 | {
 | 
 | 50 | 	uint8_t stat;
 | 
 | 51 | 	int rc;
 | 
 | 52 | 
 | 
 | 53 | 	/* XXX Add timeout */
 | 
 | 54 | 	for (;;) {
 | 
 | 55 | 		rc = fl_read_stat(ct, &stat);
 | 
 | 56 | 		if (rc) return rc;
 | 
 | 57 | 		if (!(stat & STAT_WIP)) {
 | 
 | 58 | 			if (ct->finfo->flags & FL_MICRON_BUGS)
 | 
 | 59 | 				fl_micron_status(ct);
 | 
 | 60 | 			return 0;
 | 
 | 61 | 		}
 | 
 | 62 | 	}
 | 
 | 63 | 	/* return FLASH_ERR_WIP_TIMEOUT; */
 | 
 | 64 | }
 | 
 | 65 | 
 | 
 | 66 | /* Exported for internal use */
 | 
 | 67 | int fl_wren(struct spi_flash_ctrl *ct)
 | 
 | 68 | {
 | 
 | 69 | 	int i, rc;
 | 
 | 70 | 	uint8_t stat;
 | 
 | 71 | 
 | 
 | 72 | 	/* Some flashes need it to be hammered */
 | 
 | 73 | 	for (i = 0; i < 1000; i++) {
 | 
 | 74 | 		rc = ct->cmd_wr(ct, CMD_WREN, false, 0, NULL, 0);
 | 
 | 75 | 		if (rc) return rc;
 | 
 | 76 | 		rc = fl_read_stat(ct, &stat);
 | 
 | 77 | 		if (rc) return rc;
 | 
 | 78 | 		if (stat & STAT_WIP) {
 | 
 | 79 | 			FL_ERR("LIBFLASH: WREN has WIP status set !\n");
 | 
 | 80 | 			rc = fl_sync_wait_idle(ct);
 | 
 | 81 | 			if (rc)
 | 
 | 82 | 				return rc;
 | 
 | 83 | 			continue;
 | 
 | 84 | 		}
 | 
 | 85 | 		if (stat & STAT_WEN)
 | 
 | 86 | 			return 0;
 | 
 | 87 | 	}
 | 
 | 88 | 	return FLASH_ERR_WREN_TIMEOUT;
 | 
 | 89 | }
 | 
 | 90 | 
 | 
 | 91 | int flash_read(struct flash_chip *c, uint32_t pos, void *buf, uint32_t len)
 | 
 | 92 | {
 | 
 | 93 | 	struct spi_flash_ctrl *ct = c->ctrl;
 | 
 | 94 | 
 | 
 | 95 | 	/* XXX Add sanity/bound checking */
 | 
 | 96 | 
 | 
 | 97 | 	/*
 | 
 | 98 | 	 * If the controller supports read and either we are in 3b mode
 | 
 | 99 | 	 * or we are in 4b *and* the controller supports it, then do a
 | 
 | 100 | 	 * high level read.
 | 
 | 101 | 	 */
 | 
 | 102 | 	if ((!c->mode_4b || ct->set_4b) && ct->read)
 | 
 | 103 | 		return ct->read(ct, pos, buf, len);
 | 
 | 104 | 
 | 
 | 105 | 	/* Otherwise, go manual if supported */
 | 
 | 106 | 	if (!ct->cmd_rd)
 | 
 | 107 | 		return FLASH_ERR_CTRL_CMD_UNSUPPORTED;
 | 
 | 108 | 	return ct->cmd_rd(ct, CMD_READ, true, pos, buf, len);
 | 
 | 109 | }
 | 
 | 110 | 
 | 
 | 111 | static void fl_get_best_erase(struct flash_chip *c, uint32_t dst, uint32_t size,
 | 
 | 112 | 			      uint32_t *chunk, uint8_t *cmd)
 | 
 | 113 | {
 | 
 | 114 | 	/* Smaller than 32k, use 4k */
 | 
 | 115 | 	if ((dst & 0x7fff) || (size < 0x8000)) {
 | 
 | 116 | 		*chunk = 0x1000;
 | 
 | 117 | 		*cmd = CMD_SE;
 | 
 | 118 | 		return;
 | 
 | 119 | 	}
 | 
 | 120 | 	/* Smaller than 64k and 32k is supported, use it */
 | 
 | 121 | 	if ((c->info.flags & FL_ERASE_32K) &&
 | 
 | 122 | 	    ((dst & 0xffff) || (size < 0x10000))) {
 | 
 | 123 | 		*chunk = 0x8000;
 | 
 | 124 | 		*cmd = CMD_BE32K;
 | 
 | 125 | 		return;
 | 
 | 126 | 	}
 | 
 | 127 | 	/* If 64K is not supported, use whatever smaller size is */
 | 
 | 128 | 	if (!(c->info.flags & FL_ERASE_64K)) {
 | 
 | 129 | 		if (c->info.flags & FL_ERASE_32K) {
 | 
 | 130 | 			*chunk = 0x8000;
 | 
 | 131 | 			*cmd = CMD_BE32K;
 | 
 | 132 | 		} else {
 | 
 | 133 | 			*chunk = 0x1000;
 | 
 | 134 | 			*cmd = CMD_SE;
 | 
 | 135 | 		}
 | 
 | 136 | 		return;
 | 
 | 137 | 	}
 | 
 | 138 | 	/* Allright, let's go for 64K */
 | 
 | 139 | 	*chunk = 0x10000;
 | 
 | 140 | 	*cmd = CMD_BE;
 | 
 | 141 | }
 | 
 | 142 | 
 | 
 | 143 | int flash_erase(struct flash_chip *c, uint32_t dst, uint32_t size)
 | 
 | 144 | {
 | 
 | 145 | 	struct spi_flash_ctrl *ct = c->ctrl;
 | 
 | 146 | 	uint32_t chunk;
 | 
 | 147 | 	uint8_t cmd;
 | 
 | 148 | 	int rc;
 | 
 | 149 | 
 | 
 | 150 | 	/* Some sanity checking */
 | 
 | 151 | 	if (((dst + size) <= dst) || !size || (dst + size) > c->tsize)
 | 
 | 152 | 		return FLASH_ERR_PARM_ERROR;
 | 
 | 153 | 
 | 
 | 154 | 	/* Check boundaries fit erase blocks */
 | 
 | 155 | 	if ((dst | size) & c->min_erase_mask)
 | 
 | 156 | 		return FLASH_ERR_ERASE_BOUNDARY;
 | 
 | 157 | 
 | 
 | 158 | 	FL_DBG("LIBFLASH: Erasing 0x%08x..0%08x...\n", dst, dst + size);
 | 
 | 159 | 
 | 
 | 160 | 	/* Use controller erase if supported */
 | 
 | 161 | 	if (ct->erase)
 | 
 | 162 | 		return ct->erase(ct, dst, size);
 | 
 | 163 | 
 | 
 | 164 | 	/* Allright, loop as long as there's something to erase */
 | 
 | 165 | 	while(size) {
 | 
 | 166 | 		/* How big can we make it based on alignent & size */
 | 
 | 167 | 		fl_get_best_erase(c, dst, size, &chunk, &cmd);
 | 
 | 168 | 
 | 
 | 169 | 		/* Poke write enable */
 | 
 | 170 | 		rc = fl_wren(ct);
 | 
 | 171 | 		if (rc)
 | 
 | 172 | 			return rc;
 | 
 | 173 | 
 | 
 | 174 | 		/* Send erase command */
 | 
 | 175 | 		rc = ct->cmd_wr(ct, cmd, true, dst, NULL, 0);
 | 
 | 176 | 		if (rc)
 | 
 | 177 | 			return rc;
 | 
 | 178 | 
 | 
 | 179 | 		/* Wait for write complete */
 | 
 | 180 | 		rc = fl_sync_wait_idle(ct);
 | 
 | 181 | 		if (rc)
 | 
 | 182 | 			return rc;
 | 
 | 183 | 
 | 
 | 184 | 		size -= chunk;
 | 
 | 185 | 		dst += chunk;
 | 
 | 186 | 	}
 | 
 | 187 | 	return 0;
 | 
 | 188 | }
 | 
 | 189 | 
 | 
 | 190 | int flash_erase_chip(struct flash_chip *c)
 | 
 | 191 | {
 | 
 | 192 | 	struct spi_flash_ctrl *ct = c->ctrl;
 | 
 | 193 | 	int rc;
 | 
 | 194 | 
 | 
 | 195 | 	/* XXX TODO: Fallback to using normal erases */
 | 
 | 196 | 	if (!(c->info.flags & (FL_ERASE_CHIP|FL_ERASE_BULK)))
 | 
 | 197 | 		return FLASH_ERR_CHIP_ER_NOT_SUPPORTED;
 | 
 | 198 | 
 | 
 | 199 | 	FL_DBG("LIBFLASH: Erasing chip...\n");
 | 
 | 200 | 	
 | 
 | 201 | 	/* Use controller erase if supported */
 | 
 | 202 | 	if (ct->erase)
 | 
 | 203 | 		return ct->erase(ct, 0, 0xffffffff);
 | 
 | 204 | 
 | 
 | 205 | 	rc = fl_wren(ct);
 | 
 | 206 | 	if (rc) return rc;
 | 
 | 207 | 
 | 
 | 208 | 	if (c->info.flags & FL_ERASE_CHIP)
 | 
 | 209 | 		rc = ct->cmd_wr(ct, CMD_CE, false, 0, NULL, 0);
 | 
 | 210 | 	else
 | 
 | 211 | 		rc = ct->cmd_wr(ct, CMD_MIC_BULK_ERASE, false, 0, NULL, 0);
 | 
 | 212 | 	if (rc)
 | 
 | 213 | 		return rc;
 | 
 | 214 | 
 | 
 | 215 | 	/* Wait for write complete */
 | 
 | 216 | 	return fl_sync_wait_idle(ct);
 | 
 | 217 | }
 | 
 | 218 | 
 | 
 | 219 | static int fl_wpage(struct flash_chip *c, uint32_t dst, const void *src,
 | 
 | 220 | 		    uint32_t size)
 | 
 | 221 | {
 | 
 | 222 | 	struct spi_flash_ctrl *ct = c->ctrl;
 | 
 | 223 | 	int rc;
 | 
 | 224 | 
 | 
 | 225 | 	if (size < 1 || size > 0x100)
 | 
 | 226 | 		return FLASH_ERR_BAD_PAGE_SIZE;
 | 
 | 227 | 
 | 
 | 228 | 	rc = fl_wren(ct);
 | 
 | 229 | 	if (rc) return rc;
 | 
 | 230 | 
 | 
 | 231 | 	rc = ct->cmd_wr(ct, CMD_PP, true, dst, src, size);
 | 
 | 232 | 	if (rc)
 | 
 | 233 | 		return rc;
 | 
 | 234 | 
 | 
 | 235 | 	/* Wait for write complete */
 | 
 | 236 | 	return fl_sync_wait_idle(ct);
 | 
 | 237 | }
 | 
 | 238 | 
 | 
 | 239 | int flash_write(struct flash_chip *c, uint32_t dst, const void *src,
 | 
 | 240 | 		uint32_t size, bool verify)
 | 
 | 241 | {
 | 
 | 242 | 	struct spi_flash_ctrl *ct = c->ctrl;
 | 
 | 243 | 	uint32_t todo = size;
 | 
 | 244 | 	uint32_t d = dst;
 | 
 | 245 | 	const void *s = src;
 | 
 | 246 | 	uint8_t vbuf[0x100];
 | 
 | 247 | 	int rc;	
 | 
 | 248 | 
 | 
 | 249 | 	/* Some sanity checking */
 | 
 | 250 | 	if (((dst + size) <= dst) || !size || (dst + size) > c->tsize)
 | 
 | 251 | 		return FLASH_ERR_PARM_ERROR;
 | 
 | 252 | 
 | 
 | 253 | 	FL_DBG("LIBFLASH: Writing to 0x%08x..0%08x...\n", dst, dst + size);
 | 
 | 254 | 
 | 
 | 255 | 	/*
 | 
 | 256 | 	 * If the controller supports write and either we are in 3b mode
 | 
 | 257 | 	 * or we are in 4b *and* the controller supports it, then do a
 | 
 | 258 | 	 * high level write.
 | 
 | 259 | 	 */
 | 
 | 260 | 	if ((!c->mode_4b || ct->set_4b) && ct->write) {
 | 
 | 261 | 		rc = ct->write(ct, dst, src, size);
 | 
 | 262 | 		if (rc)
 | 
 | 263 | 			return rc;
 | 
 | 264 | 		goto writing_done;
 | 
 | 265 | 	}
 | 
 | 266 | 
 | 
 | 267 | 	/* Otherwise, go manual if supported */
 | 
 | 268 | 	if (!ct->cmd_wr)
 | 
 | 269 | 		return FLASH_ERR_CTRL_CMD_UNSUPPORTED;
 | 
 | 270 | 
 | 
 | 271 | 	/* Iterate for each page to write */
 | 
 | 272 | 	while(todo) {
 | 
 | 273 | 		uint32_t chunk;
 | 
 | 274 | 
 | 
 | 275 | 		/* Handle misaligned start */
 | 
 | 276 | 		chunk = 0x100 - (d & 0xff);
 | 
 | 277 | 		if (chunk > 0x100)
 | 
 | 278 | 			chunk = 0x100;
 | 
 | 279 | 		if (chunk > todo)
 | 
 | 280 | 			chunk = todo;
 | 
 | 281 | 
 | 
 | 282 | 		rc = fl_wpage(c, d, s, chunk);
 | 
 | 283 | 		if (rc) return rc;
 | 
 | 284 | 		d += chunk;
 | 
 | 285 | 		s += chunk;
 | 
 | 286 | 		todo -= chunk;
 | 
 | 287 | 	}
 | 
 | 288 | 
 | 
 | 289 |  writing_done:
 | 
 | 290 | 	if (!verify)
 | 
 | 291 | 		return 0;
 | 
 | 292 | 
 | 
 | 293 | 	/* Verify */
 | 
 | 294 | 	FL_DBG("LIBFLASH: Verifying...\n");
 | 
 | 295 | 
 | 
 | 296 | 	while(size) {
 | 
 | 297 | 		uint32_t chunk;
 | 
 | 298 | 
 | 
 | 299 | 		chunk = sizeof(vbuf);
 | 
 | 300 | 		if (chunk > size)
 | 
 | 301 | 			chunk = size;
 | 
 | 302 | 		rc = flash_read(c, dst, vbuf, chunk);
 | 
 | 303 | 		if (rc) return rc;
 | 
 | 304 | 		if (memcmp(vbuf, src, chunk)) {
 | 
 | 305 | 			FL_ERR("LIBFLASH: Miscompare at 0x%08x\n", dst);
 | 
 | 306 | 			return FLASH_ERR_VERIFY_FAILURE;
 | 
 | 307 | 		}
 | 
 | 308 | 		dst += chunk;
 | 
 | 309 | 		src += chunk;
 | 
 | 310 | 		size -= chunk;
 | 
 | 311 | 	}
 | 
 | 312 | 	return 0;
 | 
 | 313 | }
 | 
 | 314 | 
 | 
 | 315 | enum sm_comp_res {
 | 
 | 316 | 	sm_no_change,
 | 
 | 317 | 	sm_need_write,
 | 
 | 318 | 	sm_need_erase,
 | 
 | 319 | };
 | 
 | 320 | 
 | 
 | 321 | static enum sm_comp_res flash_smart_comp(struct flash_chip *c,
 | 
 | 322 | 					 const void *src,
 | 
 | 323 | 					 uint32_t offset, uint32_t size)
 | 
 | 324 | {
 | 
 | 325 | 	uint8_t *b = c->smart_buf + offset;
 | 
 | 326 | 	const uint8_t *s = src;
 | 
 | 327 | 	bool is_same = true;
 | 
 | 328 | 	uint32_t i;
 | 
 | 329 | 
 | 
 | 330 | 	/* SRC DEST  NEED_ERASE
 | 
 | 331 | 	 *  0   1       0
 | 
 | 332 | 	 *  1   1       0
 | 
 | 333 |          *  0   0       0
 | 
 | 334 |          *  1   0       1
 | 
 | 335 |          */
 | 
 | 336 | 	for (i = 0; i < size; i++) {
 | 
 | 337 | 		/* Any bit need to be set, need erase */
 | 
 | 338 | 		if (s[i] & ~b[i])
 | 
 | 339 | 			return sm_need_erase;
 | 
 | 340 | 		if (is_same && (b[i] != s[i]))
 | 
 | 341 | 			is_same = false;
 | 
 | 342 | 	}
 | 
 | 343 | 	return is_same ? sm_no_change : sm_need_write;
 | 
 | 344 | }
 | 
 | 345 | 
 | 
 | 346 | int flash_smart_write(struct flash_chip *c, uint32_t dst, const void *src,
 | 
 | 347 | 		      uint32_t size)
 | 
 | 348 | {
 | 
 | 349 | 	uint32_t er_size = c->min_erase_mask + 1;
 | 
 | 350 | 	uint32_t end = dst + size;
 | 
 | 351 | 	int rc;	
 | 
 | 352 | 
 | 
 | 353 | 	/* Some sanity checking */
 | 
 | 354 | 	if (end <= dst || !size || end > c->tsize) {
 | 
 | 355 | 		FL_DBG("LIBFLASH: Smart write param error\n");
 | 
 | 356 | 		return FLASH_ERR_PARM_ERROR;
 | 
 | 357 | 	}
 | 
 | 358 | 
 | 
 | 359 | 	FL_DBG("LIBFLASH: Smart writing to 0x%08x..0%08x...\n",
 | 
 | 360 | 	       dst, dst + size);
 | 
 | 361 | 
 | 
 | 362 | 	/* As long as we have something to write ... */
 | 
 | 363 | 	while(dst < end) {
 | 
 | 364 | 		uint32_t page, off, chunk;
 | 
 | 365 | 		enum sm_comp_res sr;
 | 
 | 366 | 
 | 
 | 367 | 		/* Figure out which erase page we are in and read it */
 | 
 | 368 | 		page = dst & ~c->min_erase_mask;
 | 
 | 369 | 		off = dst & c->min_erase_mask;
 | 
 | 370 | 		FL_DBG("LIBFLASH:   reading page 0x%08x..0x%08x...",
 | 
 | 371 | 		       page, page + er_size);
 | 
 | 372 | 		rc = flash_read(c, page, c->smart_buf, er_size);
 | 
 | 373 | 		if (rc) {
 | 
 | 374 | 			FL_DBG(" error %d!\n", rc);
 | 
 | 375 | 			return rc;
 | 
 | 376 | 		}
 | 
 | 377 | 
 | 
 | 378 | 		/* Locate the chunk of data we are working on */
 | 
 | 379 | 		chunk = er_size - off;
 | 
 | 380 | 		if (size < chunk)
 | 
 | 381 | 			chunk = size;
 | 
 | 382 | 
 | 
 | 383 | 		/* Compare against what we are writing and ff */
 | 
 | 384 | 		sr = flash_smart_comp(c, src, off, chunk);
 | 
 | 385 | 		switch(sr) {
 | 
 | 386 | 		case sm_no_change:
 | 
 | 387 | 			/* Identical, skip it */
 | 
 | 388 | 			FL_DBG(" same !\n");
 | 
 | 389 | 			break;
 | 
 | 390 | 		case sm_need_write:
 | 
 | 391 | 			/* Just needs writing over */
 | 
 | 392 | 			FL_DBG(" need write !\n");
 | 
 | 393 | 			rc = flash_write(c, dst, src, chunk, true);
 | 
 | 394 | 			if (rc) {
 | 
 | 395 | 				FL_DBG("LIBFLASH: Write error %d !\n", rc);
 | 
 | 396 | 				return rc;
 | 
 | 397 | 			}
 | 
 | 398 | 			break;
 | 
 | 399 | 		case sm_need_erase:
 | 
 | 400 | 			FL_DBG(" need erase !\n");
 | 
 | 401 | 			rc = flash_erase(c, page, er_size);
 | 
 | 402 | 			if (rc) {
 | 
 | 403 | 				FL_DBG("LIBFLASH: erase error %d !\n", rc);
 | 
 | 404 | 				return rc;
 | 
 | 405 | 			}
 | 
 | 406 | 			/* Then update the portion of the buffer and write the block */
 | 
 | 407 | 			memcpy(c->smart_buf + off, src, chunk);
 | 
 | 408 | 			rc = flash_write(c, page, c->smart_buf, er_size, true);
 | 
 | 409 | 			if (rc) {
 | 
 | 410 | 				FL_DBG("LIBFLASH: write error %d !\n", rc);
 | 
 | 411 | 				return rc;
 | 
 | 412 | 			}
 | 
 | 413 | 			break;
 | 
 | 414 | 		}
 | 
 | 415 | 		dst += chunk;
 | 
 | 416 | 		src += chunk;
 | 
 | 417 | 		size -= chunk;
 | 
 | 418 | 	}
 | 
 | 419 | 	return 0;
 | 
 | 420 | }
 | 
 | 421 | 
 | 
 | 422 | static int fl_chip_id(struct spi_flash_ctrl *ct, uint8_t *id_buf,
 | 
 | 423 | 		      uint32_t *id_size)
 | 
 | 424 | {
 | 
 | 425 | 	int rc;
 | 
 | 426 | 	uint8_t stat;
 | 
 | 427 | 
 | 
 | 428 | 	/* Check initial status */
 | 
 | 429 | 	rc = fl_read_stat(ct, &stat);
 | 
 | 430 | 	if (rc)
 | 
 | 431 | 		return rc;
 | 
 | 432 | 
 | 
 | 433 | 	/* If stuck writing, wait for idle */
 | 
 | 434 | 	if (stat & STAT_WIP) {
 | 
 | 435 | 		FL_ERR("LIBFLASH: Flash in writing state ! Waiting...\n");
 | 
 | 436 | 		rc = fl_sync_wait_idle(ct);
 | 
 | 437 | 		if (rc)
 | 
 | 438 | 			return rc;
 | 
 | 439 | 	} else
 | 
 | 440 | 		FL_DBG("LIBFLASH: Init status: %02x\n", stat);
 | 
 | 441 | 
 | 
 | 442 | 	/* Fallback to get ID manually */
 | 
 | 443 | 	rc = ct->cmd_rd(ct, CMD_RDID, false, 0, id_buf, 3);
 | 
 | 444 | 	if (rc)
 | 
 | 445 | 		return rc;
 | 
 | 446 | 	*id_size = 3;
 | 
 | 447 | 
 | 
 | 448 | 	return 0;
 | 
 | 449 | }
 | 
 | 450 | 
 | 
 | 451 | static int flash_identify(struct flash_chip *c)
 | 
 | 452 | {
 | 
 | 453 | 	struct spi_flash_ctrl *ct = c->ctrl;
 | 
 | 454 | 	const struct flash_info *info;
 | 
 | 455 | 	uint32_t iid, id_size;
 | 
 | 456 | #define MAX_ID_SIZE	16
 | 
 | 457 | 	uint8_t id[MAX_ID_SIZE];
 | 
 | 458 | 	int rc, i;
 | 
 | 459 | 
 | 
 | 460 | 	if (ct->chip_id) {
 | 
 | 461 | 		/* High level controller interface */
 | 
 | 462 | 		id_size = MAX_ID_SIZE;
 | 
 | 463 | 		rc = ct->chip_id(ct, id, &id_size);
 | 
 | 464 | 	} else
 | 
 | 465 | 		rc = fl_chip_id(ct, id, &id_size);
 | 
 | 466 | 	if (rc)
 | 
 | 467 | 		return rc;
 | 
 | 468 | 	if (id_size < 3)
 | 
 | 469 | 		return FLASH_ERR_CHIP_UNKNOWN;
 | 
 | 470 | 
 | 
 | 471 | 	/* Convert to a dword for lookup */
 | 
 | 472 | 	iid = id[0];
 | 
 | 473 | 	iid = (iid << 8) | id[1];
 | 
 | 474 | 	iid = (iid << 8) | id[2];
 | 
 | 475 | 
 | 
 | 476 | 	FL_DBG("LIBFLASH: Flash ID: %02x.%02x.%02x (%06x)\n",
 | 
 | 477 | 	       id[0], id[1], id[2], iid);
 | 
 | 478 | 
 | 
 | 479 | 	/* Lookup in flash_info */
 | 
 | 480 | 	for (i = 0; i < ARRAY_SIZE(flash_info); i++) {
 | 
 | 481 | 		info = &flash_info[i];
 | 
 | 482 | 		if (info->id == iid)
 | 
 | 483 | 			break;		
 | 
 | 484 | 	}
 | 
 | 485 | 	if (info->id != iid)
 | 
 | 486 | 		return FLASH_ERR_CHIP_UNKNOWN;
 | 
 | 487 | 
 | 
 | 488 | 	c->info = *info;
 | 
 | 489 | 	c->tsize = info->size;
 | 
 | 490 | 	ct->finfo = &c->info;
 | 
 | 491 | 
 | 
 | 492 | 	/*
 | 
 | 493 | 	 * Let controller know about our settings and possibly
 | 
 | 494 | 	 * override them
 | 
 | 495 | 	 */
 | 
 | 496 | 	if (ct->setup) {
 | 
 | 497 | 		rc = ct->setup(ct, &c->tsize);
 | 
 | 498 | 		if (rc)
 | 
 | 499 | 			return rc;
 | 
 | 500 | 	}
 | 
 | 501 | 
 | 
 | 502 | 	/* Calculate min erase granularity */
 | 
 | 503 | 	if (c->info.flags & FL_ERASE_4K)
 | 
 | 504 | 		c->min_erase_mask = 0xfff;
 | 
 | 505 | 	else if (c->info.flags & FL_ERASE_32K)
 | 
 | 506 | 		c->min_erase_mask = 0x7fff;
 | 
 | 507 | 	else if (c->info.flags & FL_ERASE_64K)
 | 
 | 508 | 		c->min_erase_mask = 0xffff;
 | 
 | 509 | 	else {
 | 
 | 510 | 		/* No erase size ? oops ... */
 | 
 | 511 | 		FL_ERR("LIBFLASH: No erase sizes !\n");
 | 
 | 512 | 		return FLASH_ERR_CTRL_CONFIG_MISMATCH;
 | 
 | 513 | 	}
 | 
 | 514 | 
 | 
 | 515 | 	FL_DBG("LIBFLASH: Found chip %s size %dM erase granule: %dK\n",
 | 
 | 516 | 	       c->info.name, c->tsize >> 20, (c->min_erase_mask + 1) >> 10);
 | 
 | 517 | 
 | 
 | 518 | 	return 0;
 | 
 | 519 | }
 | 
 | 520 | 
 | 
 | 521 | static int flash_set_4b(struct flash_chip *c, bool enable)
 | 
 | 522 | {
 | 
 | 523 | 	struct spi_flash_ctrl *ct = c->ctrl;
 | 
 | 524 | 	int rc;
 | 
 | 525 | 
 | 
 | 526 | 	/* Some flash chips want this */
 | 
 | 527 | 	rc = fl_wren(ct);
 | 
 | 528 | 	if (rc) {
 | 
 | 529 | 		FL_ERR("LIBFLASH: Error %d enabling write for set_4b\n", rc);
 | 
 | 530 | 		/* Ignore the error & move on (could be wrprotect chip) */
 | 
 | 531 | 	}
 | 
 | 532 | 
 | 
 | 533 | 	/* Ignore error in case chip is write protected */
 | 
 | 534 | 
 | 
 | 535 | 	return ct->cmd_wr(ct, enable ? CMD_EN4B : CMD_EX4B, false, 0, NULL, 0);
 | 
 | 536 | }
 | 
 | 537 | 
 | 
 | 538 | int flash_force_4b_mode(struct flash_chip *c, bool enable_4b)
 | 
 | 539 | {
 | 
 | 540 | 	struct spi_flash_ctrl *ct = c->ctrl;
 | 
 | 541 | 	int rc;
 | 
 | 542 | 
 | 
 | 543 | 	/*
 | 
 | 544 | 	 * We only allow force 4b if both controller and flash do 4b
 | 
 | 545 | 	 * as this is mainly used if a 3rd party tries to directly
 | 
 | 546 | 	 * access a direct mapped read region
 | 
 | 547 | 	 */
 | 
 | 548 | 	if (enable_4b && !((c->info.flags & FL_CAN_4B) && ct->set_4b))
 | 
 | 549 | 		return FLASH_ERR_4B_NOT_SUPPORTED;
 | 
 | 550 | 
 | 
 | 551 | 	/* Only send to flash directly on controllers that implement
 | 
 | 552 | 	 * the low level callbacks
 | 
 | 553 | 	 */
 | 
 | 554 | 	if (ct->cmd_wr) {
 | 
 | 555 | 		rc = flash_set_4b(c, enable_4b);
 | 
 | 556 | 		if (rc)
 | 
 | 557 | 			return rc;
 | 
 | 558 | 	}
 | 
 | 559 | 
 | 
 | 560 | 	/* Then inform the controller */
 | 
 | 561 | 	if (ct->set_4b)
 | 
 | 562 | 		rc = ct->set_4b(ct, enable_4b);
 | 
 | 563 | 	return rc;
 | 
 | 564 | }
 | 
 | 565 | 
 | 
 | 566 | static int flash_configure(struct flash_chip *c)
 | 
 | 567 | {
 | 
 | 568 | 	struct spi_flash_ctrl *ct = c->ctrl;
 | 
 | 569 | 	int rc;
 | 
 | 570 | 
 | 
 | 571 | 	/* Crop flash size if necessary */
 | 
 | 572 | 	if (c->tsize > 0x01000000 && !(c->info.flags & FL_CAN_4B)) {
 | 
 | 573 | 		FL_ERR("LIBFLASH: Flash chip cropped to 16M, no 4b mode\n");
 | 
 | 574 | 		c->tsize = 0x01000000;
 | 
 | 575 | 	}
 | 
 | 576 | 
 | 
 | 577 | 	/* If flash chip > 16M, enable 4b mode */
 | 
 | 578 | 	if (c->tsize > 0x01000000) {
 | 
 | 579 | 		FL_DBG("LIBFLASH: Flash >16MB, enabling 4B mode...\n");
 | 
 | 580 | 
 | 
 | 581 | 		/* Set flash to 4b mode if we can */
 | 
 | 582 | 		if (ct->cmd_wr) {
 | 
 | 583 | 			rc = flash_set_4b(c, true);
 | 
 | 584 | 			if (rc) {
 | 
 | 585 | 				FL_ERR("LIBFLASH: Failed to set flash 4b mode\n");
 | 
 | 586 | 				return rc;
 | 
 | 587 | 			}
 | 
 | 588 | 		}
 | 
 | 589 | 
 | 
 | 590 | 
 | 
 | 591 | 		/* Set controller to 4b mode if supported */
 | 
 | 592 | 		if (ct->set_4b) {
 | 
 | 593 | 			FL_DBG("LIBFLASH: Enabling controller 4B mode...\n");
 | 
 | 594 | 			rc = ct->set_4b(ct, true);
 | 
 | 595 | 			if (rc) {
 | 
 | 596 | 				FL_ERR("LIBFLASH: Failed"
 | 
 | 597 | 				       " to set controller 4b mode\n");
 | 
 | 598 | 				return rc;
 | 
 | 599 | 			}
 | 
 | 600 | 		}
 | 
 | 601 | 	} else {
 | 
 | 602 | 		FL_DBG("LIBFLASH: Flash <=16MB, disabling 4B mode...\n");
 | 
 | 603 | 
 | 
 | 604 | 		/*
 | 
 | 605 | 		 * If flash chip supports 4b mode, make sure we disable
 | 
 | 606 | 		 * it in case it was left over by the previous user
 | 
 | 607 | 		 */
 | 
 | 608 | 		if (c->info.flags & FL_CAN_4B) {
 | 
 | 609 | 			rc = flash_set_4b(c, false);
 | 
 | 610 | 			if (rc) {
 | 
 | 611 | 				FL_ERR("LIBFLASH: Failed to"
 | 
 | 612 | 				       " clear flash 4b mode\n");
 | 
 | 613 | 				return rc;
 | 
 | 614 | 			}
 | 
 | 615 | 		}
 | 
 | 616 | 
 | 
 | 617 | 		/* Set controller to 3b mode if mode switch is supported */
 | 
 | 618 | 		if (ct->set_4b) {
 | 
 | 619 | 			FL_DBG("LIBFLASH: Disabling controller 4B mode...\n");
 | 
 | 620 | 			rc = ct->set_4b(ct, false);
 | 
 | 621 | 			if (rc) {
 | 
 | 622 | 				FL_ERR("LIBFLASH: Failed to"
 | 
 | 623 | 				       " clear controller 4b mode\n");
 | 
 | 624 | 				return rc;
 | 
 | 625 | 			}
 | 
 | 626 | 		}
 | 
 | 627 | 	}
 | 
 | 628 | 	return 0;
 | 
 | 629 | }
 | 
 | 630 | 
 | 
 | 631 | int flash_get_info(struct flash_chip *chip, const char **name,
 | 
 | 632 | 		   uint32_t *total_size, uint32_t *erase_granule)
 | 
 | 633 | {
 | 
 | 634 | 	if (name)
 | 
 | 635 | 		*name = chip->info.name;
 | 
 | 636 | 	if (total_size)
 | 
 | 637 | 		*total_size = chip->tsize;
 | 
 | 638 | 	if (erase_granule)
 | 
 | 639 | 		*erase_granule = chip->min_erase_mask + 1;
 | 
 | 640 | 	return 0;
 | 
 | 641 | }
 | 
 | 642 | 
 | 
 | 643 | int flash_init(struct spi_flash_ctrl *ctrl, struct flash_chip **flash)
 | 
 | 644 | {
 | 
 | 645 | 	struct flash_chip *c;
 | 
 | 646 | 	int rc;
 | 
 | 647 | 
 | 
 | 648 | 	*flash = NULL;
 | 
 | 649 | 	c = malloc(sizeof(struct flash_chip));
 | 
 | 650 | 	if (!c)
 | 
 | 651 | 		return FLASH_ERR_MALLOC_FAILED;
 | 
 | 652 | 	memset(c, 0, sizeof(*c));
 | 
 | 653 | 	c->ctrl = ctrl;
 | 
 | 654 | 
 | 
 | 655 | 	rc = flash_identify(c);
 | 
 | 656 | 	if (rc) {
 | 
 | 657 | 		FL_ERR("LIBFLASH: Flash identification failed\n");
 | 
 | 658 | 		goto bail;
 | 
 | 659 | 	}
 | 
 | 660 | 	c->smart_buf = malloc(c->min_erase_mask + 1);
 | 
 | 661 | 	if (!c->smart_buf) {
 | 
 | 662 | 		FL_ERR("LIBFLASH: Failed to allocate smart buffer !\n");
 | 
 | 663 | 		rc = FLASH_ERR_MALLOC_FAILED;
 | 
 | 664 | 		goto bail;
 | 
 | 665 | 	}
 | 
 | 666 | 	rc = flash_configure(c);
 | 
 | 667 | 	if (rc)
 | 
 | 668 | 		FL_ERR("LIBFLASH: Flash configuration failed\n");
 | 
 | 669 |  bail:
 | 
 | 670 | 	if (rc) {
 | 
 | 671 | 		free(c);
 | 
 | 672 | 		return rc;
 | 
 | 673 | 	}
 | 
 | 674 | 	*flash = c;
 | 
 | 675 | 	return 0;
 | 
 | 676 | }
 | 
 | 677 | 
 | 
 | 678 | void flash_exit(struct flash_chip *chip)
 | 
 | 679 | {
 | 
 | 680 | 	/* XXX Make sure we are idle etc... */
 | 
 | 681 | 	free(chip);
 | 
 | 682 | }
 | 
 | 683 | 
 |