Nico Huber | d518563 | 2024-01-05 18:44:41 +0100 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the flashrom project. |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License as published by |
| 6 | * the Free Software Foundation; either version 2 of the License, or |
| 7 | * (at your option) any later version. |
| 8 | * |
| 9 | * This program is distributed in the hope that it will be useful, |
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | * GNU General Public License for more details. |
| 13 | */ |
| 14 | |
| 15 | #ifndef __SPI_COMMAND_H__ |
| 16 | #define __SPI_COMMAND_H__ 1 |
| 17 | |
| 18 | #include <stdlib.h> |
| 19 | #include <stdbool.h> |
| 20 | |
| 21 | /* |
| 22 | * Modern SPI flashes support dual and quad i/o modes. However, there are |
| 23 | * subtle differences about which parts of a transactions are transferred |
| 24 | * in which mode. The transaction is generally divided into three phases: |
| 25 | * * opcode |
| 26 | * * address |
| 27 | * * data |
| 28 | * |
| 29 | * For each phase, the number of concurrently transferred bits is specified, |
| 30 | * hence we get a triple like |
| 31 | * * 1-1-1 |
| 32 | * which tells us that all three phases are transferred in single i/o |
| 33 | * mode. Or, for instance, |
| 34 | * * 1-4-4 |
| 35 | * which tells us the opcode is transferred in single i/o mode, but |
| 36 | * the address and data are transferred in quad i/o mode. |
| 37 | * |
| 38 | * There are a few common combinations, often chips support all of them: |
| 39 | * * 1-1-1 single i/o |
| 40 | * * 1-1-2 dual output (for reads, only the flash outputs two bits at once) |
| 41 | * * 1-2-2 dual i/o (both controller and flash can transfer two bits at once) |
| 42 | * * 1-1-4 quad output (for reads, only the flash outputs four bits at once) |
| 43 | * * 1-4-4 quad i/o (both controller and flash can transfer four bits at once) |
| 44 | * * 4-4-4 QPI |
| 45 | * In all modes that transfer the opcode in single i/o, the opcode tells the |
| 46 | * flash what to expect, i.e. how further bytes will be transferred. This |
| 47 | * achieves backwards compatibility with simple SPI controllers. The QPI |
| 48 | * mode, OTOH, is not backwards compatible and usually needs to be entered |
| 49 | * first with a special opcode. In QPI mode, only fast-read instructions |
| 50 | * (w/ dummy cycles) are supported; the number of dummy cycles is often |
| 51 | * configurable. |
| 52 | * |
| 53 | * For dual i/o, MOSI and MISO lines are bidirectional. So this can work |
| 54 | * without any special setup, if both controller and flash are compatible. |
| 55 | * |
| 56 | * For quad i/o, usually the flash's /HOLD and /WP pins are re-purposed, and |
| 57 | * the controller needs additional pins. The pin muxes inside the flash are |
| 58 | * usually controlled by a quad-enable (QE) bit in the status register. This |
| 59 | * is *not* to be confused with entering QPI mode. Quad-enable merely says |
| 60 | * that the pins are available for data transfer. |
| 61 | */ |
| 62 | enum io_mode { |
| 63 | SINGLE_IO_1_1_1, |
| 64 | DUAL_OUT_1_1_2, |
| 65 | DUAL_IO_1_2_2, |
| 66 | QUAD_OUT_1_1_4, |
| 67 | QUAD_IO_1_4_4, |
| 68 | QPI_4_4_4, |
| 69 | }; |
| 70 | |
Nico Huber | 1b1deda | 2024-04-18 00:35:48 +0200 | [diff] [blame] | 71 | enum io_mode spi_current_io_mode(const struct flashctx *); |
| 72 | |
Nico Huber | 4760b6e | 2024-01-06 23:45:28 +0100 | [diff] [blame] | 73 | /* describes properties of a read operation */ |
| 74 | struct spi_read_op { |
| 75 | enum io_mode io_mode; |
| 76 | bool native_4ba; |
| 77 | uint8_t opcode; |
| 78 | uint8_t mode_byte; /* optional byte to send after the address, if != 0 */ |
| 79 | uint8_t dummy_len; /* dummy bytes (including optional mode byte) */ |
| 80 | }; |
| 81 | |
Nico Huber | a1b7f35 | 2024-03-25 18:32:11 +0100 | [diff] [blame] | 82 | const struct spi_read_op *get_spi_read_op(const struct flashctx *); |
| 83 | |
| 84 | static inline unsigned int spi_dummy_cycles(const struct spi_read_op *const op) |
| 85 | { |
| 86 | return op->dummy_len * 8 |
| 87 | / (op->io_mode == SINGLE_IO_1_1_1 ? 1 |
| 88 | : (op->io_mode <= DUAL_IO_1_2_2 ? 2 : 4)); |
| 89 | } |
| 90 | |
Nico Huber | d518563 | 2024-01-05 18:44:41 +0100 | [diff] [blame] | 91 | struct spi_command { |
| 92 | enum io_mode io_mode; |
| 93 | size_t opcode_len; /* bytes to write in opcode i/o phase */ |
| 94 | size_t address_len; /* bytes to write in address i/o phase */ |
| 95 | size_t write_len; /* bytes to write in data i/o phase */ |
| 96 | size_t high_z_len; /* dummy bytes to skip in data i/o phase */ |
| 97 | size_t read_len; /* bytes to read in data i/o phase */ |
| 98 | const unsigned char *writearr; |
| 99 | unsigned char *readarr; |
| 100 | }; |
| 101 | #define NULL_SPI_CMD { 0, 0, 0, 0, 0, 0, NULL, NULL, } |
| 102 | |
| 103 | static inline size_t spi_write_len(const struct spi_command *const cmd) |
| 104 | { |
| 105 | return cmd->opcode_len + cmd->address_len + cmd->write_len; |
| 106 | } |
| 107 | |
| 108 | static inline size_t spi_read_len(const struct spi_command *const cmd) |
| 109 | { |
| 110 | return cmd->high_z_len + cmd->read_len; |
| 111 | } |
| 112 | |
| 113 | static inline bool spi_is_empty(const struct spi_command *const cmd) |
| 114 | { |
| 115 | return !spi_write_len(cmd) && !spi_read_len(cmd); |
| 116 | } |
| 117 | |
| 118 | int spi_send_command(const struct flashctx *, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr); |
| 119 | int spi_send_multicommand(const struct flashctx *, struct spi_command *cmds); |
| 120 | |
| 121 | #endif /* !__SPI_COMMAND_H__ */ |