coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
i210.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include "i210.h"
4 #include <device/device.h>
5 #include <console/console.h>
6 #include <device/pci.h>
7 #include <device/pci_ids.h>
8 #include <device/pci_ops.h>
9 #include <device/pci_def.h>
10 #include <string.h>
11 #include <types.h>
12 #include <delay.h>
13 
14 /* This is a private function to wait for a bit mask in a given register */
15 /* To avoid endless loops, a time-out is implemented here. */
16 static int wait_done(uint32_t *reg, uint32_t mask)
17 {
19 
20  while (!(*reg & mask)) {
21  udelay(1);
22  if (!--timeout)
23  return I210_NOT_READY;
24  }
25  return I210_SUCCESS;
26 }
27 
28 /** \brief This function can read the configuration space of the MACPHY
29  * For this purpose, the EEPROM interface is used. No direct access
30  * to the flash memory will be done.
31  * @param *dev Pointer to the PCI device of this MACPHY
32  * @param address Address inside the flash where reading will start
33  * @param count Number of words (16 bit values) to read
34  * @param *buffer Pointer to the buffer where to store read data
35  * @return void I210_NO_ERROR or an error code
36  */
39 {
40  uint32_t bar;
41  uint32_t *eeprd;
42  uint32_t i;
43 
44  /* Get the BAR to memory mapped space*/
46  if ((!bar) || ((address + count) > 0x40))
47  return I210_INVALID_PARAM;
48  eeprd = (uint32_t *)(bar + I210_REG_EEREAD);
49  /* Prior to start ensure flash interface is ready by checking DONE-bit */
50  if (wait_done(eeprd, I210_DONE))
51  return I210_NOT_READY;
52 
53  /*OK, interface is ready, we can use it now */
54  for (i = 0; i < count; i++) {
55  /* To start a read cycle write desired address in bits 12..2 */
56  *eeprd = ((address + i) << 2) & 0x1FFC;
57  /* Wait until read is done */
58  if (wait_done(eeprd, I210_DONE))
59  return I210_READ_ERROR;
60  /* Here, we can read back desired word in bits 31..16 */
61  buffer[i] = (*eeprd & 0xffff0000) >> 16;
62  }
63  return I210_SUCCESS;
64 }
65 
66 /** \brief This function computes the checksum for the configuration space.
67  * The address range for the checksum is 0x00..0x3e.
68  * @param *dev Pointer to the PCI device of this MACPHY
69  * @param *checksum Pointer to the buffer where to store the checksum
70  * @return void I210_NO_ERROR or an error code
71  */
73 {
74  uint16_t eep_data[0x40];
75  uint32_t i;
76 
77  /* First read back data to compute the checksum for */
78  if (read_flash(dev, 0, 0x3f, eep_data))
79  return I210_READ_ERROR;
80  /* The checksum is computed in that way that after summarize all the */
81  /* data from word address 0 to 0x3f the result is 0xBABA. */
82  *checksum = 0;
83  for (i = 0; i < 0x3f; i++)
84  *checksum += eep_data[i];
86  return I210_SUCCESS;
87 }
88 
89 /** \brief This function can write the configuration space of the MACPHY
90  * For this purpose, the EEPROM interface is used. No direct access
91  * to the flash memory will be done. This function will update
92  * the checksum after a value was changed.
93  * @param *dev Pointer to the PCI device of this MACPHY
94  * @param address Address inside the flash where writing will start
95  * @param count Number of words (16 bit values) to write
96  * @param *buffer Pointer to the buffer where data to write is stored in
97  * @return void I210_NO_ERROR or an error code
98  */
101 {
102  uint32_t bar;
103  uint32_t *eepwr;
104  uint32_t *eectrl;
106  uint32_t i;
107 
108  /* Get the BAR to memory mapped space */
109  bar = pci_read_config32(dev, 0x10);
110  if ((!bar) || ((address + count) > 0x40))
111  return I210_INVALID_PARAM;
112  eepwr = (uint32_t *)(bar + I210_REG_EEWRITE);
113  eectrl = (uint32_t *)(bar + I210_REG_EECTRL);
114  /* Prior to start ensure flash interface is ready by checking DONE-bit */
115  if (wait_done(eepwr, I210_DONE))
116  return I210_NOT_READY;
117 
118  /* OK, interface is ready, we can use it now */
119  for (i = 0; i < count; i++) {
120  /* To start a write cycle write desired address in bits 12..2 */
121  /* and data to write in bits 31..16 into EEWRITE-register */
122  *eepwr = ((((address + i) << 2) & 0x1FFC) | (buffer[i] << 16));
123  /* Wait until write is done */
124  if (wait_done(eepwr, I210_DONE))
125  return I210_WRITE_ERROR;
126  }
127  /* Since we have modified data, we need to update the checksum */
128  if (compute_checksum(dev, &checksum))
129  return I210_CHECKSUM_ERROR;
130  *eepwr = (0x3f << 2) | checksum << 16;
131  if (wait_done(eepwr, I210_DONE))
132  return I210_WRITE_ERROR;
133  /* Up to now, desired data was written into shadowed RAM. We now need */
134  /* to perform a flash cycle to bring the shadowed RAM into flash. */
135  /* To start a flash cycle we need to set FLUPD and wait for FLDONE. */
136  *eectrl = *eectrl | I210_FLUPD;
137  if (wait_done(eectrl, I210_FLUDONE))
139  return I210_SUCCESS;
140 }
141 
142 /** \brief This function can read the MAC address out of the MACPHY
143  * @param *dev Pointer to the PCI device of this MACPHY
144  * @param *MACAdr Pointer to the buffer where to store read MAC address
145  * @return void I210_NO_ERROR or an error code
146  */
147 static uint32_t read_mac_adr(struct device *dev, uint8_t *mac_adr)
148 {
149  uint16_t adr[3];
150  if (!dev || !mac_adr)
151  return I210_INVALID_PARAM;
152  if (read_flash(dev, 0, 3, adr))
153  return I210_READ_ERROR;
154  /* Copy the address into destination. This is done because of possible */
155  /* not matching alignment for destination to uint16_t boundary. */
156  memcpy(mac_adr, (uint8_t *)adr, 6);
157  return I210_SUCCESS;
158 }
159 
160 /** \brief This function can write the MAC address to the MACPHY
161  * @param *dev Pointer to the PCI device of this MACPHY
162  * @param *MACAdr Pointer to the buffer where the desired MAC address is
163  * @return void I210_NO_ERROR or an error code
164  */
165 static uint32_t write_mac_adr(struct device *dev, uint8_t *mac_adr)
166 {
167  uint16_t adr[3];
168  if (!dev || !mac_adr)
169  return I210_INVALID_PARAM;
170  /* Copy desired address into a local buffer to avoid alignment issues */
171  memcpy((uint8_t *)adr, mac_adr, 6);
172  return write_flash(dev, 0, 3, adr);
173 }
174 
175 /** \brief This function is the driver entry point for the init phase
176  * of the PCI bus allocator. It will program a MAC address
177  * into the MACPHY.
178  * @param *dev Pointer to the used PCI device
179  * @return void Nothing is given back
180  */
181 static void init(struct device *dev)
182 {
183  uint8_t cur_adr[6];
184  uint8_t adr_to_set[6];
185  enum cb_err status;
186 
187  /*Check first whether there is a valid MAC address available */
188  status = mainboard_get_mac_address(dev, adr_to_set);
189  if (status != CB_SUCCESS) {
190  printk(BIOS_NOTICE, "I210: Mainboard has no address, keep the one in MAC.\n");
191  return;
192  }
193  /* Before we will write a new address, check the existing one */
194  if (read_mac_adr(dev, cur_adr)) {
195  printk(BIOS_ERR, "I210: Not able to read MAC address.\n");
196  return;
197  }
198  if (memcmp(cur_adr, adr_to_set, 6)) {
199  if (write_mac_adr(dev, adr_to_set))
200  printk(BIOS_ERR, "I210: Error setting MAC address\n");
201  else
202  printk(BIOS_INFO, "I210: MAC address changed.\n");
203  } else {
204  printk(BIOS_INFO, "I210: MAC address is up to date.\n");
205  }
206  return;
207 }
208 
209 static void enable_bus_master(struct device *dev)
210 {
211  if (CONFIG(PCI_ALLOW_BUS_MASTER_ANY_DEVICE))
213 }
214 
215 static struct device_operations i210_ops = {
217  .set_resources = pci_dev_set_resources,
218  .enable_resources = pci_dev_enable_resources,
219  .init = init,
220  .final = enable_bus_master,
221 };
222 
223 static const unsigned short i210_device_ids[] = { 0x1537, 0x1538, 0x1533, 0 };
224 
225 static const struct pci_driver i210_driver __pci_driver = {
226  .ops = &i210_ops,
227  .vendor = PCI_VID_INTEL,
228  .devices = i210_device_ids,
229 };
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
cb_err
coreboot error codes
Definition: cb_err.h:15
@ CB_SUCCESS
Call completed successfully.
Definition: cb_err.h:16
#define printk(level,...)
Definition: stdlib.h:16
@ CONFIG
Definition: dsi_common.h:201
uint64_t address
Definition: fw_cfg_if.h:0
static uint32_t write_flash(struct device *dev, uint32_t address, uint32_t count, uint16_t *buffer)
This function can write the configuration space of the MACPHY For this purpose, the EEPROM interface ...
Definition: i210.c:99
static const struct pci_driver i210_driver __pci_driver
Definition: i210.c:225
static uint32_t write_mac_adr(struct device *dev, uint8_t *mac_adr)
This function can write the MAC address to the MACPHY.
Definition: i210.c:165
static void enable_bus_master(struct device *dev)
Definition: i210.c:209
static uint32_t read_mac_adr(struct device *dev, uint8_t *mac_adr)
This function can read the MAC address out of the MACPHY.
Definition: i210.c:147
static uint32_t compute_checksum(struct device *dev, uint16_t *checksum)
This function computes the checksum for the configuration space.
Definition: i210.c:72
static int wait_done(uint32_t *reg, uint32_t mask)
Definition: i210.c:16
static const unsigned short i210_device_ids[]
Definition: i210.c:223
static uint32_t read_flash(struct device *dev, uint32_t address, uint32_t count, uint16_t *buffer)
This function can read the configuration space of the MACPHY For this purpose, the EEPROM interface i...
Definition: i210.c:37
static struct device_operations i210_ops
Definition: i210.c:215
static void init(struct device *dev)
This function is the driver entry point for the init phase of the PCI bus allocator.
Definition: i210.c:181
enum cb_err mainboard_get_mac_address(struct device *dev, uint8_t mac[MAC_ADDR_LEN])
This function will search for a MAC address which can be assigned to a MACPHY.
Definition: mainboard.c:56
#define I210_SUCCESS
Definition: i210.h:22
#define I210_FLUDONE
Definition: i210.h:12
#define I210_DONE
Definition: i210.h:16
#define I210_NOT_READY
Definition: i210.h:24
#define I210_FLASH_UPDATE_ERROR
Definition: i210.h:28
#define I210_READ_ERROR
Definition: i210.h:25
#define I210_REG_EEWRITE
Definition: i210.h:14
#define I210_WRITE_ERROR
Definition: i210.h:26
#define I210_FLUPD
Definition: i210.h:11
#define I210_CHECKSUM_ERROR
Definition: i210.h:27
#define I210_REG_EEREAD
Definition: i210.h:13
#define I210_TARGET_CHECKSUM
Definition: i210.h:17
#define I210_INVALID_PARAM
Definition: i210.h:23
#define I210_REG_EECTRL
Definition: i210.h:10
#define I210_POLL_TIMEOUT_US
Definition: i210.h:20
static __always_inline void pci_or_config16(const struct device *dev, u16 reg, u16 ormask)
Definition: pci_ops.h:180
static __always_inline u32 pci_read_config32(const struct device *dev, u16 reg)
Definition: pci_ops.h:58
static uint8_t checksum(uint8_t *data, int offset)
Definition: ipmi_fru.c:70
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_NOTICE
BIOS_NOTICE - Unexpected but relatively insignificant.
Definition: loglevel.h:100
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
#define PCI_COMMAND_MASTER
Definition: pci_def.h:13
#define PCI_BASE_ADDRESS_0
Definition: pci_def.h:63
#define PCI_COMMAND
Definition: pci_def.h:10
void pci_dev_enable_resources(struct device *dev)
Definition: pci_device.c:721
void pci_dev_read_resources(struct device *dev)
Definition: pci_device.c:534
void pci_dev_set_resources(struct device *dev)
Definition: pci_device.c:691
#define PCI_VID_INTEL
Definition: pci_ids.h:2157
u8 buffer[C2P_BUFFER_MAXSIZE]
Definition: psp_smm.c:18
static const int mask[4]
Definition: gpio.c:308
unsigned short uint16_t
Definition: stdint.h:11
unsigned int uint32_t
Definition: stdint.h:14
unsigned char uint8_t
Definition: stdint.h:8
int memcmp(const void *s1, const void *s2, size_t n)
Definition: memcmp.c:3
void(* read_resources)(struct device *dev)
Definition: device.h:39
Definition: device.h:107
void udelay(uint32_t us)
Definition: udelay.c:15
#define count