Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 6 Mar 2018 23:39:43 +0000 (UTC)
From:      Oleksandr Tymoshenko <gonzo@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r330558 - head/sys/dev/ichiic
Message-ID:  <201803062339.w26NdhEl098447@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: gonzo
Date: Tue Mar  6 23:39:43 2018
New Revision: 330558
URL: https://svnweb.freebsd.org/changeset/base/330558

Log:
  [ig4] Add support for i2c controllers on Skylake and Kaby Lake
  
  This was tested by Ben on  HP Chromebook 13 G1 with a
  Skylake CPU and Sunrise Point-LP I2C controller and by me on
  Minnowboard Turbot with Atom E3826 (formerly Bay Trail)
  
  Submitted by:	Ben Pye <ben@curlybracket.co.uk>
  Reviewed by:	gonzo
  Obtained from:	DragonflyBSD (a4549657 by Imre Vadász)
  MFC after:	2 weeks
  Differential Revision:	https://reviews.freebsd.org/D13654

Modified:
  head/sys/dev/ichiic/ig4_acpi.c
  head/sys/dev/ichiic/ig4_iic.c
  head/sys/dev/ichiic/ig4_pci.c
  head/sys/dev/ichiic/ig4_reg.h
  head/sys/dev/ichiic/ig4_var.h

Modified: head/sys/dev/ichiic/ig4_acpi.c
==============================================================================
--- head/sys/dev/ichiic/ig4_acpi.c	Tue Mar  6 23:28:12 2018	(r330557)
+++ head/sys/dev/ichiic/ig4_acpi.c	Tue Mar  6 23:39:43 2018	(r330558)
@@ -85,6 +85,8 @@ ig4iic_acpi_attach(device_t dev)
 	sc = device_get_softc(dev);
 
 	sc->dev = dev;
+	/* All the HIDs matched are Atom SOCs. */
+	sc->version = IG4_ATOM;
 	sc->regs_rid = 0;
 	sc->regs_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
 					  &sc->regs_rid, RF_ACTIVE);

Modified: head/sys/dev/ichiic/ig4_iic.c
==============================================================================
--- head/sys/dev/ichiic/ig4_iic.c	Tue Mar  6 23:28:12 2018	(r330557)
+++ head/sys/dev/ichiic/ig4_iic.c	Tue Mar  6 23:39:43 2018	(r330558)
@@ -525,22 +525,38 @@ ig4iic_attach(ig4iic_softc_t *sc)
 	mtx_init(&sc->io_lock, "IG4 I/O lock", NULL, MTX_DEF);
 	sx_init(&sc->call_lock, "IG4 call lock");
 
-	v = reg_read(sc, IG4_REG_COMP_TYPE);
-	v = reg_read(sc, IG4_REG_COMP_PARAM1);
-	v = reg_read(sc, IG4_REG_GENERAL);
-	if ((v & IG4_GENERAL_SWMODE) == 0) {
-		v |= IG4_GENERAL_SWMODE;
-		reg_write(sc, IG4_REG_GENERAL, v);
+	if (sc->version == IG4_ATOM)
+		v = reg_read(sc, IG4_REG_COMP_TYPE);
+	
+	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
+		v = reg_read(sc, IG4_REG_COMP_PARAM1);
 		v = reg_read(sc, IG4_REG_GENERAL);
+		/*
+		 * The content of IG4_REG_GENERAL is different for each
+		 * controller version.
+		 */
+		if (sc->version == IG4_HASWELL &&
+		    (v & IG4_GENERAL_SWMODE) == 0) {
+			v |= IG4_GENERAL_SWMODE;
+			reg_write(sc, IG4_REG_GENERAL, v);
+			v = reg_read(sc, IG4_REG_GENERAL);
+		}
 	}
 
