blob: 32d27f7912f322de18a47161fb9e71bc379571a0 [file] [log] [blame]
Werner Zeh63693dc2015-02-13 12:18:58 +01001/*
2 * This file is part of the coreboot project.
3 *
Mario Scheithauera39aede2017-11-06 16:47:27 +01004 * Copyright (C) 2014-2017 Siemens AG
Werner Zeh63693dc2015-02-13 12:18:58 +01005 *
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.
9 *
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.
Werner Zeh63693dc2015-02-13 12:18:58 +010014 */
15
16#include "i210.h"
17#include <device/device.h>
18#include <console/console.h>
19#include <device/pci.h>
20#include <device/pci_ids.h>
21#include <device/pci_ops.h>
Werner Zehbd316422017-10-16 08:53:34 +020022#include <device/pci_def.h>
Werner Zeh63693dc2015-02-13 12:18:58 +010023#include <string.h>
24#include <types.h>
25#include <delay.h>
26
Werner Zeh63693dc2015-02-13 12:18:58 +010027/* This is a private function to wait for a bit mask in a given register */
28/* To avoid endless loops, a time-out is implemented here. */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +020029static int wait_done(uint32_t *reg, uint32_t mask)
Werner Zeh63693dc2015-02-13 12:18:58 +010030{
Werner Zeh608d9912016-04-26 09:26:14 +020031 uint32_t timeout = I210_POLL_TIMEOUT_US;
Werner Zeh63693dc2015-02-13 12:18:58 +010032
33 while (!(*reg & mask)) {
34 udelay(1);
35 if (!--timeout)
36 return I210_NOT_READY;
37 }
38 return I210_SUCCESS;
39}
40
41/** \brief This function can read the configuration space of the MACPHY
42 * For this purpose, the EEPROM interface is used. No direct access
43 * to the flash memory will be done.
44 * @param *dev Pointer to the PCI device of this MACPHY
45 * @param address Address inside the flash where reading will start
46 * @param count Number of words (16 bit values) to read
47 * @param *buffer Pointer to the buffer where to store read data
48 * @return void I210_NO_ERROR or an error code
49 */
Werner Zeh608d9912016-04-26 09:26:14 +020050static uint32_t read_flash(struct device *dev, uint32_t address,
51 uint32_t count, uint16_t *buffer)
Werner Zeh63693dc2015-02-13 12:18:58 +010052{
Werner Zeh608d9912016-04-26 09:26:14 +020053 uint32_t bar;
54 uint32_t *eeprd;
55 uint32_t i;
Werner Zeh63693dc2015-02-13 12:18:58 +010056
57 /* Get the BAR to memory mapped space*/
58 bar = pci_read_config32(dev, PCI_BASE_ADDRESS_0);
59 if ((!bar) || ((address + count) > 0x40))
60 return I210_INVALID_PARAM;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +020061 eeprd = (uint32_t *)(bar + I210_REG_EEREAD);
Werner Zeh63693dc2015-02-13 12:18:58 +010062 /* Prior to start ensure flash interface is ready by checking DONE-bit */
63 if (wait_done(eeprd, I210_DONE))
64 return I210_NOT_READY;
65
66 /*OK, interface is ready, we can use it now */
67 for (i = 0; i < count; i++) {
68 /* To start a read cycle write desired address in bits 12..2 */
69 *eeprd = ((address + i) << 2) & 0x1FFC;
70 /* Wait until read is done */
71 if (wait_done(eeprd, I210_DONE))
72 return I210_READ_ERROR;
73 /* Here, we can read back desired word in bits 31..16 */
74 buffer[i] = (*eeprd & 0xffff0000) >> 16;
75 }
76 return I210_SUCCESS;
77}
78
79/** \brief This function computes the checksum for the configuration space.
80 * The address range for the checksum is 0x00..0x3e.
81 * @param *dev Pointer to the PCI device of this MACPHY
82 * @param *checksum Pointer to the buffer where to store the checksum
83 * @return void I210_NO_ERROR or an error code
84 */
Werner Zeh608d9912016-04-26 09:26:14 +020085static uint32_t compute_checksum(struct device *dev, uint16_t *checksum)
Werner Zeh63693dc2015-02-13 12:18:58 +010086{
Werner Zeh608d9912016-04-26 09:26:14 +020087 uint16_t eep_data[0x40];
88 uint32_t i;
Werner Zeh63693dc2015-02-13 12:18:58 +010089
90 /* First read back data to compute the checksum for */
91 if (read_flash(dev, 0, 0x3f, eep_data))
92 return I210_READ_ERROR;
93 /* The checksum is computed in that way that after summarize all the */
94 /* data from word address 0 to 0x3f the result is 0xBABA. */
95 *checksum = 0;
96 for (i = 0; i < 0x3f; i++)
97 *checksum += eep_data[i];
98 *checksum = I210_TARGET_CHECKSUM - *checksum;
99 return I210_SUCCESS;
100}
101
102/** \brief This function can write the configuration space of the MACPHY
103 * For this purpose, the EEPROM interface is used. No direct access
104 * to the flash memory will be done. This function will update
105 * the checksum after a value was changed.
106 * @param *dev Pointer to the PCI device of this MACPHY
107 * @param address Address inside the flash where writing will start
108 * @param count Number of words (16 bit values) to write
109 * @param *buffer Pointer to the buffer where data to write is stored in
110 * @return void I210_NO_ERROR or an error code
111 */
Werner Zeh608d9912016-04-26 09:26:14 +0200112static uint32_t write_flash(struct device *dev, uint32_t address,
113 uint32_t count, uint16_t *buffer)
Werner Zeh63693dc2015-02-13 12:18:58 +0100114{
Werner Zeh608d9912016-04-26 09:26:14 +0200115 uint32_t bar;
116 uint32_t *eepwr;
117 uint32_t *eectrl;
118 uint16_t checksum;
119 uint32_t i;
Werner Zeh63693dc2015-02-13 12:18:58 +0100120
121 /* Get the BAR to memory mapped space */
122 bar = pci_read_config32(dev, 0x10);
123 if ((!bar) || ((address + count) > 0x40))
124 return I210_INVALID_PARAM;
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200125 eepwr = (uint32_t *)(bar + I210_REG_EEWRITE);
126 eectrl = (uint32_t *)(bar + I210_REG_EECTRL);
Werner Zeh63693dc2015-02-13 12:18:58 +0100127 /* Prior to start ensure flash interface is ready by checking DONE-bit */
128 if (wait_done(eepwr, I210_DONE))
129 return I210_NOT_READY;
130
131 /* OK, interface is ready, we can use it now */
132 for (i = 0; i < count; i++) {
133 /* To start a write cycle write desired address in bits 12..2 */
134 /* and data to write in bits 31..16 into EEWRITE-register */
135 *eepwr = ((((address + i) << 2) & 0x1FFC) | (buffer[i] << 16));
136 /* Wait until write is done */
137 if (wait_done(eepwr, I210_DONE))
138 return I210_WRITE_ERROR;
139 }
140 /* Since we have modified data, we need to update the checksum */
141 if (compute_checksum(dev, &checksum))
142 return I210_CHECKSUM_ERROR;
143 *eepwr = (0x3f << 2) | checksum << 16;
144 if (wait_done(eepwr, I210_DONE))
145 return I210_WRITE_ERROR;
146 /* Up to now, desired data was written into shadowed RAM. We now need */
Werner Zeh608d9912016-04-26 09:26:14 +0200147 /* to perform a flash cycle to bring the shadowed RAM into flash. */
148 /* To start a flash cycle we need to set FLUPD and wait for FLDONE. */
Werner Zeh63693dc2015-02-13 12:18:58 +0100149 *eectrl = *eectrl | I210_FLUPD;
150 if (wait_done(eectrl, I210_FLUDONE))
151 return I210_FLASH_UPDATE_ERROR;
152 return I210_SUCCESS;
153}
154
155/** \brief This function can read the MAC address out of the MACPHY
156 * @param *dev Pointer to the PCI device of this MACPHY
157 * @param *MACAdr Pointer to the buffer where to store read MAC address
158 * @return void I210_NO_ERROR or an error code
159 */
Werner Zeh608d9912016-04-26 09:26:14 +0200160static uint32_t read_mac_adr(struct device *dev, uint8_t *mac_adr)
Werner Zeh63693dc2015-02-13 12:18:58 +0100161{
Werner Zeh608d9912016-04-26 09:26:14 +0200162 uint16_t adr[3];
Werner Zeh63693dc2015-02-13 12:18:58 +0100163 if (!dev || !mac_adr)
164 return I210_INVALID_PARAM;
165 if (read_flash(dev, 0, 3, adr))
166 return I210_READ_ERROR;
Werner Zeh608d9912016-04-26 09:26:14 +0200167 /* Copy the address into destination. This is done because of possible */
168 /* not matching alignment for destination to uint16_t boundary. */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200169 memcpy(mac_adr, (uint8_t *)adr, 6);
Werner Zeh63693dc2015-02-13 12:18:58 +0100170 return I210_SUCCESS;
171}
172
173/** \brief This function can write the MAC address to the MACPHY
174 * @param *dev Pointer to the PCI device of this MACPHY
175 * @param *MACAdr Pointer to the buffer where the desired MAC address is
176 * @return void I210_NO_ERROR or an error code
177 */
Werner Zeh608d9912016-04-26 09:26:14 +0200178static uint32_t write_mac_adr(struct device *dev, uint8_t *mac_adr)
Werner Zeh63693dc2015-02-13 12:18:58 +0100179{
Werner Zeh608d9912016-04-26 09:26:14 +0200180 uint16_t adr[3];
Werner Zeh63693dc2015-02-13 12:18:58 +0100181 if (!dev || !mac_adr)
182 return I210_INVALID_PARAM;
183 /* Copy desired address into a local buffer to avoid alignment issues */
Elyes HAOUASb0b0c8c2018-07-08 12:33:47 +0200184 memcpy((uint8_t *)adr, mac_adr, 6);
Werner Zeh63693dc2015-02-13 12:18:58 +0100185 return write_flash(dev, 0, 3, adr);
186}
187
188/** \brief This function is the driver entry point for the init phase
189 * of the PCI bus allocator. It will program a MAC address
190 * into the MACPHY.
191 * @param *dev Pointer to the used PCI device
192 * @return void Nothing is given back
193 */
194static void init(struct device *dev)
195{
Werner Zeh608d9912016-04-26 09:26:14 +0200196 uint8_t cur_adr[6];
197 uint8_t adr_to_set[6];
Werner Zeh63693dc2015-02-13 12:18:58 +0100198 enum cb_err status;
199
200 /*Check first whether there is a valid MAC address available */
Werner Zehe22d96c2016-06-29 07:53:47 +0200201 status = mainboard_get_mac_address(dev, adr_to_set);
Werner Zeh63693dc2015-02-13 12:18:58 +0100202 if (status != CB_SUCCESS) {
203 printk(BIOS_ERR, "I210: No valid MAC address found\n");
204 return;
205 }
206 /* Before we will write a new address, check the existing one */
207 if (read_mac_adr(dev, cur_adr)) {
208 printk(BIOS_ERR, "I210: Not able to read MAC address.\n");
209 return;
210 }
211 if (memcmp(cur_adr, adr_to_set, 6)) {
212 if (write_mac_adr(dev, adr_to_set))
213 printk(BIOS_ERR, "I210: Error setting MAC address\n");
214 else
215 printk(BIOS_INFO, "I210: MAC address changed.\n");
216 } else {
217 printk(BIOS_INFO, "I210: MAC address is up to date.\n");
218 }
219 return;
220}
221
Elyes HAOUAS712ef1f22018-05-02 21:57:42 +0200222static void set_resources(struct device *dev)
Werner Zehbd316422017-10-16 08:53:34 +0200223{
224 pci_dev_set_resources(dev);
225 dev->command |= PCI_COMMAND_MASTER;
226}
227
Werner Zeh63693dc2015-02-13 12:18:58 +0100228static struct device_operations i210_ops = {
229 .read_resources = pci_dev_read_resources,
Werner Zehbd316422017-10-16 08:53:34 +0200230 .set_resources = set_resources,
Werner Zeh63693dc2015-02-13 12:18:58 +0100231 .enable_resources = pci_dev_enable_resources,
232 .init = init,
233 .scan_bus = 0,
234 .ops_pci = 0,
235};
236
Werner Zeh77319322018-05-30 07:05:26 +0200237static const unsigned short i210_device_ids[] = { 0x1537, 0x1538, 0x1533, 0 };
Werner Zeh63693dc2015-02-13 12:18:58 +0100238
239static const struct pci_driver i210_driver __pci_driver = {
240 .ops = &i210_ops,
241 .vendor = PCI_VENDOR_ID_INTEL,
242 .devices = i210_device_ids,
243};