1*0d6140beSAndroid Build Coastguard Worker /*
2*0d6140beSAndroid Build Coastguard Worker * This file is part of the flashrom project.
3*0d6140beSAndroid Build Coastguard Worker *
4*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2013 Ricardo Ribalda - Qtechnology A/S
5*0d6140beSAndroid Build Coastguard Worker * Copyright (C) 2011, 2014 Stefan Tauner
6*0d6140beSAndroid Build Coastguard Worker *
7*0d6140beSAndroid Build Coastguard Worker * Based on nicinctel_spi.c and ichspi.c
8*0d6140beSAndroid Build Coastguard Worker *
9*0d6140beSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
10*0d6140beSAndroid Build Coastguard Worker * it under the terms of the GNU General Public License as published by
11*0d6140beSAndroid Build Coastguard Worker * the Free Software Foundation; version 2 of the License.
12*0d6140beSAndroid Build Coastguard Worker *
13*0d6140beSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
14*0d6140beSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*0d6140beSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*0d6140beSAndroid Build Coastguard Worker * GNU General Public License for more details.
17*0d6140beSAndroid Build Coastguard Worker */
18*0d6140beSAndroid Build Coastguard Worker
19*0d6140beSAndroid Build Coastguard Worker /*
20*0d6140beSAndroid Build Coastguard Worker * Datasheet: Intel 82580 Quad/Dual Gigabit Ethernet LAN Controller Datasheet
21*0d6140beSAndroid Build Coastguard Worker * 3.3.1.4: General EEPROM Software Access
22*0d6140beSAndroid Build Coastguard Worker * 4.7: Access to shared resources (FIXME: we should probably use this semaphore interface)
23*0d6140beSAndroid Build Coastguard Worker * 7.4: Register Descriptions
24*0d6140beSAndroid Build Coastguard Worker */
25*0d6140beSAndroid Build Coastguard Worker /*
26*0d6140beSAndroid Build Coastguard Worker * Datasheet: Intel Ethernet Controller I210: Datasheet
27*0d6140beSAndroid Build Coastguard Worker * 8.4.3: EEPROM-Mode Read Register
28*0d6140beSAndroid Build Coastguard Worker * 8.4.6: EEPROM-Mode Write Register
29*0d6140beSAndroid Build Coastguard Worker * Write process inspired on kernel e1000_i210.c
30*0d6140beSAndroid Build Coastguard Worker */
31*0d6140beSAndroid Build Coastguard Worker
32*0d6140beSAndroid Build Coastguard Worker #include <stdlib.h>
33*0d6140beSAndroid Build Coastguard Worker #include <unistd.h>
34*0d6140beSAndroid Build Coastguard Worker #include "flash.h"
35*0d6140beSAndroid Build Coastguard Worker #include "spi.h"
36*0d6140beSAndroid Build Coastguard Worker #include "programmer.h"
37*0d6140beSAndroid Build Coastguard Worker #include "hwaccess_physmap.h"
38*0d6140beSAndroid Build Coastguard Worker #include "platform/pci.h"
39*0d6140beSAndroid Build Coastguard Worker
40*0d6140beSAndroid Build Coastguard Worker #define PCI_VENDOR_ID_INTEL 0x8086
41*0d6140beSAndroid Build Coastguard Worker #define MEMMAP_SIZE 0x1c /* Only EEC, EERD and EEWR are needed. */
42*0d6140beSAndroid Build Coastguard Worker
43*0d6140beSAndroid Build Coastguard Worker #define EEC 0x10 /* EEPROM/Flash Control Register */
44*0d6140beSAndroid Build Coastguard Worker #define EERD 0x14 /* EEPROM Read Register */
45*0d6140beSAndroid Build Coastguard Worker #define EEWR 0x18 /* EEPROM Write Register */
46*0d6140beSAndroid Build Coastguard Worker
47*0d6140beSAndroid Build Coastguard Worker /* EPROM/Flash Control Register bits */
48*0d6140beSAndroid Build Coastguard Worker #define EE_SCK 0
49*0d6140beSAndroid Build Coastguard Worker #define EE_CS 1
50*0d6140beSAndroid Build Coastguard Worker #define EE_SI 2
51*0d6140beSAndroid Build Coastguard Worker #define EE_SO 3
52*0d6140beSAndroid Build Coastguard Worker #define EE_REQ 6
53*0d6140beSAndroid Build Coastguard Worker #define EE_GNT 7
54*0d6140beSAndroid Build Coastguard Worker #define EE_PRES 8
55*0d6140beSAndroid Build Coastguard Worker #define EE_SIZE 11
56*0d6140beSAndroid Build Coastguard Worker #define EE_SIZE_MASK 0xf
57*0d6140beSAndroid Build Coastguard Worker #define EE_FLUPD 23
58*0d6140beSAndroid Build Coastguard Worker #define EE_FLUDONE 26
59*0d6140beSAndroid Build Coastguard Worker
60*0d6140beSAndroid Build Coastguard Worker /* EEPROM Read Register bits */
61*0d6140beSAndroid Build Coastguard Worker #define EERD_START 0
62*0d6140beSAndroid Build Coastguard Worker #define EERD_DONE 1
63*0d6140beSAndroid Build Coastguard Worker #define EERD_ADDR 2
64*0d6140beSAndroid Build Coastguard Worker #define EERD_DATA 16
65*0d6140beSAndroid Build Coastguard Worker
66*0d6140beSAndroid Build Coastguard Worker /* EEPROM Write Register bits */
67*0d6140beSAndroid Build Coastguard Worker #define EEWR_CMDV 0
68*0d6140beSAndroid Build Coastguard Worker #define EEWR_DONE 1
69*0d6140beSAndroid Build Coastguard Worker #define EEWR_ADDR 2
70*0d6140beSAndroid Build Coastguard Worker #define EEWR_DATA 16
71*0d6140beSAndroid Build Coastguard Worker
72*0d6140beSAndroid Build Coastguard Worker #define EE_PAGE_MASK 0x3f
73*0d6140beSAndroid Build Coastguard Worker
74*0d6140beSAndroid Build Coastguard Worker #define UNPROG_DEVICE 0x1509
75*0d6140beSAndroid Build Coastguard Worker
76*0d6140beSAndroid Build Coastguard Worker struct nicintel_eeprom_data {
77*0d6140beSAndroid Build Coastguard Worker struct pci_dev *nicintel_pci;
78*0d6140beSAndroid Build Coastguard Worker uint8_t *nicintel_eebar;
79*0d6140beSAndroid Build Coastguard Worker
80*0d6140beSAndroid Build Coastguard Worker /* Intel 82580 variable(s) */
81*0d6140beSAndroid Build Coastguard Worker uint32_t eec;
82*0d6140beSAndroid Build Coastguard Worker
83*0d6140beSAndroid Build Coastguard Worker /* Intel I210 variable(s) */
84*0d6140beSAndroid Build Coastguard Worker bool done_i210_write;
85*0d6140beSAndroid Build Coastguard Worker };
86*0d6140beSAndroid Build Coastguard Worker
87*0d6140beSAndroid Build Coastguard Worker /*
88*0d6140beSAndroid Build Coastguard Worker * Warning: is_i210() below makes assumptions on these PCI ids.
89*0d6140beSAndroid Build Coastguard Worker * It may have to be updated when this list is extended.
90*0d6140beSAndroid Build Coastguard Worker */
91*0d6140beSAndroid Build Coastguard Worker static const struct dev_entry nics_intel_ee[] = {
92*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x150e, OK, "Intel", "82580 Quad Gigabit Ethernet Controller (Copper)"},
93*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x150f, NT , "Intel", "82580 Quad Gigabit Ethernet Controller (Fiber)"},
94*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1510, NT , "Intel", "82580 Quad Gigabit Ethernet Controller (Backplane)"},
95*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1511, NT , "Intel", "82580 Quad Gigabit Ethernet Controller (Ext. PHY)"},
96*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1511, NT , "Intel", "82580 Dual Gigabit Ethernet Controller (Copper)"},
97*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, UNPROG_DEVICE, OK, "Intel", "Unprogrammed 82580 Quad/Dual Gigabit Ethernet Controller"},
98*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1531, OK, "Intel", "I210 Gigabit Network Connection Unprogrammed"},
99*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1532, NT, "Intel", "I211 Gigabit Network Connection Unprogrammed"},
100*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1533, OK, "Intel", "I210 Gigabit Network Connection"},
101*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1536, NT, "Intel", "I210 Gigabit Network Connection SERDES Fiber"},
102*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1537, NT, "Intel", "I210 Gigabit Network Connection SERDES Backplane"},
103*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1538, NT, "Intel", "I210 Gigabit Network Connection SGMII"},
104*0d6140beSAndroid Build Coastguard Worker {PCI_VENDOR_ID_INTEL, 0x1539, NT, "Intel", "I211 Gigabit Network Connection"},
105*0d6140beSAndroid Build Coastguard Worker {0},
106*0d6140beSAndroid Build Coastguard Worker };
107*0d6140beSAndroid Build Coastguard Worker
is_i210(uint16_t device_id)108*0d6140beSAndroid Build Coastguard Worker static inline bool is_i210(uint16_t device_id)
109*0d6140beSAndroid Build Coastguard Worker {
110*0d6140beSAndroid Build Coastguard Worker return (device_id & 0xfff0) == 0x1530;
111*0d6140beSAndroid Build Coastguard Worker }
112*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_probe_i210(struct flashctx * flash)113*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_probe_i210(struct flashctx *flash)
114*0d6140beSAndroid Build Coastguard Worker {
115*0d6140beSAndroid Build Coastguard Worker /* Emulated eeprom has a fixed size of 4 KB */
116*0d6140beSAndroid Build Coastguard Worker flash->chip->total_size = 4;
117*0d6140beSAndroid Build Coastguard Worker flash->chip->page_size = flash->chip->total_size * 1024;
118*0d6140beSAndroid Build Coastguard Worker flash->chip->tested = TEST_OK_PREWB;
119*0d6140beSAndroid Build Coastguard Worker flash->chip->gran = WRITE_GRAN_1BYTE_IMPLICIT_ERASE;
120*0d6140beSAndroid Build Coastguard Worker flash->chip->block_erasers->eraseblocks[0].size = flash->chip->page_size;
121*0d6140beSAndroid Build Coastguard Worker flash->chip->block_erasers->eraseblocks[0].count = 1;
122*0d6140beSAndroid Build Coastguard Worker
123*0d6140beSAndroid Build Coastguard Worker return 1;
124*0d6140beSAndroid Build Coastguard Worker }
125*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_probe_82580(struct flashctx * flash)126*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_probe_82580(struct flashctx *flash)
127*0d6140beSAndroid Build Coastguard Worker {
128*0d6140beSAndroid Build Coastguard Worker const struct nicintel_eeprom_data *data = flash->mst->opaque.data;
129*0d6140beSAndroid Build Coastguard Worker
130*0d6140beSAndroid Build Coastguard Worker if (data->nicintel_pci->device_id == UNPROG_DEVICE)
131*0d6140beSAndroid Build Coastguard Worker flash->chip->total_size = 16; /* Fall back to minimum supported size. */
132*0d6140beSAndroid Build Coastguard Worker else {
133*0d6140beSAndroid Build Coastguard Worker uint32_t tmp = pci_mmio_readl(data->nicintel_eebar + EEC);
134*0d6140beSAndroid Build Coastguard Worker tmp = ((tmp >> EE_SIZE) & EE_SIZE_MASK);
135*0d6140beSAndroid Build Coastguard Worker switch (tmp) {
136*0d6140beSAndroid Build Coastguard Worker case 7:
137*0d6140beSAndroid Build Coastguard Worker flash->chip->total_size = 16;
138*0d6140beSAndroid Build Coastguard Worker break;
139*0d6140beSAndroid Build Coastguard Worker case 8:
140*0d6140beSAndroid Build Coastguard Worker flash->chip->total_size = 32;
141*0d6140beSAndroid Build Coastguard Worker break;
142*0d6140beSAndroid Build Coastguard Worker default:
143*0d6140beSAndroid Build Coastguard Worker msg_cerr("Unsupported chip size 0x%"PRIx32"\n", tmp);
144*0d6140beSAndroid Build Coastguard Worker return 0;
145*0d6140beSAndroid Build Coastguard Worker }
146*0d6140beSAndroid Build Coastguard Worker }
147*0d6140beSAndroid Build Coastguard Worker
148*0d6140beSAndroid Build Coastguard Worker flash->chip->page_size = EE_PAGE_MASK + 1;
149*0d6140beSAndroid Build Coastguard Worker flash->chip->tested = TEST_OK_PREWB;
150*0d6140beSAndroid Build Coastguard Worker flash->chip->gran = WRITE_GRAN_1BYTE_IMPLICIT_ERASE;
151*0d6140beSAndroid Build Coastguard Worker flash->chip->block_erasers->eraseblocks[0].size = (EE_PAGE_MASK + 1);
152*0d6140beSAndroid Build Coastguard Worker flash->chip->block_erasers->eraseblocks[0].count = (flash->chip->total_size * 1024) / (EE_PAGE_MASK + 1);
153*0d6140beSAndroid Build Coastguard Worker
154*0d6140beSAndroid Build Coastguard Worker return 1;
155*0d6140beSAndroid Build Coastguard Worker }
156*0d6140beSAndroid Build Coastguard Worker
157*0d6140beSAndroid Build Coastguard Worker #define MAX_ATTEMPTS 10000000
nicintel_ee_read_word(uint8_t * eebar,unsigned int addr,uint16_t * data)158*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_read_word(uint8_t *eebar, unsigned int addr, uint16_t *data)
159*0d6140beSAndroid Build Coastguard Worker {
160*0d6140beSAndroid Build Coastguard Worker uint32_t tmp = BIT(EERD_START) | (addr << EERD_ADDR);
161*0d6140beSAndroid Build Coastguard Worker pci_mmio_writel(tmp, eebar + EERD);
162*0d6140beSAndroid Build Coastguard Worker
163*0d6140beSAndroid Build Coastguard Worker /* Poll done flag. 10.000.000 cycles seem to be enough. */
164*0d6140beSAndroid Build Coastguard Worker uint32_t i;
165*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < MAX_ATTEMPTS; i++) {
166*0d6140beSAndroid Build Coastguard Worker tmp = pci_mmio_readl(eebar + EERD);
167*0d6140beSAndroid Build Coastguard Worker if (tmp & BIT(EERD_DONE)) {
168*0d6140beSAndroid Build Coastguard Worker *data = (tmp >> EERD_DATA) & 0xffff;
169*0d6140beSAndroid Build Coastguard Worker return 0;
170*0d6140beSAndroid Build Coastguard Worker }
171*0d6140beSAndroid Build Coastguard Worker }
172*0d6140beSAndroid Build Coastguard Worker
173*0d6140beSAndroid Build Coastguard Worker return -1;
174*0d6140beSAndroid Build Coastguard Worker }
175*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_read(struct flashctx * flash,uint8_t * buf,unsigned int addr,unsigned int len)176*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_read(struct flashctx *flash, uint8_t *buf, unsigned int addr, unsigned int len)
177*0d6140beSAndroid Build Coastguard Worker {
178*0d6140beSAndroid Build Coastguard Worker const struct nicintel_eeprom_data *opaque_data = flash->mst->opaque.data;
179*0d6140beSAndroid Build Coastguard Worker uint16_t data;
180*0d6140beSAndroid Build Coastguard Worker
181*0d6140beSAndroid Build Coastguard Worker /* The NIC interface always reads 16 b words so we need to convert the address and handle odd address
182*0d6140beSAndroid Build Coastguard Worker * explicitly at the start (and also at the end in the loop below). */
183*0d6140beSAndroid Build Coastguard Worker if (addr & 1) {
184*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data))
185*0d6140beSAndroid Build Coastguard Worker return -1;
186*0d6140beSAndroid Build Coastguard Worker *buf++ = data & 0xff;
187*0d6140beSAndroid Build Coastguard Worker addr++;
188*0d6140beSAndroid Build Coastguard Worker len--;
189*0d6140beSAndroid Build Coastguard Worker }
190*0d6140beSAndroid Build Coastguard Worker
191*0d6140beSAndroid Build Coastguard Worker while (len > 0) {
192*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data))
193*0d6140beSAndroid Build Coastguard Worker return -1;
194*0d6140beSAndroid Build Coastguard Worker *buf++ = data & 0xff;
195*0d6140beSAndroid Build Coastguard Worker addr++;
196*0d6140beSAndroid Build Coastguard Worker len--;
197*0d6140beSAndroid Build Coastguard Worker if (len > 0) {
198*0d6140beSAndroid Build Coastguard Worker *buf++ = (data >> 8) & 0xff;
199*0d6140beSAndroid Build Coastguard Worker addr++;
200*0d6140beSAndroid Build Coastguard Worker len--;
201*0d6140beSAndroid Build Coastguard Worker }
202*0d6140beSAndroid Build Coastguard Worker }
203*0d6140beSAndroid Build Coastguard Worker
204*0d6140beSAndroid Build Coastguard Worker return 0;
205*0d6140beSAndroid Build Coastguard Worker }
206*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_write_word_i210(uint8_t * eebar,unsigned int addr,uint16_t data)207*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_write_word_i210(uint8_t *eebar, unsigned int addr, uint16_t data)
208*0d6140beSAndroid Build Coastguard Worker {
209*0d6140beSAndroid Build Coastguard Worker uint32_t eewr;
210*0d6140beSAndroid Build Coastguard Worker
211*0d6140beSAndroid Build Coastguard Worker eewr = addr << EEWR_ADDR;
212*0d6140beSAndroid Build Coastguard Worker eewr |= data << EEWR_DATA;
213*0d6140beSAndroid Build Coastguard Worker eewr |= BIT(EEWR_CMDV);
214*0d6140beSAndroid Build Coastguard Worker pci_mmio_writel(eewr, eebar + EEWR);
215*0d6140beSAndroid Build Coastguard Worker
216*0d6140beSAndroid Build Coastguard Worker default_delay(5);
217*0d6140beSAndroid Build Coastguard Worker int i;
218*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < MAX_ATTEMPTS; i++)
219*0d6140beSAndroid Build Coastguard Worker if (pci_mmio_readl(eebar + EEWR) & BIT(EEWR_DONE))
220*0d6140beSAndroid Build Coastguard Worker return 0;
221*0d6140beSAndroid Build Coastguard Worker return -1;
222*0d6140beSAndroid Build Coastguard Worker }
223*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_write_i210(struct flashctx * flash,const uint8_t * buf,unsigned int addr,unsigned int len)224*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_write_i210(struct flashctx *flash, const uint8_t *buf,
225*0d6140beSAndroid Build Coastguard Worker unsigned int addr, unsigned int len)
226*0d6140beSAndroid Build Coastguard Worker {
227*0d6140beSAndroid Build Coastguard Worker struct nicintel_eeprom_data *opaque_data = flash->mst->opaque.data;
228*0d6140beSAndroid Build Coastguard Worker opaque_data->done_i210_write = true;
229*0d6140beSAndroid Build Coastguard Worker
230*0d6140beSAndroid Build Coastguard Worker if (addr & 1) {
231*0d6140beSAndroid Build Coastguard Worker uint16_t data;
232*0d6140beSAndroid Build Coastguard Worker
233*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data)) {
234*0d6140beSAndroid Build Coastguard Worker msg_perr("Timeout reading heading byte\n");
235*0d6140beSAndroid Build Coastguard Worker return -1;
236*0d6140beSAndroid Build Coastguard Worker }
237*0d6140beSAndroid Build Coastguard Worker
238*0d6140beSAndroid Build Coastguard Worker data &= 0xff;
239*0d6140beSAndroid Build Coastguard Worker data |= (buf ? (buf[0]) : 0xff) << 8;
240*0d6140beSAndroid Build Coastguard Worker
241*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_write_word_i210(opaque_data->nicintel_eebar, addr / 2, data)) {
242*0d6140beSAndroid Build Coastguard Worker msg_perr("Timeout writing heading word\n");
243*0d6140beSAndroid Build Coastguard Worker return -1;
244*0d6140beSAndroid Build Coastguard Worker }
245*0d6140beSAndroid Build Coastguard Worker
246*0d6140beSAndroid Build Coastguard Worker if (buf)
247*0d6140beSAndroid Build Coastguard Worker buf ++;
248*0d6140beSAndroid Build Coastguard Worker addr ++;
249*0d6140beSAndroid Build Coastguard Worker len --;
250*0d6140beSAndroid Build Coastguard Worker }
251*0d6140beSAndroid Build Coastguard Worker
252*0d6140beSAndroid Build Coastguard Worker while (len > 0) {
253*0d6140beSAndroid Build Coastguard Worker uint16_t data;
254*0d6140beSAndroid Build Coastguard Worker
255*0d6140beSAndroid Build Coastguard Worker if (len == 1) {
256*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_read_word(opaque_data->nicintel_eebar, addr / 2, &data)) {
257*0d6140beSAndroid Build Coastguard Worker msg_perr("Timeout reading tail byte\n");
258*0d6140beSAndroid Build Coastguard Worker return -1;
259*0d6140beSAndroid Build Coastguard Worker }
260*0d6140beSAndroid Build Coastguard Worker
261*0d6140beSAndroid Build Coastguard Worker data &= 0xff00;
262*0d6140beSAndroid Build Coastguard Worker data |= buf ? (buf[0]) : 0xff;
263*0d6140beSAndroid Build Coastguard Worker } else {
264*0d6140beSAndroid Build Coastguard Worker if (buf)
265*0d6140beSAndroid Build Coastguard Worker data = buf[0] | (buf[1] << 8);
266*0d6140beSAndroid Build Coastguard Worker else
267*0d6140beSAndroid Build Coastguard Worker data = 0xffff;
268*0d6140beSAndroid Build Coastguard Worker }
269*0d6140beSAndroid Build Coastguard Worker
270*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_write_word_i210(opaque_data->nicintel_eebar, addr / 2, data)) {
271*0d6140beSAndroid Build Coastguard Worker msg_perr("Timeout writing Shadow RAM\n");
272*0d6140beSAndroid Build Coastguard Worker return -1;
273*0d6140beSAndroid Build Coastguard Worker }
274*0d6140beSAndroid Build Coastguard Worker
275*0d6140beSAndroid Build Coastguard Worker if (buf)
276*0d6140beSAndroid Build Coastguard Worker buf += 2;
277*0d6140beSAndroid Build Coastguard Worker if (len > 2)
278*0d6140beSAndroid Build Coastguard Worker len -= 2;
279*0d6140beSAndroid Build Coastguard Worker else
280*0d6140beSAndroid Build Coastguard Worker len = 0;
281*0d6140beSAndroid Build Coastguard Worker addr += 2;
282*0d6140beSAndroid Build Coastguard Worker }
283*0d6140beSAndroid Build Coastguard Worker
284*0d6140beSAndroid Build Coastguard Worker return 0;
285*0d6140beSAndroid Build Coastguard Worker }
286*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_erase_i210(struct flashctx * flash,unsigned int addr,unsigned int len)287*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_erase_i210(struct flashctx *flash, unsigned int addr, unsigned int len)
288*0d6140beSAndroid Build Coastguard Worker {
289*0d6140beSAndroid Build Coastguard Worker return nicintel_ee_write_i210(flash, NULL, addr, len);
290*0d6140beSAndroid Build Coastguard Worker }
291*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_bitset(uint8_t * eebar,int reg,int bit,bool val)292*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_bitset(uint8_t *eebar, int reg, int bit, bool val)
293*0d6140beSAndroid Build Coastguard Worker {
294*0d6140beSAndroid Build Coastguard Worker uint32_t tmp;
295*0d6140beSAndroid Build Coastguard Worker
296*0d6140beSAndroid Build Coastguard Worker tmp = pci_mmio_readl(eebar + reg);
297*0d6140beSAndroid Build Coastguard Worker if (val)
298*0d6140beSAndroid Build Coastguard Worker tmp |= BIT(bit);
299*0d6140beSAndroid Build Coastguard Worker else
300*0d6140beSAndroid Build Coastguard Worker tmp &= ~BIT(bit);
301*0d6140beSAndroid Build Coastguard Worker pci_mmio_writel(tmp, eebar + reg);
302*0d6140beSAndroid Build Coastguard Worker
303*0d6140beSAndroid Build Coastguard Worker return -1;
304*0d6140beSAndroid Build Coastguard Worker }
305*0d6140beSAndroid Build Coastguard Worker
306*0d6140beSAndroid Build Coastguard Worker /* Shifts one byte out while receiving another one by bitbanging (denoted "direct access" in the datasheet). */
nicintel_ee_bitbang(uint8_t * eebar,uint8_t mosi,uint8_t * miso)307*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_bitbang(uint8_t *eebar, uint8_t mosi, uint8_t *miso)
308*0d6140beSAndroid Build Coastguard Worker {
309*0d6140beSAndroid Build Coastguard Worker uint8_t out = 0x0;
310*0d6140beSAndroid Build Coastguard Worker
311*0d6140beSAndroid Build Coastguard Worker int i;
312*0d6140beSAndroid Build Coastguard Worker for (i = 7; i >= 0; i--) {
313*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_SI, mosi & BIT(i));
314*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_SCK, 1);
315*0d6140beSAndroid Build Coastguard Worker if (miso != NULL) {
316*0d6140beSAndroid Build Coastguard Worker uint32_t tmp = pci_mmio_readl(eebar + EEC);
317*0d6140beSAndroid Build Coastguard Worker if (tmp & BIT(EE_SO))
318*0d6140beSAndroid Build Coastguard Worker out |= BIT(i);
319*0d6140beSAndroid Build Coastguard Worker }
320*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_SCK, 0);
321*0d6140beSAndroid Build Coastguard Worker }
322*0d6140beSAndroid Build Coastguard Worker
323*0d6140beSAndroid Build Coastguard Worker if (miso != NULL)
324*0d6140beSAndroid Build Coastguard Worker *miso = out;
325*0d6140beSAndroid Build Coastguard Worker
326*0d6140beSAndroid Build Coastguard Worker return 0;
327*0d6140beSAndroid Build Coastguard Worker }
328*0d6140beSAndroid Build Coastguard Worker
329*0d6140beSAndroid Build Coastguard Worker /* Polls the WIP bit of the status register of the attached EEPROM via bitbanging. */
nicintel_ee_ready(uint8_t * eebar)330*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_ready(uint8_t *eebar)
331*0d6140beSAndroid Build Coastguard Worker {
332*0d6140beSAndroid Build Coastguard Worker unsigned int i;
333*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < 1000; i++) {
334*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_CS, 0);
335*0d6140beSAndroid Build Coastguard Worker
336*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitbang(eebar, JEDEC_RDSR, NULL);
337*0d6140beSAndroid Build Coastguard Worker uint8_t rdsr;
338*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitbang(eebar, 0x00, &rdsr);
339*0d6140beSAndroid Build Coastguard Worker
340*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_CS, 1);
341*0d6140beSAndroid Build Coastguard Worker default_delay(1);
342*0d6140beSAndroid Build Coastguard Worker if (!(rdsr & SPI_SR_WIP)) {
343*0d6140beSAndroid Build Coastguard Worker return 0;
344*0d6140beSAndroid Build Coastguard Worker }
345*0d6140beSAndroid Build Coastguard Worker }
346*0d6140beSAndroid Build Coastguard Worker return -1;
347*0d6140beSAndroid Build Coastguard Worker }
348*0d6140beSAndroid Build Coastguard Worker
349*0d6140beSAndroid Build Coastguard Worker /* Requests direct access to the SPI pins. */
nicintel_ee_req(uint8_t * eebar)350*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_req(uint8_t *eebar)
351*0d6140beSAndroid Build Coastguard Worker {
352*0d6140beSAndroid Build Coastguard Worker uint32_t tmp;
353*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_REQ, 1);
354*0d6140beSAndroid Build Coastguard Worker
355*0d6140beSAndroid Build Coastguard Worker tmp = pci_mmio_readl(eebar + EEC);
356*0d6140beSAndroid Build Coastguard Worker if (!(tmp & BIT(EE_GNT))) {
357*0d6140beSAndroid Build Coastguard Worker msg_perr("Enabling eeprom access failed.\n");
358*0d6140beSAndroid Build Coastguard Worker return 1;
359*0d6140beSAndroid Build Coastguard Worker }
360*0d6140beSAndroid Build Coastguard Worker
361*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_SCK, 0);
362*0d6140beSAndroid Build Coastguard Worker return 0;
363*0d6140beSAndroid Build Coastguard Worker }
364*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_write_82580(struct flashctx * flash,const uint8_t * buf,unsigned int addr,unsigned int len)365*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_write_82580(struct flashctx *flash, const uint8_t *buf, unsigned int addr, unsigned int len)
366*0d6140beSAndroid Build Coastguard Worker {
367*0d6140beSAndroid Build Coastguard Worker const struct nicintel_eeprom_data *opaque_data = flash->mst->opaque.data;
368*0d6140beSAndroid Build Coastguard Worker uint8_t *eebar = opaque_data->nicintel_eebar;
369*0d6140beSAndroid Build Coastguard Worker
370*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_req(eebar))
371*0d6140beSAndroid Build Coastguard Worker return -1;
372*0d6140beSAndroid Build Coastguard Worker
373*0d6140beSAndroid Build Coastguard Worker int ret = -1;
374*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_ready(eebar))
375*0d6140beSAndroid Build Coastguard Worker goto out;
376*0d6140beSAndroid Build Coastguard Worker
377*0d6140beSAndroid Build Coastguard Worker while (len > 0) {
378*0d6140beSAndroid Build Coastguard Worker /* WREN */
379*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_CS, 0);
380*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitbang(eebar, JEDEC_WREN, NULL);
381*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_CS, 1);
382*0d6140beSAndroid Build Coastguard Worker default_delay(1);
383*0d6140beSAndroid Build Coastguard Worker
384*0d6140beSAndroid Build Coastguard Worker /* data */
385*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_CS, 0);
386*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitbang(eebar, JEDEC_BYTE_PROGRAM, NULL);
387*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitbang(eebar, (addr >> 8) & 0xff, NULL);
388*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitbang(eebar, addr & 0xff, NULL);
389*0d6140beSAndroid Build Coastguard Worker while (len > 0) {
390*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitbang(eebar, (buf) ? *buf++ : 0xff, NULL);
391*0d6140beSAndroid Build Coastguard Worker len--;
392*0d6140beSAndroid Build Coastguard Worker addr++;
393*0d6140beSAndroid Build Coastguard Worker if (!(addr & EE_PAGE_MASK))
394*0d6140beSAndroid Build Coastguard Worker break;
395*0d6140beSAndroid Build Coastguard Worker }
396*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_CS, 1);
397*0d6140beSAndroid Build Coastguard Worker default_delay(1);
398*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_ready(eebar))
399*0d6140beSAndroid Build Coastguard Worker goto out;
400*0d6140beSAndroid Build Coastguard Worker }
401*0d6140beSAndroid Build Coastguard Worker ret = 0;
402*0d6140beSAndroid Build Coastguard Worker out:
403*0d6140beSAndroid Build Coastguard Worker nicintel_ee_bitset(eebar, EEC, EE_REQ, 0); /* Give up direct access. */
404*0d6140beSAndroid Build Coastguard Worker return ret;
405*0d6140beSAndroid Build Coastguard Worker }
406*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_erase_82580(struct flashctx * flash,unsigned int addr,unsigned int len)407*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_erase_82580(struct flashctx *flash, unsigned int addr, unsigned int len)
408*0d6140beSAndroid Build Coastguard Worker {
409*0d6140beSAndroid Build Coastguard Worker return nicintel_ee_write_82580(flash, NULL, addr, len);
410*0d6140beSAndroid Build Coastguard Worker }
411*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_shutdown_i210(void * opaque_data)412*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_shutdown_i210(void *opaque_data)
413*0d6140beSAndroid Build Coastguard Worker {
414*0d6140beSAndroid Build Coastguard Worker struct nicintel_eeprom_data *data = opaque_data;
415*0d6140beSAndroid Build Coastguard Worker int ret = 0;
416*0d6140beSAndroid Build Coastguard Worker
417*0d6140beSAndroid Build Coastguard Worker if (!data->done_i210_write)
418*0d6140beSAndroid Build Coastguard Worker goto out;
419*0d6140beSAndroid Build Coastguard Worker
420*0d6140beSAndroid Build Coastguard Worker uint32_t flup = pci_mmio_readl(data->nicintel_eebar + EEC);
421*0d6140beSAndroid Build Coastguard Worker
422*0d6140beSAndroid Build Coastguard Worker flup |= BIT(EE_FLUPD);
423*0d6140beSAndroid Build Coastguard Worker pci_mmio_writel(flup, data->nicintel_eebar + EEC);
424*0d6140beSAndroid Build Coastguard Worker
425*0d6140beSAndroid Build Coastguard Worker int i;
426*0d6140beSAndroid Build Coastguard Worker for (i = 0; i < MAX_ATTEMPTS; i++)
427*0d6140beSAndroid Build Coastguard Worker if (pci_mmio_readl(data->nicintel_eebar + EEC) & BIT(EE_FLUDONE))
428*0d6140beSAndroid Build Coastguard Worker goto out;
429*0d6140beSAndroid Build Coastguard Worker
430*0d6140beSAndroid Build Coastguard Worker ret = -1;
431*0d6140beSAndroid Build Coastguard Worker msg_perr("Flash update failed\n");
432*0d6140beSAndroid Build Coastguard Worker
433*0d6140beSAndroid Build Coastguard Worker out:
434*0d6140beSAndroid Build Coastguard Worker free(data);
435*0d6140beSAndroid Build Coastguard Worker return ret;
436*0d6140beSAndroid Build Coastguard Worker }
437*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_shutdown_82580(void * opaque_data)438*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_shutdown_82580(void *opaque_data)
439*0d6140beSAndroid Build Coastguard Worker {
440*0d6140beSAndroid Build Coastguard Worker struct nicintel_eeprom_data *data = opaque_data;
441*0d6140beSAndroid Build Coastguard Worker uint8_t *eebar = data->nicintel_eebar;
442*0d6140beSAndroid Build Coastguard Worker int ret = 0;
443*0d6140beSAndroid Build Coastguard Worker
444*0d6140beSAndroid Build Coastguard Worker if (data->nicintel_pci->device_id != UNPROG_DEVICE) {
445*0d6140beSAndroid Build Coastguard Worker uint32_t old_eec = data->eec;
446*0d6140beSAndroid Build Coastguard Worker /* Request bitbanging and unselect the chip first to be safe. */
447*0d6140beSAndroid Build Coastguard Worker if (nicintel_ee_req(eebar) || nicintel_ee_bitset(eebar, EEC, EE_CS, 1)) {
448*0d6140beSAndroid Build Coastguard Worker ret = -1;
449*0d6140beSAndroid Build Coastguard Worker goto out;
450*0d6140beSAndroid Build Coastguard Worker }
451*0d6140beSAndroid Build Coastguard Worker
452*0d6140beSAndroid Build Coastguard Worker /* Try to restore individual bits we care about. */
453*0d6140beSAndroid Build Coastguard Worker ret = nicintel_ee_bitset(eebar, EEC, EE_SCK, old_eec & BIT(EE_SCK));
454*0d6140beSAndroid Build Coastguard Worker ret |= nicintel_ee_bitset(eebar, EEC, EE_SI, old_eec & BIT(EE_SI));
455*0d6140beSAndroid Build Coastguard Worker ret |= nicintel_ee_bitset(eebar, EEC, EE_CS, old_eec & BIT(EE_CS));
456*0d6140beSAndroid Build Coastguard Worker /* REQ will be cleared by hardware anyway after 2 seconds of inactivity
457*0d6140beSAndroid Build Coastguard Worker * on the SPI pins (3.3.2.1). */
458*0d6140beSAndroid Build Coastguard Worker ret |= nicintel_ee_bitset(eebar, EEC, EE_REQ, old_eec & BIT(EE_REQ));
459*0d6140beSAndroid Build Coastguard Worker }
460*0d6140beSAndroid Build Coastguard Worker
461*0d6140beSAndroid Build Coastguard Worker out:
462*0d6140beSAndroid Build Coastguard Worker free(data);
463*0d6140beSAndroid Build Coastguard Worker return ret;
464*0d6140beSAndroid Build Coastguard Worker }
465*0d6140beSAndroid Build Coastguard Worker
466*0d6140beSAndroid Build Coastguard Worker static const struct opaque_master opaque_master_nicintel_ee_82580 = {
467*0d6140beSAndroid Build Coastguard Worker .probe = nicintel_ee_probe_82580,
468*0d6140beSAndroid Build Coastguard Worker .read = nicintel_ee_read,
469*0d6140beSAndroid Build Coastguard Worker .write = nicintel_ee_write_82580,
470*0d6140beSAndroid Build Coastguard Worker .erase = nicintel_ee_erase_82580,
471*0d6140beSAndroid Build Coastguard Worker .shutdown = nicintel_ee_shutdown_82580,
472*0d6140beSAndroid Build Coastguard Worker };
473*0d6140beSAndroid Build Coastguard Worker
474*0d6140beSAndroid Build Coastguard Worker static const struct opaque_master opaque_master_nicintel_ee_i210 = {
475*0d6140beSAndroid Build Coastguard Worker .probe = nicintel_ee_probe_i210,
476*0d6140beSAndroid Build Coastguard Worker .read = nicintel_ee_read,
477*0d6140beSAndroid Build Coastguard Worker .write = nicintel_ee_write_i210,
478*0d6140beSAndroid Build Coastguard Worker .erase = nicintel_ee_erase_i210,
479*0d6140beSAndroid Build Coastguard Worker .shutdown = nicintel_ee_shutdown_i210,
480*0d6140beSAndroid Build Coastguard Worker };
481*0d6140beSAndroid Build Coastguard Worker
nicintel_ee_init(const struct programmer_cfg * cfg)482*0d6140beSAndroid Build Coastguard Worker static int nicintel_ee_init(const struct programmer_cfg *cfg)
483*0d6140beSAndroid Build Coastguard Worker {
484*0d6140beSAndroid Build Coastguard Worker const struct opaque_master *mst;
485*0d6140beSAndroid Build Coastguard Worker uint32_t eec = 0;
486*0d6140beSAndroid Build Coastguard Worker uint8_t *eebar;
487*0d6140beSAndroid Build Coastguard Worker
488*0d6140beSAndroid Build Coastguard Worker struct pci_dev *dev = pcidev_init(cfg, nics_intel_ee, PCI_BASE_ADDRESS_0);
489*0d6140beSAndroid Build Coastguard Worker if (!dev)
490*0d6140beSAndroid Build Coastguard Worker return 1;
491*0d6140beSAndroid Build Coastguard Worker
492*0d6140beSAndroid Build Coastguard Worker uint32_t io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0);
493*0d6140beSAndroid Build Coastguard Worker if (!io_base_addr)
494*0d6140beSAndroid Build Coastguard Worker return 1;
495*0d6140beSAndroid Build Coastguard Worker
496*0d6140beSAndroid Build Coastguard Worker if (!is_i210(dev->device_id)) {
497*0d6140beSAndroid Build Coastguard Worker eebar = rphysmap("Intel Gigabit NIC w/ SPI EEPROM", io_base_addr, MEMMAP_SIZE);
498*0d6140beSAndroid Build Coastguard Worker if (!eebar)
499*0d6140beSAndroid Build Coastguard Worker return 1;
500*0d6140beSAndroid Build Coastguard Worker
501*0d6140beSAndroid Build Coastguard Worker if (dev->device_id != UNPROG_DEVICE) {
502*0d6140beSAndroid Build Coastguard Worker eec = pci_mmio_readl(eebar + EEC);
503*0d6140beSAndroid Build Coastguard Worker
504*0d6140beSAndroid Build Coastguard Worker /* C.f. 3.3.1.5 for the detection mechanism (maybe? contradicting
505*0d6140beSAndroid Build Coastguard Worker the EE_PRES definition),
506*0d6140beSAndroid Build Coastguard Worker and 3.3.1.7 for possible recovery. */
507*0d6140beSAndroid Build Coastguard Worker if (!(eec & BIT(EE_PRES))) {
508*0d6140beSAndroid Build Coastguard Worker msg_perr("Controller reports no EEPROM is present.\n");
509*0d6140beSAndroid Build Coastguard Worker return 1;
510*0d6140beSAndroid Build Coastguard Worker }
511*0d6140beSAndroid Build Coastguard Worker }
512*0d6140beSAndroid Build Coastguard Worker
513*0d6140beSAndroid Build Coastguard Worker mst = &opaque_master_nicintel_ee_82580;
514*0d6140beSAndroid Build Coastguard Worker } else {
515*0d6140beSAndroid Build Coastguard Worker eebar = rphysmap("Intel i210 NIC w/ emulated EEPROM",
516*0d6140beSAndroid Build Coastguard Worker io_base_addr + 0x12000, MEMMAP_SIZE);
517*0d6140beSAndroid Build Coastguard Worker if (!eebar)
518*0d6140beSAndroid Build Coastguard Worker return 1;
519*0d6140beSAndroid Build Coastguard Worker
520*0d6140beSAndroid Build Coastguard Worker mst = &opaque_master_nicintel_ee_i210;
521*0d6140beSAndroid Build Coastguard Worker }
522*0d6140beSAndroid Build Coastguard Worker
523*0d6140beSAndroid Build Coastguard Worker struct nicintel_eeprom_data *data = calloc(1, sizeof(*data));
524*0d6140beSAndroid Build Coastguard Worker if (!data) {
525*0d6140beSAndroid Build Coastguard Worker msg_perr("Unable to allocate space for OPAQUE master data\n");
526*0d6140beSAndroid Build Coastguard Worker return 1;
527*0d6140beSAndroid Build Coastguard Worker }
528*0d6140beSAndroid Build Coastguard Worker data->nicintel_pci = dev;
529*0d6140beSAndroid Build Coastguard Worker data->nicintel_eebar = eebar;
530*0d6140beSAndroid Build Coastguard Worker data->eec = eec;
531*0d6140beSAndroid Build Coastguard Worker data->done_i210_write = false;
532*0d6140beSAndroid Build Coastguard Worker
533*0d6140beSAndroid Build Coastguard Worker return register_opaque_master(mst, data);
534*0d6140beSAndroid Build Coastguard Worker }
535*0d6140beSAndroid Build Coastguard Worker
536*0d6140beSAndroid Build Coastguard Worker const struct programmer_entry programmer_nicintel_eeprom = {
537*0d6140beSAndroid Build Coastguard Worker .name = "nicintel_eeprom",
538*0d6140beSAndroid Build Coastguard Worker .type = PCI,
539*0d6140beSAndroid Build Coastguard Worker .devs.dev = nics_intel_ee,
540*0d6140beSAndroid Build Coastguard Worker .init = nicintel_ee_init,
541*0d6140beSAndroid Build Coastguard Worker };
542