diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index 987dc6512a3c5e4f80182e71b21635659835117b..85386da47a047db176860653a5e568483f6467b3 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -54,6 +54,7 @@ enum {
 	X86_NONE,
 	X86_SYSCON_ME,		/* Intel Management Engine */
 	X86_SYSCON_GMA,		/* Intel Graphics Media Accelerator */
+	X86_SYSCON_PINCONF,	/* Intel x86 pin configuration */
 };
 
 struct cpuid_result {
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index 6e0234af5bd1ead74c31578c367ae860c687b854..dc90df205005d37c2a5d3b8f0bbd9061ceacd5d4 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -23,6 +23,7 @@ obj-y += cmd_mtrr.o
 obj-y	+= northbridge-uclass.o
 obj-$(CONFIG_I8259_PIC) += i8259.o
 obj-$(CONFIG_I8254_TIMER) += i8254.o
+obj-y	+= pinctrl_ich6.o
 obj-y	+= pirq_routing.o
 obj-y	+= relocate.o
 obj-y += physmem.o
diff --git a/arch/x86/lib/pinctrl_ich6.c b/arch/x86/lib/pinctrl_ich6.c
new file mode 100644
index 0000000000000000000000000000000000000000..3f94cdf2dacad9dfee75081a22df4764c39b9e14
--- /dev/null
+++ b/arch/x86/lib/pinctrl_ich6.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2016 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <pch.h>
+#include <pci.h>
+#include <asm/cpu.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/pci.h>
+#include <dm/pinctrl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define GPIO_USESEL_OFFSET(x)	(x)
+#define GPIO_IOSEL_OFFSET(x)	(x + 4)
+#define GPIO_LVL_OFFSET(x)	((x) ? (x) + 8 : 0xc)
+#define GPI_INV			0x2c
+
+#define IOPAD_MODE_MASK			0x7
+#define IOPAD_PULL_ASSIGN_SHIFT		7
+#define IOPAD_PULL_ASSIGN_MASK		(0x3 << IOPAD_PULL_ASSIGN_SHIFT)
+#define IOPAD_PULL_STRENGTH_SHIFT	9
+#define IOPAD_PULL_STRENGTH_MASK	(0x3 << IOPAD_PULL_STRENGTH_SHIFT)
+
+static int ich6_pinctrl_set_value(uint16_t base, unsigned offset, int value)
+{
+	if (value)
+		setio_32(base, 1UL << offset);
+	else
+		clrio_32(base, 1UL << offset);
+
+	return 0;
+}
+
+static int ich6_pinctrl_set_function(uint16_t base, unsigned offset, int func)
+{
+	if (func)
+		setio_32(base, 1UL << offset);
+	else
+		clrio_32(base, 1UL << offset);
+
+	return 0;
+}
+
+static int ich6_pinctrl_set_direction(uint16_t base, unsigned offset, int dir)
+{
+	if (!dir)
+		setio_32(base, 1UL << offset);
+	else
+		clrio_32(base, 1UL << offset);
+
+	return 0;
+}
+
+static int ich6_pinctrl_cfg_pin(s32 gpiobase, s32 iobase, int pin_node)
+{
+	bool is_gpio, invert;
+	u32 gpio_offset[2];
+	int pad_offset;
+	int dir, val;
+	int ret;
+
+	/*
+	 * GPIO node is not mandatory, so we only do the pinmuxing if the
+	 * node exists.
+	 */
+	ret = fdtdec_get_int_array(gd->fdt_blob, pin_node, "gpio-offset",
+				   gpio_offset, 2);
+	if (!ret) {
+		/* Do we want to force the GPIO mode? */
+		is_gpio = fdtdec_get_bool(gd->fdt_blob, pin_node, "mode-gpio");
+		if (is_gpio)
+			ich6_pinctrl_set_function(GPIO_USESEL_OFFSET(gpiobase) +
+						gpio_offset[0], gpio_offset[1],
+						1);
+
+		dir = fdtdec_get_int(gd->fdt_blob, pin_node, "direction", -1);
+		if (dir != -1)
+			ich6_pinctrl_set_direction(GPIO_IOSEL_OFFSET(gpiobase) +
+						 gpio_offset[0], gpio_offset[1],
+						 dir);
+
+		val = fdtdec_get_int(gd->fdt_blob, pin_node, "output-value",
+				     -1);
+		if (val != -1)
+			ich6_pinctrl_set_value(GPIO_LVL_OFFSET(gpiobase) +
+					     gpio_offset[0], gpio_offset[1],
+					     val);
+
+		invert = fdtdec_get_bool(gd->fdt_blob, pin_node, "invert");
+		if (invert)
+			setio_32(gpiobase + GPI_INV, 1 << gpio_offset[1]);
+		debug("gpio %#x bit %d, is_gpio %d, dir %d, val %d, invert %d\n",
+		      gpio_offset[0], gpio_offset[1], is_gpio, dir, val,
+		      invert);
+	}
+
+	/* if iobase is present, let's configure the pad */
+	if (iobase != -1) {
+		int iobase_addr;
+
+		/*
+		 * The offset for the same pin for the IOBASE and GPIOBASE are
+		 * different, so instead of maintaining a lookup table,
+		 * the device tree should provide directly the correct
+		 * value for both mapping.
+		 */
+		pad_offset = fdtdec_get_int(gd->fdt_blob, pin_node,
+					    "pad-offset", -1);
+		if (pad_offset == -1)
+			return 0;
+
+		/* compute the absolute pad address */
+		iobase_addr = iobase + pad_offset;
+
+		/*
+		 * Do we need to set a specific function mode?
+		 * If someone put also 'mode-gpio', this option will
+		 * be just ignored by the controller
+		 */
+		val = fdtdec_get_int(gd->fdt_blob, pin_node, "mode-func", -1);
+		if (val != -1)
+			clrsetbits_le32(iobase_addr, IOPAD_MODE_MASK, val);
+
+		/* Configure the pull-up/down if needed */
+		val = fdtdec_get_int(gd->fdt_blob, pin_node, "pull-assign", -1);
+		if (val != -1)
+			clrsetbits_le32(iobase_addr,
+					IOPAD_PULL_ASSIGN_MASK,
+					val << IOPAD_PULL_ASSIGN_SHIFT);
+
+		val = fdtdec_get_int(gd->fdt_blob, pin_node, "pull-strength",
+				     -1);
+		if (val != -1)
+			clrsetbits_le32(iobase_addr,
+					IOPAD_PULL_STRENGTH_MASK,
+					val << IOPAD_PULL_STRENGTH_SHIFT);
+
+		debug("%s: pad cfg [0x%x]: %08x\n", __func__, pad_offset,
+		      readl(iobase_addr));
+	}
+
+	return 0;
+}
+
+static int ich6_pinctrl_probe(struct udevice *dev)
+{
+	struct udevice *pch;
+	int pin_node;
+	int ret;
+	u32 gpiobase;
+	u32 iobase = -1;
+
+	debug("%s: start\n", __func__);
+	ret = uclass_first_device(UCLASS_PCH, &pch);
+	if (ret)
+		return ret;
+	if (!pch)
+		return -ENODEV;
+
+	/*
+	 * Get the memory/io base address to configure every pins.
+	 * IOBASE is used to configure the mode/pads
+	 * GPIOBASE is used to configure the direction and default value
+	 */
+	ret = pch_get_gpio_base(pch, &gpiobase);
+	if (ret) {
+		debug("%s: invalid GPIOBASE address (%08x)\n", __func__,
+		      gpiobase);
+		return -EINVAL;
+	}
+
+	/*
+	 * Get the IOBASE, this is not mandatory as this is not
+	 * supported by all the CPU
+	 */
+	ret = pch_get_io_base(pch, &iobase);
+	if (ret && ret != -ENOSYS) {
+		debug("%s: invalid IOBASE address (%08x)\n", __func__, iobase);
+		return -EINVAL;
+	}
+
+	for (pin_node = fdt_first_subnode(gd->fdt_blob, dev->of_offset);
+	     pin_node > 0;
+	     pin_node = fdt_next_subnode(gd->fdt_blob, pin_node)) {
+		/* Configure the pin */
+		ret = ich6_pinctrl_cfg_pin(gpiobase, iobase, pin_node);
+		if (ret != 0) {
+			debug("%s: invalid configuration for the pin %d\n",
+			      __func__, pin_node);
+			return ret;
+		}
+	}
+	debug("%s: done\n", __func__);
+
+	return 0;
+}
+
+static const struct udevice_id ich6_pinctrl_match[] = {
+	{ .compatible = "intel,x86-pinctrl", .data = X86_SYSCON_PINCONF },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(ich6_pinctrl) = {
+	.name = "ich6_pinctrl",
+	.id = UCLASS_SYSCON,
+	.of_match = ich6_pinctrl_match,
+	.probe = ich6_pinctrl_probe,
+};
diff --git a/doc/device-tree-bindings/gpio/intel,x86-pinctrl.txt b/doc/device-tree-bindings/gpio/intel,x86-pinctrl.txt
index 45ab1afc395d1e919a856d6fdcb00fe2769680fa..be5d51cc19ae245496c1aeddae63027bd7eac32e 100644
--- a/doc/device-tree-bindings/gpio/intel,x86-pinctrl.txt
+++ b/doc/device-tree-bindings/gpio/intel,x86-pinctrl.txt
@@ -19,6 +19,7 @@ in case of 'mode-gpio' property set:
 - direction         - (optional) this set the direction of the gpio.
 - pull-str          - (optional) this set the pull strength of the pin.
 - pull-assign       - (optional) this set the pull assignement (up/down) of the pin.
+- invert            - (optional) this input pin is inverted
 
 Example: