1 /***********************license start***************
2 * Copyright (c) 2003-2008 Cavium Networks (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 Networks 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 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24 * AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25 * OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26 * RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27 * REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28 * DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29 * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30 * PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31 * POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE RISK ARISING OUT
32 * OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
35 * For any questions regarding licensing please contact marketing@caviumnetworks.com
37 ***********************license end**************************************/
47 * This file provides bootbus flash operations
49 * <hr>$Revision: 41586 $<hr>
54 #include "cvmx-config.h"
56 #include "cvmx-sysinfo.h"
57 #include "cvmx-spinlock.h"
58 #include "cvmx-flash.h"
60 #define MAX_NUM_FLASH_CHIPS 8 /* Maximum number of flash chips */
61 #define MAX_NUM_REGIONS 8 /* Maximum number of block regions per chip */
64 #define CFI_CMDSET_NONE 0
65 #define CFI_CMDSET_INTEL_EXTENDED 1
66 #define CFI_CMDSET_AMD_STANDARD 2
67 #define CFI_CMDSET_INTEL_STANDARD 3
68 #define CFI_CMDSET_AMD_EXTENDED 4
69 #define CFI_CMDSET_MITSU_STANDARD 256
70 #define CFI_CMDSET_MITSU_EXTENDED 257
71 #define CFI_CMDSET_SST 258
75 void * base_ptr; /**< Memory pointer to start of flash */
76 int is_16bit; /**< Chip is 16bits wide in 8bit mode */
77 uint16_t vendor; /**< Vendor ID of Chip */
78 int size; /**< Size of the chip in bytes */
79 uint64_t erase_timeout; /**< Erase timeout in cycles */
80 uint64_t write_timeout; /**< Write timeout in cycles */
81 int num_regions; /**< Number of block regions */
82 cvmx_flash_region_t region[MAX_NUM_REGIONS];
85 static CVMX_SHARED cvmx_flash_t flash_info[MAX_NUM_FLASH_CHIPS];
86 static CVMX_SHARED cvmx_spinlock_t flash_lock = CVMX_SPINLOCK_UNLOCKED_INITIALIZER;
91 * Read a byte from flash
93 * @param chip_id Chip to read from
94 * @param offset Offset into the chip
97 static uint8_t __cvmx_flash_read8(int chip_id, int offset)
99 return *(volatile uint8_t *)(flash_info[chip_id].base_ptr + offset);
105 * Read a byte from flash (for commands)
107 * @param chip_id Chip to read from
108 * @param offset Offset into the chip
111 static uint8_t __cvmx_flash_read_cmd(int chip_id, int offset)
113 if (flash_info[chip_id].is_16bit)
115 return __cvmx_flash_read8(chip_id, offset);
121 * Read 16bits from flash (for commands)
123 * @param chip_id Chip to read from
124 * @param offset Offset into the chip
127 static uint16_t __cvmx_flash_read_cmd16(int chip_id, int offset)
129 uint16_t v = __cvmx_flash_read_cmd(chip_id, offset);
130 v |= __cvmx_flash_read_cmd(chip_id, offset + 1)<<8;
137 * Write a byte to flash
139 * @param chip_id Chip to write to
140 * @param offset Offset into the chip
141 * @param data Value to write
143 static void __cvmx_flash_write8(int chip_id, int offset, uint8_t data)
145 volatile uint8_t *flash_ptr = (volatile uint8_t *)flash_info[chip_id].base_ptr;
146 flash_ptr[offset] = data;
152 * Write a byte to flash (for commands)
154 * @param chip_id Chip to write to
155 * @param offset Offset into the chip
156 * @param data Value to write
158 static void __cvmx_flash_write_cmd(int chip_id, int offset, uint8_t data)
160 volatile uint8_t *flash_ptr = (volatile uint8_t *)flash_info[chip_id].base_ptr;
161 flash_ptr[offset<<flash_info[chip_id].is_16bit] = data;
167 * Query a address and see if a CFI flash chip is there.
169 * @param chip_id Chip ID data to fill in if the chip is there
170 * @param base_ptr Memory pointer to the start address to query
171 * @return Zero on success, Negative on failure
173 static int __cvmx_flash_queury_cfi(int chip_id, void *base_ptr)
176 cvmx_flash_t *flash = flash_info + chip_id;
178 /* Set the minimum needed for the read and write primitives to work */
179 flash->base_ptr = base_ptr;
180 flash->is_16bit = 1; /* FIXME: Currently assumes the chip is 16bits */
182 /* Put flash in CFI query mode */
183 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
184 __cvmx_flash_write_cmd(chip_id, 0x55, 0x98);
186 /* Make sure we get the QRY response we should */
187 if ((__cvmx_flash_read_cmd(chip_id, 0x10) != 'Q') ||
188 (__cvmx_flash_read_cmd(chip_id, 0x11) != 'R') ||
189 (__cvmx_flash_read_cmd(chip_id, 0x12) != 'Y'))
191 flash->base_ptr = NULL;
195 /* Read the 16bit vendor ID */
196 flash->vendor = __cvmx_flash_read_cmd16(chip_id, 0x13);
198 /* Read the write timeout. The timeout is microseconds(us) is 2^0x1f
199 typically. The worst case is this value time 2^0x23 */
200 flash->write_timeout = 1ull << (__cvmx_flash_read_cmd(chip_id, 0x1f) +
201 __cvmx_flash_read_cmd(chip_id, 0x23));
203 /* Read the erase timeout. The timeout is milliseconds(ms) is 2^0x21
204 typically. The worst case is this value time 2^0x25 */
205 flash->erase_timeout = 1ull << (__cvmx_flash_read_cmd(chip_id, 0x21) +
206 __cvmx_flash_read_cmd(chip_id, 0x25));
208 /* Get the flash size. This is 2^0x27 */
209 flash->size = 1<<__cvmx_flash_read_cmd(chip_id, 0x27);
211 /* Get the number of different sized block regions from 0x2c */
212 flash->num_regions = __cvmx_flash_read_cmd(chip_id, 0x2c);
214 int start_offset = 0;
215 /* Loop through all regions get information about each */
216 for (region=0; region<flash->num_regions; region++)
218 cvmx_flash_region_t *rgn_ptr = flash->region + region;
219 rgn_ptr->start_offset = start_offset;
221 /* The number of blocks in each region is a 16 bit little endian
222 endian field. It is encoded at 0x2d + region*4 as (blocks-1) */
223 uint16_t blocks = __cvmx_flash_read_cmd16(chip_id, 0x2d + region*4);
224 rgn_ptr->num_blocks = 1u + blocks;
226 /* The size of each block is a 16 bit little endian endian field. It
227 is encoded at 0x2d + region*4 + 2 as (size/256). Zero is a special
228 case representing 128 */
229 uint16_t size = __cvmx_flash_read_cmd16(chip_id, 0x2d + region*4 + 2);
231 rgn_ptr->block_size = 128;
233 rgn_ptr->block_size = 256u * size;
235 start_offset += rgn_ptr->block_size * rgn_ptr->num_blocks;
238 /* Take the chip out of CFI query mode */
239 switch (flash_info[chip_id].vendor)
241 case CFI_CMDSET_AMD_STANDARD:
242 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0);
243 case CFI_CMDSET_INTEL_STANDARD:
244 case CFI_CMDSET_INTEL_EXTENDED:
245 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff);
249 /* Convert the timeouts to cycles */
250 flash->write_timeout *= cvmx_sysinfo_get()->cpu_clock_hz / 1000000;
251 flash->erase_timeout *= cvmx_sysinfo_get()->cpu_clock_hz / 1000;
254 /* Print the information about the chip */
255 cvmx_dprintf("cvmx-flash: Base pointer: %p\n"
259 " Erase timeout: %llu cycles\n"
260 " Write timeout: %llu cycles\n",
262 (unsigned int)flash->vendor,
265 (unsigned long long)flash->erase_timeout,
266 (unsigned long long)flash->write_timeout);
268 for (region=0; region<flash->num_regions; region++)
270 cvmx_dprintf(" Region %d: offset 0x%x, %d blocks, %d bytes/block\n",
272 flash->region[region].start_offset,
273 flash->region[region].num_blocks,
274 flash->region[region].block_size);
283 * Initialize the flash access library
285 void cvmx_flash_initialize(void)
290 memset(flash_info, 0, sizeof(flash_info));
292 /* Loop through each boot bus chip select region */
293 for (boot_region=0; boot_region<MAX_NUM_FLASH_CHIPS; boot_region++)
295 cvmx_mio_boot_reg_cfgx_t region_cfg;
296 region_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFG0 + boot_region*8);
297 /* Only try chip select regions that are enabled. This assumes the
298 bootloader already setup the flash */
301 /* Convert the hardware address to a pointer. Note that the bootbus,
302 unlike memory, isn't 1:1 mapped in the simple exec */
303 void *base_ptr = cvmx_phys_to_ptr((region_cfg.s.base<<16) | 0xffffffff80000000ull);
304 if (__cvmx_flash_queury_cfi(chip_id, base_ptr) == 0)
306 /* Valid CFI flash chip found */
313 cvmx_dprintf("cvmx-flash: No CFI chips found\n");
318 * Return a pointer to the flash chip
320 * @param chip_id Chip ID to return
321 * @return NULL if the chip doesn't exist
323 void *cvmx_flash_get_base(int chip_id)
325 return flash_info[chip_id].base_ptr;
330 * Return the number of erasable regions on the chip
332 * @param chip_id Chip to return info for
333 * @return Number of regions
335 int cvmx_flash_get_num_regions(int chip_id)
337 return flash_info[chip_id].num_regions;
342 * Return information about a flash chips region
344 * @param chip_id Chip to get info for
345 * @param region Region to get info for
346 * @return Region information
348 const cvmx_flash_region_t *cvmx_flash_get_region_info(int chip_id, int region)
350 return flash_info[chip_id].region + region;
355 * Erase a block on the flash chip
357 * @param chip_id Chip to erase a block on
358 * @param region Region to erase a block in
359 * @param block Block number to erase
360 * @return Zero on success. Negative on failure
362 int cvmx_flash_erase_block(int chip_id, int region, int block)
364 cvmx_spinlock_lock(&flash_lock);
366 cvmx_dprintf("cvmx-flash: Erasing chip %d, region %d, block %d\n",
367 chip_id, region, block);
370 int offset = flash_info[chip_id].region[region].start_offset +
371 block * flash_info[chip_id].region[region].block_size;
373 switch (flash_info[chip_id].vendor)
375 case CFI_CMDSET_AMD_STANDARD:
377 /* Send the erase sector command sequence */
378 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
379 __cvmx_flash_write_cmd(chip_id, 0x555, 0xaa);
380 __cvmx_flash_write_cmd(chip_id, 0x2aa, 0x55);
381 __cvmx_flash_write_cmd(chip_id, 0x555, 0x80);
382 __cvmx_flash_write_cmd(chip_id, 0x555, 0xaa);
383 __cvmx_flash_write_cmd(chip_id, 0x2aa, 0x55);
384 __cvmx_flash_write8(chip_id, offset, 0x30);
386 /* Loop checking status */
387 uint8_t status = __cvmx_flash_read8(chip_id, offset);
388 uint64_t start_cycle = cvmx_get_cycle();
391 /* Read the status and xor it with the old status so we can
392 find toggling bits */
393 uint8_t old_status = status;
394 status = __cvmx_flash_read8(chip_id, offset);
395 uint8_t toggle = status ^ old_status;
397 /* Check if the erase in progress bit is toggling */
400 /* Check hardware timeout */
403 /* Chip has signalled a timeout. Reread the status */
404 old_status = __cvmx_flash_read8(chip_id, offset);
405 status = __cvmx_flash_read8(chip_id, offset);
406 toggle = status ^ old_status;
408 /* Check if the erase in progress bit is toggling */
411 cvmx_dprintf("cvmx-flash: Hardware timeout erasing block\n");
412 cvmx_spinlock_unlock(&flash_lock);
416 break; /* Not toggling, erase complete */
420 break; /* Not toggling, erase complete */
422 if (cvmx_get_cycle() > start_cycle + flash_info[chip_id].erase_timeout)
424 cvmx_dprintf("cvmx-flash: Timeout erasing block\n");
425 cvmx_spinlock_unlock(&flash_lock);
430 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
431 cvmx_spinlock_unlock(&flash_lock);
434 case CFI_CMDSET_INTEL_STANDARD:
435 case CFI_CMDSET_INTEL_EXTENDED:
437 /* Send the erase sector command sequence */
438 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff); /* Reset the flash chip */
439 __cvmx_flash_write8(chip_id, offset, 0x20);
440 __cvmx_flash_write8(chip_id, offset, 0xd0);
442 /* Loop checking status */
443 uint8_t status = __cvmx_flash_read8(chip_id, offset);
444 uint64_t start_cycle = cvmx_get_cycle();
445 while ((status & 0x80) == 0)
447 if (cvmx_get_cycle() > start_cycle + flash_info[chip_id].erase_timeout)
449 cvmx_dprintf("cvmx-flash: Timeout erasing block\n");
450 cvmx_spinlock_unlock(&flash_lock);
453 status = __cvmx_flash_read8(chip_id, offset);
456 /* Check the final status */
459 cvmx_dprintf("cvmx-flash: Hardware failure erasing block\n");
460 cvmx_spinlock_unlock(&flash_lock);
464 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff); /* Reset the flash chip */
465 cvmx_spinlock_unlock(&flash_lock);
470 cvmx_dprintf("cvmx-flash: Unsupported flash vendor\n");
471 cvmx_spinlock_unlock(&flash_lock);
477 * Write a block on the flash chip
479 * @param chip_id Chip to write a block on
480 * @param region Region to write a block in
481 * @param block Block number to write
482 * @param data Data to write
483 * @return Zero on success. Negative on failure
485 int cvmx_flash_write_block(int chip_id, int region, int block, const void *data)
487 cvmx_spinlock_lock(&flash_lock);
489 cvmx_dprintf("cvmx-flash: Writing chip %d, region %d, block %d\n",
490 chip_id, region, block);
492 int offset = flash_info[chip_id].region[region].start_offset +
493 block * flash_info[chip_id].region[region].block_size;
494 int len = flash_info[chip_id].region[region].block_size;
495 const uint8_t *ptr = (const uint8_t *)data;
497 switch (flash_info[chip_id].vendor)
499 case CFI_CMDSET_AMD_STANDARD:
501 /* Loop through one byte at a time */
504 /* Send the program sequence */
505 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
506 __cvmx_flash_write_cmd(chip_id, 0x555, 0xaa);
507 __cvmx_flash_write_cmd(chip_id, 0x2aa, 0x55);
508 __cvmx_flash_write_cmd(chip_id, 0x555, 0xa0);
509 __cvmx_flash_write8(chip_id, offset, *ptr);
511 /* Loop polling for status */
512 uint64_t start_cycle = cvmx_get_cycle();
515 uint8_t status = __cvmx_flash_read8(chip_id, offset);
516 if (((status ^ *ptr) & (1<<7)) == 0)
517 break; /* Data matches, this byte is done */
518 else if (status & (1<<5))
520 /* Hardware timeout, recheck status */
521 status = __cvmx_flash_read8(chip_id, offset);
522 if (((status ^ *ptr) & (1<<7)) == 0)
523 break; /* Data matches, this byte is done */
526 cvmx_dprintf("cvmx-flash: Hardware write timeout\n");
527 cvmx_spinlock_unlock(&flash_lock);
532 if (cvmx_get_cycle() > start_cycle + flash_info[chip_id].write_timeout)
534 cvmx_dprintf("cvmx-flash: Timeout writing block\n");
535 cvmx_spinlock_unlock(&flash_lock);
540 /* Increment to the next byte */
545 __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
546 cvmx_spinlock_unlock(&flash_lock);
549 case CFI_CMDSET_INTEL_STANDARD:
550 case CFI_CMDSET_INTEL_EXTENDED:
552 cvmx_dprintf("%s:%d len=%d\n", __FUNCTION__, __LINE__, len);
553 /* Loop through one byte at a time */
556 /* Send the program sequence */
557 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff); /* Reset the flash chip */
558 __cvmx_flash_write8(chip_id, offset, 0x40);
559 __cvmx_flash_write8(chip_id, offset, *ptr);
561 /* Loop polling for status */
562 uint8_t status = __cvmx_flash_read8(chip_id, offset);
563 uint64_t start_cycle = cvmx_get_cycle();
564 while ((status & 0x80) == 0)
566 if (cvmx_get_cycle() > start_cycle + flash_info[chip_id].write_timeout)
568 cvmx_dprintf("cvmx-flash: Timeout writing block\n");
569 cvmx_spinlock_unlock(&flash_lock);
572 status = __cvmx_flash_read8(chip_id, offset);
575 /* Check the final status */
578 cvmx_dprintf("cvmx-flash: Hardware failure erasing block\n");
579 cvmx_spinlock_unlock(&flash_lock);
583 /* Increment to the next byte */
587 cvmx_dprintf("%s:%d\n", __FUNCTION__, __LINE__);
589 __cvmx_flash_write_cmd(chip_id, 0x00, 0xff); /* Reset the flash chip */
590 cvmx_spinlock_unlock(&flash_lock);
595 cvmx_dprintf("cvmx-flash: Unsupported flash vendor\n");
596 cvmx_spinlock_unlock(&flash_lock);
602 * Erase and write data to a flash
604 * @param address Memory address to write to
605 * @param data Data to write
606 * @param len Length of the data
607 * @return Zero on success. Negative on failure
609 int cvmx_flash_write(void *address, const void *data, int len)
613 /* Find which chip controls this address. Don't allow the write to span
615 for (chip_id=0; chip_id<MAX_NUM_FLASH_CHIPS; chip_id++)
617 if ((flash_info[chip_id].base_ptr <= address) &&
618 (flash_info[chip_id].base_ptr + flash_info[chip_id].size >= address + len))
622 if (chip_id == MAX_NUM_FLASH_CHIPS)
624 cvmx_dprintf("cvmx-flash: Unable to find chip that contains address %p\n", address);
628 cvmx_flash_t *flash = flash_info + chip_id;
630 /* Determine which block region we need to start writing to */
631 void *region_base = flash->base_ptr;
633 while (region_base + flash->region[region].num_blocks * flash->region[region].block_size <= address)
636 region_base = flash->base_ptr + flash->region[region].start_offset;
639 /* Determine which block in the region to start at */
640 int block = (address - region_base) / flash->region[region].block_size;
642 /* Require all writes to start on block boundries */
643 if (address != region_base + block*flash->region[region].block_size)
645 cvmx_dprintf("cvmx-flash: Write address not aligned on a block boundry\n");
649 /* Loop until we're out of data */
652 /* Erase the current block */
653 if (cvmx_flash_erase_block(chip_id, region, block))
655 /* Write the new data */
656 if (cvmx_flash_write_block(chip_id, region, block, data))
659 /* Increment to the next block */
660 data += flash->region[region].block_size;
661 len -= flash->region[region].block_size;
663 if (block >= flash->region[region].num_blocks)