Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: m25p80: add support of SPI 1-2-2 and 1-4-4 protocols

Before this patch, m25p80_read() supported few SPI protocols:
- regular SPI 1-1-1
- SPI Dual Output 1-1-2
- SPI Quad Output 1-1-4
On the other hand, m25p80_write() only supported SPI 1-1-1.

This patch updates both m25p80_read() and m25p80_write() functions to let
them support SPI 1-2-2 and SPI 1-4-4 protocols for Fast Read and Page
Program SPI commands.

It adopts a conservative approach to avoid regressions. Hence the new
implementations try to be as close as possible to the old implementations,
so the main differences are:
- the tx_nbits values now being set properly for the spi_transfer
structures carrying the (op code + address/dummy) bytes
- and the spi_transfer structure being split into 2 spi_transfer
structures when the numbers of I/O lines are different for op code and
for address/dummy byte transfers on the SPI bus.

Besides, the current spi-nor framework supports neither the SPI 2-2-2 nor
the SPI 4-4-4 protocols. So, for now, we don't need to update the
m25p80_{read|write}_reg() functions as SPI 1-1-1 is the only one possible
protocol.

Signed-off-by: Cyrille Pitchen <cyrille.pitchen@atmel.com>
Reviewed-by: Marek Vasut <marek.vasut@gmail.com>

authored by

Cyrille Pitchen and committed by
Cyrille Pitchen
138f5dc6 cfc5604c

