|
14 | 14 | #define SPINOR_OP_CLSR 0x30 /* Clear status register 1 */
|
15 | 15 | #define SPINOR_OP_RD_ANY_REG 0x65 /* Read any register */
|
16 | 16 | #define SPINOR_OP_WR_ANY_REG 0x71 /* Write any register */
|
| 17 | +#define SPINOR_REG_CYPRESS_CFR1V 0x00800002 |
| 18 | +#define SPINOR_REG_CYPRESS_CFR1V_QUAD_EN BIT(1) /* Quad Enable */ |
17 | 19 | #define SPINOR_REG_CYPRESS_CFR2V 0x00800003
|
18 | 20 | #define SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24 0xb
|
19 | 21 | #define SPINOR_REG_CYPRESS_CFR3V 0x00800004
|
@@ -113,6 +115,68 @@ static int cypress_nor_octal_dtr_dis(struct spi_nor *nor)
|
113 | 115 | return 0;
|
114 | 116 | }
|
115 | 117 |
|
| 118 | +/** |
| 119 | + * cypress_nor_quad_enable_volatile() - enable Quad I/O mode in volatile |
| 120 | + * register. |
| 121 | + * @nor: pointer to a 'struct spi_nor' |
| 122 | + * |
| 123 | + * It is recommended to update volatile registers in the field application due |
| 124 | + * to a risk of the non-volatile registers corruption by power interrupt. This |
| 125 | + * function sets Quad Enable bit in CFR1 volatile. If users set the Quad Enable |
| 126 | + * bit in the CFR1 non-volatile in advance (typically by a Flash programmer |
| 127 | + * before mounting Flash on PCB), the Quad Enable bit in the CFR1 volatile is |
| 128 | + * also set during Flash power-up. |
| 129 | + * |
| 130 | + * Return: 0 on success, -errno otherwise. |
| 131 | + */ |
| 132 | +static int cypress_nor_quad_enable_volatile(struct spi_nor *nor) |
| 133 | +{ |
| 134 | + struct spi_mem_op op; |
| 135 | + u8 addr_mode_nbytes = nor->params->addr_mode_nbytes; |
| 136 | + u8 cfr1v_written; |
| 137 | + int ret; |
| 138 | + |
| 139 | + op = (struct spi_mem_op) |
| 140 | + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, |
| 141 | + SPINOR_REG_CYPRESS_CFR1V, |
| 142 | + nor->bouncebuf); |
| 143 | + |
| 144 | + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); |
| 145 | + if (ret) |
| 146 | + return ret; |
| 147 | + |
| 148 | + if (nor->bouncebuf[0] & SPINOR_REG_CYPRESS_CFR1V_QUAD_EN) |
| 149 | + return 0; |
| 150 | + |
| 151 | + /* Update the Quad Enable bit. */ |
| 152 | + nor->bouncebuf[0] |= SPINOR_REG_CYPRESS_CFR1V_QUAD_EN; |
| 153 | + op = (struct spi_mem_op) |
| 154 | + CYPRESS_NOR_WR_ANY_REG_OP(addr_mode_nbytes, |
| 155 | + SPINOR_REG_CYPRESS_CFR1V, 1, |
| 156 | + nor->bouncebuf); |
| 157 | + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); |
| 158 | + if (ret) |
| 159 | + return ret; |
| 160 | + |
| 161 | + cfr1v_written = nor->bouncebuf[0]; |
| 162 | + |
| 163 | + /* Read back and check it. */ |
| 164 | + op = (struct spi_mem_op) |
| 165 | + CYPRESS_NOR_RD_ANY_REG_OP(addr_mode_nbytes, |
| 166 | + SPINOR_REG_CYPRESS_CFR1V, |
| 167 | + nor->bouncebuf); |
| 168 | + ret = spi_nor_read_any_reg(nor, &op, nor->reg_proto); |
| 169 | + if (ret) |
| 170 | + return ret; |
| 171 | + |
| 172 | + if (nor->bouncebuf[0] != cfr1v_written) { |
| 173 | + dev_err(nor->dev, "CFR1: Read back test failed\n"); |
| 174 | + return -EIO; |
| 175 | + } |
| 176 | + |
| 177 | + return 0; |
| 178 | +} |
| 179 | + |
116 | 180 | /**
|
117 | 181 | * cypress_nor_set_page_size() - Set page size which corresponds to the flash
|
118 | 182 | * configuration.
|
@@ -143,6 +207,58 @@ static int cypress_nor_set_page_size(struct spi_nor *nor)
|
143 | 207 | return 0;
|
144 | 208 | }
|
145 | 209 |
|
| 210 | +static int |
| 211 | +s25hx_t_post_bfpt_fixup(struct spi_nor *nor, |
| 212 | + const struct sfdp_parameter_header *bfpt_header, |
| 213 | + const struct sfdp_bfpt *bfpt) |
| 214 | +{ |
| 215 | + /* Replace Quad Enable with volatile version */ |
| 216 | + nor->params->quad_enable = cypress_nor_quad_enable_volatile; |
| 217 | + |
| 218 | + return cypress_nor_set_page_size(nor); |
| 219 | +} |
| 220 | + |
| 221 | +static void s25hx_t_post_sfdp_fixup(struct spi_nor *nor) |
| 222 | +{ |
| 223 | + struct spi_nor_erase_type *erase_type = |
| 224 | + nor->params->erase_map.erase_type; |
| 225 | + unsigned int i; |
| 226 | + |
| 227 | + /* |
| 228 | + * In some parts, 3byte erase opcodes are advertised by 4BAIT. |
| 229 | + * Convert them to 4byte erase opcodes. |
| 230 | + */ |
| 231 | + for (i = 0; i < SNOR_ERASE_TYPE_MAX; i++) { |
| 232 | + switch (erase_type[i].opcode) { |
| 233 | + case SPINOR_OP_SE: |
| 234 | + erase_type[i].opcode = SPINOR_OP_SE_4B; |
| 235 | + break; |
| 236 | + case SPINOR_OP_BE_4K: |
| 237 | + erase_type[i].opcode = SPINOR_OP_BE_4K_4B; |
| 238 | + break; |
| 239 | + default: |
| 240 | + break; |
| 241 | + } |
| 242 | + } |
| 243 | +} |
| 244 | + |
| 245 | +static void s25hx_t_late_init(struct spi_nor *nor) |
| 246 | +{ |
| 247 | + struct spi_nor_flash_parameter *params = nor->params; |
| 248 | + |
| 249 | + /* Fast Read 4B requires mode cycles */ |
| 250 | + params->reads[SNOR_CMD_READ_FAST].num_mode_clocks = 8; |
| 251 | + |
| 252 | + /* The writesize should be ECC data unit size */ |
| 253 | + params->writesize = 16; |
| 254 | +} |
| 255 | + |
| 256 | +static struct spi_nor_fixups s25hx_t_fixups = { |
| 257 | + .post_bfpt = s25hx_t_post_bfpt_fixup, |
| 258 | + .post_sfdp = s25hx_t_post_sfdp_fixup, |
| 259 | + .late_init = s25hx_t_late_init, |
| 260 | +}; |
| 261 | + |
146 | 262 | /**
|
147 | 263 | * cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes.
|
148 | 264 | * @nor: pointer to a 'struct spi_nor'
|
@@ -319,6 +435,22 @@ static const struct flash_info spansion_nor_parts[] = {
|
319 | 435 | { "s25fl256l", INFO(0x016019, 0, 64 * 1024, 512)
|
320 | 436 | NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
|
321 | 437 | FIXUP_FLAGS(SPI_NOR_4B_OPCODES) },
|
| 438 | + { "s25hl512t", INFO6(0x342a1a, 0x0f0390, 256 * 1024, 256) |
| 439 | + PARSE_SFDP |
| 440 | + MFR_FLAGS(USE_CLSR) |
| 441 | + .fixups = &s25hx_t_fixups }, |
| 442 | + { "s25hl01gt", INFO6(0x342a1b, 0x0f0390, 256 * 1024, 512) |
| 443 | + PARSE_SFDP |
| 444 | + MFR_FLAGS(USE_CLSR) |
| 445 | + .fixups = &s25hx_t_fixups }, |
| 446 | + { "s25hs512t", INFO6(0x342b1a, 0x0f0390, 256 * 1024, 256) |
| 447 | + PARSE_SFDP |
| 448 | + MFR_FLAGS(USE_CLSR) |
| 449 | + .fixups = &s25hx_t_fixups }, |
| 450 | + { "s25hs01gt", INFO6(0x342b1b, 0x0f0390, 256 * 1024, 512) |
| 451 | + PARSE_SFDP |
| 452 | + MFR_FLAGS(USE_CLSR) |
| 453 | + .fixups = &s25hx_t_fixups }, |
322 | 454 | { "cy15x104q", INFO6(0x042cc2, 0x7f7f7f, 512 * 1024, 1)
|
323 | 455 | FLAGS(SPI_NOR_NO_ERASE) },
|
324 | 456 | { "s28hs512t", INFO(0x345b1a, 0, 256 * 1024, 256)
|
|
0 commit comments