blob: cb2414f30cb9800640b1403e6106db0384823e39 [file] [log] [blame]
Werner Zeh63693dc2015-02-13 12:18:58 +01001/*
2 * This file is part of the coreboot project.
3 *
Werner Zeh63693dc2015-02-13 12:18:58 +01004 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
Werner Zeh63693dc2015-02-13 12:18:58 +010012 */
13
14#include "i210.h"
15#include <device/device.h>
16#include <console/console.h>
17#include <device/pci.h>
18#include <device/pci_ids.h>
19#include <device/pci_ops.h>
Werner Zehbd316422017-10-16 08:53:34 +020020#include <device/pci_def.h>
Werner Zeh63693dc2015-02-13 12:18:58 +010021#include <string.h>
22#include <types.h>
23#include <delay.h>
24
Werner Zeh63693dc2015-02-13 12:18:58 +010025/* This is a private function to wait for a bit mask in a given register */
26/* To avoid endless loops, a time-out is implemented here. */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +020027static int wait_done(uint32_t *reg, uint32_t mask)
Werner Zeh63693dc2015-02-13 12:18:58 +010028{
Werner Zeh608d9912016-04-26 09:26:14 +020029 uint32_t timeout = I210_POLL_TIMEOUT_US;
Werner Zeh63693dc2015-02-13 12:18:58 +010030
31 while (!(*reg & mask)) {
32 udelay(1);
33 if (!--timeout)
34 return I210_NOT_READY;
35 }
36 return I210_SUCCESS;
37}
38
39/** \brief This function can read the configuration space of the MACPHY
40 * For this purpose, the EEPROM interface is used. No direct access
41 * to the flash memory will be done.
42 * @param *dev Pointer to the PCI device of this MACPHY
43 * @param address Address inside the flash where reading will start
44 * @param count Number of words (16 bit values) to read
45 * @param *buffer Pointer to the buffer where to store read data
46 * @return void I210_NO_ERROR or an error code
47 */
Werner Zeh608d9912016-04-26 09:26:14 +020048static uint32_t read_flash(struct device *dev, uint32_t address,
49 uint32_t count, uint16_t *buffer)
Werner Zeh63693dc2015-02-13 12:18:58 +010050{
Werner Zeh608d9912016-04-26 09:26:14 +020051 uint32_t bar;
52 uint32_t *eeprd;
53 uint32_t i;
Werner Zeh63693dc2015-02-13 12:18:58 +010054
55 /* Get the BAR to memory mapped space*/
56 bar = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
57 if ((!bar) || ((address + count) > 0x40))
58 return I210_INVALID_PARAM;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +020059 eeprd = (uint32_t *)(bar + I210_REG_EEREAD);
Werner Zeh63693dc2015-02-13 12:18:58 +010060 /* Prior to start ensure flash interface is ready by checking DONE-bit */
61 if (wait_done(eeprd, I210_DONE))
62 return I210_NOT_READY;
63
64 /*OK, interface is ready, we can use it now */
65 for (i = 0; i < count; i++) {
66 /* To start a read cycle write desired address in bits 12..2 */
67 *eeprd = ((address + i) << 2) & 0x1FFC;
68 /* Wait until read is done */
69 if (wait_done(eeprd, I210_DONE))
70 return I210_READ_ERROR;
71 /* Here, we can read back desired word in bits 31..16 */
72 buffer[i] = (*eeprd & 0xffff0000) >> 16;
73 }
74 return I210_SUCCESS;
75}
76
77/** \brief This function computes the checksum for the configuration space.
78 * The address range for the checksum is 0x00..0x3e.
79 * @param *dev Pointer to the PCI device of this MACPHY
80 * @param *checksum Pointer to the buffer where to store the checksum
81 * @return void I210_NO_ERROR or an error code
82 */
Werner Zeh608d9912016-04-26 09:26:14 +020083static uint32_t compute_checksum(struct device *dev, uint16_t *checksum)
Werner Zeh63693dc2015-02-13 12:18:58 +010084{
Werner Zeh608d9912016-04-26 09:26:14 +020085 uint16_t eep_data[0x40];
86 uint32_t i;
Werner Zeh63693dc2015-02-13 12:18:58 +010087
88 /* First read back data to compute the checksum for */
89 if (read_flash(dev, 0, 0x3f, eep_data))
90 return I210_READ_ERROR;
91 /* The checksum is computed in that way that after summarize all the */
92 /* data from word address 0 to 0x3f the result is 0xBABA. */
93 *checksum = 0;
94 for (i = 0; i < 0x3f; i++)
95 *checksum += eep_data[i];
96 *checksum = I210_TARGET_CHECKSUM - *checksum;
97 return I210_SUCCESS;
98}
99
100/** \brief This function can write the configuration space of the MACPHY
101 * For this purpose, the EEPROM interface is used. No direct access
102 * to the flash memory will be done. This function will update
103 * the checksum after a value was changed.
104 * @param *dev Pointer to the PCI device of this MACPHY
105 * @param address Address inside the flash where writing will start
106 * @param count Number of words (16 bit values) to write
107 * @param *buffer Pointer to the buffer where data to write is stored in
108 * @return void I210_NO_ERROR or an error code
109 */
Werner Zeh608d9912016-04-26 09:26:14 +0200110static uint32_t write_flash(struct device *dev, uint32_t address,
111 uint32_t count, uint16_t *buffer)
Werner Zeh63693dc2015-02-13 12:18:58 +0100112{
Werner Zeh608d9912016-04-26 09:26:14 +0200113 uint32_t bar;
114 uint32_t *eepwr;
115 uint32_t *eectrl;
116 uint16_t checksum;
117 uint32_t i;
Werner Zeh63693dc2015-02-13 12:18:58 +0100118
119 /* Get the BAR to memory mapped space */
120 bar = pci_read_config32(dev, 0x10);
121 if ((!bar) || ((address + count) > 0x40))
122 return I210_INVALID_PARAM;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200123 eepwr = (uint32_t *)(bar + I210_REG_EEWRITE);
124 eectrl = (uint32_t *)(bar + I210_REG_EECTRL);
Werner Zeh63693dc2015-02-13 12:18:58 +0100125 /* Prior to start ensure flash interface is ready by checking DONE-bit */
126 if (wait_done(eepwr, I210_DONE))
127 return I210_NOT_READY;
128
129 /* OK, interface is ready, we can use it now */
130 for (i = 0; i < count; i++) {
131 /* To start a write cycle write desired address in bits 12..2 */
132 /* and data to write in bits 31..16 into EEWRITE-register */
133 *eepwr = ((((address + i) << 2) & 0x1FFC) | (buffer[i] << 16));
134 /* Wait until write is done */
135 if (wait_done(eepwr, I210_DONE))
136 return I210_WRITE_ERROR;
137 }
138 /* Since we have modified data, we need to update the checksum */
139 if (compute_checksum(dev, &checksum))
140 return I210_CHECKSUM_ERROR;
141 *eepwr = (0x3f << 2) | checksum << 16;
142 if (wait_done(eepwr, I210_DONE))
143 return I210_WRITE_ERROR;
144 /* Up to now, desired data was written into shadowed RAM. We now need */
Werner Zeh608d9912016-04-26 09:26:14 +0200145 /* to perform a flash cycle to bring the shadowed RAM into flash. */
146 /* To start a flash cycle we need to set FLUPD and wait for FLDONE. */
Werner Zeh63693dc2015-02-13 12:18:58 +0100147 *eectrl = *eectrl | I210_FLUPD;
148 if (wait_done(eectrl, I210_FLUDONE))
149 return I210_FLASH_UPDATE_ERROR;
150 return I210_SUCCESS;
151}
152
153/** \brief This function can read the MAC address out of the MACPHY
154 * @param *dev Pointer to the PCI device of this MACPHY
155 * @param *MACAdr Pointer to the buffer where to store read MAC address
156 * @return void I210_NO_ERROR or an error code
157 */
Werner Zeh608d9912016-04-26 09:26:14 +0200158static uint32_t read_mac_adr(struct device *dev, uint8_t *mac_adr)
Werner Zeh63693dc2015-02-13 12:18:58 +0100159{
Werner Zeh608d9912016-04-26 09:26:14 +0200160 uint16_t adr[3];
Werner Zeh63693dc2015-02-13 12:18:58 +0100161 if (!dev || !mac_adr)
162 return I210_INVALID_PARAM;
163 if (read_flash(dev, 0, 3, adr))
164 return I210_READ_ERROR;
Werner Zeh608d9912016-04-26 09:26:14 +0200165 /* Copy the address into destination. This is done because of possible */
166 /* not matching alignment for destination to uint16_t boundary. */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200167 memcpy(mac_adr, (uint8_t *)adr, 6);
Werner Zeh63693dc2015-02-13 12:18:58 +0100168 return I210_SUCCESS;
169}
170
171/** \brief This function can write the MAC address to the MACPHY
172 * @param *dev Pointer to the PCI device of this MACPHY
173 * @param *MACAdr Pointer to the buffer where the desired MAC address is
174 * @return void I210_NO_ERROR or an error code
175 */
Werner Zeh608d9912016-04-26 09:26:14 +0200176static uint32_t write_mac_adr(struct device *dev, uint8_t *mac_adr)
Werner Zeh63693dc2015-02-13 12:18:58 +0100177{
Werner Zeh608d9912016-04-26 09:26:14 +0200178 uint16_t adr[3];
Werner Zeh63693dc2015-02-13 12:18:58 +0100179 if (!dev || !mac_adr)
180 return I210_INVALID_PARAM;
181 /* Copy desired address into a local buffer to avoid alignment issues */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200182 memcpy((uint8_t *)adr, mac_adr, 6);
Werner Zeh63693dc2015-02-13 12:18:58 +0100183 return write_flash(dev, 0, 3, adr);
184}
185
186/** \brief This function is the driver entry point for the init phase
187 * of the PCI bus allocator. It will program a MAC address
188 * into the MACPHY.
189 * @param *dev Pointer to the used PCI device
190 * @return void Nothing is given back
191 */
192static void init(struct device *dev)
193{
Werner Zeh608d9912016-04-26 09:26:14 +0200194 uint8_t cur_adr[6];
195 uint8_t adr_to_set[6];
Werner Zeh63693dc2015-02-13 12:18:58 +0100196 enum cb_err status;
197
198 /*Check first whether there is a valid MAC address available */
Werner Zehe22d96c2016-06-29 07:53:47 +0200199 status = mainboard_get_mac_address(dev, adr_to_set);
Werner Zeh63693dc2015-02-13 12:18:58 +0100200 if (status != CB_SUCCESS) {
201 printk(BIOS_ERR, "I210: No valid MAC address found\n");
202 return;
203 }
204 /* Before we will write a new address, check the existing one */
205 if (read_mac_adr(dev, cur_adr)) {
206 printk(BIOS_ERR, "I210: Not able to read MAC address.\n");
207 return;
208 }
209 if (memcmp(cur_adr, adr_to_set, 6)) {
210 if (write_mac_adr(dev, adr_to_set))
211 printk(BIOS_ERR, "I210: Error setting MAC address\n");
212 else
213 printk(BIOS_INFO, "I210: MAC address changed.\n");
214 } else {
215 printk(BIOS_INFO, "I210: MAC address is up to date.\n");
216 }
217 return;
218}
219
Elyes HAOUAS712ef1f22018-05-02 21:57:42 +0200220static void set_resources(struct device *dev)
Werner Zehbd316422017-10-16 08:53:34 +0200221{
222 pci_dev_set_resources(dev);
223 dev->command |= PCI_COMMAND_MASTER;
224}
225
Werner Zeh63693dc2015-02-13 12:18:58 +0100226static struct device_operations i210_ops = {
227 .read_resources = pci_dev_read_resources,
Werner Zehbd316422017-10-16 08:53:34 +0200228 .set_resources = set_resources,
Werner Zeh63693dc2015-02-13 12:18:58 +0100229 .enable_resources = pci_dev_enable_resources,
230 .init = init,
Werner Zeh63693dc2015-02-13 12:18:58 +0100231};
232
Werner Zeh77319322018-05-30 07:05:26 +0200233static const unsigned short i210_device_ids[] = { 0x1537, 0x1538, 0x1533, 0 };
Werner Zeh63693dc2015-02-13 12:18:58 +0100234
235static const struct pci_driver i210_driver __pci_driver = {
236 .ops = &i210_ops,
237 .vendor = PCI_VENDOR_ID_INTEL,
238 .devices = i210_device_ids,
239};