xref: /aosp_15_r20/external/flashrom/nicintel_spi.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2010 Carl-Daniel Hailfinger
5  * Copyright (C) 2010 Idwer Vollering
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  */
16 
17 /*
18  * Datasheets:
19  * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer's Manual
20  * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx
21  * http://www.intel.com/content/www/us/en/ethernet-controllers/pci-pci-x-family-gbe-controllers-software-dev-manual.html
22  *
23  * PCIe GbE Controllers Open Source Software Developer's Manual
24  * http://www.intel.com/content/www/us/en/ethernet-controllers/pcie-gbe-controllers-open-source-manual.html
25  *
26  * Intel 82574 Gigabit Ethernet Controller Family Datasheet
27  * http://www.intel.com/content/www/us/en/ethernet-controllers/82574l-gbe-controller-datasheet.html
28  *
29  * Intel 82599 10 GbE Controller Datasheet (331520)
30  * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82599-10-gbe-controller-datasheet.pdf
31  */
32 
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include "flash.h"
36 #include "programmer.h"
37 #include "hwaccess_physmap.h"
38 #include "platform/pci.h"
39 
40 #define PCI_VENDOR_ID_INTEL 0x8086
41 #define MEMMAP_SIZE getpagesize()
42 
43 /* EEPROM/Flash Control & Data Register */
44 #define EECD	0x10
45 /* Flash Access Register */
46 #define FLA	0x1c
47 
48 /*
49  * Register bits of EECD.
50  * Table 13-6
51  *
52  * Bit 04, 05: FWE (Flash Write Enable Control)
53  * 00b = not allowed (on some cards this sends an erase command if bit 31 (FL_ER) of FLA is set)
54  * 01b = flash writes disabled
55  * 10b = flash writes enabled
56  * 11b = not allowed
57  */
58 #define FLASH_WRITES_DISABLED	0x10 /* FWE: 10000b */
59 #define FLASH_WRITES_ENABLED	0x20 /* FWE: 100000b */
60 
61 /* Flash Access register bits
62  * Table 13-9
63  */
64 #define FL_SCK	0
65 #define FL_CS	1
66 #define FL_SI	2
67 #define FL_SO	3
68 #define FL_REQ	4
69 #define FL_GNT	5
70 #define FL_LOCKED  6
71 #define FL_ABORT   7
72 #define FL_CLR_ERR 8
73 /* Currently unused */
74 // #define FL_BUSY	30
75 // #define FL_ER	31
76 
77 struct nicintel_spi_data {
78 	uint8_t *spibar;
79 };
80 
81 static const struct dev_entry nics_intel_spi[] = {
82 	{PCI_VENDOR_ID_INTEL, 0x105e, OK, "Intel", "82571EB Gigabit Ethernet Controller"},
83 	{PCI_VENDOR_ID_INTEL, 0x1076, OK, "Intel", "82541GI Gigabit Ethernet Controller"},
84 	{PCI_VENDOR_ID_INTEL, 0x107c, OK, "Intel", "82541PI Gigabit Ethernet Controller"},
85 	{PCI_VENDOR_ID_INTEL, 0x10b9, OK, "Intel", "82572EI Gigabit Ethernet Controller"},
86 	{PCI_VENDOR_ID_INTEL, 0x10d3, OK, "Intel", "82574L Gigabit Ethernet Controller"},
87 
88 	{PCI_VENDOR_ID_INTEL, 0x10d8, NT, "Intel", "82599 10 Gigabit Unprogrammed Network Controller"},
89 	{PCI_VENDOR_ID_INTEL, 0x10f7, NT, "Intel", "82599 10 Gigabit KX4 Dual Port Network Controller"},
90 	{PCI_VENDOR_ID_INTEL, 0x10f8, NT, "Intel", "82599 10 Gigabit Dual Port Backplane Controller"},
91 	{PCI_VENDOR_ID_INTEL, 0x10f9, NT, "Intel", "82599 10 Gigabit CX4 Dual Port Network Controller"},
92 	{PCI_VENDOR_ID_INTEL, 0x10fb, NT, "Intel", "82599 10-Gigabit SFI/SFP+ Network Controller"},
93 	{PCI_VENDOR_ID_INTEL, 0x10fc, OK, "Intel", "82599 10 Gigabit XAUI/BX4 Dual Port Network Controller"},
94 	{PCI_VENDOR_ID_INTEL, 0x1517, NT, "Intel", "82599 10 Gigabit KR Network Controller"},
95 	{PCI_VENDOR_ID_INTEL, 0x151c, NT, "Intel", "82599 10 Gigabit TN Network Controller"},
96 	{PCI_VENDOR_ID_INTEL, 0x1529, NT, "Intel", "82599 10 Gigabit Dual Port Network Controller with FCoE"},
97 	{PCI_VENDOR_ID_INTEL, 0x152a, NT, "Intel", "82599 10 Gigabit Dual Port Backplane Controller with FCoE"},
98 	{PCI_VENDOR_ID_INTEL, 0x1557, NT, "Intel", "82599 10 Gigabit SFI Network Controller"},
99 
100 	{PCI_VENDOR_ID_INTEL, 0x1531, OK, "Intel", "I210 Gigabit Network Connection Unprogrammed"},
101 	{PCI_VENDOR_ID_INTEL, 0x1532, NT, "Intel", "I211 Gigabit Network Connection Unprogrammed"},
102 	{PCI_VENDOR_ID_INTEL, 0x1533, NT, "Intel", "I210 Gigabit Network Connection"},
103 	{PCI_VENDOR_ID_INTEL, 0x1536, NT, "Intel", "I210 Gigabit Network Connection SERDES Fiber"},
104 	{PCI_VENDOR_ID_INTEL, 0x1537, NT, "Intel", "I210 Gigabit Network Connection SERDES Backplane"},
105 	{PCI_VENDOR_ID_INTEL, 0x1538, NT, "Intel", "I210 Gigabit Network Connection SGMII"},
106 	{PCI_VENDOR_ID_INTEL, 0x1539, NT, "Intel", "I211 Gigabit Network Connection"},
107 
108 	{0},
109 };
110 
nicintel_request_spibus(void * spi_data)111 static void nicintel_request_spibus(void *spi_data)
112 {
113 	struct nicintel_spi_data *data = spi_data;
114 	uint32_t tmp;
115 
116 	tmp = pci_mmio_readl(data->spibar + FLA);
117 	tmp |= BIT(FL_REQ);
118 	pci_mmio_writel(tmp, data->spibar + FLA);
119 
120 	/* Wait until we are allowed to use the SPI bus. */
121 	while (!(pci_mmio_readl(data->spibar + FLA) & BIT(FL_GNT))) ;
122 }
123 
nicintel_release_spibus(void * spi_data)124 static void nicintel_release_spibus(void *spi_data)
125 {
126 	struct nicintel_spi_data *data = spi_data;
127 	uint32_t tmp;
128 
129 	tmp = pci_mmio_readl(data->spibar + FLA);
130 	tmp &= ~BIT(FL_REQ);
131 	pci_mmio_writel(tmp, data->spibar + FLA);
132 }
133 
nicintel_bitbang_set_cs(int val,void * spi_data)134 static void nicintel_bitbang_set_cs(int val, void *spi_data)
135 {
136 	struct nicintel_spi_data *data = spi_data;
137 	uint32_t tmp;
138 
139 	tmp = pci_mmio_readl(data->spibar + FLA);
140 	tmp &= ~BIT(FL_CS);
141 	tmp |= (val << FL_CS);
142 	pci_mmio_writel(tmp, data->spibar + FLA);
143 }
144 
nicintel_bitbang_set_sck(int val,void * spi_data)145 static void nicintel_bitbang_set_sck(int val, void *spi_data)
146 {
147 	struct nicintel_spi_data *data = spi_data;
148 	uint32_t tmp;
149 
150 	tmp = pci_mmio_readl(data->spibar + FLA);
151 	tmp &= ~BIT(FL_SCK);
152 	tmp |= (val << FL_SCK);
153 	pci_mmio_writel(tmp, data->spibar + FLA);
154 }
155 
nicintel_bitbang_set_mosi(int val,void * spi_data)156 static void nicintel_bitbang_set_mosi(int val, void *spi_data)
157 {
158 	struct nicintel_spi_data *data = spi_data;
159 	uint32_t tmp;
160 
161 	tmp = pci_mmio_readl(data->spibar + FLA);
162 	tmp &= ~BIT(FL_SI);
163 	tmp |= (val << FL_SI);
164 	pci_mmio_writel(tmp, data->spibar + FLA);
165 }
166 
nicintel_bitbang_set_sck_set_mosi(int sck,int mosi,void * spi_data)167 static void nicintel_bitbang_set_sck_set_mosi(int sck, int mosi, void *spi_data)
168 {
169 	struct nicintel_spi_data *data = spi_data;
170 	uint32_t tmp;
171 
172 	tmp = pci_mmio_readl(data->spibar + FLA);
173 	tmp &= ~BIT(FL_SCK);
174 	tmp &= ~BIT(FL_SI);
175 	tmp |= (sck << FL_SCK);
176 	tmp |= (mosi << FL_SI);
177 	pci_mmio_writel(tmp, data->spibar + FLA);
178 }
179 
nicintel_bitbang_get_miso(void * spi_data)180 static int nicintel_bitbang_get_miso(void *spi_data)
181 {
182 	struct nicintel_spi_data *data = spi_data;
183 	uint32_t tmp;
184 
185 	tmp = pci_mmio_readl(data->spibar + FLA);
186 	tmp = (tmp >> FL_SO) & 0x1;
187 	return tmp;
188 }
189 
nicintel_bitbang_set_sck_get_miso(int sck,void * spi_data)190 static int nicintel_bitbang_set_sck_get_miso(int sck, void *spi_data)
191 {
192 	struct nicintel_spi_data *data = spi_data;
193 	uint32_t tmp;
194 
195 	tmp = pci_mmio_readl(data->spibar + FLA);
196 	tmp &= ~BIT(FL_SCK);
197 	tmp |= (sck << FL_SCK);
198 	pci_mmio_writel(tmp, data->spibar + FLA);
199 	return (tmp >> FL_SO) & 0x1;
200 }
201 
202 static const struct bitbang_spi_master bitbang_spi_master_nicintel = {
203 	.set_cs			= nicintel_bitbang_set_cs,
204 	.set_sck		= nicintel_bitbang_set_sck,
205 	.set_mosi		= nicintel_bitbang_set_mosi,
206 	.set_sck_set_mosi	= nicintel_bitbang_set_sck_set_mosi,
207 	.set_sck_get_miso	= nicintel_bitbang_set_sck_get_miso,
208 	.get_miso		= nicintel_bitbang_get_miso,
209 	.request_bus		= nicintel_request_spibus,
210 	.release_bus		= nicintel_release_spibus,
211 	.half_period		= 1,
212 };
213 
nicintel_spi_shutdown(void * spi_data)214 static int nicintel_spi_shutdown(void *spi_data)
215 {
216 	struct nicintel_spi_data *data = spi_data;
217 	uint32_t tmp;
218 
219 	/* Disable writes manually. See the comment about EECD in nicintel_spi_init() for details. */
220 	tmp = pci_mmio_readl(data->spibar + EECD);
221 	tmp &= ~FLASH_WRITES_ENABLED;
222 	tmp |= FLASH_WRITES_DISABLED;
223 	pci_mmio_writel(tmp, data->spibar + EECD);
224 
225 	free(data);
226 	return 0;
227 }
228 
nicintel_spi_82599_enable_flash(struct nicintel_spi_data * data)229 static int nicintel_spi_82599_enable_flash(struct nicintel_spi_data *data)
230 {
231 	uint32_t tmp;
232 
233 	/* Automatic restore of EECD on shutdown is not possible because EECD
234 	 * does not only contain FLASH_WRITES_DISABLED|FLASH_WRITES_ENABLED,
235 	 * but other bits with side effects as well. Those other bits must be
236 	 * left untouched.
237 	 */
238 	tmp = pci_mmio_readl(data->spibar + EECD);
239 	tmp &= ~FLASH_WRITES_DISABLED;
240 	tmp |= FLASH_WRITES_ENABLED;
241 	pci_mmio_writel(tmp, data->spibar + EECD);
242 
243 	/* test if FWE is really set to allow writes */
244 	tmp = pci_mmio_readl(data->spibar + EECD);
245 	if ( (tmp & FLASH_WRITES_DISABLED) || !(tmp & FLASH_WRITES_ENABLED) ) {
246 		msg_perr("Enabling flash write access failed.\n");
247 		return 1;
248 	}
249 
250 	if (register_shutdown(nicintel_spi_shutdown, data))
251 		return 1;
252 
253 	return 0;
254 }
255 
nicintel_spi_i210_shutdown(void * data)256 static int nicintel_spi_i210_shutdown(void *data)
257 {
258 	free(data);
259 	return 0;
260 }
261 
nicintel_spi_i210_enable_flash(struct nicintel_spi_data * data)262 static int nicintel_spi_i210_enable_flash(struct nicintel_spi_data *data)
263 {
264 	uint32_t tmp;
265 
266 	tmp = pci_mmio_readl(data->spibar + FLA);
267 	if (tmp & BIT(FL_LOCKED)) {
268 		msg_perr("Flash is in Secure Mode. Abort.\n");
269 		return 1;
270 	}
271 
272 	if (tmp & BIT(FL_ABORT)) {
273 		tmp |= BIT(FL_CLR_ERR);
274 		pci_mmio_writel(tmp, data->spibar + FLA);
275 		tmp = pci_mmio_readl(data->spibar + FLA);
276 		if (!(tmp & BIT(FL_ABORT))) {
277 			msg_perr("Unable to clear Flash Access Error. Abort\n");
278 			return 1;
279 		}
280 	}
281 
282 	if (register_shutdown(nicintel_spi_i210_shutdown, data))
283 		return 1;
284 
285 	return 0;
286 }
287 
nicintel_spi_init(const struct programmer_cfg * cfg)288 static int nicintel_spi_init(const struct programmer_cfg *cfg)
289 {
290 	struct pci_dev *dev = NULL;
291 
292 	dev = pcidev_init(cfg, nics_intel_spi, PCI_BASE_ADDRESS_0);
293 	if (!dev)
294 		return 1;
295 
296 	uint32_t io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0);
297 	if (!io_base_addr)
298 		return 1;
299 
300 	struct nicintel_spi_data *data = calloc(1, sizeof(*data));
301 	if (!data) {
302 		msg_perr("Unable to allocate space for SPI master data\n");
303 		return 1;
304 	}
305 
306 	if ((dev->device_id & 0xfff0) == 0x1530) {
307 		data->spibar = rphysmap("Intel I210 Gigabit w/ SPI flash", io_base_addr + 0x12000,
308 					   MEMMAP_SIZE);
309 		if (!data->spibar || nicintel_spi_i210_enable_flash(data)) {
310 				free(data);
311 				return 1;
312 		}
313 	} else if (dev->device_id < 0x10d8) {
314 		data->spibar = rphysmap("Intel Gigabit NIC w/ SPI flash", io_base_addr,
315 					   MEMMAP_SIZE);
316 		if (!data->spibar || nicintel_spi_82599_enable_flash(data)) {
317 				free(data);
318 				return 1;
319 		}
320 	} else {
321 		data->spibar = rphysmap("Intel 10 Gigabit NIC w/ SPI flash", io_base_addr + 0x10000,
322 					   MEMMAP_SIZE);
323 		if (!data->spibar || nicintel_spi_82599_enable_flash(data)) {
324 				free(data);
325 				return 1;
326 		}
327 	}
328 
329 	if (register_spi_bitbang_master(&bitbang_spi_master_nicintel, data))
330 		return 1; /* shutdown function does cleanup */
331 
332 	return 0;
333 }
334 
335 const struct programmer_entry programmer_nicintel_spi = {
336 	.name			= "nicintel_spi",
337 	.type			= PCI,
338 	.devs.dev		= nics_intel_spi,
339 	.init			= nicintel_spi_init,
340 };
341