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 | * You should have received a copy of the GNU General Public License␊ |
17 | * along with this program; if not, write to the Free Software␊ |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA␊ |
19 | */␊ |
20 | ␊ |
21 | /*␊ |
22 | * Datasheets:␊ |
23 | * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer's Manual␊ |
24 | * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx␊ |
25 | * http://www.intel.com/content/www/us/en/ethernet-controllers/pci-pci-x-family-gbe-controllers-software-dev-manual.html␊ |
26 | *␊ |
27 | * PCIe GbE Controllers Open Source Software Developer's Manual␊ |
28 | * http://www.intel.com/content/www/us/en/ethernet-controllers/pcie-gbe-controllers-open-source-manual.html␊ |
29 | *␊ |
30 | * Intel 82574 Gigabit Ethernet Controller Family Datasheet␊ |
31 | * http://www.intel.com/content/www/us/en/ethernet-controllers/82574l-gbe-controller-datasheet.html␊ |
32 | *␊ |
33 | * Intel 82599 10 GbE Controller Datasheet (331520)␊ |
34 | * http://www.intel.com/content/dam/www/public/us/en/documents/datasheets/82599-10-gbe-controller-datasheet.pdf␊ |
35 | */␊ |
36 | ␊ |
37 | #include <stdlib.h>␊ |
38 | #include <unistd.h>␊ |
39 | #include "flash.h"␊ |
40 | #include "programmer.h"␊ |
41 | #include "hwaccess.h"␊ |
42 | ␊ |
43 | #define PCI_VENDOR_ID_INTEL 0x8086␊ |
44 | #define MEMMAP_SIZE getpagesize()␊ |
45 | ␊ |
46 | /* EEPROM/Flash Control & Data Register */␊ |
47 | #define EECD␉0x10␊ |
48 | /* Flash Access Register */␊ |
49 | #define FLA␉0x1c␊ |
50 | ␊ |
51 | /*␊ |
52 | * Register bits of EECD.␊ |
53 | * Table 13-6␊ |
54 | *␊ |
55 | * Bit 04, 05: FWE (Flash Write Enable Control)␊ |
56 | * 00b = not allowed (on some cards this sends an erase command if bit 31 (FL_ER) of FLA is set)␊ |
57 | * 01b = flash writes disabled␊ |
58 | * 10b = flash writes enabled␊ |
59 | * 11b = not allowed␊ |
60 | */␊ |
61 | #define FLASH_WRITES_DISABLED␉0x10 /* FWE: 10000b */␊ |
62 | #define FLASH_WRITES_ENABLED␉0x20 /* FWE: 100000b */␊ |
63 | ␊ |
64 | /* Flash Access register bits␊ |
65 | * Table 13-9␊ |
66 | */␊ |
67 | #define FL_SCK␉0␊ |
68 | #define FL_CS␉1␊ |
69 | #define FL_SI␉2␊ |
70 | #define FL_SO␉3␊ |
71 | #define FL_REQ␉4␊ |
72 | #define FL_GNT␉5␊ |
73 | /* Currently unused */␊ |
74 | // #define FL_BUSY␉30␊ |
75 | // #define FL_ER␉31␊ |
76 | ␊ |
77 | uint8_t *nicintel_spibar;␊ |
78 | ␊ |
79 | const struct dev_entry nics_intel_spi[] = {␊ |
80 | ␉{PCI_VENDOR_ID_INTEL, 0x105e, OK, "Intel", "82571EB Gigabit Ethernet Controller"},␊ |
81 | ␉{PCI_VENDOR_ID_INTEL, 0x1076, OK, "Intel", "82541GI Gigabit Ethernet Controller"},␊ |
82 | ␉{PCI_VENDOR_ID_INTEL, 0x107c, OK, "Intel", "82541PI Gigabit Ethernet Controller"},␊ |
83 | ␉{PCI_VENDOR_ID_INTEL, 0x10b9, OK, "Intel", "82572EI Gigabit Ethernet Controller"},␊ |
84 | ␉{PCI_VENDOR_ID_INTEL, 0x10d3, OK, "Intel", "82574L Gigabit Ethernet Controller"},␊ |
85 | ␊ |
86 | ␉{PCI_VENDOR_ID_INTEL, 0x10d8, NT, "Intel", "82599 10 Gigabit Unprogrammed Network Controller"},␊ |
87 | ␉{PCI_VENDOR_ID_INTEL, 0x10f7, NT, "Intel", "82599 10 Gigabit KX4 Dual Port Network Controller"},␊ |
88 | ␉{PCI_VENDOR_ID_INTEL, 0x10f8, NT, "Intel", "82599 10 Gigabit Dual Port Backplane Controller"},␊ |
89 | ␉{PCI_VENDOR_ID_INTEL, 0x10f9, NT, "Intel", "82599 10 Gigabit CX4 Dual Port Network Controller"},␊ |
90 | ␉{PCI_VENDOR_ID_INTEL, 0x10fb, NT, "Intel", "82599 10-Gigabit SFI/SFP+ Network Controller"},␊ |
91 | ␉{PCI_VENDOR_ID_INTEL, 0x10fc, OK, "Intel", "82599 10 Gigabit XAUI/BX4 Dual Port Network Controller"},␊ |
92 | ␉{PCI_VENDOR_ID_INTEL, 0x1517, NT, "Intel", "82599 10 Gigabit KR Network Controller"},␊ |
93 | ␉{PCI_VENDOR_ID_INTEL, 0x151c, NT, "Intel", "82599 10 Gigabit TN Network Controller"},␊ |
94 | ␉{PCI_VENDOR_ID_INTEL, 0x1529, NT, "Intel", "82599 10 Gigabit Dual Port Network Controller with FCoE"},␊ |
95 | ␉{PCI_VENDOR_ID_INTEL, 0x152a, NT, "Intel", "82599 10 Gigabit Dual Port Backplane Controller with FCoE"},␊ |
96 | ␉{PCI_VENDOR_ID_INTEL, 0x1557, NT, "Intel", "82599 10 Gigabit SFI Network Controller"},␊ |
97 | ␊ |
98 | ␉{0},␊ |
99 | };␊ |
100 | ␊ |
101 | static void nicintel_request_spibus(void)␊ |
102 | {␊ |
103 | ␉uint32_t tmp;␊ |
104 | ␊ |
105 | ␉tmp = pci_mmio_readl(nicintel_spibar + FLA);␊ |
106 | ␉tmp |= 1 << FL_REQ;␊ |
107 | ␉pci_mmio_writel(tmp, nicintel_spibar + FLA);␊ |
108 | ␊ |
109 | ␉/* Wait until we are allowed to use the SPI bus. */␊ |
110 | ␉while (!(pci_mmio_readl(nicintel_spibar + FLA) & (1 << FL_GNT))) ;␊ |
111 | }␊ |
112 | ␊ |
113 | static void nicintel_release_spibus(void)␊ |
114 | {␊ |
115 | ␉uint32_t tmp;␊ |
116 | ␊ |
117 | ␉tmp = pci_mmio_readl(nicintel_spibar + FLA);␊ |
118 | ␉tmp &= ~(1 << FL_REQ);␊ |
119 | ␉pci_mmio_writel(tmp, nicintel_spibar + FLA);␊ |
120 | }␊ |
121 | ␊ |
122 | static void nicintel_bitbang_set_cs(int val)␊ |
123 | {␊ |
124 | ␉uint32_t tmp;␊ |
125 | ␊ |
126 | ␉tmp = pci_mmio_readl(nicintel_spibar + FLA);␊ |
127 | ␉tmp &= ~(1 << FL_CS);␊ |
128 | ␉tmp |= (val << FL_CS);␊ |
129 | ␉pci_mmio_writel(tmp, nicintel_spibar + FLA);␊ |
130 | }␊ |
131 | ␊ |
132 | static void nicintel_bitbang_set_sck(int val)␊ |
133 | {␊ |
134 | ␉uint32_t tmp;␊ |
135 | ␊ |
136 | ␉tmp = pci_mmio_readl(nicintel_spibar + FLA);␊ |
137 | ␉tmp &= ~(1 << FL_SCK);␊ |
138 | ␉tmp |= (val << FL_SCK);␊ |
139 | ␉pci_mmio_writel(tmp, nicintel_spibar + FLA);␊ |
140 | }␊ |
141 | ␊ |
142 | static void nicintel_bitbang_set_mosi(int val)␊ |
143 | {␊ |
144 | ␉uint32_t tmp;␊ |
145 | ␊ |
146 | ␉tmp = pci_mmio_readl(nicintel_spibar + FLA);␊ |
147 | ␉tmp &= ~(1 << FL_SI);␊ |
148 | ␉tmp |= (val << FL_SI);␊ |
149 | ␉pci_mmio_writel(tmp, nicintel_spibar + FLA);␊ |
150 | }␊ |
151 | ␊ |
152 | static int nicintel_bitbang_get_miso(void)␊ |
153 | {␊ |
154 | ␉uint32_t tmp;␊ |
155 | ␊ |
156 | ␉tmp = pci_mmio_readl(nicintel_spibar + FLA);␊ |
157 | ␉tmp = (tmp >> FL_SO) & 0x1;␊ |
158 | ␉return tmp;␊ |
159 | }␊ |
160 | ␊ |
161 | static const struct bitbang_spi_master bitbang_spi_master_nicintel = {␊ |
162 | ␉.type = BITBANG_SPI_MASTER_NICINTEL,␊ |
163 | ␉.set_cs = nicintel_bitbang_set_cs,␊ |
164 | ␉.set_sck = nicintel_bitbang_set_sck,␊ |
165 | ␉.set_mosi = nicintel_bitbang_set_mosi,␊ |
166 | ␉.get_miso = nicintel_bitbang_get_miso,␊ |
167 | ␉.request_bus = nicintel_request_spibus,␊ |
168 | ␉.release_bus = nicintel_release_spibus,␊ |
169 | ␉.half_period = 1,␊ |
170 | };␊ |
171 | ␊ |
172 | static int nicintel_spi_shutdown(void *data)␊ |
173 | {␊ |
174 | ␉uint32_t tmp;␊ |
175 | ␊ |
176 | ␉/* Disable writes manually. See the comment about EECD in nicintel_spi_init() for details. */␊ |
177 | ␉tmp = pci_mmio_readl(nicintel_spibar + EECD);␊ |
178 | ␉tmp &= ~FLASH_WRITES_ENABLED;␊ |
179 | ␉tmp |= FLASH_WRITES_DISABLED;␊ |
180 | ␉pci_mmio_writel(tmp, nicintel_spibar + EECD);␊ |
181 | ␊ |
182 | ␉return 0;␊ |
183 | }␊ |
184 | ␊ |
185 | int nicintel_spi_init(void)␊ |
186 | {␊ |
187 | ␉struct pci_dev *dev = NULL;␊ |
188 | ␉uint32_t tmp;␊ |
189 | ␊ |
190 | ␉if (rget_io_perms())␊ |
191 | ␉␉return 1;␊ |
192 | ␊ |
193 | ␉dev = pcidev_init(nics_intel_spi, PCI_BASE_ADDRESS_0);␊ |
194 | ␉if (!dev)␊ |
195 | ␉␉return 1;␊ |
196 | ␊ |
197 | ␉uint32_t io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0);␊ |
198 | ␉if (!io_base_addr)␊ |
199 | ␉␉return 1;␊ |
200 | ␊ |
201 | ␉if (dev->device_id < 0x10d8) {␊ |
202 | ␉␉nicintel_spibar = rphysmap("Intel Gigabit NIC w/ SPI flash", io_base_addr,␊ |
203 | ␉␉␉␉␉ MEMMAP_SIZE);␊ |
204 | ␉} else {␊ |
205 | ␉␉nicintel_spibar = rphysmap("Intel 10 Gigabit NIC w/ SPI flash", io_base_addr + 0x10000,␊ |
206 | ␉␉␉␉␉ MEMMAP_SIZE);␊ |
207 | ␉}␊ |
208 | ␉if (nicintel_spibar == ERROR_PTR)␊ |
209 | ␉␉return 1;␊ |
210 | ␊ |
211 | ␉/* Automatic restore of EECD on shutdown is not possible because EECD␊ |
212 | ␉ * does not only contain FLASH_WRITES_DISABLED|FLASH_WRITES_ENABLED,␊ |
213 | ␉ * but other bits with side effects as well. Those other bits must be␊ |
214 | ␉ * left untouched.␊ |
215 | ␉ */␊ |
216 | ␉tmp = pci_mmio_readl(nicintel_spibar + EECD);␊ |
217 | ␉tmp &= ~FLASH_WRITES_DISABLED;␊ |
218 | ␉tmp |= FLASH_WRITES_ENABLED;␊ |
219 | ␉pci_mmio_writel(tmp, nicintel_spibar + EECD);␊ |
220 | ␊ |
221 | ␉/* test if FWE is really set to allow writes */␊ |
222 | ␉tmp = pci_mmio_readl(nicintel_spibar + EECD);␊ |
223 | ␉if ( (tmp & FLASH_WRITES_DISABLED) || !(tmp & FLASH_WRITES_ENABLED) ) {␊ |
224 | ␉␉msg_perr("Enabling flash write access failed.\n");␊ |
225 | ␉␉return 1;␊ |
226 | ␉}␊ |
227 | ␊ |
228 | ␉if (register_shutdown(nicintel_spi_shutdown, NULL))␊ |
229 | ␉␉return 1;␊ |
230 | ␊ |
231 | ␉if (register_spi_bitbang_master(&bitbang_spi_master_nicintel))␊ |
232 | ␉␉return 1;␊ |
233 | ␊ |
234 | ␉return 0;␊ |
235 | }␊ |