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