From 5072844fe448a6fdb8a45a311674406cb84091fe Mon Sep 17 00:00:00 2001 From: Piotr Dymacz Date: Wed, 2 Dec 2015 02:07:46 +0100 Subject: [PATCH] Add SFDP support in new QC/A SPI driver SFDP (serial FLASH discoverable parameters) allows to get useful information about FLASH parameters and we will use it for unknown chip, to get basic data like size, erase sector size and corresponding erase command. Plus, some other minor changes: - remove defines (we will keep it in flash.h) - use provided sector erase command --- u-boot/cpu/mips/ar7240/qca_sf.c | 145 +++++++++++++++++++++------- u-boot/include/soc/qca_soc_common.h | 3 +- 2 files changed, 114 insertions(+), 34 deletions(-) diff --git a/u-boot/cpu/mips/ar7240/qca_sf.c b/u-boot/cpu/mips/ar7240/qca_sf.c index 36e02d1..3b7f66b 100644 --- a/u-boot/cpu/mips/ar7240/qca_sf.c +++ b/u-boot/cpu/mips/ar7240/qca_sf.c @@ -7,26 +7,11 @@ */ #include +#include +#include #include #include -/* Basic SPI FLASH commands */ -#define SPI_FLASH_CMD_WRSR 0x01 -#define SPI_FLASH_CMD_PP 0x02 -#define SPI_FLASH_CMD_READ 0x03 -#define SPI_FLASH_CMD_WRDI 0x04 -#define SPI_FLASH_CMD_RDSR 0x05 -#define SPI_FLASH_CMD_WREN 0x06 - -/* SPI FLASH erase related commands */ -#define SPI_FLASH_CMD_ES_4KB 0x20 -#define SPI_FLASH_CMD_ES_32KB 0x52 -#define SPI_FLASH_CMD_ES_64KB 0xD8 -#define SPI_FLASH_CMD_ES_ALL 0xC7 - -/* Other SPI FLASH commands */ -#define SPI_FLASH_CMD_JEDEC 0x9F - /* Use CS0 by default */ static u32 qca_sf_cs_mask = QCA_SPI_SHIFT_CNT_CHNL_CS0_MASK; @@ -70,6 +55,19 @@ static void qca_sf_shift_out(u32 data_out, u32 bits_cnt, u32 terminate) qca_soc_reg_write(QCA_SPI_SHIFT_CNT_REG, reg_val); } +static u32 qca_sf_sfdp_bfpt_dword(u32 ptp_offset, u32 dword_num) +{ + u32 data_out; + + data_out = (SPI_FLASH_CMD_SFDP << 24); + data_out = data_out | (ptp_offset + ((dword_num - 1) * 4)); + + qca_sf_shift_out(data_out, 32, 0); + qca_sf_shift_out(0x0, 40, 1); + + return cpu_to_le32(qca_sf_shift_in()); +} + static inline void qca_sf_write_en(void) { qca_sf_shift_out(SPI_FLASH_CMD_WREN, 8, 1); @@ -127,28 +125,14 @@ void qca_sf_bulk_erase(u32 bank) } /* Erase one sector at provided address */ -u32 qca_sf_sect_erase(u32 bank, u32 address, u32 sect_size) +u32 qca_sf_sect_erase(u32 bank, u32 address, u32 sect_size, u8 erase_cmd) { u32 data_out; qca_sf_bank_to_cs_mask(bank); - switch (sect_size) { - case 4 * 1024: - data_out = SPI_FLASH_CMD_ES_4KB << 24; - break; - case 32 * 1024: - data_out = SPI_FLASH_CMD_ES_32KB << 24; - break; - case 64 * 1024: - data_out = SPI_FLASH_CMD_ES_64KB << 24; - break; - default: - return 1; - } - /* TODO: 4-byte addressing support */ - data_out = data_out | (address & 0x00FFFFFF); + data_out = (erase_cmd << 24) | (address & 0x00FFFFFF); qca_sf_spi_en(); qca_sf_write_en(); @@ -185,6 +169,101 @@ void qca_sf_write_page(u32 bank, u32 address, u32 length, u8 *data) qca_sf_spi_di(); } +/* + * Checks if FLASH supports SFDP and if yes, tries to get following data: + * - chip size + * - erase sector size + * - erase command + */ +u32 qca_sf_sfdp_info(u32 bank, + u32 *flash_size, + u32 *sect_size, + u8 *erase_cmd) +{ + u8 buffer[12]; + u8 ss = 0, ec = 0; + u32 data_in, i; + u32 ptp_length, ptp_offset; + + qca_sf_bank_to_cs_mask(bank); + + qca_sf_spi_en(); + + /* Shift out SFDP command with 0x0 address */ + qca_sf_shift_out(SPI_FLASH_CMD_SFDP << 24, 32, 0); + + /* 1 dummy byte and 4 bytes for SFDP signature */ + qca_sf_shift_out(0x0, 40, 0); + data_in = qca_sf_shift_in(); + + if (cpu_to_le32(data_in) != SPI_FLASH_SFDP_SIGN) { + qca_sf_shift_out(0x0, 0, 1); + qca_sf_spi_di(); + return 1; + } + + /* + * We need to check SFDP and first parameter header major versions, + * because we support now only v1, exit also if ptp_length is < 9 + */ + for (i = 0; i < 3; i++) { + qca_sf_shift_out(0x0, 32, 0); + data_in = qca_sf_shift_in(); + + memcpy(&buffer[i * 4], &data_in, 4); + } + + ptp_length = buffer[7]; + ptp_offset = buffer[8] | (buffer[10] << 16) | (buffer[9] << 8); + + if (buffer[1] != 1 || buffer[6] != 1 || ptp_length < 9) { + qca_sf_shift_out(0x0, 0, 1); + qca_sf_spi_di(); + return 1; + } + + qca_sf_shift_out(0x0, 0, 1); + + /* FLASH density (2nd DWORD in JEDEC basic FLASH parameter table) */ + data_in = qca_sf_sfdp_bfpt_dword(ptp_offset, 2); + + /* We do not support >= 4 Gbits chips */ + if ((data_in & (1 << 31)) || data_in == 0) + return 1; + + /* TODO: it seems that density is 0-based, like max. available address? */ + if (flash_size != NULL) + *flash_size = ((data_in & 0x7FFFFFFF) + 1) / 8; + + /* Sector/block erase size and command: 8th and 9th DWORD */ + data_in = qca_sf_sfdp_bfpt_dword(ptp_offset, 8); + memcpy(&buffer[0], &data_in, 4); + + data_in = qca_sf_sfdp_bfpt_dword(ptp_offset, 9); + memcpy(&buffer[4], &data_in, 4); + + /* We prefer bigger erase sectors */ + for (i = 0; i < 7; i += 2) { + if ((buffer[i + 1] != 0) && buffer[i + 1] > ss) { + ss = buffer[i + 1]; + ec = buffer[i]; + } + } + + if (ss == 0) + return 1; + + if (sect_size != NULL) + *sect_size = 1 << ss; + + if (erase_cmd != NULL) + *erase_cmd = ec; + + qca_sf_spi_di(); + + return 0; +} + /* Returns JEDEC ID for selected FLASH chip */ u32 qca_sf_jedec_id(u32 bank) { diff --git a/u-boot/include/soc/qca_soc_common.h b/u-boot/include/soc/qca_soc_common.h index 5df014c..44f6021 100644 --- a/u-boot/include/soc/qca_soc_common.h +++ b/u-boot/include/soc/qca_soc_common.h @@ -1252,7 +1252,8 @@ void qca_full_chip_reset(void); void qca_sys_clocks(u32 *cpu_clk, u32 *ddr_clk, u32 *ahb_clk, u32 *spi_clk, u32 *ref_clk); void qca_sf_bulk_erase(u32 bank); void qca_sf_write_page(u32 bank, u32 address, u32 length, u8 *data); -u32 qca_sf_sect_erase(u32 bank, u32 address, u32 sect_size); +u32 qca_sf_sect_erase(u32 bank, u32 address, u32 sect_size, u8 erase_cmd); +u32 qca_sf_sfdp_info(u32 bank, u32 *flash_size, u32 *sector_size, u8 *erase_cmd); u32 qca_sf_jedec_id(u32 bank); #endif /* !__ASSEMBLY__ */ -- 2.25.1