-	v = reg_read(sc, IG4_REG_SW_LTR_VALUE);
-	v = reg_read(sc, IG4_REG_AUTO_LTR_VALUE);
+	if (sc->version == IG4_HASWELL) {
+		v = reg_read(sc, IG4_REG_SW_LTR_VALUE);
+		v = reg_read(sc, IG4_REG_AUTO_LTR_VALUE);
+	} else if (sc->version == IG4_SKYLAKE) {
+		v = reg_read(sc, IG4_REG_ACTIVE_LTR_VALUE);
+		v = reg_read(sc, IG4_REG_IDLE_LTR_VALUE);
+	}
 
-	v = reg_read(sc, IG4_REG_COMP_VER);
-	if (v != IG4_COMP_VER) {
-		error = ENXIO;
-		goto done;
+	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
+		v = reg_read(sc, IG4_REG_COMP_VER);
+		if (v != IG4_COMP_VER) {
+			error = ENXIO;
+			goto done;
+		}
 	}
 	v = reg_read(sc, IG4_REG_SS_SCL_HCNT);
 	v = reg_read(sc, IG4_REG_SS_SCL_LCNT);
@@ -591,8 +607,13 @@ ig4iic_attach(ig4iic_softc_t *sc)
 	/*
 	 * Don't do this, it blows up the PCI config
 	 */
-	reg_write(sc, IG4_REG_RESETS, IG4_RESETS_ASSERT);
-	reg_write(sc, IG4_REG_RESETS, IG4_RESETS_DEASSERT);
+	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
+		reg_write(sc, IG4_REG_RESETS_HSW, IG4_RESETS_ASSERT_HSW);
+		reg_write(sc, IG4_REG_RESETS_HSW, IG4_RESETS_DEASSERT_HSW);
+	} else if (sc->version = IG4_SKYLAKE) {
+		reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_ASSERT_SKL);
+		reg_write(sc, IG4_REG_RESETS_SKL, IG4_RESETS_DEASSERT_SKL);
+	}
 #endif
 
 	mtx_lock(&sc->io_lock);
@@ -727,14 +748,27 @@ ig4iic_dump(ig4iic_softc_t *sc)
 	REGDUMP(sc, IG4_REG_DMA_RDLR);
 	REGDUMP(sc, IG4_REG_SDA_SETUP);
 	REGDUMP(sc, IG4_REG_ENABLE_STATUS);
-	REGDUMP(sc, IG4_REG_COMP_PARAM1);
-	REGDUMP(sc, IG4_REG_COMP_VER);
-	REGDUMP(sc, IG4_REG_COMP_TYPE);
-	REGDUMP(sc, IG4_REG_CLK_PARMS);
-	REGDUMP(sc, IG4_REG_RESETS);
-	REGDUMP(sc, IG4_REG_GENERAL);
-	REGDUMP(sc, IG4_REG_SW_LTR_VALUE);
-	REGDUMP(sc, IG4_REG_AUTO_LTR_VALUE);
+	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
+		REGDUMP(sc, IG4_REG_COMP_PARAM1);
+		REGDUMP(sc, IG4_REG_COMP_VER);
+	}
+	if (sc->version == IG4_ATOM) {
+		REGDUMP(sc, IG4_REG_COMP_TYPE);
+		REGDUMP(sc, IG4_REG_CLK_PARMS);
+	}
+	if (sc->version == IG4_HASWELL || sc->version == IG4_ATOM) {
+		REGDUMP(sc, IG4_REG_RESETS_HSW);
+		REGDUMP(sc, IG4_REG_GENERAL);
+	} else if (sc->version == IG4_SKYLAKE) {
+		REGDUMP(sc, IG4_REG_RESETS_SKL);
+	}
+	if (sc->version == IG4_HASWELL) {
+		REGDUMP(sc, IG4_REG_SW_LTR_VALUE);
+		REGDUMP(sc, IG4_REG_AUTO_LTR_VALUE);
+	} else if (sc->version == IG4_SKYLAKE) {
+		REGDUMP(sc, IG4_REG_ACTIVE_LTR_VALUE);
+		REGDUMP(sc, IG4_REG_IDLE_LTR_VALUE);
+	}
 }
 #undef REGDUMP
 

