stepan | d4b1375 | 2007-10-15 21:45:29 +0000 | [diff] [blame] | 1 | /* |
| 2 | * This file is part of the flashrom project. |
| 3 | * |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 4 | * Copyright (C) 2007, 2008, 2009 Carl-Daniel Hailfinger |
stepan | dbd3af1 | 2008-06-27 16:28:34 +0000 | [diff] [blame] | 5 | * Copyright (C) 2008 coresystems GmbH |
stepan | d4b1375 | 2007-10-15 21:45:29 +0000 | [diff] [blame] | 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify |
| 8 | * it under the terms of the GNU General Public License as published by |
| 9 | * the Free Software Foundation; version 2 of the License. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
stepan | d4b1375 | 2007-10-15 21:45:29 +0000 | [diff] [blame] | 16 | */ |
| 17 | |
| 18 | /* |
| 19 | * Contains the generic SPI framework |
| 20 | */ |
| 21 | |
oxygene | 70aa650 | 2011-03-08 07:17:44 +0000 | [diff] [blame] | 22 | #include <strings.h> |
hailfinger | 132df7b | 2010-09-15 00:13:02 +0000 | [diff] [blame] | 23 | #include <string.h> |
stepan | d4b1375 | 2007-10-15 21:45:29 +0000 | [diff] [blame] | 24 | #include "flash.h" |
hailfinger | 66966da | 2009-06-15 14:14:48 +0000 | [diff] [blame] | 25 | #include "flashchips.h" |
snelson | 8913d08 | 2010-02-26 05:48:29 +0000 | [diff] [blame] | 26 | #include "chipdrivers.h" |
hailfinger | 428f685 | 2010-07-27 22:41:39 +0000 | [diff] [blame] | 27 | #include "programmer.h" |
hailfinger | 7803156 | 2008-05-13 14:58:23 +0000 | [diff] [blame] | 28 | #include "spi.h" |
stepan | d4b1375 | 2007-10-15 21:45:29 +0000 | [diff] [blame] | 29 | |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 30 | const struct spi_master spi_master_none = { |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 31 | .max_data_read = MAX_DATA_UNSPECIFIED, |
| 32 | .max_data_write = MAX_DATA_UNSPECIFIED, |
| 33 | .command = NULL, |
| 34 | .multicommand = NULL, |
| 35 | .read = NULL, |
| 36 | .write_256 = NULL, |
| 37 | }; |
| 38 | |
| 39 | const struct spi_master *spi_master = &spi_master_none; |
| 40 | |
Souvik Ghosh | d75cd67 | 2016-06-17 14:21:39 -0700 | [diff] [blame] | 41 | int spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, |
uwe | fa98ca1 | 2008-10-18 21:14:13 +0000 | [diff] [blame] | 42 | const unsigned char *writearr, unsigned char *readarr) |
hailfinger | 35cc816 | 2007-10-16 21:09:06 +0000 | [diff] [blame] | 43 | { |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 44 | if (!spi_master->command) { |
Duncan Laurie | 870d8af | 2019-01-09 18:05:23 -0800 | [diff] [blame] | 45 | msg_pdbg("%s called, but SPI is unsupported on this " |
David Hendricks | ac1d25c | 2016-08-09 17:00:58 -0700 | [diff] [blame] | 46 | "hardware. Please report a bug at " |
| 47 | "flashrom@flashrom.org\n", __func__); |
| 48 | return 1; |
| 49 | } |
| 50 | |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 51 | return spi_master->command(flash, writecnt, readcnt, |
David Hendricks | ac1d25c | 2016-08-09 17:00:58 -0700 | [diff] [blame] | 52 | writearr, readarr); |
hailfinger | 35cc816 | 2007-10-16 21:09:06 +0000 | [diff] [blame] | 53 | } |
| 54 | |
Souvik Ghosh | d75cd67 | 2016-06-17 14:21:39 -0700 | [diff] [blame] | 55 | int spi_send_multicommand(const struct flashctx *flash, struct spi_command *cmds) |
hailfinger | 68002c2 | 2009-07-10 21:08:55 +0000 | [diff] [blame] | 56 | { |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 57 | if (!spi_master->multicommand) { |
Duncan Laurie | 870d8af | 2019-01-09 18:05:23 -0800 | [diff] [blame] | 58 | msg_pdbg("%s called, but SPI is unsupported on this " |
David Hendricks | ac1d25c | 2016-08-09 17:00:58 -0700 | [diff] [blame] | 59 | "hardware. Please report a bug at " |
| 60 | "flashrom@flashrom.org\n", __func__); |
| 61 | return 1; |
| 62 | } |
| 63 | |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 64 | return spi_master->multicommand(flash, cmds); |
hailfinger | 948b81f | 2009-07-22 15:36:50 +0000 | [diff] [blame] | 65 | } |
| 66 | |
Souvik Ghosh | d75cd67 | 2016-06-17 14:21:39 -0700 | [diff] [blame] | 67 | int default_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, |
hailfinger | 948b81f | 2009-07-22 15:36:50 +0000 | [diff] [blame] | 68 | const unsigned char *writearr, unsigned char *readarr) |
| 69 | { |
| 70 | struct spi_command cmd[] = { |
| 71 | { |
| 72 | .writecnt = writecnt, |
| 73 | .readcnt = readcnt, |
| 74 | .writearr = writearr, |
| 75 | .readarr = readarr, |
| 76 | }, { |
| 77 | .writecnt = 0, |
| 78 | .writearr = NULL, |
| 79 | .readcnt = 0, |
| 80 | .readarr = NULL, |
| 81 | }}; |
| 82 | |
Souvik Ghosh | d75cd67 | 2016-06-17 14:21:39 -0700 | [diff] [blame] | 83 | return spi_send_multicommand(flash, cmd); |
hailfinger | 948b81f | 2009-07-22 15:36:50 +0000 | [diff] [blame] | 84 | } |
| 85 | |
Souvik Ghosh | d75cd67 | 2016-06-17 14:21:39 -0700 | [diff] [blame] | 86 | int default_spi_send_multicommand(const struct flashctx *flash, struct spi_command *cmds) |
hailfinger | 948b81f | 2009-07-22 15:36:50 +0000 | [diff] [blame] | 87 | { |
| 88 | int result = 0; |
hailfinger | bb09211 | 2009-09-18 15:50:56 +0000 | [diff] [blame] | 89 | for (; (cmds->writecnt || cmds->readcnt) && !result; cmds++) { |
Souvik Ghosh | d75cd67 | 2016-06-17 14:21:39 -0700 | [diff] [blame] | 90 | result = spi_send_command(flash, cmds->writecnt, cmds->readcnt, |
hailfinger | bb09211 | 2009-09-18 15:50:56 +0000 | [diff] [blame] | 91 | cmds->writearr, cmds->readarr); |
hailfinger | 948b81f | 2009-07-22 15:36:50 +0000 | [diff] [blame] | 92 | } |
| 93 | return result; |
hailfinger | 68002c2 | 2009-07-10 21:08:55 +0000 | [diff] [blame] | 94 | } |
| 95 | |
Souvik Ghosh | d75cd67 | 2016-06-17 14:21:39 -0700 | [diff] [blame] | 96 | int default_spi_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) |
mkarcher | 8fb5759 | 2011-05-11 17:07:02 +0000 | [diff] [blame] | 97 | { |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 98 | unsigned int max_data = spi_master->max_data_read; |
David Hendricks | 1ed1d35 | 2011-11-23 17:54:37 -0800 | [diff] [blame] | 99 | int rc; |
mkarcher | 8fb5759 | 2011-05-11 17:07:02 +0000 | [diff] [blame] | 100 | if (max_data == MAX_DATA_UNSPECIFIED) { |
| 101 | msg_perr("%s called, but SPI read chunk size not defined " |
| 102 | "on this hardware. Please report a bug at " |
| 103 | "flashrom@flashrom.org\n", __func__); |
| 104 | return 1; |
| 105 | } |
Edward O'Callaghan | 2748621 | 2019-07-26 21:59:55 +1000 | [diff] [blame] | 106 | rc = spi_read_chunked(flash, buf, start, len, max_data); |
David Hendricks | 1ed1d35 | 2011-11-23 17:54:37 -0800 | [diff] [blame] | 107 | /* translate SPI-specific access denied error to generic error */ |
| 108 | if (rc == SPI_ACCESS_DENIED) |
| 109 | rc = ACCESS_DENIED; |
| 110 | return rc; |
mkarcher | 8fb5759 | 2011-05-11 17:07:02 +0000 | [diff] [blame] | 111 | } |
| 112 | |
Patrick Georgi | ab8353e | 2017-02-03 18:32:01 +0100 | [diff] [blame] | 113 | int default_spi_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len) |
mkarcher | 8fb5759 | 2011-05-11 17:07:02 +0000 | [diff] [blame] | 114 | { |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 115 | unsigned int max_data = spi_master->max_data_write; |
David Hendricks | 1ed1d35 | 2011-11-23 17:54:37 -0800 | [diff] [blame] | 116 | int rc; |
mkarcher | 8fb5759 | 2011-05-11 17:07:02 +0000 | [diff] [blame] | 117 | if (max_data == MAX_DATA_UNSPECIFIED) { |
| 118 | msg_perr("%s called, but SPI write chunk size not defined " |
| 119 | "on this hardware. Please report a bug at " |
| 120 | "flashrom@flashrom.org\n", __func__); |
| 121 | return 1; |
| 122 | } |
David Hendricks | 1ed1d35 | 2011-11-23 17:54:37 -0800 | [diff] [blame] | 123 | rc = spi_write_chunked(flash, buf, start, len, max_data); |
| 124 | /* translate SPI-specific access denied error to generic error */ |
| 125 | if (rc == SPI_ACCESS_DENIED) |
| 126 | rc = ACCESS_DENIED; |
| 127 | return rc; |
mkarcher | 8fb5759 | 2011-05-11 17:07:02 +0000 | [diff] [blame] | 128 | } |
| 129 | |
Souvik Ghosh | d75cd67 | 2016-06-17 14:21:39 -0700 | [diff] [blame] | 130 | int spi_chip_read(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) |
hailfinger | b8f7e88 | 2008-01-19 00:04:46 +0000 | [diff] [blame] | 131 | { |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 132 | if (!spi_master->read) { |
David Hendricks | ac1d25c | 2016-08-09 17:00:58 -0700 | [diff] [blame] | 133 | msg_perr("%s called, but SPI read is unsupported on this " |
| 134 | "hardware. Please report a bug at " |
| 135 | "flashrom@flashrom.org\n", __func__); |
| 136 | return 1; |
| 137 | } |
| 138 | |
Edward O'Callaghan | dfb7154 | 2020-05-14 18:41:42 +1000 | [diff] [blame] | 139 | return spi_master->read(flash, buf, start, len); |
hailfinger | b8f7e88 | 2008-01-19 00:04:46 +0000 | [diff] [blame] | 140 | } |
| 141 | |
hailfinger | ed063f5 | 2009-05-09 02:30:21 +0000 | [diff] [blame] | 142 | /* |
hailfinger | ed063f5 | 2009-05-09 02:30:21 +0000 | [diff] [blame] | 143 | * Program chip using page (256 bytes) programming. |
| 144 | * Some SPI masters can't do this, they use single byte programming instead. |
hailfinger | c7d06c6 | 2010-07-14 16:19:05 +0000 | [diff] [blame] | 145 | * The redirect to single byte programming is achieved by setting |
| 146 | * .write_256 = spi_chip_write_1 |
hailfinger | ed063f5 | 2009-05-09 02:30:21 +0000 | [diff] [blame] | 147 | */ |
hailfinger | c7d06c6 | 2010-07-14 16:19:05 +0000 | [diff] [blame] | 148 | /* real chunksize is up to 256, logical chunksize is 256 */ |
Patrick Georgi | ab8353e | 2017-02-03 18:32:01 +0100 | [diff] [blame] | 149 | int spi_chip_write_256(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len) |
hailfinger | 2c361e4 | 2008-05-13 23:03:12 +0000 | [diff] [blame] | 150 | { |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 151 | if (!spi_master->write_256) { |
David Hendricks | ac1d25c | 2016-08-09 17:00:58 -0700 | [diff] [blame] | 152 | msg_perr("%s called, but SPI page write is unsupported on this " |
| 153 | "hardware. Please report a bug at " |
| 154 | "flashrom@flashrom.org\n", __func__); |
| 155 | return 1; |
| 156 | } |
| 157 | |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 158 | return spi_master->write_256(flash, buf, start, len); |
hailfinger | c7d06c6 | 2010-07-14 16:19:05 +0000 | [diff] [blame] | 159 | } |
| 160 | |
Edward O'Callaghan | eeaac6b | 2020-10-12 19:51:56 +1100 | [diff] [blame^] | 161 | int spi_aai_write(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len) |
| 162 | { |
| 163 | return flash->mst->spi.write_aai(flash, buf, start, len); |
| 164 | } |
| 165 | |
Edward O'Callaghan | 20ba615 | 2019-08-26 23:21:09 +1000 | [diff] [blame] | 166 | int register_spi_master(const struct spi_master *mst) |
mkarcher | d264e9e | 2011-05-11 17:07:07 +0000 | [diff] [blame] | 167 | { |
Edward O'Callaghan | 20ba615 | 2019-08-26 23:21:09 +1000 | [diff] [blame] | 168 | struct registered_master rmst; |
| 169 | |
| 170 | // TODO(quasisec): Kill off these global states. |
| 171 | spi_master = mst; |
Craig Hesling | 65eb881 | 2019-08-01 09:33:56 -0700 | [diff] [blame] | 172 | buses_supported |= BUS_SPI; |
Edward O'Callaghan | 20ba615 | 2019-08-26 23:21:09 +1000 | [diff] [blame] | 173 | |
| 174 | rmst.buses_supported = BUS_SPI; |
| 175 | rmst.spi = *mst; |
| 176 | |
| 177 | return register_master(&rmst); |
David Hendricks | 9104083 | 2011-07-08 20:01:09 -0700 | [diff] [blame] | 178 | } |