|
23 | 23 | #define SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS 0 |
24 | 24 | #define SPINOR_OP_CYPRESS_RD_FAST 0xee |
25 | 25 |
|
26 | | -/** |
27 | | - * cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes. |
28 | | - * @nor: pointer to a 'struct spi_nor' |
29 | | - * @enable: whether to enable or disable Octal DTR |
30 | | - * |
31 | | - * This also sets the memory access latency cycles to 24 to allow the flash to |
32 | | - * run at up to 200MHz. |
33 | | - * |
34 | | - * Return: 0 on success, -errno otherwise. |
35 | | - */ |
36 | | -static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) |
| 26 | +/* Cypress SPI NOR flash operations. */ |
| 27 | +#define CYPRESS_NOR_WR_ANY_REG_OP(naddr, addr, ndata, buf) \ |
| 28 | + SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 0), \ |
| 29 | + SPI_MEM_OP_ADDR(naddr, addr, 0), \ |
| 30 | + SPI_MEM_OP_NO_DUMMY, \ |
| 31 | + SPI_MEM_OP_DATA_OUT(ndata, buf, 0)) |
| 32 | + |
| 33 | +static int cypress_nor_octal_dtr_en(struct spi_nor *nor) |
37 | 34 | { |
38 | 35 | struct spi_mem_op op; |
39 | 36 | u8 *buf = nor->bouncebuf; |
40 | 37 | int ret; |
41 | 38 |
|
42 | | - if (enable) { |
43 | | - /* Use 24 dummy cycles for memory array reads. */ |
44 | | - ret = spi_nor_write_enable(nor); |
45 | | - if (ret) |
46 | | - return ret; |
| 39 | + /* Use 24 dummy cycles for memory array reads. */ |
| 40 | + *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24; |
| 41 | + op = (struct spi_mem_op) |
| 42 | + CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR2V, 1, buf); |
47 | 43 |
|
48 | | - *buf = SPINOR_REG_CYPRESS_CFR2V_MEMLAT_11_24; |
49 | | - op = (struct spi_mem_op) |
50 | | - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), |
51 | | - SPI_MEM_OP_ADDR(3, SPINOR_REG_CYPRESS_CFR2V, |
52 | | - 1), |
53 | | - SPI_MEM_OP_NO_DUMMY, |
54 | | - SPI_MEM_OP_DATA_OUT(1, buf, 1)); |
| 44 | + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); |
| 45 | + if (ret) |
| 46 | + return ret; |
55 | 47 |
|
56 | | - ret = spi_mem_exec_op(nor->spimem, &op); |
57 | | - if (ret) |
58 | | - return ret; |
| 48 | + ret = spi_nor_wait_till_ready(nor); |
| 49 | + if (ret) |
| 50 | + return ret; |
59 | 51 |
|
60 | | - ret = spi_nor_wait_till_ready(nor); |
61 | | - if (ret) |
62 | | - return ret; |
| 52 | + nor->read_dummy = 24; |
63 | 53 |
|
64 | | - nor->read_dummy = 24; |
65 | | - } |
| 54 | + /* Set the octal and DTR enable bits. */ |
| 55 | + buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN; |
| 56 | + op = (struct spi_mem_op) |
| 57 | + CYPRESS_NOR_WR_ANY_REG_OP(3, SPINOR_REG_CYPRESS_CFR5V, 1, buf); |
66 | 58 |
|
67 | | - /* Set/unset the octal and DTR enable bits. */ |
68 | | - ret = spi_nor_write_enable(nor); |
| 59 | + ret = spi_nor_write_any_volatile_reg(nor, &op, nor->reg_proto); |
69 | 60 | if (ret) |
70 | 61 | return ret; |
71 | 62 |
|
72 | | - if (enable) { |
73 | | - buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_EN; |
74 | | - } else { |
75 | | - /* |
76 | | - * The register is 1-byte wide, but 1-byte transactions are not |
77 | | - * allowed in 8D-8D-8D mode. Since there is no register at the |
78 | | - * next location, just initialize the value to 0 and let the |
79 | | - * transaction go on. |
80 | | - */ |
81 | | - buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS; |
82 | | - buf[1] = 0; |
| 63 | + /* Read flash ID to make sure the switch was successful. */ |
| 64 | + ret = spi_nor_read_id(nor, 4, 3, buf, SNOR_PROTO_8_8_8_DTR); |
| 65 | + if (ret) { |
| 66 | + dev_dbg(nor->dev, "error %d reading JEDEC ID after enabling 8D-8D-8D mode\n", ret); |
| 67 | + return ret; |
83 | 68 | } |
84 | 69 |
|
85 | | - op = (struct spi_mem_op) |
86 | | - SPI_MEM_OP(SPI_MEM_OP_CMD(SPINOR_OP_WR_ANY_REG, 1), |
87 | | - SPI_MEM_OP_ADDR(enable ? 3 : 4, |
88 | | - SPINOR_REG_CYPRESS_CFR5V, |
89 | | - 1), |
90 | | - SPI_MEM_OP_NO_DUMMY, |
91 | | - SPI_MEM_OP_DATA_OUT(enable ? 1 : 2, buf, 1)); |
| 70 | + if (memcmp(buf, nor->info->id, nor->info->id_len)) |
| 71 | + return -EINVAL; |
92 | 72 |
|
93 | | - if (!enable) |
94 | | - spi_nor_spimem_setup_op(nor, &op, SNOR_PROTO_8_8_8_DTR); |
| 73 | + return 0; |
| 74 | +} |
95 | 75 |
|
96 | | - ret = spi_mem_exec_op(nor->spimem, &op); |
| 76 | +static int cypress_nor_octal_dtr_dis(struct spi_nor *nor) |
| 77 | +{ |
| 78 | + struct spi_mem_op op; |
| 79 | + u8 *buf = nor->bouncebuf; |
| 80 | + int ret; |
| 81 | + |
| 82 | + /* |
| 83 | + * The register is 1-byte wide, but 1-byte transactions are not allowed |
| 84 | + * in 8D-8D-8D mode. Since there is no register at the next location, |
| 85 | + * just initialize the value to 0 and let the transaction go on. |
| 86 | + */ |
| 87 | + buf[0] = SPINOR_REG_CYPRESS_CFR5V_OCT_DTR_DS; |
| 88 | + buf[1] = 0; |
| 89 | + op = (struct spi_mem_op) |
| 90 | + CYPRESS_NOR_WR_ANY_REG_OP(4, SPINOR_REG_CYPRESS_CFR5V, 2, buf); |
| 91 | + ret = spi_nor_write_any_volatile_reg(nor, &op, SNOR_PROTO_8_8_8_DTR); |
97 | 92 | if (ret) |
98 | 93 | return ret; |
99 | 94 |
|
100 | 95 | /* Read flash ID to make sure the switch was successful. */ |
101 | | - if (enable) |
102 | | - ret = spi_nor_read_id(nor, 4, 3, buf, SNOR_PROTO_8_8_8_DTR); |
103 | | - else |
104 | | - ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); |
105 | | - if (ret) |
| 96 | + ret = spi_nor_read_id(nor, 0, 0, buf, SNOR_PROTO_1_1_1); |
| 97 | + if (ret) { |
| 98 | + dev_dbg(nor->dev, "error %d reading JEDEC ID after disabling 8D-8D-8D mode\n", ret); |
106 | 99 | return ret; |
| 100 | + } |
107 | 101 |
|
108 | 102 | if (memcmp(buf, nor->info->id, nor->info->id_len)) |
109 | 103 | return -EINVAL; |
110 | 104 |
|
111 | 105 | return 0; |
112 | 106 | } |
113 | 107 |
|
| 108 | +/** |
| 109 | + * cypress_nor_octal_dtr_enable() - Enable octal DTR on Cypress flashes. |
| 110 | + * @nor: pointer to a 'struct spi_nor' |
| 111 | + * @enable: whether to enable or disable Octal DTR |
| 112 | + * |
| 113 | + * This also sets the memory access latency cycles to 24 to allow the flash to |
| 114 | + * run at up to 200MHz. |
| 115 | + * |
| 116 | + * Return: 0 on success, -errno otherwise. |
| 117 | + */ |
| 118 | +static int cypress_nor_octal_dtr_enable(struct spi_nor *nor, bool enable) |
| 119 | +{ |
| 120 | + return enable ? cypress_nor_octal_dtr_en(nor) : |
| 121 | + cypress_nor_octal_dtr_dis(nor); |
| 122 | +} |
| 123 | + |
114 | 124 | static void s28hs512t_default_init(struct spi_nor *nor) |
115 | 125 | { |
116 | 126 | nor->params->octal_dtr_enable = cypress_nor_octal_dtr_enable; |
|
0 commit comments