mirror of
https://github.com/corundum/corundum.git
synced 2025-01-16 08:12:53 +08:00
Add firmware update utility
This commit is contained in:
parent
dd3374626f
commit
9ec0b71a1a
@ -15,7 +15,7 @@ mqnic-config: mqnic-config.c mqnic.c timespec.c
|
||||
mqnic-dump: mqnic-dump.c mqnic.c
|
||||
$(CC) $(CFLAGS) $^ -o $@
|
||||
|
||||
mqnic-fw: mqnic-fw.c mqnic.c
|
||||
mqnic-fw: mqnic-fw.c mqnic.c flash.c flash_spi.c flash_bpi.c fpga_id.c bitfile.c
|
||||
$(CC) $(CFLAGS) $^ -o $@
|
||||
|
||||
perout: perout.c timespec.c
|
||||
|
183
utils/bitfile.c
Normal file
183
utils/bitfile.c
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "bitfile.h"
|
||||
|
||||
struct bitfile *bitfile_create_from_file(const char *bit_file_name)
|
||||
{
|
||||
struct bitfile *bf;
|
||||
FILE *fp;
|
||||
char *buffer;
|
||||
char *data;
|
||||
size_t len;
|
||||
|
||||
fp = fopen(bit_file_name, "rb");
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
fprintf(stderr, "Failed to open file\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
len = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
buffer = calloc(len + sizeof(struct bitfile), 1);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate memory\n");
|
||||
goto fail_file;
|
||||
}
|
||||
|
||||
bf = (struct bitfile *)buffer;
|
||||
data = buffer + sizeof(struct bitfile);
|
||||
|
||||
if (fread(data, 1, len, fp) < len)
|
||||
{
|
||||
fprintf(stderr, "Error reading file\n");
|
||||
goto fail_buffer;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (bitfile_parse(bf, data, len))
|
||||
{
|
||||
fprintf(stderr, "Failed to parse bitfile\n");
|
||||
goto fail_buffer;
|
||||
}
|
||||
|
||||
return bf;
|
||||
|
||||
fail_buffer:
|
||||
free(buffer);
|
||||
fail_file:
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bitfile *bitfile_create_from_buffer(char *buffer, size_t len)
|
||||
{
|
||||
struct bitfile *bf;
|
||||
|
||||
bf = calloc(1, sizeof(struct bitfile));
|
||||
|
||||
if (!bf)
|
||||
{
|
||||
fprintf(stderr, "Failed to allocate memory\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bitfile_parse(bf, buffer, len))
|
||||
{
|
||||
fprintf(stderr, "Failed to parse bitfile\n");
|
||||
free(bf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bf;
|
||||
}
|
||||
|
||||
int bitfile_parse(struct bitfile *bf, char *buffer, size_t len)
|
||||
{
|
||||
char *ptr;
|
||||
size_t l;
|
||||
|
||||
ptr = buffer;
|
||||
|
||||
bf->header = ptr;
|
||||
|
||||
// drop unknown field
|
||||
l = be16toh(*((uint16_t *)ptr));
|
||||
ptr += 2+l;
|
||||
|
||||
// drop unknown field
|
||||
ptr += 2;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int field_type = *ptr;
|
||||
ptr += 1;
|
||||
|
||||
if (field_type == 'e')
|
||||
{
|
||||
l = be32toh(*((uint32_t *)ptr));
|
||||
bf->data_len = l;
|
||||
bf->data = ptr+4;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = be16toh(*((uint16_t *)ptr));
|
||||
ptr += 2;
|
||||
}
|
||||
|
||||
switch (field_type)
|
||||
{
|
||||
case 'a':
|
||||
bf->name = ptr;
|
||||
break;
|
||||
case 'b':
|
||||
bf->part = ptr;
|
||||
break;
|
||||
case 'c':
|
||||
bf->date = ptr;
|
||||
break;
|
||||
case 'd':
|
||||
bf->time = ptr;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown field type 0x%02x\n", field_type);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ptr += l;
|
||||
}
|
||||
|
||||
fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void bitfile_close(struct bitfile *bf)
|
||||
{
|
||||
if (bf)
|
||||
{
|
||||
free(bf);
|
||||
}
|
||||
}
|
||||
|
56
utils/bitfile.h
Normal file
56
utils/bitfile.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef BITFILE_H
|
||||
#define BITFILE_H
|
||||
|
||||
struct bitfile {
|
||||
char *header;
|
||||
char *name;
|
||||
char *part;
|
||||
char *date;
|
||||
char *time;
|
||||
|
||||
size_t data_len;
|
||||
char *data;
|
||||
};
|
||||
|
||||
struct bitfile *bitfile_create_from_file(const char *bit_file_name);
|
||||
|
||||
struct bitfile *bitfile_create_from_buffer(char *buffer, size_t len);
|
||||
|
||||
int bitfile_parse(struct bitfile *bf, char *buffer, size_t len);
|
||||
|
||||
void bitfile_close(struct bitfile *bf);
|
||||
|
||||
#endif // BITFILE_H
|
136
utils/flash.c
Normal file
136
utils/flash.c
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
extern const struct flash_driver spi_flash_driver;
|
||||
extern const struct flash_driver bpi_flash_driver;
|
||||
|
||||
struct flash_device *flash_open_spi(int data_width, volatile uint8_t *ctrl_reg)
|
||||
{
|
||||
struct flash_device *fdev;
|
||||
|
||||
if (!ctrl_reg)
|
||||
return NULL;
|
||||
|
||||
fdev = calloc(1, sizeof(struct flash_device));
|
||||
|
||||
if (!fdev)
|
||||
return NULL;
|
||||
|
||||
fdev->driver = &spi_flash_driver;
|
||||
|
||||
fdev->data_width = data_width;
|
||||
|
||||
fdev->ctrl_reg = ctrl_reg;
|
||||
|
||||
if (fdev->driver->init(fdev))
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
||||
return fdev;
|
||||
|
||||
err:
|
||||
flash_release(fdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct flash_device *flash_open_bpi(int data_width, volatile uint8_t *ctrl_reg, volatile uint8_t *addr_reg, volatile uint8_t *data_reg)
|
||||
{
|
||||
struct flash_device *fdev;
|
||||
|
||||
if (!ctrl_reg || !addr_reg || !data_reg)
|
||||
return NULL;
|
||||
|
||||
fdev = calloc(1, sizeof(struct flash_device));
|
||||
|
||||
if (!fdev)
|
||||
return NULL;
|
||||
|
||||
fdev->driver = &bpi_flash_driver;
|
||||
|
||||
fdev->data_width = data_width;
|
||||
|
||||
fdev->ctrl_reg = ctrl_reg;
|
||||
fdev->addr_reg = addr_reg;
|
||||
fdev->data_reg = data_reg;
|
||||
|
||||
if (fdev->driver->init(fdev))
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
|
||||
return fdev;
|
||||
|
||||
err:
|
||||
flash_release(fdev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void flash_release(struct flash_device *fdev)
|
||||
{
|
||||
if (!fdev)
|
||||
return;
|
||||
|
||||
fdev->driver->release(fdev);
|
||||
|
||||
free(fdev);
|
||||
}
|
||||
|
||||
int flash_read(struct flash_device *fdev, size_t addr, size_t len, void* dest)
|
||||
{
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
return fdev->driver->read(fdev, addr, len, dest);
|
||||
}
|
||||
|
||||
int flash_write(struct flash_device *fdev, size_t addr, size_t len, void* src)
|
||||
{
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
return fdev->driver->write(fdev, addr, len, src);
|
||||
}
|
||||
|
||||
int flash_erase(struct flash_device *fdev, size_t addr, size_t len)
|
||||
{
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
return fdev->driver->erase(fdev, addr, len);
|
||||
}
|
||||
|
96
utils/flash.h
Normal file
96
utils/flash.h
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef FLASH_H
|
||||
#define FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define FLASH_ERASE_REGIONS 2
|
||||
|
||||
struct flash_driver;
|
||||
struct flash_ops;
|
||||
|
||||
struct flash_erase_region_info {
|
||||
size_t block_count;
|
||||
size_t block_size;
|
||||
size_t region_start;
|
||||
size_t region_end;
|
||||
};
|
||||
|
||||
struct flash_device {
|
||||
const struct flash_driver *driver;
|
||||
const struct flash_ops *ops;
|
||||
|
||||
volatile uint8_t *ctrl_reg;
|
||||
volatile uint8_t *addr_reg;
|
||||
volatile uint8_t *data_reg;
|
||||
|
||||
size_t size;
|
||||
int data_width;
|
||||
|
||||
size_t write_buffer_size;
|
||||
size_t erase_block_size;
|
||||
|
||||
int protocol;
|
||||
int bulk_protocol;
|
||||
|
||||
int read_dummy_cycles;
|
||||
|
||||
int erase_region_count;
|
||||
struct flash_erase_region_info erase_region[FLASH_ERASE_REGIONS];
|
||||
};
|
||||
|
||||
struct flash_ops {
|
||||
void (*init)(struct flash_device *fdev);
|
||||
int (*sector_erase)(struct flash_device *fdev, size_t addr);
|
||||
int (*buffered_program)(struct flash_device *fdev, size_t addr, size_t len, void *src);
|
||||
};
|
||||
|
||||
struct flash_driver {
|
||||
int (*init)(struct flash_device *fdev);
|
||||
void (*release)(struct flash_device *fdev);
|
||||
int (*read)(struct flash_device *fdev, size_t addr, size_t len, void* dest);
|
||||
int (*write)(struct flash_device *fdev, size_t addr, size_t len, void* src);
|
||||
int (*erase)(struct flash_device *fdev, size_t addr, size_t len);
|
||||
};
|
||||
|
||||
struct flash_device *flash_open_spi(int data_width, volatile uint8_t *ctrl_reg);
|
||||
struct flash_device *flash_open_bpi(int data_width, volatile uint8_t *ctrl_reg, volatile uint8_t *addr_reg, volatile uint8_t *data_reg);
|
||||
void flash_release(struct flash_device *fdev);
|
||||
int flash_read(struct flash_device *fdev, size_t addr, size_t len, void* dest);
|
||||
int flash_write(struct flash_device *fdev, size_t addr, size_t len, void* src);
|
||||
int flash_erase(struct flash_device *fdev, size_t addr, size_t len);
|
||||
|
||||
#endif /* FLASH_H */
|
671
utils/flash_bpi.c
Normal file
671
utils/flash_bpi.c
Normal file
@ -0,0 +1,671 @@
|
||||
/*
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define reg_read32(reg) (*((volatile uint32_t *)(reg)))
|
||||
#define reg_write32(reg, val) (*((volatile uint32_t *)(reg))) = (val)
|
||||
|
||||
#define CFI_QUERY_ADDR 0x55
|
||||
#define CFI_QUERY_DATA 0x98
|
||||
#define CFI_READ_ARRAY 0xFF
|
||||
#define CFI_READ_ARRAY_ALT 0xF0
|
||||
#define CFI_ID_0 0x10
|
||||
#define CFI_ID_1 0x11
|
||||
#define CFI_ID_2 0x12
|
||||
#define CFI_PRI_CMD_SET_0 0x13
|
||||
#define CFI_PRI_CMD_SET_1 0x14
|
||||
#define CFI_DEVICE_SIZE 0x27
|
||||
#define CFI_WRITE_BUFFER_SIZE_0 0x2A
|
||||
#define CFI_WRITE_BUFFER_SIZE_1 0x2B
|
||||
#define CFI_ERASE_REGION_COUNT 0x2C
|
||||
#define CFI_ERASE_REGION_1_INFO_0 0x2D
|
||||
#define CFI_ERASE_REGION_1_INFO_1 0x2E
|
||||
#define CFI_ERASE_REGION_1_INFO_2 0x2F
|
||||
#define CFI_ERASE_REGION_1_INFO_3 0x30
|
||||
#define CFI_ERASE_REGION_2_INFO_0 0x31
|
||||
#define CFI_ERASE_REGION_2_INFO_1 0x32
|
||||
#define CFI_ERASE_REGION_2_INFO_2 0x33
|
||||
#define CFI_ERASE_REGION_2_INFO_3 0x34
|
||||
|
||||
#define BPI_INTEL_READ_ARRAY 0xFF
|
||||
#define BPI_INTEL_READ_STATUS_REG 0x70
|
||||
#define BPI_INTEL_READ_ID 0x90
|
||||
#define BPI_INTEL_CLEAR_STATUS_REG 0x50
|
||||
#define BPI_INTEL_READ_CONFIG_REG_SETUP 0x60
|
||||
#define BPI_INTEL_SET_READ_CONFIG_REG 0x03
|
||||
#define BPI_INTEL_BLOCK_LOCK_SETUP 0x60
|
||||
#define BPI_INTEL_BLOCK_LOCK 0x01
|
||||
#define BPI_INTEL_BLOCK_UNLOCK 0xD0
|
||||
#define BPI_INTEL_BLOCK_ERASE_SETUP 0x20
|
||||
#define BPI_INTEL_BLOCK_ERASE_CONFIRM 0xD0
|
||||
#define BPI_INTEL_BUFFERED_PROGRAM_SETUP 0xE8
|
||||
#define BPI_INTEL_BUFFERED_PROGRAM_CONFIRM 0xD0
|
||||
|
||||
#define BPI_AMD_UNLOCK_ADDR_1 0x555
|
||||
#define BPI_AMD_UNLOCK_DATA_1 0xAA
|
||||
#define BPI_AMD_UNLOCK_ADDR_2 0x2AA
|
||||
#define BPI_AMD_UNLOCK_DATA_2 0x55
|
||||
#define BPI_AMD_UNLOCK_BYPASS_ENTER_ADDR 0x555
|
||||
#define BPI_AMD_UNLOCK_BYPASS_ENTER_DATA 0x20
|
||||
#define BPI_AMD_UNLOCK_BYPASS_RESET_1 0x90
|
||||
#define BPI_AMD_UNLOCK_BYPASS_RESET_2 0x00
|
||||
#define BPI_AMD_BLOCK_ERASE_SETUP 0x80
|
||||
#define BPI_AMD_BLOCK_ERASE_CONFIRM 0x30
|
||||
#define BPI_AMD_BUFFERED_PROGRAM_SETUP 0x25
|
||||
#define BPI_AMD_BUFFERED_PROGRAM_CONFIRM 0x29
|
||||
#define BPI_AMD_READ_ARRAY 0xF0
|
||||
|
||||
#define BPI_MICRON_READ_ARRAY 0xFF
|
||||
#define BPI_MICRON_READ_STATUS_REG 0x70
|
||||
#define BPI_MICRON_READ_ID 0x90
|
||||
#define BPI_MICRON_CLEAR_STATUS_REG 0x50
|
||||
#define BPI_MICRON_READ_CONFIG_REG_SETUP 0x60
|
||||
#define BPI_MICRON_SET_READ_CONFIG_REG 0x03
|
||||
#define BPI_MICRON_BLOCK_LOCK_SETUP 0x60
|
||||
#define BPI_MICRON_BLOCK_LOCK 0x01
|
||||
#define BPI_MICRON_BLOCK_UNLOCK 0xD0
|
||||
#define BPI_MICRON_BLOCK_ERASE_SETUP 0x20
|
||||
#define BPI_MICRON_BLOCK_ERASE_CONFIRM 0xD0
|
||||
#define BPI_MICRON_BUFFERED_PROGRAM_SETUP 0xE9
|
||||
#define BPI_MICRON_BUFFERED_PROGRAM_CONFIRM 0xD0
|
||||
|
||||
#define FLASH_CE_N (1 << 0)
|
||||
#define FLASH_OE_N (1 << 1)
|
||||
#define FLASH_WE_N (1 << 2)
|
||||
#define FLASH_ADV_N (1 << 3)
|
||||
#define FLASH_DQ_OE (1 << 8)
|
||||
#define FLASH_REGION_OE (1 << 16)
|
||||
|
||||
void bpi_flash_set_addr(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
reg_write32(fdev->addr_reg, addr);
|
||||
}
|
||||
|
||||
uint16_t bpi_flash_read_cur(struct flash_device *fdev)
|
||||
{
|
||||
uint16_t val;
|
||||
|
||||
reg_write32(fdev->ctrl_reg, FLASH_REGION_OE | FLASH_WE_N);
|
||||
reg_read32(fdev->data_reg); // dummy read
|
||||
val = reg_read32(fdev->data_reg);
|
||||
reg_write32(fdev->ctrl_reg, FLASH_OE_N | FLASH_WE_N | FLASH_ADV_N);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
uint16_t bpi_flash_read_word(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
return bpi_flash_read_cur(fdev);
|
||||
}
|
||||
|
||||
void bpi_flash_write_cur(struct flash_device *fdev, uint16_t data)
|
||||
{
|
||||
reg_write32(fdev->data_reg, data);
|
||||
reg_write32(fdev->ctrl_reg, FLASH_REGION_OE | FLASH_DQ_OE | FLASH_OE_N);
|
||||
reg_read32(fdev->data_reg); // dummy read
|
||||
reg_write32(fdev->ctrl_reg, FLASH_OE_N | FLASH_WE_N | FLASH_ADV_N);
|
||||
}
|
||||
|
||||
void bpi_flash_write_word(struct flash_device *fdev, size_t addr, uint16_t data)
|
||||
{
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, data);
|
||||
}
|
||||
|
||||
void bpi_flash_deselect(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_word(fdev, 0, CFI_READ_ARRAY);
|
||||
reg_write32(fdev->ctrl_reg, FLASH_CE_N | FLASH_OE_N | FLASH_WE_N | FLASH_ADV_N);
|
||||
}
|
||||
|
||||
// Intel flash ops (0x0001)
|
||||
|
||||
uint16_t bpi_flash_intel_read_status_register(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_READ_STATUS_REG);
|
||||
return bpi_flash_read_cur(fdev);
|
||||
}
|
||||
|
||||
void bpi_flash_intel_clear_status_register(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_CLEAR_STATUS_REG);
|
||||
}
|
||||
|
||||
void bpi_flash_intel_init(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_intel_clear_status_register(fdev);
|
||||
}
|
||||
|
||||
int bpi_flash_intel_sector_erase(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BLOCK_LOCK_SETUP);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BLOCK_UNLOCK);
|
||||
|
||||
if (bpi_flash_intel_read_status_register(fdev) & 0x30)
|
||||
{
|
||||
fprintf(stderr, "Failed to unlock block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BLOCK_ERASE_SETUP);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BLOCK_ERASE_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_intel_read_status_register(fdev) & 0x80)) {};
|
||||
|
||||
if (bpi_flash_intel_read_status_register(fdev) & 0x30)
|
||||
{
|
||||
fprintf(stderr, "Failed to erase block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_intel_buffered_program(struct flash_device *fdev, size_t addr, size_t len, void *src)
|
||||
{
|
||||
uint8_t *s = src;
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BUFFERED_PROGRAM_SETUP);
|
||||
bpi_flash_write_cur(fdev, len-1);
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
bpi_flash_write_word(fdev, addr+i, s[0] | (s[1] << 8));
|
||||
s += 2;
|
||||
}
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_INTEL_BUFFERED_PROGRAM_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_intel_read_status_register(fdev) & 0x80)) {};
|
||||
|
||||
if (bpi_flash_intel_read_status_register(fdev) & 0x30)
|
||||
{
|
||||
fprintf(stderr, "Failed to write block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_ops bpi_flash_intel_ops = {
|
||||
.init = bpi_flash_intel_init,
|
||||
.sector_erase = bpi_flash_intel_sector_erase,
|
||||
.buffered_program = bpi_flash_intel_buffered_program
|
||||
};
|
||||
|
||||
// AMD flash ops (0x0002)
|
||||
|
||||
void bpi_flash_amd_unlock(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_word(fdev, BPI_AMD_UNLOCK_ADDR_1, BPI_AMD_UNLOCK_DATA_1);
|
||||
bpi_flash_write_word(fdev, BPI_AMD_UNLOCK_ADDR_2, BPI_AMD_UNLOCK_DATA_2);
|
||||
}
|
||||
|
||||
void bpi_flash_amd_write_buffer_abort_reset(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_amd_unlock(fdev);
|
||||
bpi_flash_write_word(fdev, BPI_AMD_UNLOCK_ADDR_1, BPI_AMD_READ_ARRAY);
|
||||
}
|
||||
|
||||
void bpi_flash_amd_init(struct flash_device *fdev)
|
||||
{
|
||||
// write-to-buffer-abort reset (just in case)
|
||||
bpi_flash_amd_write_buffer_abort_reset(fdev);
|
||||
}
|
||||
|
||||
int bpi_flash_amd_wait_for_operation(struct flash_device *fdev, uint16_t stop_mask)
|
||||
{
|
||||
uint16_t read_1, read_2, read_3;
|
||||
|
||||
while (1)
|
||||
{
|
||||
read_1 = bpi_flash_read_cur(fdev);
|
||||
read_2 = bpi_flash_read_cur(fdev);
|
||||
read_3 = bpi_flash_read_cur(fdev);
|
||||
|
||||
if ((read_1 ^ read_2) & (read_2 ^ read_3) & 0x40)
|
||||
{
|
||||
if (read_1 & stop_mask)
|
||||
{
|
||||
return read_1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int bpi_flash_amd_sector_erase(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
bpi_flash_amd_unlock(fdev);
|
||||
bpi_flash_write_word(fdev, BPI_AMD_UNLOCK_ADDR_1, BPI_AMD_BLOCK_ERASE_SETUP);
|
||||
bpi_flash_amd_unlock(fdev);
|
||||
bpi_flash_write_word(fdev, addr, BPI_AMD_BLOCK_ERASE_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_read_cur(fdev) & 0x08)) {};
|
||||
|
||||
if (bpi_flash_amd_wait_for_operation(fdev, 0x20) & 0x20)
|
||||
{
|
||||
// write-to-buffer-abort reset
|
||||
bpi_flash_amd_write_buffer_abort_reset(fdev);
|
||||
|
||||
fprintf(stderr, "Failed to erase block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_amd_buffered_program(struct flash_device *fdev, size_t addr, size_t len, void *src)
|
||||
{
|
||||
uint8_t *s = src;
|
||||
|
||||
bpi_flash_amd_unlock(fdev);
|
||||
bpi_flash_write_word(fdev, addr, BPI_AMD_BUFFERED_PROGRAM_SETUP);
|
||||
bpi_flash_write_cur(fdev, len-1);
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
bpi_flash_write_word(fdev, addr+i, s[0] | (s[1] << 8));
|
||||
s += 2;
|
||||
}
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_AMD_BUFFERED_PROGRAM_CONFIRM);
|
||||
|
||||
if (bpi_flash_amd_wait_for_operation(fdev, 0x22) & 0x22)
|
||||
{
|
||||
// write-to-buffer-abort reset
|
||||
bpi_flash_amd_write_buffer_abort_reset(fdev);
|
||||
|
||||
fprintf(stderr, "Failed to write block\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_ops bpi_flash_amd_ops = {
|
||||
.init = bpi_flash_amd_init,
|
||||
.sector_erase = bpi_flash_amd_sector_erase,
|
||||
.buffered_program = bpi_flash_amd_buffered_program
|
||||
};
|
||||
|
||||
// Micron flash ops (0x0002)
|
||||
|
||||
uint16_t bpi_flash_micron_read_status_register(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_READ_STATUS_REG);
|
||||
return bpi_flash_read_cur(fdev);
|
||||
}
|
||||
|
||||
void bpi_flash_micron_clear_status_register(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_CLEAR_STATUS_REG);
|
||||
}
|
||||
|
||||
void bpi_flash_micron_init(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_micron_clear_status_register(fdev);
|
||||
}
|
||||
|
||||
int bpi_flash_micron_sector_erase(struct flash_device *fdev, size_t addr)
|
||||
{
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BLOCK_LOCK_SETUP);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BLOCK_UNLOCK);
|
||||
|
||||
if (bpi_flash_micron_read_status_register(fdev) & 0x30)
|
||||
{
|
||||
fprintf(stderr, "Failed to unlock block\n");
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BLOCK_ERASE_SETUP);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BLOCK_ERASE_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_micron_read_status_register(fdev) & 0x80)) {};
|
||||
|
||||
if (bpi_flash_micron_read_status_register(fdev) & 0x30)
|
||||
{
|
||||
fprintf(stderr, "Failed to erase block\n");
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_micron_buffered_program(struct flash_device *fdev, size_t addr, size_t len, void *src)
|
||||
{
|
||||
uint8_t *s = src;
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BUFFERED_PROGRAM_SETUP);
|
||||
bpi_flash_write_cur(fdev, len-1);
|
||||
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
bpi_flash_write_word(fdev, addr+i, s[0] | (s[1] << 8));
|
||||
s += 2;
|
||||
}
|
||||
|
||||
bpi_flash_set_addr(fdev, addr);
|
||||
bpi_flash_write_cur(fdev, BPI_MICRON_BUFFERED_PROGRAM_CONFIRM);
|
||||
|
||||
while (!(bpi_flash_micron_read_status_register(fdev) & 0x80)) {};
|
||||
|
||||
if (bpi_flash_micron_read_status_register(fdev) & 0x30)
|
||||
{
|
||||
fprintf(stderr, "Failed to write block\n");
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
return -1;
|
||||
}
|
||||
|
||||
bpi_flash_write_cur(fdev, CFI_READ_ARRAY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_ops bpi_flash_micron_ops = {
|
||||
.init = bpi_flash_micron_init,
|
||||
.sector_erase = bpi_flash_micron_sector_erase,
|
||||
.buffered_program = bpi_flash_micron_buffered_program
|
||||
};
|
||||
|
||||
|
||||
void bpi_flash_release(struct flash_device *fdev)
|
||||
{
|
||||
bpi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
int bpi_flash_init(struct flash_device *fdev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
// CFI query
|
||||
bpi_flash_write_word(fdev, CFI_QUERY_ADDR, CFI_QUERY_DATA);
|
||||
|
||||
if (bpi_flash_read_word(fdev, CFI_ID_0) != 'Q')
|
||||
{
|
||||
// may be Intel flash in sync read mode; attempt switch to async
|
||||
bpi_flash_write_word(fdev, 0xf94f, BPI_INTEL_READ_CONFIG_REG_SETUP);
|
||||
bpi_flash_write_word(fdev, 0xf94f, BPI_INTEL_SET_READ_CONFIG_REG);
|
||||
bpi_flash_write_word(fdev, CFI_QUERY_ADDR, CFI_QUERY_DATA);
|
||||
}
|
||||
|
||||
if (bpi_flash_read_word(fdev, CFI_ID_0) != 'Q' && ((bpi_flash_read_cur(fdev) ^ bpi_flash_read_cur(fdev)) & 0x44))
|
||||
{
|
||||
// may be AMD flash in write buffer abort; perform write buffer abort reset
|
||||
bpi_flash_amd_write_buffer_abort_reset(fdev);
|
||||
bpi_flash_write_word(fdev, CFI_QUERY_ADDR, CFI_QUERY_DATA);
|
||||
}
|
||||
|
||||
if (bpi_flash_read_word(fdev, CFI_ID_0) != 'Q' ||
|
||||
bpi_flash_read_word(fdev, CFI_ID_1) != 'R' ||
|
||||
bpi_flash_read_word(fdev, CFI_ID_2) != 'Y')
|
||||
{
|
||||
fprintf(stderr, "Failed to read flash ID\n");
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
fdev->protocol = bpi_flash_read_word(fdev, CFI_PRI_CMD_SET_0) | (bpi_flash_read_word(fdev, CFI_PRI_CMD_SET_1) << 8);
|
||||
|
||||
printf("Command set: %d\n", fdev->protocol);
|
||||
|
||||
switch (fdev->protocol)
|
||||
{
|
||||
case 0x0001:
|
||||
// Intel command set (P30)
|
||||
fdev->ops = &bpi_flash_intel_ops;
|
||||
break;
|
||||
case 0x0002:
|
||||
// AMD command set (S29, MT28)
|
||||
fdev->ops = &bpi_flash_amd_ops;
|
||||
break;
|
||||
case 0x0200:
|
||||
// Micron
|
||||
fdev->ops = &bpi_flash_micron_ops;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown command set: %d\n", fdev->protocol);
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
uint8_t flash_size = bpi_flash_read_word(fdev, CFI_DEVICE_SIZE);
|
||||
fdev->size = ((size_t)1) << flash_size;
|
||||
|
||||
printf("Flash size: %d MB\n", 1 << (flash_size-20));
|
||||
|
||||
uint16_t write_buffer_size = bpi_flash_read_word(fdev, CFI_WRITE_BUFFER_SIZE_0) | (bpi_flash_read_word(fdev, CFI_WRITE_BUFFER_SIZE_1) << 8);
|
||||
fdev->write_buffer_size = ((size_t)1) << write_buffer_size;
|
||||
|
||||
printf("Write buffer size: %ld B\n", fdev->write_buffer_size);
|
||||
|
||||
fdev->erase_region_count = bpi_flash_read_word(fdev, CFI_ERASE_REGION_COUNT);
|
||||
|
||||
printf("Erase regions: %d\n", fdev->erase_region_count);
|
||||
|
||||
if (fdev->erase_region_count > 0)
|
||||
{
|
||||
fdev->erase_region[0].block_count = (bpi_flash_read_word(fdev, CFI_ERASE_REGION_1_INFO_0) | (bpi_flash_read_word(fdev, CFI_ERASE_REGION_1_INFO_1) << 8)) + 1;
|
||||
fdev->erase_region[0].block_size = (bpi_flash_read_word(fdev, CFI_ERASE_REGION_1_INFO_2) | (bpi_flash_read_word(fdev, CFI_ERASE_REGION_1_INFO_3) << 8)) * 256;
|
||||
fdev->erase_region[0].region_start = 0;
|
||||
fdev->erase_region[0].region_end = fdev->erase_region[0].region_start + fdev->erase_region[0].block_count * fdev->erase_region[0].block_size;
|
||||
|
||||
fdev->erase_block_size = fdev->erase_region[0].block_size;
|
||||
|
||||
printf("Erase region 0 block count: %ld\n", fdev->erase_region[0].block_count);
|
||||
printf("Erase region 0 block size: %ld B\n", fdev->erase_region[0].block_size);
|
||||
printf("Erase region 0 start: 0x%08lx\n", fdev->erase_region[0].region_start);
|
||||
printf("Erase region 0 end: 0x%08lx\n", fdev->erase_region[0].region_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "No erase regions found!\n");
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (fdev->erase_region_count > 1)
|
||||
{
|
||||
fdev->erase_region[1].block_count = (bpi_flash_read_word(fdev, CFI_ERASE_REGION_2_INFO_0) | (bpi_flash_read_word(fdev, CFI_ERASE_REGION_2_INFO_1) << 8)) + 1;
|
||||
fdev->erase_region[1].block_size = (bpi_flash_read_word(fdev, CFI_ERASE_REGION_2_INFO_2) | (bpi_flash_read_word(fdev, CFI_ERASE_REGION_2_INFO_3) << 8)) * 256;
|
||||
fdev->erase_region[1].region_start = fdev->erase_region[0].region_end;
|
||||
fdev->erase_region[1].region_end = fdev->erase_region[1].region_start + fdev->erase_region[1].block_count * fdev->erase_region[1].block_size;
|
||||
|
||||
if (fdev->erase_region[1].block_size > fdev->erase_block_size)
|
||||
{
|
||||
fdev->erase_block_size = fdev->erase_region[1].block_size;
|
||||
}
|
||||
|
||||
printf("Erase region 1 block count: %ld\n", fdev->erase_region[1].block_count);
|
||||
printf("Erase region 1 block size: %ld B\n", fdev->erase_region[1].block_size);
|
||||
printf("Erase region 1 start: 0x%08lx\n", fdev->erase_region[1].region_start);
|
||||
printf("Erase region 1 end: 0x%08lx\n", fdev->erase_region[1].region_end);
|
||||
}
|
||||
|
||||
printf("Erase block size: %ld B\n", fdev->erase_block_size);
|
||||
|
||||
fdev->ops->init(fdev);
|
||||
|
||||
err:
|
||||
bpi_flash_release(fdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int bpi_flash_read(struct flash_device *fdev, size_t addr, size_t len, void *dest)
|
||||
{
|
||||
char *d = dest;
|
||||
|
||||
bpi_flash_write_word(fdev, 0, CFI_READ_ARRAY);
|
||||
|
||||
if (addr & 1)
|
||||
{
|
||||
*d = bpi_flash_read_word(fdev, addr >> 1) >> 8;
|
||||
addr++;
|
||||
len--;
|
||||
d++;
|
||||
}
|
||||
|
||||
while (len > 1)
|
||||
{
|
||||
*((uint16_t *)d) = bpi_flash_read_word(fdev, addr >> 1);
|
||||
addr += 2;
|
||||
len -= 2;
|
||||
d += 2;
|
||||
}
|
||||
|
||||
if (len)
|
||||
{
|
||||
*d = bpi_flash_read_word(fdev, addr >> 1);
|
||||
addr++;
|
||||
len--;
|
||||
d++;
|
||||
}
|
||||
|
||||
bpi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_write(struct flash_device *fdev, size_t addr, size_t len, void *src)
|
||||
{
|
||||
char *s = src;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
size_t seg = len;
|
||||
|
||||
// align to buffer size
|
||||
if (seg > fdev->write_buffer_size - (addr & (fdev->write_buffer_size-1)))
|
||||
{
|
||||
seg = fdev->write_buffer_size - (addr & (fdev->write_buffer_size-1));
|
||||
}
|
||||
|
||||
if (fdev->ops->buffered_program(fdev, addr >> 1, seg >> 1, s))
|
||||
{
|
||||
fprintf(stderr, "Buffered write failed\n");
|
||||
bpi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr += seg;
|
||||
len -= seg;
|
||||
s += seg;
|
||||
}
|
||||
|
||||
bpi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bpi_flash_erase(struct flash_device *fdev, size_t addr, size_t len)
|
||||
{
|
||||
size_t erase_block_size = fdev->erase_block_size;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
// determine sector size
|
||||
erase_block_size = 0;
|
||||
|
||||
for (int k = 0; k < fdev->erase_region_count; k++)
|
||||
{
|
||||
if (addr >= fdev->erase_region[k].region_start && addr < fdev->erase_region[k].region_end)
|
||||
{
|
||||
erase_block_size = fdev->erase_region[k].block_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!erase_block_size)
|
||||
{
|
||||
fprintf(stderr, "Address does not match an erase region\n");
|
||||
bpi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// check size and alignment
|
||||
if (addr & (erase_block_size-1) || len < erase_block_size)
|
||||
{
|
||||
fprintf(stderr, "Invalid erase request\n");
|
||||
bpi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// block erase
|
||||
if (fdev->ops->sector_erase(fdev, addr >> 1))
|
||||
{
|
||||
fprintf(stderr, "Failed to erase sector\n");
|
||||
bpi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len <= erase_block_size)
|
||||
break;
|
||||
|
||||
addr += erase_block_size;
|
||||
len -= erase_block_size;
|
||||
}
|
||||
|
||||
bpi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_driver bpi_flash_driver = {
|
||||
.init = bpi_flash_init,
|
||||
.release = bpi_flash_release,
|
||||
.read = bpi_flash_read,
|
||||
.write = bpi_flash_write,
|
||||
.erase = bpi_flash_erase
|
||||
};
|
||||
|
584
utils/flash_spi.c
Normal file
584
utils/flash_spi.c
Normal file
@ -0,0 +1,584 @@
|
||||
/*
|
||||
|
||||
Copyright 2020, The Regents of the University of California.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE REGENTS OF THE UNIVERSITY OF CALIFORNIA ''AS
|
||||
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
||||
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of The Regents of the University of California.
|
||||
|
||||
*/
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define reg_read32(reg) (*((volatile uint32_t *)(reg)))
|
||||
#define reg_write32(reg, val) (*((volatile uint32_t *)(reg))) = (val)
|
||||
|
||||
#define SPI_CMD_RESET_ENABLE 0x66
|
||||
#define SPI_CMD_RESET_MEMORY 0x99
|
||||
#define SPI_CMD_READ_ID 0x9F
|
||||
#define SPI_CMD_READ 0x03
|
||||
#define SPI_CMD_FAST_READ 0x0B
|
||||
#define SPI_CMD_FAST_READ_DUAL_OUT 0x3B
|
||||
#define SPI_CMD_FAST_READ_DUAL_IO 0xBB
|
||||
#define SPI_CMD_FAST_READ_QUAD_OUT 0x6B
|
||||
#define SPI_CMD_FAST_READ_QUAD_IO 0xEB
|
||||
#define SPI_CMD_DTR_FAST_READ 0x0D
|
||||
#define SPI_CMD_DTR_FAST_READ_DUAL_OUT 0x3D
|
||||
#define SPI_CMD_DTR_FAST_READ_DUAL_IO 0xBD
|
||||
#define SPI_CMD_DTR_FAST_READ_QUAD_OUT 0x6D
|
||||
#define SPI_CMD_DTR_FAST_READ_QUAD_IO 0xED
|
||||
#define SPI_CMD_4B_READ 0x13
|
||||
#define SPI_CMD_4B_FAST_READ 0x0C
|
||||
#define SPI_CMD_4B_FAST_READ_DUAL_OUT 0x3C
|
||||
#define SPI_CMD_4B_FAST_READ_DUAL_IO 0xBC
|
||||
#define SPI_CMD_4B_FAST_READ_QUAD_OUT 0x6C
|
||||
#define SPI_CMD_4B_FAST_READ_QUAD_IO 0xEC
|
||||
#define SPI_CMD_4B_DTR_FAST_READ 0x0E
|
||||
#define SPI_CMD_4B_DTR_FAST_READ_DUAL_IO 0xBE
|
||||
#define SPI_CMD_4B_DTR_FAST_READ_QUAD_IO 0xEE
|
||||
#define SPI_CMD_WRITE_ENABLE 0x06
|
||||
#define SPI_CMD_WRITE_DISABLE 0x04
|
||||
#define SPI_CMD_READ_STATUS_REG 0x05
|
||||
#define SPI_CMD_READ_FLAG_STATUS_REG 0x70
|
||||
#define SPI_CMD_READ_NV_CONFIG_REG 0xB5
|
||||
#define SPI_CMD_READ_V_CONFIG_REG 0x85
|
||||
#define SPI_CMD_READ_EV_CONFIG_REG 0x65
|
||||
#define SPI_CMD_READ_EXT_ADDR_REG 0xC8
|
||||
#define SPI_CMD_WRITE_STATUS_REG 0x01
|
||||
#define SPI_CMD_WRITE_NV_CONFIG_REG 0xB1
|
||||
#define SPI_CMD_WRITE_V_CONFIG_REG 0x81
|
||||
#define SPI_CMD_WRITE_EV_CONFIG_REG 0x61
|
||||
#define SPI_CMD_WRITE_EXT_ADDR_REG 0xC5
|
||||
#define SPI_CMD_CLEAR_FLAG_STATUS_REG 0x50
|
||||
#define SPI_CMD_PAGE_PROGRAM 0x02
|
||||
#define SPI_CMD_PAGE_PROGRAM_DUAL_IN 0xA2
|
||||
#define SPI_CMD_PAGE_PROGRAM_DUAL_IN_EXT 0xD2
|
||||
#define SPI_CMD_PAGE_PROGRAM_QUAD_IN 0x32
|
||||
#define SPI_CMD_PAGE_PROGRAM_QUAD_IN_EXT 0x38
|
||||
#define SPI_CMD_4B_PAGE_PROGRAM 0x12
|
||||
#define SPI_CMD_4B_PAGE_PROGRAM_QUAD_IN 0x34
|
||||
#define SPI_CMD_4B_PAGE_PROGRAM_QUAD_IN_EXT 0x3E
|
||||
#define SPI_CMD_32KB_SUBSECTOR_ERASE 0x52
|
||||
#define SPI_CMD_4KB_SUBSECTOR_ERASE 0x20
|
||||
#define SPI_CMD_SECTOR_ERASE 0xD8
|
||||
#define SPI_CMD_BULK_ERASE 0xC7
|
||||
#define SPI_CMD_4B_4KB_SUBSECTOR_ERASE 0x21
|
||||
#define SPI_CMD_4B_SECTOR_ERASE 0xDC
|
||||
#define SPI_CMD_PROGRAM_SUSPEND 0x75
|
||||
#define SPI_CMD_PROGRAM_RESUME 0x7A
|
||||
#define SPI_CMD_READ_OTP_ARRAY 0x4B
|
||||
#define SPI_CMD_PROGRAM_OTP_ARRAY 0x42
|
||||
#define SPI_CMD_ENTER_4B_ADDR_MODE 0xB7
|
||||
#define SPI_CMD_EXIT_4B_ADDR_MODE 0xE9
|
||||
#define SPI_CMD_ENTER_QUAD_IO_MODE 0x35
|
||||
#define SPI_CMD_EXIT_QUAD_IO_MODE 0xF5
|
||||
#define SPI_CMD_ENTER_DEEP_POWER_DOWN 0xB9
|
||||
#define SPI_CMD_EXIT_DEEP_POWER_DOWN 0xAB
|
||||
|
||||
#define SPI_PROTO_STR 0
|
||||
#define SPI_PROTO_DTR 1
|
||||
#define SPI_PROTO_DUAL_STR 2
|
||||
#define SPI_PROTO_DUAL_DTR 3
|
||||
#define SPI_PROTO_QUAD_STR 4
|
||||
#define SPI_PROTO_QUAD_DTR 5
|
||||
|
||||
#define SPI_PAGE_SIZE 0x100
|
||||
#define SPI_SUBSECTOR_SIZE 0x1000
|
||||
#define SPI_SECTOR_SIZE 0x10000
|
||||
|
||||
#define FLASH_D_0 (1 << 0)
|
||||
#define FLASH_D_1 (1 << 1)
|
||||
#define FLASH_D_2 (1 << 2)
|
||||
#define FLASH_D_3 (1 << 3)
|
||||
#define FLASH_D_01 (FLASH_D_0 | FLASH_D_1)
|
||||
#define FLASH_D_0123 (FLASH_D_0 | FLASH_D_1 | FLASH_D_2 | FLASH_D_3)
|
||||
#define FLASH_OE_0 (1 << 8)
|
||||
#define FLASH_OE_1 (1 << 9)
|
||||
#define FLASH_OE_2 (1 << 10)
|
||||
#define FLASH_OE_3 (1 << 11)
|
||||
#define FLASH_OE_01 (FLASH_OE_0 | FLASH_OE_1)
|
||||
#define FLASH_OE_0123 (FLASH_OE_0 | FLASH_OE_1 | FLASH_OE_2 | FLASH_OE_3)
|
||||
#define FLASH_CLK (1 << 16)
|
||||
#define FLASH_CS_N (1 << 17)
|
||||
|
||||
void spi_flash_select(struct flash_device *fdev)
|
||||
{
|
||||
reg_write32(fdev->ctrl_reg, 0);
|
||||
}
|
||||
|
||||
void spi_flash_deselect(struct flash_device *fdev)
|
||||
{
|
||||
reg_write32(fdev->ctrl_reg, FLASH_CS_N);
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_byte(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val = 0;
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case SPI_PROTO_STR:
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
reg_write32(fdev->ctrl_reg, 0);
|
||||
val |= ((reg_read32(fdev->ctrl_reg) & FLASH_D_1) != 0) << i;
|
||||
reg_write32(fdev->ctrl_reg, FLASH_CLK);
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_DTR:
|
||||
break;
|
||||
case SPI_PROTO_DUAL_STR:
|
||||
for (int i = 6; i >= 0; i -= 2)
|
||||
{
|
||||
reg_write32(fdev->ctrl_reg, 0);
|
||||
val |= (reg_read32(fdev->ctrl_reg) & FLASH_D_01) << i;
|
||||
reg_write32(fdev->ctrl_reg, FLASH_CLK);
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_DUAL_DTR:
|
||||
break;
|
||||
case SPI_PROTO_QUAD_STR:
|
||||
for (int i = 4; i >= 0; i -= 4)
|
||||
{
|
||||
reg_write32(fdev->ctrl_reg, 0);
|
||||
val |= (reg_read32(fdev->ctrl_reg) & FLASH_D_0123) << i;
|
||||
reg_write32(fdev->ctrl_reg, FLASH_CLK);
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_QUAD_DTR:
|
||||
break;
|
||||
}
|
||||
|
||||
reg_write32(fdev->ctrl_reg, 0);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void spi_flash_write_byte(struct flash_device *fdev, uint8_t val, int protocol)
|
||||
{
|
||||
uint8_t bit;
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case SPI_PROTO_STR:
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
bit = (val >> i) & 0x1;
|
||||
reg_write32(fdev->ctrl_reg, bit | FLASH_OE_0);
|
||||
reg_write32(fdev->ctrl_reg, bit | FLASH_OE_0 | FLASH_CLK);
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_DTR:
|
||||
break;
|
||||
case SPI_PROTO_DUAL_STR:
|
||||
for (int i = 6; i >= 0; i -= 2)
|
||||
{
|
||||
bit = (val >> i) & 0x3;
|
||||
reg_write32(fdev->ctrl_reg, bit | FLASH_OE_01);
|
||||
reg_write32(fdev->ctrl_reg, bit | FLASH_OE_01 | FLASH_CLK);
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_DUAL_DTR:
|
||||
break;
|
||||
case SPI_PROTO_QUAD_STR:
|
||||
for (int i = 4; i >= 0; i -= 4)
|
||||
{
|
||||
bit = (val >> i) & 0xf;
|
||||
reg_write32(fdev->ctrl_reg, bit | FLASH_OE_0123);
|
||||
reg_write32(fdev->ctrl_reg, bit | FLASH_OE_0123 | FLASH_CLK);
|
||||
}
|
||||
break;
|
||||
case SPI_PROTO_QUAD_DTR:
|
||||
break;
|
||||
}
|
||||
|
||||
reg_write32(fdev->ctrl_reg, 0);
|
||||
}
|
||||
|
||||
void spi_flash_write_addr(struct flash_device *fdev, size_t addr, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, (addr >> 16) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 8) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 0) & 0xff, protocol);
|
||||
}
|
||||
|
||||
void spi_flash_write_addr_4b(struct flash_device *fdev, size_t addr, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, (addr >> 24) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 16) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 8) & 0xff, protocol);
|
||||
spi_flash_write_byte(fdev, (addr >> 0) & 0xff, protocol);
|
||||
}
|
||||
|
||||
void spi_flash_write_enable(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_WRITE_ENABLE, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
void spi_flash_write_disable(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_WRITE_DISABLE, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_status_register(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_STATUS_REG, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
void spi_flash_write_status_register(struct flash_device *fdev, uint8_t val, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_WRITE_STATUS_REG, protocol);
|
||||
spi_flash_write_byte(fdev, val, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_flag_status_register(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_FLAG_STATUS_REG, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
void spi_flash_clear_flag_status_register(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_CLEAR_FLAG_STATUS_REG, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
uint8_t spi_flash_read_volatile_config_register(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
uint8_t val;
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_V_CONFIG_REG, protocol);
|
||||
val = spi_flash_read_byte(fdev, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
return val;
|
||||
}
|
||||
|
||||
void spi_flash_write_volatile_config_register(struct flash_device *fdev, uint8_t val, int protocol)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_WRITE_V_CONFIG_REG, protocol);
|
||||
spi_flash_write_byte(fdev, val, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
void spi_flash_reset(struct flash_device *fdev, int protocol)
|
||||
{
|
||||
spi_flash_deselect(fdev);
|
||||
spi_flash_write_byte(fdev, SPI_CMD_RESET_ENABLE, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
reg_read32(fdev->ctrl_reg); // dummy read
|
||||
reg_read32(fdev->ctrl_reg); // dummy read
|
||||
spi_flash_write_byte(fdev, SPI_CMD_RESET_MEMORY, protocol);
|
||||
spi_flash_deselect(fdev);
|
||||
reg_read32(fdev->ctrl_reg); // dummy read
|
||||
reg_read32(fdev->ctrl_reg); // dummy read
|
||||
}
|
||||
|
||||
void spi_flash_release(struct flash_device *fdev)
|
||||
{
|
||||
spi_flash_deselect(fdev);
|
||||
}
|
||||
|
||||
int spi_flash_init(struct flash_device *fdev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!fdev)
|
||||
return -1;
|
||||
|
||||
spi_flash_reset(fdev, SPI_PROTO_STR);
|
||||
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ_ID, SPI_PROTO_STR);
|
||||
int mfr_id = spi_flash_read_byte(fdev, SPI_PROTO_STR);
|
||||
int mem_type = spi_flash_read_byte(fdev, SPI_PROTO_STR);
|
||||
int mem_capacity = spi_flash_read_byte(fdev, SPI_PROTO_STR);
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
printf("Manufacturer ID: 0x%02x\n", mfr_id);
|
||||
printf("Memory type: 0x%02x\n", mem_type);
|
||||
printf("Memory capacity: 0x%02x\n", mem_capacity);
|
||||
|
||||
// convert from BCD
|
||||
mem_capacity = (mem_capacity & 0xf) + (((mem_capacity >> 4) & 0xf) * 10);
|
||||
|
||||
fdev->size = ((size_t)1) << (mem_capacity+6);
|
||||
|
||||
printf("Flash size: %ld MB\n", fdev->size / (1 << 20));
|
||||
|
||||
fdev->protocol = SPI_PROTO_STR;
|
||||
fdev->bulk_protocol = SPI_PROTO_STR;
|
||||
fdev->read_dummy_cycles = 0;
|
||||
fdev->write_buffer_size = SPI_PAGE_SIZE;
|
||||
fdev->erase_block_size = SPI_SUBSECTOR_SIZE;
|
||||
|
||||
printf("Write buffer size: %ld B\n", fdev->write_buffer_size);
|
||||
printf("Erase block size: %ld B\n", fdev->erase_block_size);
|
||||
|
||||
if (fdev->data_width == 4)
|
||||
{
|
||||
spi_flash_write_volatile_config_register(fdev, 0xFB, SPI_PROTO_STR);
|
||||
fdev->bulk_protocol = SPI_PROTO_QUAD_STR;
|
||||
fdev->read_dummy_cycles = 10;
|
||||
}
|
||||
|
||||
spi_flash_release(fdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int spi_flash_read(struct flash_device *fdev, size_t addr, size_t len, void *dest)
|
||||
{
|
||||
char *d = dest;
|
||||
|
||||
int protocol = SPI_PROTO_STR;
|
||||
|
||||
if (fdev->data_width == 4)
|
||||
{
|
||||
protocol = SPI_PROTO_QUAD_STR;
|
||||
}
|
||||
|
||||
if (addr > 0xffffff)
|
||||
{
|
||||
// four byte address read
|
||||
if (protocol == SPI_PROTO_QUAD_STR)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_FAST_READ_QUAD_IO, SPI_PROTO_STR);
|
||||
}
|
||||
else
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_READ, SPI_PROTO_STR);
|
||||
}
|
||||
spi_flash_write_addr_4b(fdev, addr, protocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal read
|
||||
if (protocol == SPI_PROTO_QUAD_STR)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_FAST_READ_QUAD_IO, SPI_PROTO_STR);
|
||||
}
|
||||
else
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_READ, SPI_PROTO_STR);
|
||||
}
|
||||
spi_flash_write_addr(fdev, addr, protocol);
|
||||
}
|
||||
|
||||
if (protocol != SPI_PROTO_STR)
|
||||
{
|
||||
// dummy cycles
|
||||
for (int i = 0; i < fdev->read_dummy_cycles; i++)
|
||||
{
|
||||
reg_write32(fdev->ctrl_reg, FLASH_CLK);
|
||||
reg_write32(fdev->ctrl_reg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
*d = spi_flash_read_byte(fdev, protocol);
|
||||
len--;
|
||||
d++;
|
||||
}
|
||||
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_flash_write(struct flash_device *fdev, size_t addr, size_t len, void *src)
|
||||
{
|
||||
char *s = src;
|
||||
|
||||
int protocol = SPI_PROTO_STR;
|
||||
|
||||
if (fdev->data_width == 4)
|
||||
{
|
||||
protocol = SPI_PROTO_QUAD_STR;
|
||||
}
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
spi_flash_write_enable(fdev, SPI_PROTO_STR);
|
||||
|
||||
if (!(spi_flash_read_status_register(fdev, SPI_PROTO_STR) & 0x02))
|
||||
{
|
||||
fprintf(stderr, "Failed to enable writing\n");
|
||||
spi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (addr > 0xffffff)
|
||||
{
|
||||
// four byte address page program
|
||||
if (protocol == SPI_PROTO_QUAD_STR)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_PAGE_PROGRAM_QUAD_IN_EXT, SPI_PROTO_STR);
|
||||
}
|
||||
else
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_PAGE_PROGRAM, SPI_PROTO_STR);
|
||||
}
|
||||
spi_flash_write_addr_4b(fdev, addr, protocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
// normal page program
|
||||
if (protocol == SPI_PROTO_QUAD_STR)
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_PAGE_PROGRAM_QUAD_IN_EXT, SPI_PROTO_STR);
|
||||
}
|
||||
else
|
||||
{
|
||||
spi_flash_write_byte(fdev, SPI_CMD_PAGE_PROGRAM, SPI_PROTO_STR);
|
||||
}
|
||||
spi_flash_write_addr(fdev, addr, protocol);
|
||||
}
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
spi_flash_write_byte(fdev, *s, protocol);
|
||||
addr++;
|
||||
s++;
|
||||
len--;
|
||||
|
||||
if ((addr & 0xff) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
// wait for operation to complete
|
||||
while (spi_flash_read_status_register(fdev, SPI_PROTO_STR) & 0x01) {};
|
||||
}
|
||||
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int spi_flash_erase(struct flash_device *fdev, size_t addr, size_t len)
|
||||
{
|
||||
size_t erase_block_size = fdev->erase_block_size;
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
// determine sector size
|
||||
erase_block_size = 0;
|
||||
|
||||
if ((addr & (SPI_SECTOR_SIZE-1)) == 0 && len >= SPI_SECTOR_SIZE)
|
||||
{
|
||||
erase_block_size = SPI_SECTOR_SIZE;
|
||||
}
|
||||
else if ((addr & (SPI_SUBSECTOR_SIZE-1)) == 0 && len >= SPI_SUBSECTOR_SIZE)
|
||||
{
|
||||
erase_block_size = SPI_SUBSECTOR_SIZE;
|
||||
}
|
||||
|
||||
// check size and alignment
|
||||
if (!erase_block_size)
|
||||
{
|
||||
fprintf(stderr, "Invalid erase request\n");
|
||||
spi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// enable writing
|
||||
spi_flash_write_enable(fdev, SPI_PROTO_STR);
|
||||
|
||||
if (!(spi_flash_read_status_register(fdev, SPI_PROTO_STR) & 0x02))
|
||||
{
|
||||
fprintf(stderr, "Failed to enable writing\n");
|
||||
spi_flash_deselect(fdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// block erase
|
||||
if (addr > 0xffffff)
|
||||
{
|
||||
if (erase_block_size == SPI_SECTOR_SIZE)
|
||||
{
|
||||
// four byte address sector erase
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_SECTOR_ERASE, SPI_PROTO_STR);
|
||||
spi_flash_write_addr_4b(fdev, addr, SPI_PROTO_STR);
|
||||
}
|
||||
else if (erase_block_size == SPI_SUBSECTOR_SIZE)
|
||||
{
|
||||
// normal 4KB subsector erase
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4B_4KB_SUBSECTOR_ERASE, SPI_PROTO_STR);
|
||||
spi_flash_write_addr_4b(fdev, addr, SPI_PROTO_STR);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (erase_block_size == SPI_SECTOR_SIZE)
|
||||
{
|
||||
// normal sector erase
|
||||
spi_flash_write_byte(fdev, SPI_CMD_SECTOR_ERASE, SPI_PROTO_STR);
|
||||
spi_flash_write_addr(fdev, addr, SPI_PROTO_STR);
|
||||
}
|
||||
else if (erase_block_size == SPI_SUBSECTOR_SIZE)
|
||||
{
|
||||
// normal 4KB subsector erase
|
||||
spi_flash_write_byte(fdev, SPI_CMD_4KB_SUBSECTOR_ERASE, SPI_PROTO_STR);
|
||||
spi_flash_write_addr(fdev, addr, SPI_PROTO_STR);
|
||||
}
|
||||
}
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
// wait for operation to complete
|
||||
while (spi_flash_read_status_register(fdev, SPI_PROTO_STR) & 0x01) {};
|
||||
|
||||
if (len <= erase_block_size)
|
||||
break;
|
||||
|
||||
addr += erase_block_size;
|
||||
len -= erase_block_size;
|
||||
}
|
||||
|
||||
spi_flash_deselect(fdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct flash_driver spi_flash_driver = {
|
||||
.init = spi_flash_init,
|
||||
.release = spi_flash_release,
|
||||
.read = spi_flash_read,
|
||||
.write = spi_flash_write,
|
||||
.erase = spi_flash_erase
|
||||
};
|
||||
|
1212
utils/mqnic-fw.c
1212
utils/mqnic-fw.c
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user