+79 -23
+79 -23
drivers/mtd/devices/m25p80.c
··· 78 78 { 79 79 struct m25p *flash = nor->priv; 80 80 struct spi_device *spi = flash->spi; 81 - struct spi_transfer t[2] = {}; 81 + unsigned int inst_nbits, addr_nbits, data_nbits, data_idx; 82 + struct spi_transfer t[3] = {}; 82 83 struct spi_message m; 83 84 int cmd_sz = m25p_cmdsz(nor); 84 85 ssize_t ret; 86 + 87 + /* get transfer protocols. */ 88 + inst_nbits = spi_nor_get_protocol_inst_nbits(nor->write_proto); 89 + addr_nbits = spi_nor_get_protocol_addr_nbits(nor->write_proto); 90 + data_nbits = spi_nor_get_protocol_data_nbits(nor->write_proto); 85 91 86 92 spi_message_init(&m); 87 93 ··· 98 92 m25p_addr2cmd(nor, to, flash->command); 99 93 100 94 t[0].tx_buf = flash->command; 95 + t[0].tx_nbits = inst_nbits; 101 96 t[0].len = cmd_sz; 102 97 spi_message_add_tail(&t[0], &m); 103 98 104 - t[1].tx_buf = buf; 105 - t[1].len = len; 106 - spi_message_add_tail(&t[1], &m); 99 + /* split the op code and address bytes into two transfers if needed. */ 100 + data_idx = 1; 101 + if (addr_nbits != inst_nbits) { 102 + t[0].len = 1; 103 + 104 + t[1].tx_buf = &flash->command[1]; 105 + t[1].tx_nbits = addr_nbits; 106 + t[1].len = cmd_sz - 1; 107 + spi_message_add_tail(&t[1], &m); 108 + 109 + data_idx = 2; 110 + } 111 + 112 + t[data_idx].tx_buf = buf; 113 + t[data_idx].tx_nbits = data_nbits; 114 + t[data_idx].len = len; 115 + spi_message_add_tail(&t[data_idx], &m); 107 116 108 117 ret = spi_sync(spi, &m); 109 118 if (ret) ··· 130 109 return ret; 131 110 } 132 111 133 - static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor) 134 - { 135 - return spi_nor_get_protocol_data_nbits(nor->read_proto); 136 - } 137 - 138 112 /* 139 113 * Read an address range from the nor chip. The address range 140 114 * may be any size provided it is within the physical boundaries. ··· 139 123 { 140 124 struct m25p *flash = nor->priv; 141 125 struct spi_device *spi = flash->spi; 142 - struct spi_transfer t[2]; 126 + unsigned int inst_nbits, addr_nbits, data_nbits, data_idx; 127 + struct spi_transfer t[3]; 143 128 struct spi_message m; 144 129 unsigned int dummy = nor->read_dummy; 145 130 ssize_t ret; 131 + int cmd_sz; 132 + 133 + /* get transfer protocols. */ 134 + inst_nbits = spi_nor_get_protocol_inst_nbits(nor->read_proto); 135 + addr_nbits = spi_nor_get_protocol_addr_nbits(nor->read_proto); 136 + data_nbits = spi_nor_get_protocol_data_nbits(nor->read_proto); 146 137 147 138 /* convert the dummy cycles to the number of bytes */ 148 - dummy /= 8; 139 + dummy = (dummy * addr_nbits) / 8; 149 140 150 141 if (spi_flash_read_supported(spi)) { 151 142 struct spi_flash_read_message msg; ··· 165 142 msg.read_opcode = nor->read_opcode; 166 143 msg.addr_width = nor->addr_width; 167 144 msg.dummy_bytes = dummy; 168 - /* TODO: Support other combinations */ 169 - msg.opcode_nbits = SPI_NBITS_SINGLE; 170 - msg.addr_nbits = SPI_NBITS_SINGLE; 171 - msg.data_nbits = m25p80_rx_nbits(nor); 145 + msg.opcode_nbits = inst_nbits; 146 + msg.addr_nbits = addr_nbits; 147 + msg.data_nbits = data_nbits; 172 148 173 149 ret = spi_flash_read(spi, &msg); 174 150 if (ret < 0) ··· 182 160 m25p_addr2cmd(nor, from, flash->command); 183 161 184 162 t[0].tx_buf = flash->command; 163 + t[0].tx_nbits = inst_nbits; 185 164 t[0].len = m25p_cmdsz(nor) + dummy; 186 165 spi_message_add_tail(&t[0], &m); 187 166 188 - t[1].rx_buf = buf; 189 - t[1].rx_nbits = m25p80_rx_nbits(nor); 190 - t[1].len = min3(len, spi_max_transfer_size(spi), 191 - spi_max_message_size(spi) - t[0].len); 192 - spi_message_add_tail(&t[1], &m); 167 + /* 168 + * Set all dummy/mode cycle bits to avoid sending some manufacturer 169 + * specific pattern, which might make the memory enter its Continuous 170 + * Read mode by mistake. 171 + * Based on the different mode cycle bit patterns listed and described 172 + * in the JESD216B specification, the 0xff value works for all memories 173 + * and all manufacturers. 174 + */ 175 + cmd_sz = t[0].len; 176 + memset(flash->command + cmd_sz - dummy, 0xff, dummy); 177 + 178 + /* split the op code and address bytes into two transfers if needed. */ 179 + data_idx = 1; 180 + if (addr_nbits != inst_nbits) { 181 + t[0].len = 1; 182 + 183 + t[1].tx_buf = &flash->command[1]; 184 + t[1].tx_nbits = addr_nbits; 185 + t[1].len = cmd_sz - 1; 186 + spi_message_add_tail(&t[1], &m); 187 + 188 + data_idx = 2; 189 + } 190 + 191 + t[data_idx].rx_buf = buf; 192 + t[data_idx].rx_nbits = data_nbits; 193 + t[data_idx].len = min3(len, spi_max_transfer_size(spi), 194 + spi_max_message_size(spi) - cmd_sz); 195 + spi_message_add_tail(&t[data_idx], &m); 193 196 194 197 ret = spi_sync(spi, &m); 195 198 if (ret) 196 199 return ret; 197 200 198 - ret = m.actual_length - m25p_cmdsz(nor) - dummy; 201 + ret = m.actual_length - cmd_sz; 199 202 if (ret < 0) 200 203 return -EIO; 201 204 return ret; ··· 265 218 spi_set_drvdata(spi, flash); 266 219 flash->spi = spi; 267 220 268 - if (spi->mode & SPI_RX_QUAD) 221 + if (spi->mode & SPI_RX_QUAD) { 269 222 hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4; 270 - else if (spi->mode & SPI_RX_DUAL) 223 + 224 + if (spi->mode & SPI_TX_QUAD) 225 + hwcaps.mask |= (SNOR_HWCAPS_READ_1_4_4 | 226 + SNOR_HWCAPS_PP_1_1_4 | 227 + SNOR_HWCAPS_PP_1_4_4); 228 + } else if (spi->mode & SPI_RX_DUAL) { 271 229 hwcaps.mask |= SNOR_HWCAPS_READ_1_1_2; 230 + 231 + if (spi->mode & SPI_TX_DUAL) 232 + hwcaps.mask |= SNOR_HWCAPS_READ_1_2_2; 233 + } 272 234 273 235 if (data && data->name) 274 236 nor->mtd.name = data->name;