Read/Write the MTD flash via Octeon Simple Executive

0

Cavium Octeon appliance has mtd0 to 5 flash present. I want to log/dump firmware/Simple Executive crash backtrace to one of the solid state storage/ flash in the appliance. For that I try to initialize the flash with simple executive helping function in cvmx-flash.c;

cvmx_flash_initialize();

but on boot up the initialize function in Simple Executive prints

cvmx-flash: No CFI chips found

The cvmx_flash_initialize() in cvmx-flash.c code is shared below;

void cvmx_flash_initialize(void){
int boot_region;
int chip_id = 0;

memset(flash_info, 0, sizeof(flash_info));

/* Loop through each boot bus chip select region */
for (boot_region=0; boot_region<MAX_NUM_FLASH_CHIPS; boot_region++)
{
    cvmx_mio_boot_reg_cfgx_t region_cfg;
    region_cfg.u64 = cvmx_read_csr(CVMX_MIO_BOOT_REG_CFG0 + boot_region*8);
    /* Only try chip select regions that are enabled. This assumes the
        bootloader already setup the flash */
    if (region_cfg.s.en)
    {

        /* Convert the hardware address to a pointer. Note that the bootbus,
            unlike memory, isn't 1:1 mapped in the simple exec */
        void *base_ptr = cvmx_phys_to_ptr((region_cfg.s.base<<16) | 0xffffffff80000000ull);

        if (__cvmx_flash_query_cfi(chip_id, base_ptr) == 0)
        {
            /* Valid CFI flash chip found */
            chip_id++;
        }
    }
}

if (chip_id == 0){
    cvmx_dprintf("cvmx-flash: No CFI chips found\n");

}}

The __cvmx_flash_query_cfi(chip_id, base_ptr) function fails in following QRY verification;

 /* Make sure we get the QRY response we should */
if ((__cvmx_flash_read_cmd(chip_id, 0x10) != 'Q') ||
    (__cvmx_flash_read_cmd(chip_id, 0x11) != 'R') ||
    (__cvmx_flash_read_cmd(chip_id, 0x12) != 'Y'))
{
    flash->base_ptr = NULL;
    return -1;
}

The __cvmx_flash_query_cfi(chip_id, base_ptr) complete function is shared below;

static int __cvmx_flash_query_cfi(int chip_id, void *base_ptr){
int region;
cvmx_flash_t *flash = flash_info + chip_id;

/* Set the minimum needed for the read and write primitives to work */
flash->base_ptr = base_ptr;
flash->is_16bit = 1;   /* FIXME: Currently assumes the chip is 16bits */

/* Put flash in CFI query mode */
__cvmx_flash_write_cmd(chip_id, 0x00, 0xf0); /* Reset the flash chip */
__cvmx_flash_write_cmd(chip_id, 0x55, 0x98);

/* Make sure we get the QRY response we should */
if ((__cvmx_flash_read_cmd(chip_id, 0x10) != 'Q') ||
    (__cvmx_flash_read_cmd(chip_id, 0x11) != 'R') ||
    (__cvmx_flash_read_cmd(chip_id, 0x12) != 'Y'))
{
    flash->base_ptr = NULL;
    return -1;
}

/* Read the 16bit vendor ID */
flash->vendor = __cvmx_flash_read_cmd16(chip_id, 0x13);

/* Read the write timeout. The timeout is microseconds(us) is 2^0x1f
    typically. The worst case is this value time 2^0x23 */
flash->write_timeout = 1ull << (__cvmx_flash_read_cmd(chip_id, 0x1f) +
                                __cvmx_flash_read_cmd(chip_id, 0x23));

/* Read the erase timeout. The timeout is milliseconds(ms) is 2^0x21
    typically. The worst case is this value time 2^0x25 */
flash->erase_timeout = 1ull << (__cvmx_flash_read_cmd(chip_id, 0x21) +
                                __cvmx_flash_read_cmd(chip_id, 0x25));

/* Get the flash size. This is 2^0x27 */
flash->size = 1<<__cvmx_flash_read_cmd(chip_id, 0x27);

/* Get the number of different sized block regions from 0x2c */
flash->num_regions = __cvmx_flash_read_cmd(chip_id, 0x2c);

int start_offset = 0;
/* Loop through all regions get information about each */
for (region=0; region<flash->num_regions; region++)
{
    cvmx_flash_region_t *rgn_ptr = flash->region + region;
    rgn_ptr->start_offset = start_offset;

    /* The number of blocks in each region is a 16 bit little endian
        endian field. It is encoded at 0x2d + region*4 as (blocks-1) */
    uint16_t blocks = __cvmx_flash_read_cmd16(chip_id, 0x2d + region*4);
    rgn_ptr->num_blocks =  1u + blocks;

    /* The size of each block is a 16 bit little endian endian field. It
        is encoded at 0x2d + region*4 + 2 as (size/256). Zero is a special
        case representing 128 */
    uint16_t size = __cvmx_flash_read_cmd16(chip_id, 0x2d + region*4 + 2);
    if (size == 0)
        rgn_ptr->block_size = 128;
    else
        rgn_ptr->block_size = 256u * size;

    start_offset += rgn_ptr->block_size * rgn_ptr->num_blocks;
}

/* Take the chip out of CFI query mode */
switch (flash_info[chip_id].vendor)
{
    case CFI_CMDSET_AMD_STANDARD:
        __cvmx_flash_write_cmd(chip_id, 0x00, 0xf0);
    case CFI_CMDSET_INTEL_STANDARD:
    case CFI_CMDSET_INTEL_EXTENDED:
        __cvmx_flash_write_cmd(chip_id, 0x00, 0xff);
        break;
}

/* Convert the timeouts to cycles */
flash->write_timeout *= cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000000;
flash->erase_timeout *= cvmx_clock_get_rate(CVMX_CLOCK_CORE) / 1000;

#if DEBUG
/* Print the information about the chip */
cvmx_dprintf("cvmx-flash: Base pointer:  %p\n"
       "            Vendor:        0x%04x\n"
       "            Size:          %d bytes\n"
       "            Num regions:   %d\n"
       "            Erase timeout: %llu cycles\n"
       "            Write timeout: %llu cycles\n",
       flash->base_ptr,
       (unsigned int)flash->vendor,
       flash->size,
       flash->num_regions,
       (unsigned long long)flash->erase_timeout,
       (unsigned long long)flash->write_timeout);

for (region=0; region<flash->num_regions; region++)
{
    cvmx_dprintf("            Region %d: offset 0x%x, %d blocks, %d bytes/block\n",
           region,
           flash->region[region].start_offset,
           flash->region[region].num_blocks,
           flash->region[region].block_size);
}
#endif

return 0;}

