2 * This file is part of the coreboot project.
4 * Copyright (C) 2014 Siemens AG.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <device/device.h>
22 #include <console/console.h>
23 #include <device/pci.h>
24 #include <device/pci_ids.h>
25 #include <device/pci_ops.h>
30 /* We need one function we can call to get a MAC address to use */
31 /* This function can be coded somewhere else but must exist. */
32 extern enum cb_err
mainboard_get_mac_address(u16 bus
, u8 devfn
, u8 mac
[6]);
34 /* This is a private function to wait for a bit mask in a given register */
35 /* To avoid endless loops, a time-out is implemented here. */
36 static int wait_done(u32
* reg
, u32 mask
)
38 u32 timeout
= I210_POLL_TIMEOUT_US
;
40 while (!(*reg
& mask
)) {
43 return I210_NOT_READY
;
48 /** \brief This function can read the configuration space of the MACPHY
49 * For this purpose, the EEPROM interface is used. No direct access
50 * to the flash memory will be done.
51 * @param *dev Pointer to the PCI device of this MACPHY
52 * @param address Address inside the flash where reading will start
53 * @param count Number of words (16 bit values) to read
54 * @param *buffer Pointer to the buffer where to store read data
55 * @return void I210_NO_ERROR or an error code
57 static u32
read_flash(struct device
*dev
, u32 address
, u32 count
, u16
*buffer
)
63 /* Get the BAR to memory mapped space*/
64 bar
= pci_read_config32(dev
, PCI_BASE_ADDRESS_0
);
65 if ((!bar
) || ((address
+ count
) > 0x40))
66 return I210_INVALID_PARAM
;
67 eeprd
= (u32
*)(bar
+ I210_REG_EEREAD
);
68 /* Prior to start ensure flash interface is ready by checking DONE-bit */
69 if (wait_done(eeprd
, I210_DONE
))
70 return I210_NOT_READY
;
72 /*OK, interface is ready, we can use it now */
73 for (i
= 0; i
< count
; i
++) {
74 /* To start a read cycle write desired address in bits 12..2 */
75 *eeprd
= ((address
+ i
) << 2) & 0x1FFC;
76 /* Wait until read is done */
77 if (wait_done(eeprd
, I210_DONE
))
78 return I210_READ_ERROR
;
79 /* Here, we can read back desired word in bits 31..16 */
80 buffer
[i
] = (*eeprd
& 0xffff0000) >> 16;
85 /** \brief This function computes the checksum for the configuration space.
86 * The address range for the checksum is 0x00..0x3e.
87 * @param *dev Pointer to the PCI device of this MACPHY
88 * @param *checksum Pointer to the buffer where to store the checksum
89 * @return void I210_NO_ERROR or an error code
91 static u32
compute_checksum(struct device
*dev
, u16
*checksum
)
96 /* First read back data to compute the checksum for */
97 if (read_flash(dev
, 0, 0x3f, eep_data
))
98 return I210_READ_ERROR
;
99 /* The checksum is computed in that way that after summarize all the */
100 /* data from word address 0 to 0x3f the result is 0xBABA. */
102 for (i
= 0; i
< 0x3f; i
++)
103 *checksum
+= eep_data
[i
];
104 *checksum
= I210_TARGET_CHECKSUM
- *checksum
;
108 /** \brief This function can write the configuration space of the MACPHY
109 * For this purpose, the EEPROM interface is used. No direct access
110 * to the flash memory will be done. This function will update
111 * the checksum after a value was changed.
112 * @param *dev Pointer to the PCI device of this MACPHY
113 * @param address Address inside the flash where writing will start
114 * @param count Number of words (16 bit values) to write
115 * @param *buffer Pointer to the buffer where data to write is stored in
116 * @return void I210_NO_ERROR or an error code
118 static u32
write_flash(struct device
*dev
, u32 address
, u32 count
, u16
*buffer
)
126 /* Get the BAR to memory mapped space */
127 bar
= pci_read_config32(dev
, 0x10);
128 if ((!bar
) || ((address
+ count
) > 0x40))
129 return I210_INVALID_PARAM
;
130 eepwr
= (u32
*)(bar
+ I210_REG_EEWRITE
);
131 eectrl
= (u32
*)(bar
+ I210_REG_EECTRL
);
132 /* Prior to start ensure flash interface is ready by checking DONE-bit */
133 if (wait_done(eepwr
, I210_DONE
))
134 return I210_NOT_READY
;
136 /* OK, interface is ready, we can use it now */
137 for (i
= 0; i
< count
; i
++) {
138 /* To start a write cycle write desired address in bits 12..2 */
139 /* and data to write in bits 31..16 into EEWRITE-register */
140 *eepwr
= ((((address
+ i
) << 2) & 0x1FFC) | (buffer
[i
] << 16));
141 /* Wait until write is done */
142 if (wait_done(eepwr
, I210_DONE
))
143 return I210_WRITE_ERROR
;
145 /* Since we have modified data, we need to update the checksum */
146 if (compute_checksum(dev
, &checksum
))
147 return I210_CHECKSUM_ERROR
;
148 *eepwr
= (0x3f << 2) | checksum
<< 16;
149 if (wait_done(eepwr
, I210_DONE
))
150 return I210_WRITE_ERROR
;
151 /* Up to now, desired data was written into shadowed RAM. We now need */
152 /* to perform a flash cycle to bring the shadowed RAM into flash memory. */
153 /* To start a flash cycle we need to set FLUPD-bit and wait for FLDONE. */
154 *eectrl
= *eectrl
| I210_FLUPD
;
155 if (wait_done(eectrl
, I210_FLUDONE
))
156 return I210_FLASH_UPDATE_ERROR
;
160 /** \brief This function can read the MAC address out of the MACPHY
161 * @param *dev Pointer to the PCI device of this MACPHY
162 * @param *MACAdr Pointer to the buffer where to store read MAC address
163 * @return void I210_NO_ERROR or an error code
165 static u32
read_mac_adr(struct device
*dev
, u8
*mac_adr
)
168 if (!dev
|| !mac_adr
)
169 return I210_INVALID_PARAM
;
170 if (read_flash(dev
, 0, 3, adr
))
171 return I210_READ_ERROR
;
172 /* Copy the address into destination. This is done because of */
173 /* possible not matching alignment for destination to u16 boundary. */
174 memcpy(mac_adr
, (u8
*)adr
, 6);
178 /** \brief This function can write the MAC address to the MACPHY
179 * @param *dev Pointer to the PCI device of this MACPHY
180 * @param *MACAdr Pointer to the buffer where the desired MAC address is
181 * @return void I210_NO_ERROR or an error code
183 static u32
write_mac_adr(struct device
*dev
, u8
*mac_adr
)
186 if (!dev
|| !mac_adr
)
187 return I210_INVALID_PARAM
;
188 /* Copy desired address into a local buffer to avoid alignment issues */
189 memcpy((u8
*)adr
, mac_adr
, 6);
190 return write_flash(dev
, 0, 3, adr
);
193 /** \brief This function is the driver entry point for the init phase
194 * of the PCI bus allocator. It will program a MAC address
196 * @param *dev Pointer to the used PCI device
197 * @return void Nothing is given back
199 static void init(struct device
*dev
)
205 /*Check first whether there is a valid MAC address available */
206 status
= mainboard_get_mac_address(dev
->bus
->subordinate
,
207 dev
->path
.pci
.devfn
, adr_to_set
);
208 if (status
!= CB_SUCCESS
) {
209 printk(BIOS_ERR
, "I210: No valid MAC address found\n");
212 /* Before we will write a new address, check the existing one */
213 if (read_mac_adr(dev
, cur_adr
)) {
214 printk(BIOS_ERR
, "I210: Not able to read MAC address.\n");
217 if (memcmp(cur_adr
, adr_to_set
, 6)) {
218 if (write_mac_adr(dev
, adr_to_set
))
219 printk(BIOS_ERR
, "I210: Error setting MAC address\n");
221 printk(BIOS_INFO
, "I210: MAC address changed.\n");
223 printk(BIOS_INFO
, "I210: MAC address is up to date.\n");
228 static struct device_operations i210_ops
= {
229 .read_resources
= pci_dev_read_resources
,
230 .set_resources
= pci_dev_set_resources
,
231 .enable_resources
= pci_dev_enable_resources
,
237 static const unsigned short i210_device_ids
[] = { 0x1538, 0x1533, 0 };
239 static const struct pci_driver i210_driver __pci_driver
= {
241 .vendor
= PCI_VENDOR_ID_INTEL
,
242 .devices
= i210_device_ids
,