Add SFDP support in new QC/A SPI driver
authorPiotr Dymacz <pepe2k@gmail.com>
Wed, 2 Dec 2015 01:07:46 +0000 (02:07 +0100)
committerPiotr Dymacz <pepe2k@gmail.com>
Wed, 2 Dec 2015 01:07:46 +0000 (02:07 +0100)
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
u-boot/include/soc/qca_soc_common.h

index 36e02d112e5ab55343604653e5e66dccf0522eb0..3b7f66b8ae5e202c87bfe3d83ce7261b6e22bb71 100644 (file)
@@ -7,26 +7,11 @@
  */
 
 #include <config.h>
+#include <common.h>
+#include <flash.h>
 #include <asm/addrspace.h>
 #include <soc/qca_soc_common.h>
 
-/* 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)
 {
index 5df014c17cbd0c559610e4c937a03ac9f3463240..44f6021f2091bf6adc306908173f294806b2fc7f 100644 (file)
@@ -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__ */