Modified: head/sys/dev/ichiic/ig4_pci.c
==============================================================================
--- head/sys/dev/ichiic/ig4_pci.c	Tue Mar  6 23:28:12 2018	(r330557)
+++ head/sys/dev/ichiic/ig4_pci.c	Tue Mar  6 23:39:43 2018	(r330558)
@@ -74,34 +74,74 @@ static int ig4iic_pci_detach(device_t dev);
 #define PCI_CHIP_BRASWELL_I2C_5 	0x22c58086
 #define PCI_CHIP_BRASWELL_I2C_6 	0x22c68086
 #define PCI_CHIP_BRASWELL_I2C_7 	0x22c78086
+#define PCI_CHIP_SKYLAKE_I2C_0		0x9d608086
+#define PCI_CHIP_SKYLAKE_I2C_1		0x9d618086
+#define PCI_CHIP_SKYLAKE_I2C_2		0x9d628086
+#define PCI_CHIP_SKYLAKE_I2C_3		0x9d638086
+#define PCI_CHIP_SKYLAKE_I2C_4		0x9d648086
+#define PCI_CHIP_SKYLAKE_I2C_5		0x9d658086
 
 static int
 ig4iic_pci_probe(device_t dev)
 {
+	ig4iic_softc_t *sc = device_get_softc(dev);
+
 	switch(pci_get_devid(dev)) {
 	case PCI_CHIP_LYNXPT_LP_I2C_1:
 		device_set_desc(dev, "Intel Lynx Point-LP I2C Controller-1");
+		sc->version = IG4_HASWELL;
 		break;
 	case PCI_CHIP_LYNXPT_LP_I2C_2:
 		device_set_desc(dev, "Intel Lynx Point-LP I2C Controller-2");
+		sc->version = IG4_HASWELL;
 		break;
 	case PCI_CHIP_BRASWELL_I2C_1:
 		device_set_desc(dev, "Intel Braswell Serial I/O I2C Port 1");
+		sc->version = IG4_ATOM;
 		break;
 	case PCI_CHIP_BRASWELL_I2C_2:
 		device_set_desc(dev, "Intel Braswell Serial I/O I2C Port 2");
+		sc->version = IG4_ATOM;
 		break;
 	case PCI_CHIP_BRASWELL_I2C_3:
 		device_set_desc(dev, "Intel Braswell Serial I/O I2C Port 3");
+		sc->version = IG4_ATOM;
 		break;
 	case PCI_CHIP_BRASWELL_I2C_5:
 		device_set_desc(dev, "Intel Braswell Serial I/O I2C Port 5");
+		sc->version = IG4_ATOM;
 		break;
 	case PCI_CHIP_BRASWELL_I2C_6:
 		device_set_desc(dev, "Intel Braswell Serial I/O I2C Port 6");
+		sc->version = IG4_ATOM;
 		break;
 	case PCI_CHIP_BRASWELL_I2C_7:
 		device_set_desc(dev, "Intel Braswell Serial I/O I2C Port 7");
+		sc->version = IG4_ATOM;
+		break;
+	case PCI_CHIP_SKYLAKE_I2C_0:
+		device_set_desc(dev, "Intel Sunrise Point-LP I2C Controller-0");
+		sc->version = IG4_SKYLAKE;
+		break;
+	case PCI_CHIP_SKYLAKE_I2C_1:
+		device_set_desc(dev, "Intel Sunrise Point-LP I2C Controller-1");
+		sc->version = IG4_SKYLAKE;
+		break;
+	case PCI_CHIP_SKYLAKE_I2C_2:
+		device_set_desc(dev, "Intel Sunrise Point-LP I2C Controller-2");
+		sc->version = IG4_SKYLAKE;
+		break;
+	case PCI_CHIP_SKYLAKE_I2C_3:
+		device_set_desc(dev, "Intel Sunrise Point-LP I2C Controller-3");
+		sc->version = IG4_SKYLAKE;
+		break;
+	case PCI_CHIP_SKYLAKE_I2C_4:
+		device_set_desc(dev, "Intel Sunrise Point-LP I2C Controller-4");
+		sc->version = IG4_SKYLAKE;
+		break;
+	case PCI_CHIP_SKYLAKE_I2C_5:
+		device_set_desc(dev, "Intel Sunrise Point-LP I2C Controller-5");
+		sc->version = IG4_SKYLAKE;
 		break;
 	default:
 		return (ENXIO);

Modified: head/sys/dev/ichiic/ig4_reg.h
==============================================================================
--- head/sys/dev/ichiic/ig4_reg.h	Tue Mar  6 23:28:12 2018	(r330557)
+++ head/sys/dev/ichiic/ig4_reg.h	Tue Mar  6 23:39:43 2018	(r330558)
@@ -109,12 +109,21 @@
 #define IG4_REG_DMA_RDLR	0x0090	/* RW	DMA Receive Data Level */
 #define IG4_REG_SDA_SETUP	0x0094	/* RW	SDA Setup */
 #define IG4_REG_ENABLE_STATUS	0x009C	/* RO	Enable Status */
+/* Available at least on Atom SoCs and Haswell mobile. */
 #define IG4_REG_COMP_PARAM1	0x00F4	/* RO	Component Parameter */
 #define IG4_REG_COMP_VER	0x00F8	/* RO	Component Version */
+/* Available at least on Atom SoCs */
 #define IG4_REG_COMP_TYPE	0x00FC	/* RO	Probe width/endian? (linux) */
+/* Available on Skylake-U/Y and Kaby Lake-U/Y */
+#define IG4_REG_RESETS_SKL	0x0204	/* RW	Reset Register */
+#define IG4_REG_ACTIVE_LTR_VALUE 0x0210	/* RW	Active LTR Value */
+#define IG4_REG_IDLE_LTR_VALUE	0x0214	/* RW	Idle LTR Value */
+/* Available at least on Atom SoCs */
 #define IG4_REG_CLK_PARMS	0x0800	/* RW	Clock Parameters */
-#define IG4_REG_RESETS		0x0804	/* RW	Reset Register */
+/* Available at least on Atom SoCs and Haswell mobile */
+#define IG4_REG_RESETS_HSW	0x0804	/* RW	Reset Register */
 #define IG4_REG_GENERAL		0x0808	/* RW	General Register */
+/* These LTR config registers are at least available on Haswell mobile. */
 #define IG4_REG_SW_LTR_VALUE	0x0810	/* RW	SW LTR Value */
 #define IG4_REG_AUTO_LTR_VALUE	0x0814	/* RW	Auto LTR Value */
 
@@ -566,8 +575,12 @@
  *	10	(reserved)
  *	11	I2C host controller is in reset.
  */
-#define IG4_RESETS_ASSERT	0x0003
-#define IG4_RESETS_DEASSERT	0x0000
+#define IG4_RESETS_ASSERT_HSW	0x0003
+#define IG4_RESETS_DEASSERT_HSW	0x0000
+
+/* Skylake-U/Y and Kaby Lake-U/Y have the reset bits inverted */
+#define IG4_RESETS_DEASSERT_SKL	0x0003
+#define IG4_RESETS_ASSERT_SKL	0x0000
 
 /*
  * GENERAL - (RW) General Reigster				22.2.38

Modified: head/sys/dev/ichiic/ig4_var.h
==============================================================================
--- head/sys/dev/ichiic/ig4_var.h	Tue Mar  6 23:28:12 2018	(r330557)
+++ head/sys/dev/ichiic/ig4_var.h	Tue Mar  6 23:39:43 2018	(r330558)
@@ -47,6 +47,7 @@
 #define IG4_RBUFMASK	(IG4_RBUFSIZE - 1)
 
 enum ig4_op { IG4_IDLE, IG4_READ, IG4_WRITE };
+enum ig4_vers { IG4_HASWELL, IG4_ATOM, IG4_SKYLAKE };
 
 struct ig4iic_softc {
 	device_t	dev;
@@ -58,6 +59,7 @@ struct ig4iic_softc {
 	int		intr_rid;
 	void		*intr_handle;
 	int		intr_type;
+	enum ig4_vers	version;
 	enum ig4_op	op;
 	int		cmd;
 	int		rnext;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201803062339.w26NdhEl098447>