Werner Zeh (werner.zeh(a)siemens.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8404
-gerrit
commit a67f91fdbebde8bee1fab9f1699862ac06cd0016
Author: Werner Zeh <werner.zeh(a)siemens.com>
Date: Tue Feb 10 15:09:00 2015 +0100
drivers/intel/i210: Add new driver for Intel i210 MACPHY
Add a new driver for Intel i210 MACPHY with the goal to
update the MAC address in i210 if it is found
during PCI scan.
Change-Id: I4d4e797543a9f278fb649596f63ae8e1f285b3c3
Signed-off-by: Werner Zeh <werner.zeh(a)siemens.com>
---
src/drivers/intel/Makefile.inc | 1 +
src/drivers/intel/i210/Makefile.inc | 1 +
src/drivers/intel/i210/i210.c | 241 ++++++++++++++++++++++++++++++++++++
src/drivers/intel/i210/i210.h | 56 +++++++++
4 files changed, 299 insertions(+)
diff --git a/src/drivers/intel/Makefile.inc b/src/drivers/intel/Makefile.inc
index 7bc6dd5..6cf8f00 100644
--- a/src/drivers/intel/Makefile.inc
+++ b/src/drivers/intel/Makefile.inc
@@ -1,3 +1,4 @@
subdirs-y += gma
subdirs-y += wifi
subdirs-$(CONFIG_PLATFORM_USES_FSP) += fsp
+subdirs-$(CONFIG_DRIVER_INTEL_I210) += i210
\ No newline at end of file
diff --git a/src/drivers/intel/i210/Makefile.inc b/src/drivers/intel/i210/Makefile.inc
new file mode 100644
index 0000000..a1f15de
--- /dev/null
+++ b/src/drivers/intel/i210/Makefile.inc
@@ -0,0 +1 @@
+ramstage-y += i210.c
\ No newline at end of file
diff --git a/src/drivers/intel/i210/i210.c b/src/drivers/intel/i210/i210.c
new file mode 100644
index 0000000..76326a8
--- /dev/null
+++ b/src/drivers/intel/i210/i210.c
@@ -0,0 +1,241 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Siemens AG.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "i210.h"
+#include <device/device.h>
+#include <console/console.h>
+#include <string.h>
+#include <types.h>
+
+/* We need one function we can call to get a MAC address to use */
+/* This function can be coded somewhere else but must exist. */
+extern enum cb_err get_mac_address(u32 pci_bdf, u8 mac[6]);
+
+/* This is a private function to wait for a bit mask in a given register */
+/* To avoid endless loops, a time-out is implemented here. */
+static int wait_done(u32* reg, u32 mask)
+{
+ u32 timeout = I210_POLL_TIMEOUT_US;
+ do {
+ if (!(*reg & mask)) {
+ udelay(1);
+ timeout--;
+ }
+ } while((!(*reg & mask)) && timeout);
+ return timeout ? I210_NO_ERROR : I210_NOT_READY;
+}
+
+/** \brief This function is the driver entry point for the init phase
+ * of the PCI bus allocator. It will program a MAC address
+ * into the MACPHY.
+ * @param *dev Pointer to the used PCI device
+ * @return void Nothing is given back
+ */
+static void init(struct device *dev)
+{
+ u8 cur_adr[6];
+ u8 adr_to_set[6];
+ enum cb_err status;
+
+ /*Check first whether there is a valid MAC address available */
+ status = get_mac_address((dev->bus->subordinate << 16) |
+ dev->path.pci.devfn << 8, adr_to_set);
+ if (status != CB_SUCCESS) {
+ printk(BIOS_ERR, "I210: No valid MAC address found\n");
+ return;
+ }
+ /* Before we will write a new address, check the existing one */
+ if (read_mac_adr(dev, cur_adr)) {
+ printk(BIOS_ERR, "I210: Not able to read MAC address.\n");
+ return;
+ }
+ if (memcmp(cur_adr, adr_to_set, 6)) {
+ if (write_mac_adr(dev, adr_to_set)) {
+ printk(BIOS_ERR, "I210: Error setting MAC address\n");
+ } else {
+ printk(BIOS_INFO, "I210: MAC address changed.\n");
+ }
+ } else {
+ printk(BIOS_INFO, "I210: MAC address is up to date.\n");
+ }
+ return;
+}
+
+/** \brief This function can read the MAC address out of the MACPHY
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param *MACAdr Pointer to the buffer where to store read MAC address
+ * @return void I210_NO_ERROR or an error code
+ */
+static u32 read_mac_adr(struct device *dev, u8 *MACAdr)
+{
+ u16 adr[3];
+ if (!dev || !MACAdr)
+ return I210_INVALID_PARAM;
+ if (read_flash(dev, 0, 3, adr))
+ return I210_READ_ERROR;
+ /* Copy the address into destination. This is done because of */
+ /* possible not matching alignment for destination to u16 boundary. */
+ memcpy(MACAdr, (u8*)adr, 6);
+ return I210_NO_ERROR;
+}
+
+/** \brief This function can write the MAC address to the MACPHY
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param *MACAdr Pointer to the buffer where the desired MAC address is
+ * @return void I210_NO_ERROR or an error code
+ */
+static u32 write_mac_adr(struct device *dev, u8 *MACAdr)
+{
+ u16 adr[3];
+ if (!dev || !MACAdr)
+ return I210_INVALID_PARAM;
+ /* Copy desired address into a local buffer to avoid alignment issues */
+ memcpy((u8*)adr, MACAdr, 6);
+ return write_flash(dev, 0, 3, adr);
+}
+
+/** \brief This function can read the configuration space of the MACPHY
+ * For this purpose, the EEPROM interface is used. No direct access
+ * to the flash memory will be done.
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param address Address inside the flash where reading will start
+ * @param count Number of words (16 bit values) to read
+ * @param *buffer Pointer to the buffer where to store read data
+ * @return void I210_NO_ERROR or an error code
+ */
+static u32 read_flash(struct device *dev, u32 address, u32 count, u16 *buffer)
+{
+ u32 bar;
+ u32 *eeprd;
+ u32 i;
+
+ /* Get the BAR to memory mapped space*/
+ bar = pci_read_config32(dev, 0x10);
+ if ((!bar) || ((address + count) > 0x40))
+ return I210_INVALID_PARAM;
+ eeprd = (u32*)(bar + I210_REG_EEREAD);
+ /* Prior to start ensure flash interface is ready by checking DONE-bit */
+ if (wait_done(eeprd, I210_DONE))
+ return I210_NOT_READY;
+
+ /*OK, interface is ready, we can use it now */
+ for (i = 0; i < count; i++) {
+ /* To start a read cycle write desired address in bits 12..2 */
+ *eeprd = ((address + i) << 2) & 0x1FFC;
+ /* Wait until read is done */
+ if (wait_done(eeprd, I210_DONE))
+ return I210_READ_ERROR;
+ /* Here, we can read back desired word in bits 31..16 */
+ buffer[i] = (*eeprd & 0xffff0000) >> 16;
+ }
+ return I210_NO_ERROR;
+}
+
+/** \brief This function can write the configuration space of the MACPHY
+ * For this purpose, the EEPROM interface is used. No direct access
+ * to the flash memory will be done. This function will update
+ * the checksum after a value was changed.
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param address Address inside the flash where writing will start
+ * @param count Number of words (16 bit values) to write
+ * @param *buffer Pointer to the buffer where data to write is stored in
+ * @return void I210_NO_ERROR or an error code
+ */
+static u32 write_flash(struct device *dev, u32 address, u32 count, u16 *buffer)
+{
+ u32 bar;
+ u32 *eepwr;
+ u32 *eectrl;
+ u16 checksum;
+ u32 i;
+
+ /* Get the BAR to memory mapped space */
+ bar = pci_read_config32(dev, 0x10);
+ if ((!bar) || ((address + count) > 0x40))
+ return I210_INVALID_PARAM;
+ eepwr = (u32*)(bar + I210_REG_EEWRITE);
+ eectrl = (u32*)(bar + I210_REG_EECTRL);
+ /* Prior to start ensure flash interface is ready by checking DONE-bit */
+ if (wait_done(eepwr, I210_DONE))
+ return I210_NOT_READY;
+
+ /* OK, interface is ready, we can use it now */
+ for (i = 0; i < count; i++) {
+ /* To start a write cycle write desired address in bits 12..2 */
+ /* and data to write in bits 31..16 into EEWRITE-register */
+ *eepwr = ((((address + i) << 2) & 0x1FFC) | (buffer[i] << 16));
+ /* Wait until write is done */
+ if (wait_done(eepwr, I210_DONE))
+ return I210_WRITE_ERROR;
+ }
+ /* Since we have modified data, we need to update the checksum */
+ if (compute_checksum(dev, &checksum))
+ return I210_CHECKSUM_ERROR;
+ *eepwr = (0x3f << 2) | checksum << 16;
+ if (wait_done(eepwr, I210_DONE))
+ return I210_WRITE_ERROR;
+ /* Up to now, desired data was written into shadowed RAM. We now need */
+ /* to perform a flash cycle to bring the shadowed RAM into flash memory. */
+ /* To start a flash cycle we need to set FLUPD-bit and wait for FLDONE. */
+ *eectrl = *eectrl | I210_FLUPD;
+ if (wait_done(eectrl, I210_FLUDONE))
+ return I210_FLASH_UPDATE_ERROR;
+ else
+ return I210_NO_ERROR;
+}
+
+/** \brief This function computes the checksum for the configuration space.
+ * The address range for the checksum is 0x00..0x3e.
+ * @param *dev Pointer to the PCI device of this MACPHY
+ * @param *checksum Pointer to the buffer where to store the checksum
+ * @return void I210_NO_ERROR or an error code
+ */
+static u32 compute_checksum(struct device *dev, u16 *checksum)
+{
+ u16 eep_data[0x40];
+ u32 i;
+
+ /* First read back data to compute the checksum for */
+ if (read_flash(dev, 0, 0x3f, eep_data))
+ return I210_READ_ERROR;
+ /* The checksum is computed in that way that after summarize all the */
+ /* data from word address 0 to 0x3f the result is 0xBABA. */
+ *checksum = 0;
+ for (i = 0; i < 0x3f; i++)
+ *checksum += eep_data[i];
+ *checksum = I210_TARGET_CHECKSUM - *checksum;
+ return I210_NO_ERROR;
+}
+
+static struct device_operations i210_ops = {
+ .read_resources = pci_dev_read_resources,
+ .set_resources = pci_dev_set_resources,
+ .enable_resources = pci_dev_enable_resources,
+ .init = init,
+ .scan_bus = 0,
+ .ops_pci = 0,
+};
+
+static const unsigned short i210_device_ids[] = { 0x1538, 0x1533, 0 };
+
+static const struct pci_driver i210_driver __pci_driver = {
+ .ops = &i210_ops,
+ .vendor = PCI_VENDOR_ID_INTEL,
+ .devices = i210_device_ids,
+};
diff --git a/src/drivers/intel/i210/i210.h b/src/drivers/intel/i210/i210.h
new file mode 100644
index 0000000..c1fd58a
--- /dev/null
+++ b/src/drivers/intel/i210/i210.h
@@ -0,0 +1,56 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _INTEL_I210_H_
+#define _INTEL_I210_H_
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <device/pci_ops.h>
+#include <delay.h>
+
+#define I210_PCI_MEM_BAR_OFFSET 0x10
+#define I210_REG_EECTRL 0x12010 /* Offset for EEPROM control reg */
+#define I210_FLUPD 0x800000 /* Start flash update bit */
+#define I210_FLUDONE 0x4000000 /* Flash update done indicator */
+#define I210_REG_EEREAD 0x12014 /* Offset for EEPROM read reg */
+#define I210_REG_EEWRITE 0x12018 /* Offset for EEPROM write reg */
+#define I210_CMDV 0x01 /* command valid bit */
+#define I210_DONE 0x02 /* command done bit */
+#define I210_TARGET_CHECKSUM 0xBABA /* resulting checksum */
+
+
+/*define some other useful values here */
+#define I210_POLL_TIMEOUT_US 300000 /* 300 ms */
+/*Define some error states here*/
+#define I210_NO_ERROR 0x00000000
+#define I210_INVALID_PARAM 0x00000001
+#define I210_NOT_READY 0x00000002
+#define I210_READ_ERROR 0x00000004
+#define I210_WRITE_ERROR 0x00000008
+#define I210_CHECKSUM_ERROR 0x00000010
+#define I210_FLASH_UPDATE_ERROR 0x00000020
+
+static void init(struct device *dev);
+static u32 read_mac_adr(struct device *dev, u8 *MACAdr);
+static u32 write_mac_adr(struct device *dev, u8 *MACAdr);
+static u32 read_flash(struct device *dev, u32 address, u32 count, u16 *buffer);
+static u32 write_flash(struct device *dev, u32 address, u32 count, u16 *buffer);
+static u32 compute_checksum(struct device *dev, u16 *checksum);
+
+#endif /* _INTEL_I210_H_ */
Werner Zeh (werner.zeh(a)siemens.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8401
-gerrit
commit 2dc2d85176d62bcc19fe04a8aefe0a3080372347
Author: Werner Zeh <werner.zeh(a)siemens.com>
Date: Tue Feb 10 13:02:34 2015 +0100
fsp_baytrail: Add I2C driver
Add a driver wich can handle the internal I2C controllers
of Baytrail SoC. This driver is not suitable for the
SMBUS-controller.
Change-Id: I841c3991a2fb0f8b92b8e59ec02d62f5866f5bdf
Signed-off-by: Werner Zeh <werner.zeh(a)siemens.com>
---
src/soc/intel/fsp_baytrail/Makefile.inc | 1 +
src/soc/intel/fsp_baytrail/baytrail/i2c.h | 138 +++++++++++++++
src/soc/intel/fsp_baytrail/i2c.c | 269 ++++++++++++++++++++++++++++++
3 files changed, 408 insertions(+)
diff --git a/src/soc/intel/fsp_baytrail/Makefile.inc b/src/soc/intel/fsp_baytrail/Makefile.inc
index 3896e85..2dfb9cb 100644
--- a/src/soc/intel/fsp_baytrail/Makefile.inc
+++ b/src/soc/intel/fsp_baytrail/Makefile.inc
@@ -54,6 +54,7 @@ smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c
ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smm.c
ramstage-y += placeholders.c
+ramstage-y += i2c.c
CPPFLAGS_common += -I$(src)/soc/intel/fsp_baytrail/
CPPFLAGS_common += -I$(src)/soc/intel/fsp_baytrail/fsp
diff --git a/src/soc/intel/fsp_baytrail/baytrail/i2c.h b/src/soc/intel/fsp_baytrail/baytrail/i2c.h
new file mode 100644
index 0000000..3799fbb
--- /dev/null
+++ b/src/soc/intel/fsp_baytrail/baytrail/i2c.h
@@ -0,0 +1,138 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __SOC_INTEL_FSP_BAYTRAIL_I2C_H__
+#define __SOC_INTEL_FSP_BAYTRAIL_I2C_H__
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <device/pci_ids.h>
+#include <device/pci_def.h>
+
+/* SMBus controller settings in PCI configuration space*/
+#define I2C_PCI_VENDOR_ID 0x8086
+#define I2C0_PCI_DEV_ID 0x0f41
+#define I2C1_PCI_DEV_ID 0x0f42
+#define I2C2_PCI_DEV_ID 0x0f43
+#define I2C3_PCI_DEV_ID 0x0f44
+#define I2C4_PCI_DEV_ID 0x0f45
+#define I2C5_PCI_DEV_ID 0x0f46
+#define I2C6_PCI_DEV_ID 0x0f47
+
+#define I2C0_MEM_BASE 0xd0921000
+#define I2C1_MEM_BASE 0xd0923000
+#define I2C2_MEM_BASE 0xd0925000
+#define I2C3_MEM_BASE 0xd0927000
+#define I2C4_MEM_BASE 0xd0929000
+#define I2C5_MEM_BASE 0xd092b000
+#define I2C6_MEM_BASE 0xd092d000
+
+#define I2C_STANDARD_MODE 0x1
+#define I2C_FAST_MODE 0x2
+
+/* Define relevant registers in PCI space.*/
+#define I2C_PCI_COMMAND 0x4
+#define I2C_PCI_STATUS 0x6
+
+/* Define memory mapped registers.*/
+#define I2C_CTRL 0x0
+#define I2C_SLAVE_DISABLE 0x40
+#define I2C_RESTART_EN 0x20
+#define I2C_ADR_MODE 0x10
+#define I2C_SPEED_MASK 0x6
+#define I2C_STD_MODE 0x1
+#define I2C_FAST_MODE 0x2
+#define I2C_MASTER_ENABLE 0x1
+
+#define I2C_TARGET_ADR 0x4
+#define I2C_TARGET_ADR_MASK 0x3ff
+
+#define I2C_DATA_CMD 0x10
+#define I2C_RESTART 0x400
+#define I2C_STOP 0x200
+#define I2C_RW_CMD 0x100
+
+#define I2C_SS_SCL_HCNT 0x14 /* Counter for high period for 100 kHz SCL*/
+#define I2C_SS_SCL_LCNT 0x18 /* Counter for low period for 100 kHz SCL*/
+#define I2C_FS_SCL_HCNT 0x1c /* Counter for high period for 400 kHz SCL*/
+#define I2C_FS_SCL_LCNT 0x20 /* Counter for low period for 400 kHz SCL*/
+
+#define I2C_INTR_STAT 0x2c /* Interrupt status register, read only*/
+#define I2C_INTR_MASK 0x30 /*Interrupt mask register*/
+#define I2C_RAW_INTR_STAT 0x34 /* Raw interrupt status, read only*/
+#define I2C_START_DETECT 0x400
+#define I2C_STOP_DETECT 0x200
+#define I2C_ACTIVITY 0x100
+#define I2C_TX_ABORT 0x40
+#define I2C_RD_REQ 0x20 /* Read request in slave mode*/
+#define I2C_TX_EMPTY 0x10
+#define I2C_TX_OVERFLOW 0x8
+#define I2C_RX_FULL 0x4
+#define I2C_RX_OVERFLOW 0x2
+#define I2C_RX_UNDERFLOW 0x1
+
+#define I2C_RX_TL 0x38 /* Rx FIFO threshold level 0..255*/
+#define I2C_TX_TL 0x3c /* Tx FIFO threshold level 0..255*/
+#define I2C_CLR_INTR 0x40 /* Clear all events with a read*/
+#define I2C_CLR_TX_ABRT 0x54 /* Clear TX-Abort event with a read*/
+
+/*There are a bunch of interrupt clearing registers now which I do not use!*/
+/*So proceed somewhat later with definition*/
+#define I2C_ENABLE 0x6c /* 0: disable I2C controller, 1: enable*/
+#define I2C_STATUS 0x70
+#define I2C_MST_ACTIVITY 0x20 /* Master FSM activity*/
+#define I2C_RFF 0x10 /* Receive FIFO completely full*/
+#define I2C_RFNE 0x8 /* Receive FIFO not empty*/
+#define I2C_TFE 0x4 /* Transmit FIFO completely empty*/
+#define I2C_TFNF 0x2 /* Transmit FIFO not full*/
+#define I2C_ACTIVE 0x1 /* 1: I2C currently in operation*/
+
+#define I2C_TXFLR 0x74 /* Current transmit FIFO level*/
+#define I2C_RXFLR 0x78 /* Current receive FIFO level*/
+#define I2C_SDA_HOLD 0x7c /* Data hold time after SCL goes low*/
+#define I2C_ABORT_SOURCE 0x80
+#define I2C_ARB_LOST 0x1000 /* Arbitration lost*/
+#define I2C_MASTER_DIS 0x800 /* Master was disabled by user*/
+#define I2C_10B_RD_NORSTRT 0x400 /* 10 bit address read and RESTART disabled*/
+#define I2C_SBYTE_NORSTRT 0x200 /* START with RESTART disabled*/
+#define I2C_START_ACKDET 0x80 /* START byte was acknowledged*/
+#define I2C_TX_DATA_NOACK 0x8 /* TX data not acknowledged*/
+#define I2C_10B_ADR2_NOACK 0x4 /* Second address byte in 10 bit mode NACK*/
+#define I2C_10B_ADR1_NOACK 0x2 /* First address byte in 10 bit not ACK*/
+#define I2C_7B_ADDR_NACK 0x1 /* 7 bit address byte not acknowledged*/
+
+#define I2C_ENABLE_STATUS 0x9c
+
+/* Define some status and error values*/
+#define I2C_ERR_INVALID_ADR 0x1000000
+#define I2C_ERR_TIMEOUT 0x2000000
+#define I2C_ERR_ABORT 0x4000000
+#define I2C_NO_ERROR 0x0000000
+
+
+#define I2C_TIMEOUT 2000 /* Use 2000 us as timeout for the bus*/
+
+/* Prototype section*/
+int i2c_init(unsigned bus);
+int i2c_read(unsigned bus, unsigned chip, unsigned addr,
+ uint8_t *buf, unsigned len);
+int i2c_write(unsigned bus, unsigned chip, unsigned addr,
+ const uint8_t *buf, unsigned len);
+
+#endif /* __SOC_INTEL_FSP_BAYTRAIL_I2C_H__ */
diff --git a/src/soc/intel/fsp_baytrail/i2c.c b/src/soc/intel/fsp_baytrail/i2c.c
new file mode 100644
index 0000000..05c21a3
--- /dev/null
+++ b/src/soc/intel/fsp_baytrail/i2c.c
@@ -0,0 +1,269 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2014 Siemens AG
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <device/pci.h>
+#include <baytrail/baytrail.h>
+#include <baytrail/pci_devs.h>
+#include <baytrail/iosf.h>
+#include <delay.h>
+#include <baytrail/i2c.h>
+
+/* Wait for the transmit FIFO till there is at least one slot empty.
+ * FIFO stall due to transmit abort will be checked and resolved
+ */
+static int wait_tx_fifo(char *base_adr) {
+ int i;
+
+ if (*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff) {
+ /*Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO*/
+ i = *((volatile unsigned int *)(base_adr + I2C_CLR_TX_ABRT));
+ return I2C_ERR_ABORT |
+ (*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff);
+ }
+
+ /*Wait here for a free slot in TX-FIFO */
+ i = I2C_TIMEOUT;
+ while ((!(*((volatile unsigned int *)(base_adr + I2C_STATUS)) & I2C_TFNF))
+ && (i)) {
+ udelay(1);
+ i--;
+ }
+
+ if (i == 0) {
+ return I2C_ERR_TIMEOUT;
+ } else {
+ return I2C_NO_ERROR;
+ }
+}
+
+/* Wait for the receive FIFO till there is at least one valid entry to read.
+ * FIFO stall due to transmit abort will be checked and resolved
+ */
+static int wait_rx_fifo(char *base_adr) {
+ int i;
+
+ if (*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff) {
+ /*Reading back I2C_CLR_TX_ABRT resets abort lock on TX FIFO*/
+ i = *((volatile unsigned int *)(base_adr + I2C_CLR_TX_ABRT));
+ return I2C_ERR_ABORT |
+ (*((unsigned int *)(base_adr + I2C_ABORT_SOURCE)) & 0x1ffff);
+ }
+
+ /*Wait here for a received entry in RX-FIFO */
+ i = I2C_TIMEOUT;
+ while ((!(*((volatile unsigned int *)(base_adr + I2C_STATUS)) & I2C_RFNE))
+ && (i)) {
+ udelay(1);
+ i--;
+ }
+
+ if (i == 0) {
+ return I2C_ERR_TIMEOUT;
+ } else {
+ return I2C_NO_ERROR;
+ }
+}
+
+/* When there will be a fast switch between send and receive, one have
+ * to wait until the first operation is completely finished
+ * before starting the second operation
+ */
+static int wait_for_idle(char *base_adr)
+{
+ int i;
+ volatile int status;
+
+ /*For IDLE, increase timeout by ten times*/
+ i = I2C_TIMEOUT * 10;
+ status = *((volatile unsigned int *)(base_adr + I2C_STATUS));
+ while(((status & I2C_MST_ACTIVITY) || (!(status & I2C_TFE))) && (i)) {
+ status = *((volatile unsigned int *)(base_adr + I2C_STATUS));
+ udelay(1);
+ i--;
+ }
+
+ if (i == 0) {
+ return I2C_ERR_TIMEOUT;
+ } else {
+ return I2C_NO_ERROR;
+ }
+}
+
+/** \brief Enables I2C-controller, sets up BAR and timing parameters
+ * @param bus Number of the I2C-controller to use (0...6)
+ * @return 0 on success, otherwise error code
+ */
+int i2c_init(unsigned bus)
+{
+ device_t dev;
+ int base_adr[7] = {I2C0_MEM_BASE, I2C1_MEM_BASE, I2C2_MEM_BASE,
+ I2C3_MEM_BASE, I2C4_MEM_BASE, I2C5_MEM_BASE,
+ I2C6_MEM_BASE};
+ char *base_ptr = (char*)base_adr[bus];
+ /* Ensure the desired device is valid*/
+ if (bus > 6) {
+ printk (BIOS_ERR, "I2C: Only I2C controllers 0...6 are available");
+ return 1;
+ }
+
+ /*Set the I2C-device the user wants to use */
+ dev = dev_find_slot(0, PCI_DEVFN(I2C1_DEV, bus + 1));
+
+ /* Ensure we have the right PCI device */
+ if ((pci_read_config16(dev, 0x0) != I2C_PCI_VENDOR_ID) ||
+ (pci_read_config16(dev, 0x2) != (I2C0_PCI_DEV_ID + bus))) {
+ printk(BIOS_ERR, "I2C: Controller %d not found!", bus);
+ return 2;
+ }
+
+ /* Set memory base*/
+ pci_write_config32(dev, PCI_BASE_ADDRESS_0,(int)base_ptr);
+
+ /* Enable memory space*/
+ pci_write_config32(dev, PCI_COMMAND,
+ (pci_read_config32(dev, PCI_COMMAND) | 0x2));
+
+ /*Set up some settings of I2C controller*/
+ *((unsigned int *)(base_ptr + I2C_CTRL)) = (I2C_RESTART_EN
+ | (I2C_STANDARD_MODE << 1)
+ | I2C_MASTER_ENABLE);
+ /*Adjust frequency for standard mode to 100 kHz*/
+ /*The counter value can be computed by N=100MHz/2/I2C_CLK*/
+ /*Thus, for 100 kHz I2C_CLK, N is 0x1F4*/
+ *((unsigned int *)(base_ptr + I2C_SS_SCL_HCNT)) = 0x1f4;
+ *((unsigned int *)(base_ptr + I2C_SS_SCL_LCNT)) = 0x1f4;
+ /*For 400 kHz, the counter value is 0x7d*/
+ *((unsigned int *)(base_ptr + I2C_FS_SCL_HCNT)) = 0x7d;
+ *((unsigned int *)(base_ptr + I2C_FS_SCL_LCNT)) = 0x7d;
+
+ /* Enable the I2C controller for operation*/
+ *((unsigned int *)(base_ptr + I2C_ENABLE)) = 0x1;
+
+ printk(BIOS_INFO, "I2C: Controller %d enabled.\n", bus);
+ return I2C_NO_ERROR;
+}
+
+/** \brief Read bytes over I2C-Bus from a slave. This function tries only one
+ * time to transmit data. In case of an error (abort) error code is
+ * returned. Retransmission has to be done from caller!
+ * @param bus Number of the I2C-controller to use (0...6)
+ * @param chip 7 Bit of the slave address on I2C bus
+ * @param addr Address inside slave where to read from
+ * @param *buf Pointer to the buffer where to store read data
+ * @param len Number of bytes to read
+ * @return I2C_NO_ERROR when read was successful, otherwise error code
+ */
+int i2c_read(unsigned bus, unsigned chip, unsigned addr,
+ uint8_t *buf, unsigned len)
+{
+ int i = 0;
+ char *base_ptr = NULL;
+ device_t dev;
+ unsigned int val;
+ int stat;
+
+ /*Get base address of desired I2C-controller*/
+ dev = dev_find_slot(0, PCI_DEVFN(I2C1_DEV, bus + 1));
+ base_ptr = (char *)pci_read_config32(dev, PCI_BASE_ADDRESS_0);
+ if (base_ptr == NULL) {
+ printk(BIOS_INFO, "I2C: Invalid Base address\n");
+ return I2C_ERR_INVALID_ADR;
+ }
+
+ /*Ensure I2C controller is not active before setting slave address*/
+ stat = wait_for_idle(base_ptr);
+ if (stat != I2C_NO_ERROR) {
+ return stat;
+ }
+ /* Now we can program the desired slave address and start transfer*/
+ *((unsigned int *)(base_ptr + I2C_TARGET_ADR)) = (chip & 0xff);
+ /* Send address inside slave to read from*/
+ *((unsigned int *)(base_ptr + I2C_DATA_CMD)) = (addr & 0xff);
+
+ /* For the next byte we need a repeated start condition*/
+ val = I2C_RW_CMD | I2C_RESTART;
+ /* Now we can read desired amount of data over I2C*/
+ for (i = 0; i < len; i++) {
+ /*A read is initiated by writing dummy data to the DATA-register*/
+ *((unsigned int *)(base_ptr + I2C_DATA_CMD)) = val;
+ stat = wait_rx_fifo(base_ptr);
+ if (stat) {
+ return stat;
+ }
+ buf[i] = (*((unsigned int *)(base_ptr + I2C_DATA_CMD))) & 0xff;
+ val = I2C_RW_CMD;
+ if (i == (len -2)) {
+ /* For the last byte we need a stop condition to be generated*/
+ val |= I2C_STOP;
+ }
+ }
+ return I2C_NO_ERROR;
+}
+
+/** \brief Write bytes over I2C-Bus from a slave. This function tries only one
+ * time to transmit data. In case of an error (abort) error code is
+ * returned. Retransmission has to be done from caller!
+ * @param bus Number of the I2C-controller to use (0...6)
+ * @param chip 7 Bit of the slave address on I2C bus
+ * @param addr Address inside slave where to write to
+ * @param *buf Pointer to the buffer where data to write is stored
+ * @param len Number of bytes to write
+ * @return I2C_NO_ERROR when read was successful, otherwise error code
+ */
+int i2c_write(unsigned bus, unsigned chip, unsigned addr,
+ const uint8_t *buf, unsigned len)
+{
+ int i;
+ char *base_ptr;
+ device_t dev;
+ unsigned int val;
+ int stat;
+
+ /*Get base address of desired I2C-controller*/
+ dev = dev_find_slot(0, PCI_DEVFN(I2C1_DEV, bus + 1));
+ base_ptr = (char *)pci_read_config32(dev, PCI_BASE_ADDRESS_0);
+ if (base_ptr == NULL) {
+ return I2C_ERR_INVALID_ADR;
+ }
+
+ /*Ensure I2C controller is not active jet*/
+ stat = wait_for_idle(base_ptr);
+ if (stat) {
+ return stat;
+ }
+ /*Program slave address to use for this transfer*/
+ *((unsigned int *)(base_ptr + I2C_TARGET_ADR)) = (chip & 0xff);
+
+ /* Send address inside slave to write data to*/
+ *((unsigned int *)(base_ptr + I2C_DATA_CMD)) = (addr & 0xff);
+
+ for (i = 0; i < len; i++) {
+ val = (unsigned int)(buf[i] & 0xff); /* Take only 8 bits*/
+ if (i == (len -1)) {
+ /* For the last byte we need a stop condition to be generated*/
+ val |= I2C_STOP;
+ }
+ stat = wait_tx_fifo(base_ptr);
+ if (stat) {
+ return stat;
+ }
+ *((unsigned int *)(base_ptr + I2C_DATA_CMD)) = val;
+ }
+ return I2C_NO_ERROR;
+}
Werner Zeh (werner.zeh(a)siemens.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8403
-gerrit
commit 0354a58ced74a4de3cf6488fa48c470b8e8735ce
Author: Werner Zeh <werner.zeh(a)siemens.com>
Date: Tue Feb 10 14:34:17 2015 +0100
lint: exclude *.hex files from whitespace checking
If one needs raw binary files, .bin extension cannot
be used due to settings in .gitignore. This patch
allows to use .hex files. To avoid lint checks on these
files, exclude the .hex extension from the test.
Change-Id: I4b503229d63694c48cce12ca8cd33ea58172af01
Signed-off-by: Werner Zeh <werner.zeh(a)siemens.com>
---
util/lint/lint-stable-003-whitespace | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/util/lint/lint-stable-003-whitespace b/util/lint/lint-stable-003-whitespace
index 47853ba..f13aa98 100755
--- a/util/lint/lint-stable-003-whitespace
+++ b/util/lint/lint-stable-003-whitespace
@@ -19,6 +19,6 @@
# DESCR: Check for superfluous whitespace in the tree
LC_ALL=C export LC_ALL
-grep -l "[[:space:]][[:space:]]*$" `git ls-files src util |egrep -v "(^3rdparty|^src/vendorcode/|^util/kconfig/|^util/nvidia/cbootimage$|\<COPYING\>|\<LICENSE\>|\<README\>|_shipped$|\.patch|\.bin$)"` | \
+grep -l "[[:space:]][[:space:]]*$" `git ls-files src util |egrep -v "(^3rdparty|^src/vendorcode/|^util/kconfig/|^util/nvidia/cbootimage$|\<COPYING\>|\<LICENSE\>|\<README\>|_shipped$|\.patch$|\.bin$|\.hex$)"` | \
sed -e "s,^.*$,File & has lines ending with whitespace.,"
Werner Zeh (werner.zeh(a)siemens.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8372
-gerrit
commit 0a85f1d9db175846d448e048f2bd1ef9bea74fd8
Author: Patrick Georgi <patrick(a)georgi-clan.de>
Date: Thu Feb 5 23:38:45 2015 +0100
lint: exclude nvidia submodule from file list
From git's point of view submodules are a weird third thing between file
and directory. Avoid trying to apply file handling on a directory.
Change-Id: Ibbc9c28e1657d96413c5fb08705d30e25171254d
Signed-off-by: Patrick Georgi <patrick(a)georgi-clan.de>
---
util/lint/lint-stable-003-whitespace | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/util/lint/lint-stable-003-whitespace b/util/lint/lint-stable-003-whitespace
index 22c5c3c..47853ba 100755
--- a/util/lint/lint-stable-003-whitespace
+++ b/util/lint/lint-stable-003-whitespace
@@ -19,6 +19,6 @@
# DESCR: Check for superfluous whitespace in the tree
LC_ALL=C export LC_ALL
-grep -l "[[:space:]][[:space:]]*$" `git ls-files src util |egrep -v "(^3rdparty|^src/vendorcode/|^util/kconfig/|\<COPYING\>|\<LICENSE\>|\<README\>|_shipped$|\.patch|\.bin$)"` | \
+grep -l "[[:space:]][[:space:]]*$" `git ls-files src util |egrep -v "(^3rdparty|^src/vendorcode/|^util/kconfig/|^util/nvidia/cbootimage$|\<COPYING\>|\<LICENSE\>|\<README\>|_shipped$|\.patch|\.bin$)"` | \
sed -e "s,^.*$,File & has lines ending with whitespace.,"
Werner Zeh (werner.zeh(a)siemens.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8399
-gerrit
commit fb810e32e1bf87f7c99122ad6444d5bd93a69505
Author: Werner Zeh <werner.zeh(a)siemens.com>
Date: Tue Feb 10 10:16:12 2015 +0100
Baytrail_fsp: Add new microcode for Baytrail M
Add a new microcode for Baytrail M D0 stepping used
in cpu N2807 silicon.
In addition, a selection of the used CPU type has
beed added (I or M/D) which allows to use only the
realy needed microcode for a given CPU type.
Change-Id: I373fc9b535f1dc97eaa9f76ae46f0b69b247a8a0
Signed-off-by: Werner Zeh <werner.zeh(a)siemens.com>
---
src/soc/intel/fsp_baytrail/Kconfig | 9 +++++++++
src/soc/intel/fsp_baytrail/microcode/microcode_blob.c | 11 ++++++++---
src/soc/intel/fsp_baytrail/microcode/microcode_size.h | 6 +++++-
3 files changed, 22 insertions(+), 4 deletions(-)
diff --git a/src/soc/intel/fsp_baytrail/Kconfig b/src/soc/intel/fsp_baytrail/Kconfig
index 639071a..a7f3f77 100644
--- a/src/soc/intel/fsp_baytrail/Kconfig
+++ b/src/soc/intel/fsp_baytrail/Kconfig
@@ -51,6 +51,15 @@ config CPU_SPECIFIC_OPTIONS
select CPU_MICROCODE_ADDED_DURING_BUILD if INCLUDE_MICROCODE_IN_BUILD
select ROMSTAGE_RTC_INIT
+choice
+ prompt "Baytrail CPU type"
+ default SOC_INTEL_FSP_BAYTRAIL_I
+config SOC_INTEL_FSP_BAYTRAIL_I
+ bool "I"
+config SOC_INTEL_FSP_BAYTRAIL_MD
+ bool "M/D"
+endchoice
+
config BOOTBLOCK_CPU_INIT
string
default "soc/intel/fsp_baytrail/bootblock/bootblock.c"
diff --git a/src/soc/intel/fsp_baytrail/microcode/microcode_blob.c b/src/soc/intel/fsp_baytrail/microcode/microcode_blob.c
index 709ff92..fc5ab08 100644
--- a/src/soc/intel/fsp_baytrail/microcode/microcode_blob.c
+++ b/src/soc/intel/fsp_baytrail/microcode/microcode_blob.c
@@ -19,10 +19,15 @@
unsigned microcode[] = {
+#if IS_ENABLED(CONFIG_SOC_INTEL_FSP_BAYTRAIL_I)
/* Region size is 0x30000 - update in microcode_size.h if it gets larger. */
-#include "M0230672228.h" // M0230672: Baytrail "Super SKU" B0/B1
-#include "M0130673322.h" // M0130673: Baytrail I B2 / B3
-#include "M0130679901.h" // M0130679: Baytrail I D0
+ #include "M0230672228.h" // M0230672: Baytrail "Super SKU" B0/B1
+ #include "M0130673322.h" // M0130673: Baytrail I B2 / B3
+ #include "M0130679901.h" // M0130679: Baytrail I D0
+#elif IS_ENABLED(CONFIG_SOC_INTEL_FSP_BAYTRAIL_MD)
+ /* Region size is 0x10000 - update in microcode_size.h if it gets larger. */
+ #include "M0C30678829.h" // M0C30678: Baytrail M D Stepping
+#endif
/* Dummy terminator */
0x0, 0x0, 0x0, 0x0,
diff --git a/src/soc/intel/fsp_baytrail/microcode/microcode_size.h b/src/soc/intel/fsp_baytrail/microcode/microcode_size.h
index ec55314..213fc17 100644
--- a/src/soc/intel/fsp_baytrail/microcode/microcode_size.h
+++ b/src/soc/intel/fsp_baytrail/microcode/microcode_size.h
@@ -1,2 +1,6 @@
/* Maximum size of the area that the FSP will search for the correct microcode */
-#define MICROCODE_REGION_LENGTH 0x30000
+#if IS_ENABLED(CONFIG_SOC_INTEL_FSP_BAYTRAIL_I)
+ #define MICROCODE_REGION_LENGTH 0x30000
+#elif IS_ENABLED(CONFIG_SOC_INTEL_FSP_BAYTRAIL_MD)
+ #define MICROCODE_REGION_LENGTH 0x10000
+#endif
the following patch was just integrated into master:
commit f73179d4bea45d366c9407baf2b614ca5b44a12b
Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com>
Date: Tue Feb 10 00:37:21 2015 -0600
mainboards/asus/kfsn4-dre: Run BSP FIDVID before AP FIDVID
This resolves an issue on Shanghai dual CPU configurations where
the APs on node 0 would not start. Single CPU configurations are
unaffected by this issue.
TEST: Booted KFSN4-DRE with dual Opteron 8389 CPUs and verified
proper BSP/AP start and microcode patch levels.
Change-Id: I0f5d4e0e356c6bd64e324b4399ef43b400ecab0c
Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com>
Reviewed-on: http://review.coreboot.org/8397
Tested-by: build bot (Jenkins)
Reviewed-by: Paul Menzel <paulepanter(a)users.sourceforge.net>
Reviewed-by: Kyösti Mälkki <kyosti.malkki(a)gmail.com>
Reviewed-by: Alexandru Gagniuc <mr.nuke.me(a)gmail.com>
See http://review.coreboot.org/8397 for details.
-gerrit
Timothy Pearson (tpearson(a)raptorengineeringinc.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/8422
-gerrit
commit 2c3240ae82a56b0a63b9f8c006eaec46392320e6
Author: Timothy Pearson <tpearson(a)raptorengineeringinc.com>
Date: Tue Feb 10 22:21:39 2015 -0600
x86/boot: Generate valid ACPI processor objects
The existing code generated invalid ACPI processor objects
if the core number was greater than 9. The first invalid
object instance was autocorrected by Linux, but subsequent
instances conflicted with each other, leading to a failure
to boot if more than 10 CPU cores were installed.
The modified code will function with up to 99 cores.
Change-Id: I62dc0eb61ae2e2b7f7dcf30e9c7de09cd901a81c
Signed-off-by: Timothy Pearson <tpearson(a)raptorengineeringinc.com>
---
src/arch/x86/boot/acpigen.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/arch/x86/boot/acpigen.c b/src/arch/x86/boot/acpigen.c
index 8e7ce46..76fe2d6 100644
--- a/src/arch/x86/boot/acpigen.c
+++ b/src/arch/x86/boot/acpigen.c
@@ -293,7 +293,7 @@ int acpigen_write_processor(u8 cpuindex, u32 pblock_addr, u8 pblock_len)
len = acpigen_write_len_f();
snprintf(pscope, sizeof (pscope),
- "\\_PR.CPU%x", (unsigned int) cpuindex);
+ "\\_PR.CP%02d", (unsigned int) cpuindex);
len += acpigen_emit_namestring(pscope);
acpigen_emit_byte(cpuindex);
acpigen_emit_byte(pblock_addr & 0xff);