|
28 | 28 | #define FSR_P_ERR BIT(4) /* Program operation status */ |
29 | 29 | #define FSR_PT_ERR BIT(1) /* Protection error bit */ |
30 | 30 |
|
31 | | -static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) |
| 31 | +/* Micron ST SPI NOR flash operations. */ |
| 32 | +#define MICRON_ST_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \ |
| 33 | + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 0), \ |
| 34 | + SPI_MEM_OP_ADDR(naddr, addr, 0), \ |
| 35 | + SPI_MEM_OP_NO_DUMMY, \ |
| 36 | + SPI_MEM_OP_DATA_OUT(ndata, buf, 0)) |
| 37 | + |
| 38 | +static int micron_st_nor_octal_dtr_en(struct spi_nor *nor) |
32 | 39 | { |
33 | 40 | struct spi_mem_op op; |
34 | 41 | u8 *buf = nor->bouncebuf; |
35 | 42 | int ret; |
36 | 43 |
|
37 | | - if (enable) { |
38 | | - /* Use 20 dummy cycles for memory array reads. */ |
39 | | - ret = spi_nor_write_enable(nor); |
40 | | - if (ret) |
41 | | - return ret; |
42 | | - |
43 | | - *buf = 20; |
44 | | - op = (struct spi_mem_op) |
45 | | - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), |
46 | | - SPI_MEM_OP_ADDR(3, SPINOR_REG_MT_CFR1V, 1), |
47 | | - SPI_MEM_OP_NO_DUMMY, |
48 | | - SPI_MEM_OP_DATA_OUT(1, buf, 1)); |
49 | | - |
50 | | - ret = spi_mem_exec_op(nor->spimem, &op); |
51 | | - if (ret) |
52 | | - return ret; |
53 | | - |
54 | | - ret = spi_nor_wait_till_ready(nor); |
55 | | - if (ret) |
56 | | - return ret; |
57 | | - } |
| 44 | + /* Use 20 dummy cycles for memory array reads. */ |
| 45 | + *buf = 20; |
| 46 | + op = (struct spi_mem_op) |
| 47 | + MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR1V, 1, buf); |
| 48 | + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); |
| 49 | + if (ret) |
| 50 | + return ret; |
| 51 | + ret = spi_nor_wait_till_ready(nor); |
| 52 | + if (ret) |
| 53 | + return ret; |
58 | 54 |
|
59 | | - ret = spi_nor_write_enable(nor); |
| 55 | + buf[0] = SPINOR_MT_OCT_DTR; |
| 56 | + op = (struct spi_mem_op) |
| 57 | + MICRON_ST_NOR_WR_ANY_REG_OP(3, SPINOR_REG_MT_CFR0V, 1, buf); |
| 58 | + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); |
60 | 59 | if (ret) |
61 | 60 | return ret; |
62 | 61 |
|
63 | | - if (enable) { |
64 | | - buf[0] = SPINOR_MT_OCT_DTR; |
65 | | - } else { |
66 | | - /* |
67 | | - * The register is 1-byte wide, but 1-byte transactions are not |
68 | | - * allowed in 8D-8D-8D mode. The next register is the dummy |
69 | | - * cycle configuration register. Since the transaction needs to |
70 | | - * be at least 2 bytes wide, set the next register to its |
71 | | - * default value. This also makes sense because the value was |
72 | | - * changed when enabling 8D-8D-8D mode, it should be reset when |
73 | | - * disabling. |
74 | | - */ |
75 | | - buf[0] = SPINOR_MT_EXSPI; |
76 | | - buf[1] = SPINOR_REG_MT_CFR1V_DEF; |
| 62 | + /* Read flash ID to make sure the switch was successful. */ |
| 63 | + ret = spi_nor_read_id(nor, 0, 8, buf, SNOR_PROTO_8_8_8_DTR); |
| 64 | + if (ret) { |
| 65 | + dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret); |
| 66 | + return ret; |
77 | 67 | } |
78 | 68 |
|
79 | | - op = (struct spi_mem_op) |
80 | | - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_MT_WR_ANY_REG, 1), |
81 | | - SPI_MEM_OP_ADDR(enable ? 3 : 4, |
82 | | - SPINOR_REG_MT_CFR0V, 1), |
83 | | - SPI_MEM_OP_NO_DUMMY, |
84 | | - SPI_MEM_OP_DATA_OUT(enable ? 1 : 2, buf, 1)); |
| 69 | + if (memcmp(buf, nor->info->id, nor->info->id_len)) |
| 70 | + return -EINVAL; |
85 | 71 |
|
86 | | - if (!enable) |
87 | | - spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR); |
| 72 | + return 0; |
| 73 | +} |
| 74 | + |
| 75 | +static int micron_st_nor_octal_dtr_dis(struct spi_nor *nor) |
| 76 | +{ |
| 77 | + struct spi_mem_op op; |
| 78 | + u8 *buf = nor->bouncebuf; |
| 79 | + int ret; |
88 | 80 |
|
89 | | - ret = spi_mem_exec_op(nor->spimem, &op); |
| 81 | + /* |
| 82 | + * The register is 1-byte wide, but 1-byte transactions are not allowed |
| 83 | + * in 8D-8D-8D mode. The next register is the dummy cycle configuration |
| 84 | + * register. Since the transaction needs to be at least 2 bytes wide, |
| 85 | + * set the next register to its default value. This also makes sense |
| 86 | + * because the value was changed when enabling 8D-8D-8D mode, it should |
| 87 | + * be reset when disabling. |
| 88 | + */ |
| 89 | + buf[0] = SPINOR_MT_EXSPI; |
| 90 | + buf[1] = SPINOR_REG_MT_CFR1V_DEF; |
| 91 | + op = (struct spi_mem_op) |
| 92 | + MICRON_ST_NOR_WR_ANY_REG_OP(4, SPINOR_REG_MT_CFR0V, 2, buf); |
| 93 | + ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); |
90 | 94 | if (ret) |
91 | 95 | return ret; |
92 | 96 |
|
93 | 97 | /* Read flash ID to make sure the switch was successful. */ |
94 | | - if (enable) |
95 | | - ret = spi_nor_read_id(nor, 0, 8, buf, SNOR_PROTO_8_8_8_DTR); |
96 | | - else |
97 | | - ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); |
98 | | - if (ret) |
| 98 | + ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); |
| 99 | + if (ret) { |
| 100 | + dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret); |
99 | 101 | return ret; |
| 102 | + } |
100 | 103 |
|
101 | 104 | if (memcmp(buf, nor->info->id, nor->info->id_len)) |
102 | 105 | return -EINVAL; |
103 | 106 |
|
104 | 107 | return 0; |
105 | 108 | } |
106 | 109 |
|
| 110 | +static int micron_st_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) |
| 111 | +{ |
| 112 | + return enable ? micron_st_nor_octal_dtr_en(nor) : |
| 113 | + micron_st_nor_octal_dtr_dis(nor); |
| 114 | +} |
| 115 | + |
107 | 116 | static void mt35xu512aba_default_init(struct spi_nor *nor) |
108 | 117 | { |
109 | 118 | nor->params->octal_dtr_enable = micron_st_nor_octal_dtr_enable; |
|
0 commit comments