However on boot up the linux shows that it has mtd flash present with CFI conformant;

Bootbus flash: Setting flash for 256MB flash at 0x10000000 with 2 bank(s)

phys_mapped_flash: Found 1 x16 devices at 0x0 in 16-bit bank

phys_mapped_flash: Found 1 x16 devices at 0x8000000 in 16-bit bank

Amd/Fujitsu Extended Query Table at 0x0040 phys_mapped_flash: CFI does

not contain boot bank location. Assuming top. number of CFI chips: 2

cfi_cmdset_0002: Disabling erase-suspend-program due to code

brokenness. Creating 6 MTD partitions on "phys_mapped_flash":

0x000000000000-0x000000200000 : "FAILSAFE-BOOTLOADER"

0x000000200000-0x0000003e0000 : "NORMAL-BOOTLOADER"

0x0000003e0000-0x000000400000 : "BOOTLOADER-ENVIRONMENT"

0x000000400000-0x000002200000 : "LINUX-KERNEL"

0x000002200000-0x000007200000 : "LINUX-FS"

0x000007200000-0x000008000000 : "RESERVED-14M"

and the flinfo in u-boot displays that mtd flash is present with CFI conformant;

Bank # 1: CFI conformant flash (16 x 16) Size: 128 MB in 1024 Sectors AMD Standard command set, Manufacturer ID: 0x01, Device ID:

0x227E2228 Erase timeout: 4096 ms, write timeout: 1 ms Buffer

write timeout: 3 ms, buffer size: 64 bytes Sector Start Addresses:

B0000000 RO etc etc (lots of hex numbers displayed)

Bank # 2: CFI conformant flash (16 x 16) Size: 128 MB in 1024 Sectors

AMD Standard command set, Manufacturer ID: 0x01, Device ID: 0x227E2228

Erase timeout: 4096 ms, write timeout: 1 ms Buffer write timeout: 3 ms, buffer size: 64 bytes

Sector Start Addresses: B8000000 etc etc (lots of hex numbers displayed)

The mtd flash of the device is already being used by the u-boot and linux but how can I use the same solid state storage/flash with utility functions of cvmx-flash.c in bare metal simple executive firmware of Cavium Octeon for the said purpose (i.e dumping crash)? How octeon simple executive firmware can read/write the solid state storage/flash that is already successfully accessible by linux & uboot?

c
linux
linux-kernel
embedded
flash-memory
asked on Stack Overflow Jan 1, 2020 by neutrino • edited Apr 16, 2020 by marc_s

0 Answers

Nobody has answered this question yet.


User contributions licensed under CC BY-SA 3.0