[coreboot-gerrit] Patch set updated for coreboot: soc/intel/quark: Add I2C support

Leroy P Leahy (leroy.p.leahy@intel.com) gerrit at coreboot.org
Mon May 16 17:24:24 CEST 2016


Leroy P Leahy (leroy.p.leahy at intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14828

-gerrit

commit 017521db864ff048b42c28ea9d409cee816c15ae
Author: Lee Leahy <leroy.p.leahy at intel.com>
Date:   Sun May 15 15:12:56 2016 -0700

    soc/intel/quark: Add I2C support
    
    Add the I2C driver.
    
    TEST=Build and run on Galileo Gen2
    
    Change-Id: I53fdac93667a8ffb2c2c8f394334de2dece63d66
    Signed-off-by: Lee Leahy <leroy.p.leahy at intel.com>
---
 src/soc/intel/quark/Makefile.inc             |   1 +
 src/soc/intel/quark/gpio_i2c.c               | 185 +++++++++++++++++++++++++++
 src/soc/intel/quark/include/soc/i2c.h        | 132 +++++++++++++++++++
 src/soc/intel/quark/include/soc/ramstage.h   |   2 +
 src/soc/intel/quark/include/soc/reg_access.h |   1 +
 src/soc/intel/quark/reg_access.c             |  65 ++++++----
 6 files changed, 360 insertions(+), 26 deletions(-)

diff --git a/src/soc/intel/quark/Makefile.inc b/src/soc/intel/quark/Makefile.inc
index 3a865b8..b63e613 100644
--- a/src/soc/intel/quark/Makefile.inc
+++ b/src/soc/intel/quark/Makefile.inc
@@ -25,6 +25,7 @@ romstage-$(CONFIG_ENABLE_BUILTIN_HSUART1) += uart_common.c
 
 ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c
 ramstage-y += chip.c
+ramstage-y += gpio_i2c.c
 ramstage-y += memmap.c
 ramstage-y += northcluster.c
 ramstage-y += pmc.c
diff --git a/src/soc/intel/quark/gpio_i2c.c b/src/soc/intel/quark/gpio_i2c.c
new file mode 100644
index 0000000..edcac56
--- /dev/null
+++ b/src/soc/intel/quark/gpio_i2c.c
@@ -0,0 +1,185 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2016 Intel Corporation.
+ *
+ * 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.
+ */
+
+#include <console/console.h>
+#include <delay.h>
+#include <device/device.h>
+#include <device/i2c.h>
+#include <device/pci.h>
+#include <device/pci_ids.h>
+#include <soc/i2c.h>
+#include <soc/ramstage.h>
+#include <soc/reg_access.h>
+
+static void i2c_disable(I2C_REGS *regs)
+{
+	uint32_t status;
+	uint32_t timeout;
+
+	/* Disable I2C controller */
+	regs->ic_enable = 0;
+
+	/* Wait for the enable bit to clear */
+	timeout = 1 * 1000 * 1000;
+	status = regs->ic_enable_status;
+	while (status & IC_ENABLE_CONTROLLER) {
+		udelay(1);
+		if (--timeout == 0)
+			die("ERROR - I2C failed to disable!\n");
+		status = regs->ic_enable_status;
+	}
+
+	/* Clear any pending interrupts */
+	status = regs->ic_clr_intr;
+}
+
+int platform_i2c_transfer(unsigned bus, struct i2c_seg *segments, int count)
+{
+	uint8_t *buffer;
+	int bytes_transferred;
+	uint8_t chip;
+	uint32_t cmd;
+	int length;
+	int read_length;
+	I2C_REGS *regs;
+	uint32_t status;
+	uint32_t timeout;
+
+	regs = get_i2c_address();
+
+	/* Disable the I2C controller to get access to the registers */
+	i2c_disable(regs);
+
+	/* Set the slave address */
+	ASSERT (count > 0);
+	ASSERT (segments != NULL);
+	ASSERT (segments->read == 0);
+
+	/* Clear the start and stop detection */
+	status = regs->ic_clr_start_det;
+	status = regs->ic_clr_stop_det;
+
+	/* Set addressing mode to 7-bit and fast mode */
+	cmd = regs->ic_con;
+	cmd &= ~(IC_CON_10B | IC_CON_SPEED);
+	cmd |= IC_CON_RESTART_EN | IC_CON_7B | IC_CON_SPEED_100_KHz
+		| IC_CON_MASTER_MODE;
+	regs->ic_con = cmd;
+
+	/* Set the target chip address */
+	chip = segments->chip;
+	regs->ic_tar = chip;
+
+	/* Enable the I2C controller */
+	regs->ic_enable = IC_ENABLE_CONTROLLER;
+
+	/* Clear the interrupts */
+	status = regs->ic_clr_rx_under;
+	status = regs->ic_clr_rx_over;
+	status = regs->ic_clr_tx_over;
+	status = regs->ic_clr_tx_abrt;
+
+	/* Process each of the segments */
+	bytes_transferred = 0;
+	read_length = 0;
+	buffer = NULL;
+	while (count-- > 0) {
+		buffer = segments->buf;
+		length = segments->len;
+		ASSERT (buffer != NULL);
+		ASSERT (length >= 1);
+		ASSERT (segments->chip = chip);
+
+		if (segments->read) {
+			/* Place read commands into the FIFO */
+			read_length = length;
+			while (length > 0) {
+				/* Send stop bit after last byte */
+				cmd = IC_DATA_CMD_READ;
+				if ((count == 0) && (length == 1))
+					cmd |= IC_DATA_CMD_STOP;
+
+				/* Place read command in transmit FIFO */
+				regs->ic_data_cmd = cmd;
+				length--;
+			}
+		} else {
+			/* Write the data into the FIFO */
+			while (length > 0) {
+				/* End of the transaction? */
+				cmd = IC_DATA_CMD_WRITE | *buffer++;
+				if ((count == 0) && (length == 1))
+					cmd |= IC_DATA_CMD_STOP;
+
+				/* Place a data byte into the FIFO */
+				regs->ic_data_cmd = cmd;
+				length--;
+				bytes_transferred++;
+			}
+		}
+		segments++;
+	}
+
+	/* Wait for the end of the transaction */
+	timeout = 1 * 1000 * 1000;
+	do {
+		status = regs->ic_raw_intr_stat;
+		if (status & IC_INTR_STOP_DET)
+			break;
+		if (status & (IC_INTR_RX_OVER | IC_INTR_RX_UNDER
+				| IC_INTR_TX_ABRT | IC_INTR_TX_OVER))
+			goto transfer_fails;
+		if (timeout-- == 0) {
+			printk (BIOS_ERR,
+				"ERROR - I2C stop bit not received!\n");
+			goto transfer_fails;
+		}
+		udelay(1);
+	} while(1);
+
+	/* Finish reading the data bytes */
+	while (read_length > 0) {
+		status = regs->ic_status;
+		*buffer++ = (UINT8)regs->ic_data_cmd;
+		read_length--;
+		bytes_transferred++;
+		status = regs->ic_status;
+	}
+
+	return bytes_transferred;
+
+transfer_fails:
+	i2c_disable(regs);
+	return -1;
+}
+
+__attribute__((weak)) void mainboard_gpio_i2c_init(device_t dev)
+{
+	/* Initialize any of the GPIOs or I2C devices */
+printk(BIOS_ERR, "WEAK; mainboard_gpio_i2c_init\n");
+}
+
+static struct device_operations device_ops = {
+	.read_resources		= pci_dev_read_resources,
+	.set_resources		= pci_dev_set_resources,
+	.enable_resources	= pci_dev_enable_resources,
+	.init			= mainboard_gpio_i2c_init,
+};
+
+static const struct pci_driver gfx_driver __pci_driver = {
+	.ops	= &device_ops,
+	.vendor	= PCI_VENDOR_ID_INTEL,
+	.device	= I2CGPIO_DEVID,
+};
diff --git a/src/soc/intel/quark/include/soc/i2c.h b/src/soc/intel/quark/include/soc/i2c.h
new file mode 100644
index 0000000..9bbfcc8
--- /dev/null
+++ b/src/soc/intel/quark/include/soc/i2c.h
@@ -0,0 +1,132 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2016 Intel Corporation.
+ *
+ * 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.
+ */
+
+#ifndef _QUARK_I2C_H_
+#define _QUARK_I2C_H_
+
+typedef volatile struct _I2C_REGS {
+	volatile uint32_t ic_con;		/* 00: Control Register */
+	volatile uint32_t ic_tar;		/* 04: Master Target Address */
+	uint32_t reserved_08[2];
+	volatile uint32_t ic_data_cmd;		/* 10: Data Buffer & Command */
+	uint32_t ic_ss_scl_hcnt;   /* 14: Standard Speed Clock SCL High Count */
+	uint32_t ic_ss_scl_lcnt;   /* 18: Standard Speed Clock SCL Low Count */
+	uint32_t ic_fs_scl_hcnt;   /* 1c: Fast Speed Clock SCL High Count */
+	uint32_t ic_fs_scl_lcnt;   /* 20: Fast Speed Clock SCL Low Count */
+	uint32_t reserved_24[2];
+	volatile uint32_t ic_intr_stat;		/* 2c: Interrupt Status */
+	uint32_t ic_intr_mask;     /* 30: Interrupt Mask */
+	uint32_t ic_raw_intr_stat; /* 34: Raw Interrupt Status */
+	uint32_t ic_rx_tl;         /* 38: Receive FIFO Threshold Level */
+	uint32_t ic_tx_tl;         /* 3c: Transmit FIFO Threshold Level */
+	uint32_t ic_clr_intr;      /* 40: Clear Combined/Individual Interrupt */
+	uint32_t ic_clr_rx_under;  /* 44: Clear RX_UNDER Interrupt */
+	uint32_t ic_clr_rx_over;   /* 48: Clear RX_OVER Interrupt */
+	uint32_t ic_clr_tx_over;   /* 4c: Clear TX_OVER Interrupt */
+	uint32_t ic_clr_rd_req;    /* 50: Clear RD_REQ Interrupt */
+	uint32_t ic_clr_tx_abrt;   /* 54: Clear TX_ABRT Interrupt */
+	uint32_t reserved_58;
+	uint32_t ic_clr_activity;  /* 5c: Clear ACTIVITY Interrupt */
+	uint32_t ic_clr_stop_det;  /* 60: Clear STOP_DET Interrupt */
+	uint32_t ic_clr_start_det; /* 64: Clear START_DET Interrupt */
+	uint32_t reserved_68;
+	volatile uint32_t ic_enable;		/* 6c: Enable */
+	volatile uint32_t ic_status;		/* 70: Status */
+	uint32_t ic_txflr;			/* 74: Transmit FIFO Level */
+	uint32_t ic_rxflr;			/* 78: Receive FIFO Level */
+	uint32_t ic_sda_hold;			/* 7c: SDA Hold */
+	volatile uint32_t ic_tx_abrt_source;	/* 80: Transmit Abort Source */
+	uint32_t reserved_84[6];
+	volatile uint32_t ic_enable_status;	/* 9c: Enable Status */
+	uint32_t ic_fs_spklen;     /* a0: SS and FS Spike Suppression Limit */
+} I2C_REGS;
+
+#define IC_CON			offsetof(I2C_REGS, ic_con)
+#define IC_TAR			offsetof(I2C_REGS, ic_tar)
+#define IC_DATA_CMD		offsetof(I2C_REGS, ic_data_cmd)
+#define IC_SS_SCL_HCNT		offsetof(I2C_REGS, ic_ss_scl_hcnt)
+#define IC_SS_SCL_LCNT		offsetof(I2C_REGS, ic_ss_scl_lcnt)
+#define IC_FS_SCL_HCNT		offsetof(I2C_REGS, ic_fs_scl_hcnt)
+#define IC_FS_SCL_LCNT		offsetof(I2C_REGS, ic_fs_scl_lcnt)
+#define IC_INTR_STAT		offsetof(I2C_REGS, ic_intr_stat)
+#define IC_INTR_MASK		offsetof(I2C_REGS, ic_intr_mask)
+#define IC_RAW_INTR_STAT	offsetof(I2C_REGS, ic_raw_intr_stat)
+#define IC_RX_TL		offsetof(I2C_REGS, ic_rx_tl)
+#define IC_TX_TL		offsetof(I2C_REGS, ic_tx_tl)
+#define IC_CLR_INTR		offsetof(I2C_REGS, ic_clr_intr)
+#define IC_CLR_RX_UNDER		offsetof(I2C_REGS, ic_clr_rx_under)
+#define IC_CLR_RX_OVER		offsetof(I2C_REGS, ic_clr_rx_over)
+#define IC_CLR_TX_OVER		offsetof(I2C_REGS, ic_clr_tx_over)
+#define IC_CLR_RD_REQ		offsetof(I2C_REGS, ic_clr_rd_req)
+#define IC_CLR_TX_ABRT		offsetof(I2C_REGS, ic_clr_tx_abrt)
+#define IC_CLR_ACTIVITY		offsetof(I2C_REGS, ic_clr_activity)
+#define IC_CLR_STOP_DET		offsetof(I2C_REGS, ic_clr_stop_det)
+#define IC_CLR_START_DET	offsetof(I2C_REGS, ic_clr_start_det)
+#define IC_ENABLE		offsetof(I2C_REGS, ic_enable)
+#define IC_STATUS		offsetof(I2C_REGS, ic_status)
+#define IC_TXFLR		offsetof(I2C_REGS, ic_txflr)
+#define IC_RXFLR		offsetof(I2C_REGS, ic_rxflr)
+#define IC_SDA_HOLD		offsetof(I2C_REGS, ic_sda_hold)
+#define IC_TX_ABRT_SOURCE	offsetof(I2C_REGS, ic_tx_abrt_source)
+#define IC_ENABLE_STATUS	offsetof(I2C_REGS, ic_enable_status)
+#define IC_FS_SPKLEN		offsetof(I2C_REGS, ic_fs_spklen)
+
+/* 0x00: ic_con */
+#define IC_CON_RESTART_EN	0x00000020 /* Enable start/restart */
+#define IC_CON_10B		0x00000010 /* 10-bit addressing */
+#define IC_CON_7B               0          /* 7-bit addressing */
+#define IC_CON_SPEED		0x00000006 /* I2C bus speed */
+#define IC_CON_SPEED_400_KHz	0x00000004 /* Fast mode */
+#define IC_CON_SPEED_100_KHz	0x00000002 /* Standard mode */
+#define IC_CON_MASTER_MODE	0x00000001 /* Enable master mode */
+
+/* 0x10: ic_data_cmd */
+#define IC_DATA_CMD_RESTART	0x00000400 /* Send restart before byte */
+#define IC_DATA_CMD_STOP	0x00000200 /* Send stop after byte */
+#define IC_DATA_CMD_CMD		0x00000100 /* Type of transaction */
+#define IC_DATA_CMD_READ	IC_DATA_CMD_CMD
+#define IC_DATA_CMD_WRITE	0
+#define IC_DATA_CMD_DATA	0x000000ff /* Data byte */
+
+/* 0x2c: ic_intr_stat
+ * 0x30: ic_intr_mask
+ * 0x34: ic_raw_intr_stat
+ */
+#define IC_INTR_START_DET	0x00000400 /* Start bit detected */
+#define IC_INTR_STOP_DET	0x00000200 /* Stop bit detected */
+#define IC_INTR_ACTIVITY	0x00000100 /* Activity detected */
+#define IC_INTR_TX_ABRT		0x00000040 /* Transmit abort */
+#define IC_INTR_RD_REQ		0x00000020 /* Read request */
+#define IC_INTR_TX_EMPTY	0x00000010 /* TX FIFO is empty */
+#define IC_INTR_TX_OVER		0x00000008 /* TX FIFO overflow */
+#define IC_INTR_RX_FULL		0x00000004 /* Receive FIFO is full */
+#define IC_INTR_RX_OVER		0x00000002 /* Receive FIFO overflow */
+#define IC_INTR_RX_UNDER	0x00000001 /* Receive FIFO underflow */
+
+/* 0x6c: ic_enable
+ * 0x9c: ic_enable_status
+ */
+#define IC_ENABLE_CONTROLLER	0x00000001 /* Enable the I2C controller */
+
+/* 0x70: ic_status */
+#define IC_STATUS_MST_ACTIVITY	0x00000020 /* Master FSM activity */
+#define IC_STATUS_RFF		0x00000010 /* Receive FIFO completely full */
+#define IC_STATUS_RFNE		0x00000008 /* Receive FIFO not empty */
+#define IC_STATUS_TFE		0x00000004 /* Transmit FIFO completely empty */
+#define IC_STATUS_TFNF		0x00000002 /* Transmit FIFO not full */
+#define IC_STATUS_ACTIVITY	0x00000001 /* Activity */
+
+
+#endif /* _QUARK_I2C_H_ */
diff --git a/src/soc/intel/quark/include/soc/ramstage.h b/src/soc/intel/quark/include/soc/ramstage.h
index 19b27a8..80e2f00 100644
--- a/src/soc/intel/quark/include/soc/ramstage.h
+++ b/src/soc/intel/quark/include/soc/ramstage.h
@@ -22,4 +22,6 @@
 #include <fsp/ramstage.h>
 #include <soc/QuarkNcSocId.h>
 
+void mainboard_gpio_i2c_init(device_t dev);
+
 #endif /* _SOC_RAMSTAGE_H_ */
diff --git a/src/soc/intel/quark/include/soc/reg_access.h b/src/soc/intel/quark/include/soc/reg_access.h
index c1b0df0..66ab7b8 100644
--- a/src/soc/intel/quark/include/soc/reg_access.h
+++ b/src/soc/intel/quark/include/soc/reg_access.h
@@ -150,6 +150,7 @@ enum {
 #define REG_USB_XOR(reg_, value_) \
 	REG_USB_RXW(reg_, 0xffffffff, value_)
 
+void *get_i2c_address(void);
 void mainboard_gpio_init(void);
 void mcr_write(uint8_t opcode, uint8_t port, uint32_t reg_address);
 uint32_t mdr_read(void);
diff --git a/src/soc/intel/quark/reg_access.c b/src/soc/intel/quark/reg_access.c
index 48d5521..4734135 100644
--- a/src/soc/intel/quark/reg_access.c
+++ b/src/soc/intel/quark/reg_access.c
@@ -20,6 +20,45 @@
 #include <soc/pci_devs.h>
 #include <soc/reg_access.h>
 
+static uint32_t *get_gpio_address(uint32_t reg_address)
+{
+	uint32_t gpio_base_address;
+
+	/* Get the GPIO base address */
+	gpio_base_address = pci_read_config32(I2CGPIO_BDF, PCI_BASE_ADDRESS_1);
+	gpio_base_address &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
+	ASSERT (gpio_base_address != 0x00000000);
+
+	/* Return the GPIO register address */
+	return (uint32_t *)(gpio_base_address + reg_address);
+}
+
+void *get_i2c_address(void)
+{
+	uint32_t gpio_base_address;
+
+	/* Get the GPIO base address */
+	gpio_base_address = pci_read_config32(I2CGPIO_BDF, PCI_BASE_ADDRESS_0);
+	gpio_base_address &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
+	ASSERT (gpio_base_address != 0x00000000);
+
+	/* Return the GPIO register address */
+	return (void *)gpio_base_address;
+}
+
+static uint16_t get_legacy_gpio_address(uint32_t reg_address)
+{
+	uint32_t gpio_base_address;
+
+	/* Get the GPIO base address */
+	gpio_base_address = pci_read_config32(LPC_BDF, R_QNC_LPC_GBA_BASE);
+	ASSERT (gpio_base_address >= 0x80000000);
+	gpio_base_address &= B_QNC_LPC_GPA_BASE_MASK;
+
+	/* Return the GPIO register address */
+	return (uint16_t)(gpio_base_address + reg_address);
+}
+
 void mcr_write(uint8_t opcode, uint8_t port, uint32_t reg_address)
 {
 	pci_write_config32(MC_BDF, QNC_ACCESS_PORT_MCR,
@@ -45,19 +84,6 @@ void mea_write(uint32_t reg_address)
 		& QNC_MEA_MASK);
 }
 
-static uint32_t *get_gpio_address(uint32_t reg_address)
-{
-	uint32_t gpio_base_address;
-
-	/* Get the GPIO base address */
-	gpio_base_address = pci_read_config32(I2CGPIO_BDF, PCI_BASE_ADDRESS_1);
-	gpio_base_address &= ~PCI_BASE_ADDRESS_MEM_ATTR_MASK;
-	ASSERT (gpio_base_address != 0x00000000);
-
-	/* Return the GPIO register address */
-	return (uint32_t *)(gpio_base_address + reg_address);
-}
-
 static uint32_t reg_gpio_read(uint32_t reg_address)
 {
 	/* Read the GPIO register */
@@ -70,19 +96,6 @@ static void reg_gpio_write(uint32_t reg_address, uint32_t value)
 	*get_gpio_address(reg_address) = value;
 }
 
-static uint16_t get_legacy_gpio_address(uint32_t reg_address)
-{
-	uint32_t gpio_base_address;
-
-	/* Get the GPIO base address */
-	gpio_base_address = pci_read_config32(LPC_BDF, R_QNC_LPC_GBA_BASE);
-	ASSERT (gpio_base_address >= 0x80000000);
-	gpio_base_address &= B_QNC_LPC_GPA_BASE_MASK;
-
-	/* Return the GPIO register address */
-	return (uint16_t)(gpio_base_address + reg_address);
-}
-
 uint32_t reg_legacy_gpio_read(uint32_t reg_address)
 {
 	/* Read the legacy GPIO register */



More information about the coreboot-gerrit mailing list