1 /***********************license start***************
2 * Copyright (c) 2003-2010 Cavium Inc. (support@cavium.com). All rights
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * * Neither the name of Cavium Inc. nor the names of
19 * its contributors may be used to endorse or promote products
20 * derived from this software without specific prior written
23 * This Software, including technical data, may be subject to U.S. export control
24 * laws, including the U.S. Export Administration Act and its associated
25 * regulations, and may be subject to export or import regulations in other
28 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29 * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30 * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31 * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32 * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33 * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34 * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35 * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36 * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT OF USE OR
37 * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38 ***********************license end**************************************/
49 * This file provides bootbus flash operations
51 * <hr>$Revision: 70030 $<hr>
56 #include "cvmx-config.h"
58 #include "cvmx-sysinfo.h"
59 #include "cvmx-spinlock.h"
60 #include "cvmx-flash.h"
62 #define MAX_NUM_FLASH_CHIPS 8 /* Maximum number of flash chips */
63 #define MAX_NUM_REGIONS 8 /* Maximum number of block regions per chip */
66 #define CFI_CMDSET_NONE 0
67 #define CFI_CMDSET_INTEL_EXTENDED 1
68 #define CFI_CMDSET_AMD_STANDARD 2
69 #define CFI_CMDSET_INTEL_STANDARD 3
70 #define CFI_CMDSET_AMD_EXTENDED 4
71 #define CFI_CMDSET_MITSU_STANDARD 256
72 #define CFI_CMDSET_MITSU_EXTENDED 257
73 #define CFI_CMDSET_SST 258
77 void * base_ptr; /**< Memory pointer to start of flash */
78 int is_16bit; /**< Chip is 16bits wide in 8bit mode */
79 uint16_t vendor; /**< Vendor ID of Chip */
80 int size; /**< Size of the chip in bytes */
81 uint64_t erase_timeout; /**< Erase timeout in cycles */
82 uint64_t write_timeout; /**< Write timeout in cycles */
83 int num_regions; /**< Number of block regions */
84 cvmx_flash_region_t region[MAX_NUM_REGIONS];
87 static CVMX_SHARED cvmx_flash_t flash_info[MAX_NUM_FLASH_CHIPS];
88 static CVMX_SHARED cvmx_spinlock_t flash_lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER;
93 * Read a byte from flash
95 * @param chip_id Chip to read from
96 * @param offset Offset into the chip
99 static uint8_t __cvmx_flash_read8(int chip_id, int offset)
101 return *(volatile uint8_t *)(flash_info[chip_id].base_ptr + offset);
107 * Read a byte from flash (for commands)
109 * @param chip_id Chip to read from
110 * @param offset Offset into the chip
113 static uint8_t __cvmx_flash_read_cmd(int chip_id, int offset)
115 if (flash_info[chip_id].is_16bit)
117 return __cvmx_flash_read8(chip_id, offset);
123 * Read 16bits from flash (for commands)
125 * @param chip_id Chip to read from
126 * @param offset Offset into the chip
129 static uint16_t __cvmx_flash_read_cmd16(int chip_id, int offset)
131 uint16_t v = __cvmx_flash_read_cmd(chip_id, offset);
132 v |= __cvmx_flash_read_cmd(chip_id, offset + 1)<<8;
139 * Write a byte to flash
141 * @param chip_id Chip to write to
142 * @param offset Offset into the chip
143 * @param data Value to write
145 static void __cvmx_flash_write8(int chip_id, int offset, uint8_t data)
147 volatile uint8_t *flash_ptr = (volatile uint8_t *)flash_info[chip_id].base_ptr;
148 flash_ptr[offset] = data;
154 * Write a byte to flash (for commands)
156 * @param chip_id Chip to write to
157 * @param offset Offset into the chip
158 * @param data Value to write
160 static void __cvmx_flash_write_cmd(int chip_id, int offset, uint8_t data)
162 volatile uint8_t *flash_ptr = (volatile uint8_t *)flash_info[chip_id].base_ptr;
163 flash_ptr[offset<<flash_info[chip_id].is_16bit] = data;
169 * Query a address and see if a CFI flash chip is there.
171 * @param chip_id Chip ID data to fill in if the chip is there
172 * @param base_ptr Memory pointer to the start address to query
173 * @return Zero on success, Negative on failure
175 static int __cvmx_flash_queury_cfi(int chip_id, void *base_ptr)
178 cvmx_flash_t *flash = flash_info + chip_id;
180 /* Set the minimum needed for the read and write primitives to work */
181 flash->base_ptr = base_ptr;
182 flash->is_16bit = 1; /* FIXME: Currently assumes the chip is 16bits */
184 /* Put flash in CFI query mode */
185 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
186 __cvmx_flash_write_cmd(chip_id, 0x55, 0x98);
188 /* Make sure we get the QRY response we should */
189 if ((__cvmx_flash_read_cmd(chip_id, 0x10) != 'Q') ||
190 (__cvmx_flash_read_cmd(chip_id, 0x11) != 'R') ||
191 (__cvmx_flash_read_cmd(chip_id, 0x12) != 'Y'))
193 flash->base_ptr = NULL;
197 /* Read the 16bit vendor ID */
198 flash->vendor = __cvmx_flash_read_cmd16(chip_id, 0x13);
200 /* Read the write timeout. The timeout is microseconds(us) is 2^0x1f
201 typically. The worst case is this value time 2^0x23 */
202 flash->write_timeout = 1ull << (__cvmx_flash_read_cmd(chip_id, 0x1f) +
203 __cvmx_flash_read_cmd(chip_id, 0x23));
205 /* Read the erase timeout. The timeout is milliseconds(ms) is 2^0x21
206 typically. The worst case is this value time 2^0x25 */
207 flash->erase_timeout = 1ull << (__cvmx_flash_read_cmd(chip_id, 0x21) +
208 __cvmx_flash_read_cmd(chip_id, 0x25));
210 /* Get the flash size. This is 2^0x27 */
211 flash->size = 1<<__cvmx_flash_read_cmd(chip_id, 0x27);
213 /* Get the number of different sized block regions from 0x2c */
214 flash->num_regions = __cvmx_flash_read_cmd(chip_id, 0x2c);
216 int start_offset = 0;
217 /* Loop through all regions get information about each */
218 for (region=0; region<flash->num_regions; region++)
220 cvmx_flash_region_t *rgn_ptr = flash->region + region;
221 rgn_ptr->start_offset = start_offset;
223 /* The number of blocks in each region is a 16 bit little endian
224 endian field. It is encoded at 0x2d + region*4 as (blocks-1) */
225 uint16_t blocks = __cvmx_flash_read_cmd16(chip_id, 0x2d + region*4);
226 rgn_ptr->num_blocks = 1u + blocks;
228 /* The size of each block is a 16 bit little endian endian field. It
229 is encoded at 0x2d + region*4 + 2 as (size/256). Zero is a special
230 case representing 128 */
231 uint16_t size = __cvmx_flash_read_cmd16(chip_id, 0x2d + region*4 + 2);
233 rgn_ptr->block_size = 128;
235 rgn_ptr->block_size = 256u * size;
237 start_offset += rgn_ptr->block_size * rgn_ptr->num_blocks;
240 /* Take the chip out of CFI query mode */
241 switch (flash_info[chip_id].vendor)
243 case CFI_CMDSET_AMD_STANDARD:
244 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0);
245 case CFI_CMDSET_INTEL_STANDARD:
246 case CFI_CMDSET_INTEL_EXTENDED:
247 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff);
251 /* Convert the timeouts to cycles */
252 flash->write_timeout *= cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000000;
253 flash->erase_timeout *= cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;
256 /* Print the information about the chip */
257 cvmx_dprintf("cvmx-flash: Base pointer: %p\n"
261 " Erase timeout: %llu cycles\n"
262 " Write timeout: %llu cycles\n",
264 (unsigned int)flash->vendor,
267 (unsigned long long)flash->erase_timeout,
268 (unsigned long long)flash->write_timeout);
270 for (region=0; region<flash->num_regions; region++)
272 cvmx_dprintf(" Region %d: offset 0x%x, %d blocks, %d bytes/block\n",
274 flash->region[region].start_offset,
275 flash->region[region].num_blocks,
276 flash->region[region].block_size);
285 * Initialize the flash access library
287 void cvmx_flash_initialize(void)
292 memset(flash_info, 0, sizeof(flash_info));
294 /* Loop through each boot bus chip select region */
295 for (boot_region=0; boot_region<MAX_NUM_FLASH_CHIPS; boot_region++)
297 cvmx_mio_boot_reg_cfgx_t region_cfg;
298 region_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFG0 + boot_region*8);
299 /* Only try chip select regions that are enabled. This assumes the
300 bootloader already setup the flash */
303 /* Convert the hardware address to a pointer. Note that the bootbus,
304 unlike memory, isn't 1:1 mapped in the simple exec */
305 void *base_ptr = cvmx_phys_to_ptr((region_cfg.s.base<<16) | 0xffffffff80000000ull);
306 if (__cvmx_flash_queury_cfi(chip_id, base_ptr) == 0)
308 /* Valid CFI flash chip found */
315 cvmx_dprintf("cvmx-flash: No CFI chips found\n");
320 * Return a pointer to the flash chip
322 * @param chip_id Chip ID to return
323 * @return NULL if the chip doesn't exist
325 void *cvmx_flash_get_base(int chip_id)
327 return flash_info[chip_id].base_ptr;
332 * Return the number of erasable regions on the chip
334 * @param chip_id Chip to return info for
335 * @return Number of regions
337 int cvmx_flash_get_num_regions(int chip_id)
339 return flash_info[chip_id].num_regions;
344 * Return information about a flash chips region
346 * @param chip_id Chip to get info for
347 * @param region Region to get info for
348 * @return Region information
350 const cvmx_flash_region_t *cvmx_flash_get_region_info(int chip_id, int region)
352 return flash_info[chip_id].region + region;
357 * Erase a block on the flash chip
359 * @param chip_id Chip to erase a block on
360 * @param region Region to erase a block in
361 * @param block Block number to erase
362 * @return Zero on success. Negative on failure
364 int cvmx_flash_erase_block(int chip_id, int region, int block)
366 cvmx_spinlock_lock(&flash_lock);
368 cvmx_dprintf("cvmx-flash: Erasing chip %d, region %d, block %d\n",
369 chip_id, region, block);
372 int offset = flash_info[chip_id].region[region].start_offset +
373 block * flash_info[chip_id].region[region].block_size;
375 switch (flash_info[chip_id].vendor)
377 case CFI_CMDSET_AMD_STANDARD:
379 /* Send the erase sector command sequence */
380 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
381 __cvmx_flash_write_cmd(chip_id, 0x555, 0xaa);
382 __cvmx_flash_write_cmd(chip_id, 0x2aa, 0x55);
383 __cvmx_flash_write_cmd(chip_id, 0x555, 0x80);
384 __cvmx_flash_write_cmd(chip_id, 0x555, 0xaa);
385 __cvmx_flash_write_cmd(chip_id, 0x2aa, 0x55);
386 __cvmx_flash_write8(chip_id, offset, 0x30);
388 /* Loop checking status */
389 uint8_t status = __cvmx_flash_read8(chip_id, offset);
390 uint64_t start_cycle = cvmx_get_cycle();
393 /* Read the status and xor it with the old status so we can
394 find toggling bits */
395 uint8_t old_status = status;
396 status = __cvmx_flash_read8(chip_id, offset);
397 uint8_t toggle = status ^ old_status;
399 /* Check if the erase in progress bit is toggling */
402 /* Check hardware timeout */
405 /* Chip has signalled a timeout. Reread the status */
406 old_status = __cvmx_flash_read8(chip_id, offset);
407 status = __cvmx_flash_read8(chip_id, offset);
408 toggle = status ^ old_status;
410 /* Check if the erase in progress bit is toggling */
413 cvmx_dprintf("cvmx-flash: Hardware timeout erasing block\n");
414 cvmx_spinlock_unlock(&flash_lock);
418 break; /* Not toggling, erase complete */
422 break; /* Not toggling, erase complete */
424 if (cvmx_get_cycle() > start_cycle + flash_info[chip_id].erase_timeout)
426 cvmx_dprintf("cvmx-flash: Timeout erasing block\n");
427 cvmx_spinlock_unlock(&flash_lock);
432 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
433 cvmx_spinlock_unlock(&flash_lock);
436 case CFI_CMDSET_INTEL_STANDARD:
437 case CFI_CMDSET_INTEL_EXTENDED:
439 /* Send the erase sector command sequence */
440 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff); /* Reset the flash chip */
441 __cvmx_flash_write8(chip_id, offset, 0x20);
442 __cvmx_flash_write8(chip_id, offset, 0xd0);
444 /* Loop checking status */
445 uint8_t status = __cvmx_flash_read8(chip_id, offset);
446 uint64_t start_cycle = cvmx_get_cycle();
447 while ((status & 0x80) == 0)
449 if (cvmx_get_cycle() > start_cycle + flash_info[chip_id].erase_timeout)
451 cvmx_dprintf("cvmx-flash: Timeout erasing block\n");
452 cvmx_spinlock_unlock(&flash_lock);
455 status = __cvmx_flash_read8(chip_id, offset);
458 /* Check the final status */
461 cvmx_dprintf("cvmx-flash: Hardware failure erasing block\n");
462 cvmx_spinlock_unlock(&flash_lock);
466 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff); /* Reset the flash chip */
467 cvmx_spinlock_unlock(&flash_lock);
472 cvmx_dprintf("cvmx-flash: Unsupported flash vendor\n");
473 cvmx_spinlock_unlock(&flash_lock);
479 * Write a block on the flash chip
481 * @param chip_id Chip to write a block on
482 * @param region Region to write a block in
483 * @param block Block number to write
484 * @param data Data to write
485 * @return Zero on success. Negative on failure
487 int cvmx_flash_write_block(int chip_id, int region, int block, const void *data)
489 cvmx_spinlock_lock(&flash_lock);
491 cvmx_dprintf("cvmx-flash: Writing chip %d, region %d, block %d\n",
492 chip_id, region, block);
494 int offset = flash_info[chip_id].region[region].start_offset +
495 block * flash_info[chip_id].region[region].block_size;
496 int len = flash_info[chip_id].region[region].block_size;
497 const uint8_t *ptr = (const uint8_t *)data;
499 switch (flash_info[chip_id].vendor)
501 case CFI_CMDSET_AMD_STANDARD:
503 /* Loop through one byte at a time */
506 /* Send the program sequence */
507 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
508 __cvmx_flash_write_cmd(chip_id, 0x555, 0xaa);
509 __cvmx_flash_write_cmd(chip_id, 0x2aa, 0x55);
510 __cvmx_flash_write_cmd(chip_id, 0x555, 0xa0);
511 __cvmx_flash_write8(chip_id, offset, *ptr);
513 /* Loop polling for status */
514 uint64_t start_cycle = cvmx_get_cycle();
517 uint8_t status = __cvmx_flash_read8(chip_id, offset);
518 if (((status ^ *ptr) & (1<<7)) == 0)
519 break; /* Data matches, this byte is done */
520 else if (status & (1<<5))
522 /* Hardware timeout, recheck status */
523 status = __cvmx_flash_read8(chip_id, offset);
524 if (((status ^ *ptr) & (1<<7)) == 0)
525 break; /* Data matches, this byte is done */
528 cvmx_dprintf("cvmx-flash: Hardware write timeout\n");
529 cvmx_spinlock_unlock(&flash_lock);
534 if (cvmx_get_cycle() > start_cycle + flash_info[chip_id].write_timeout)
536 cvmx_dprintf("cvmx-flash: Timeout writing block\n");
537 cvmx_spinlock_unlock(&flash_lock);
542 /* Increment to the next byte */
547 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
548 cvmx_spinlock_unlock(&flash_lock);
551 case CFI_CMDSET_INTEL_STANDARD:
552 case CFI_CMDSET_INTEL_EXTENDED:
554 cvmx_dprintf("%s:%d len=%d\n", __FUNCTION__, __LINE__, len);
555 /* Loop through one byte at a time */
558 /* Send the program sequence */
559 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff); /* Reset the flash chip */
560 __cvmx_flash_write8(chip_id, offset, 0x40);
561 __cvmx_flash_write8(chip_id, offset, *ptr);
563 /* Loop polling for status */
564 uint8_t status = __cvmx_flash_read8(chip_id, offset);
565 uint64_t start_cycle = cvmx_get_cycle();
566 while ((status & 0x80) == 0)
568 if (cvmx_get_cycle() > start_cycle + flash_info[chip_id].write_timeout)
570 cvmx_dprintf("cvmx-flash: Timeout writing block\n");
571 cvmx_spinlock_unlock(&flash_lock);
574 status = __cvmx_flash_read8(chip_id, offset);
577 /* Check the final status */
580 cvmx_dprintf("cvmx-flash: Hardware failure erasing block\n");
581 cvmx_spinlock_unlock(&flash_lock);
585 /* Increment to the next byte */
589 cvmx_dprintf("%s:%d\n", __FUNCTION__, __LINE__);
591 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff); /* Reset the flash chip */
592 cvmx_spinlock_unlock(&flash_lock);
597 cvmx_dprintf("cvmx-flash: Unsupported flash vendor\n");
598 cvmx_spinlock_unlock(&flash_lock);
604 * Erase and write data to a flash
606 * @param address Memory address to write to
607 * @param data Data to write
608 * @param len Length of the data
609 * @return Zero on success. Negative on failure
611 int cvmx_flash_write(void *address, const void *data, int len)
615 /* Find which chip controls this address. Don't allow the write to span
617 for (chip_id=0; chip_id<MAX_NUM_FLASH_CHIPS; chip_id++)
619 if ((flash_info[chip_id].base_ptr <= address) &&
620 (flash_info[chip_id].base_ptr + flash_info[chip_id].size >= address + len))
624 if (chip_id == MAX_NUM_FLASH_CHIPS)
626 cvmx_dprintf("cvmx-flash: Unable to find chip that contains address %p\n", address);
630 cvmx_flash_t *flash = flash_info + chip_id;
632 /* Determine which block region we need to start writing to */
633 void *region_base = flash->base_ptr;
635 while (region_base + flash->region[region].num_blocks * flash->region[region].block_size <= address)
638 region_base = flash->base_ptr + flash->region[region].start_offset;
641 /* Determine which block in the region to start at */
642 int block = (address - region_base) / flash->region[region].block_size;
644 /* Require all writes to start on block boundries */
645 if (address != region_base + block*flash->region[region].block_size)
647 cvmx_dprintf("cvmx-flash: Write address not aligned on a block boundry\n");
651 /* Loop until we're out of data */
654 /* Erase the current block */
655 if (cvmx_flash_erase_block(chip_id, region, block))
657 /* Write the new data */
658 if (cvmx_flash_write_block(chip_id, region, block, data))
661 /* Increment to the next block */
662 data += flash->region[region].block_size;
663 len -= flash->region[region].block_size;
665 if (block >= flash->region[region].num_blocks)